CDSplitWireCommands.mesa (part of ChipNDale)
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Last Edited by: Monier, July 24, 1984 11:31:03 am PDT
Last Edited by: Jacobi, Jacobi, April 11, 1985 9:18:19 am PST
Last Edited by: Bertrand Serlet October 6, 1985 6:44:38 pm PDT
Last Edited by: Jacobi, July 23, 1986 3:31:45 pm PDT
DIRECTORY
CD,
CDInstances,
CDBasics,
CDRects,
CDSequencer,
CDCallSpecific,
CDOps,
CDOrient,
CDProperties,
TerminalIO;
CDSplitWireCommands: CEDAR PROGRAM
IMPORTS CDInstances, CDBasics, CDOps, CDOrient, CDProperties, CDSequencer, TerminalIO, CDRects =
BEGIN
SplitApplication: PROC [design: CD.Design, inst: CD.Instance, from, to: CD.Position] =
BEGIN
NearlyRoundToLambda: PROC[x: CD.Number] RETURNS[r: CD.Number] =
BEGIN
lambda: CD.Number = design.technology.lambda;
r ← (x/lambda)*lambda;
END;
cutPos: CD.Position;
L1, L2, W1, W2: CD.Number;
wireLeft, wireRight: CD.Object;
inter: CD.Position; -- the intersection of the two lines, if any, and the center of the wire
oldRect: CD.Rect ← CDInstances.InstRectI[inst]; -- the bounding box
oldSize: CD.Position ← CDBasics.SizeOfRect[oldRect];
vertical: BOOL ← oldSize.y > oldSize.x;
dx: CD.Number ← to.x-from.x; dy: CD.Number ← to.y-from.y;
ctr: CD.Position ← CDBasics.Center[oldRect];
--Test if vector parallel to wire
IF vertical AND (dx=0) OR (NOT vertical) AND (dy=0) THEN RETURN;
--Now we can divide and find the intersection of lines (not yet segments)
inter ← IF vertical
THEN [ctr.x, NearlyRoundToLambda[from.y+(dy*(ctr.x-from.x)/dx)]]
ELSE [NearlyRoundToLambda[dx*(ctr.y-from.y)/dy+from.x], ctr.y];
--Monier-Sindhu theorem: if inter is in cursorBox and in oldRect, then it is the intersection of segments
IF NOT (CDBasics.InsidePos[inter, CDBasics.ToRect[from, to]] AND CDBasics.InsidePos[inter, CDBasics.Extend[oldRect, -1]]) THEN RETURN;
cutPos ← IF vertical THEN [oldRect.x1, inter.y] ELSE [inter.x, oldRect.y1];
IF vertical THEN {
L1 ← cutPos.y - oldRect.y1;
L2 ← oldSize.y - L1;
W1 ← W2 ← oldSize.x;
}
ELSE {
L1 ← L2 ← oldSize.y;
W1 ← cutPos.x - oldRect.x1;
W2 ← oldSize.x - W1;
};
wireLeft ← CDRects.CreateRect[CDOrient.OrientedSize[[W1, L1], inst.orientation], inst.ob.layer];
wireRight ← CDRects.CreateRect[CDOrient.OrientedSize[[W2, L2], inst.orientation], inst.ob.layer];
CDOps.IncludeInstance[design, CDInstances.NewInstI[wireLeft, CDBasics.BaseOfRect[oldRect], inst.orientation, TRUE, CDProperties.DCopyProps[inst.properties]], FALSE];
CDOps.IncludeInstance[design, CDInstances.NewInstI[wireRight, cutPos, inst.orientation, TRUE, CDProperties.DCopyProps[inst.properties]], FALSE];
CDOps.RemoveInstance[design, inst];
END;
DoAllSplits: PROC [design: CD.Design, from, to: CD.Position, pointed: BOOLFALSE] =
BEGIN
--The mouse track defines the cut vector. Let's define the "spine" of a wire as the centerline, roughly in the middle (lambda) and following the visible length, i.e. the longer edge, not the CD length. Then we cut the wire at the position where the spine meets the cut vector. The cut always reduces the visible length of the wire. (Pff, not easy to describe without drawing!)
--A vertical wire freshly drawn has even (0) orientation.
FOR list: CD.InstanceList ← CDOps.InstList[design], list.rest WHILE list#NIL DO
IF list.first.selected AND list.first.ob.class.wireTyped THEN SplitApplication[design, list.first, from, to];
ENDLOOP;
END;
SplitWireCommandS: PROC [comm: CDSequencer.Command] =
BEGIN
TerminalIO.WriteRope["split selected\n"];
DoAllSplits[design: comm.design, from: comm.sPos, to: comm.pos, pointed: FALSE]
END;
CDSequencer.ImplementCommand[$SplitWireS, SplitWireCommandS];
END.