<> <> <> <> DIRECTORY CD, CDBasics, CDBasicsInline, CDCells, CDDirectory, CDInstances, CDIO, CDLayers, CDProperties, CDRects, CDRoutingObjects, Process, SymTab, TokenIO; CDRoutingObjectsImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDBasicsInline, CDCells, CDDirectory, CDInstances, CDIO, CDLayers, CDProperties, CDRects, Process, SymTab, TokenIO EXPORTS CDRoutingObjects SHARES CDDirectory, CDRects = BEGIN OPEN CDRoutingObjects; <<>> TestLength: PROC [n: INT, last: INT] RETURNS [NAT] = { IF n>=last THEN ERROR; RETURN [n]; }; Bounds: PROC [rp: RoutingSpecific] RETURNS [ir, bbox: CD.Rect _ CDBasics.empty] = { FOR i: NAT IN [0 .. rp.size) DO node: Node = rp[i]; FOR j: NAT IN [0 .. node.size) DO bbox _ CDBasics.Surround[bbox, CDBasics.MoveRect[node[j].object.bbox, node[j].position]]; IF ~CDLayers.SuppressIR[node[j].object.layer] THEN ir _ CDBasics.Surround[ir, CDBasics.MoveRect[CD.InterestRect[node[j].object], node[j].position]]; ENDLOOP; ENDLOOP; bbox _ CDBasics.Surround[bbox, ir]; }; CreateRoutingObject: PUBLIC PROC [nodes: LIST OF Node, ir: CD.Rect] RETURNS [routing: CD.Object] = { rp: RoutingSpecific; irx: CD.Rect; size: NAT; cnt: INT _ 0; FOR list: LIST OF Node _ nodes, list.rest WHILE list#NIL DO cnt _ cnt + 1 ENDLOOP; size _ TestLength[cnt, 32760]; rp _ NEW[RoutingRep[size]]; FOR i: NAT IN [0 .. size) DO rp[i] _ nodes.first; nodes _ nodes.rest ENDLOOP; routing _ NEW[CD.ObjectRep _ [class: routingClass, specific: rp]]; [irx, routing.bbox] _ Bounds[rp]; rp.ir _ (IF CDBasics.NonEmpty[ir] THEN ir ELSE irx); IF ~CDBasics.NonEmpty[rp.ir] THEN { rp.ir _ routing.bbox; IF ~CDBasics.NonEmpty[rp.ir] THEN rp.ir _ [0, 0, 1, 1]; }; routing.bbox _ CDBasics.Surround[rp.ir, routing.bbox]; SetSimplificationTreshhold[routing]; }; <<>> CreateNode: PUBLIC PROC [geometry: LIST OF PlacedObject, properties: CD.PropList _ NIL] RETURNS [node: Node] = { size: NAT; cnt: INT _ 0; FOR list: LIST OF PlacedObject _ geometry, list.rest WHILE list#NIL DO cnt _ cnt + 1 ENDLOOP; size _ TestLength[cnt, 13000]; node _ NEW[NodeRep[size]]; node.properties _ CDProperties.DCopyProps[properties]; --skip uncopyable entries right now FOR i: NAT IN [0 .. size) DO node[i] _ geometry.first; geometry _ geometry.rest ENDLOOP; }; CreateNodes: PUBLIC PROC [table: SymTab.Ref] RETURNS [nodes: LIST OF Node _ NIL] = { EachPair: SymTab.EachPairAction = { geometry: REF LIST OF PlacedObject = NARROW[val]; node: Node = CreateNode[geometry^, LIST [[key: $SignalName, val: key]]]; nodes _ CONS[node, nodes]; }; [] _ SymTab.Pairs[table, EachPair]; }; InterestRectRO: CD.RectProc = { RETURN [NARROW[ob.specific, RoutingSpecific].ir]; }; ExpandRO: CDDirectory.ExpandProc = { rp: RoutingSpecific = NARROW[me.specific]; instances: LIST OF CD.Instance _ NIL; topAccessible _ childAccessible _ TRUE; FOR i: NAT IN [0 .. rp.size) DO node: Node = rp[i]; FOR j: NAT IN [0 .. node.size) DO IF node[j].object.class.composed AND ~node[j].object.immutable THEN childAccessible _ FALSE; instances _ CONS [ CDInstances.NewInst[ ob: node[j].object, trans: [node[j].position], properties: CDProperties.DCopyProps[node.properties] ], instances]; ENDLOOP; ENDLOOP; new _ CDCells.CreateCell[il: instances, ir: rp.ir]; CDCells.ToSequenceMode[new]; IF into#NIL THEN { CDDirectory.SetOwner[into, new, FALSE]; IF fromOrNil=into THEN childAccessible _ TRUE; }; }; MyCompose: PROC [posInRO: CD.Position, rOInWorld: CD.Transformation] RETURNS [CD.Transformation] = INLINE { RETURN [[ off: CDBasicsInline.MapPoint[posInRO, rOInWorld], orient: rOInWorld.orient ]]; }; DrawSelectionRO: CD.DrawProc = { rp: RoutingSpecific = NARROW[ob.specific]; IF pr.scaleHint0 THEN pr.drawRect[pr, CDBasics.MapRect[rp.ir, trans], CD.shadeLayer] ELSE pr.drawOutLine[pr, CDBasics.MapRect[rp.ir, trans], CD.selectionLayer] }; DrawMeRO: CD.DrawProc = { mapClip: CD.Rect _ CDBasics.DeMapRect[pr.interestClip, trans].itemInCell; <<--clipping boundary in object coordinates>> rp: RoutingSpecific _ NARROW[ob.specific]; FOR i: NAT IN [0 .. rp.size) DO node: Node = rp[i]; IF pr.stopFlag^ THEN RETURN; FOR j: NAT IN [0 .. node.size) DO IF CDBasics.Intersect[mapClip, CDBasics.MoveRect[node[j].object.bbox, node[j].position]] THEN { pr.drawChild[pr, node[j].object, MyCompose[node[j].position, trans], node.properties]; } ENDLOOP; ENDLOOP; }; QuickDrawMeRO: CD.DrawProc = { rp: RoutingSpecific _ NARROW[ob.specific]; IF pr.scaleHint0 THEN pr.drawOutLine[pr, CDBasics.MapRect[rp.ir, trans], CD.outlineLayer] ELSE { mapClip: CD.Rect _ CDBasics.DeMapRect[pr.interestClip, trans].itemInCell; <<--clipping boundary in object coordinates>> FOR i: NAT IN [0 .. rp.size) DO node: Node = rp[i]; IF pr.stopFlag^ THEN RETURN; FOR j: NAT IN [0 .. node.size) DO IF CDBasics.Intersect[mapClip, CDBasics.MoveRect[node[j].object.bbox, node[j].position]] THEN { IF node[j].object.class=CDRects.bareRectClass THEN pr.drawRect[pr: pr, r: CDBasicsInline.MapRect[node[j].object.bbox, MyCompose[node[j].position, trans]], l: node[j].object.layer ] ELSE node[j].object.class.quickDrawMe[pr: pr, ob: node[j].object, trans: MyCompose[node[j].position, trans], readOnlyInstProps: node.properties ]; } ENDLOOP; Process.Yield[]; ENDLOOP; IF pr.checkPriority THEN pr.priorityChecker[pr]; } }; EnumerateChildObjectsRO: CDDirectory.EnumerateChildObjectsProc = { rp: RoutingSpecific _ NARROW[me.specific]; FOR i: NAT IN [0 .. rp.size) DO node: Node = rp[i]; FOR j: NAT IN [0 .. node.size) DO IF node[j].object.class.composed THEN IF quit _ proc[node[j].object, data] THEN RETURN; ENDLOOP; ENDLOOP; }; ReplaceDChildsRO: CDDirectory.ReplaceDChildsProc = { rp: RoutingSpecific _ NARROW[me.specific]; FOR i: NAT IN [0 .. rp.size) DO node: Node = rp[i]; FOR j: NAT IN [0 .. node.size) DO FOR replaceList: CDDirectory.ReplaceList _ replace, replaceList.rest WHILE replaceList#NIL DO IF replaceList.first.old=node[j].object THEN { IF me.immutable THEN ERROR; changed _ TRUE; node[j].position _ CDBasics.AddPoints[node[j].position, replaceList.first.trans.off]; <<--we ignore rotations... [They are not used in inter design copy]>> node[j].object _ replaceList.first.old; }; ENDLOOP; ENDLOOP; ENDLOOP; IF changed THEN { bbox: CD.Rect _ Bounds[rp].bbox; IF ~CDBasics.NonEmpty[bbox] THEN bbox _ [0, 0, 1, 1]; IF bbox#me.bbox THEN { me.bbox _ bbox; CDDirectory.PropagateResize[design, me]; }; } }; AnotherRO: CDDirectory.AnotherProc = { CopyNode: PROC [node: Node] RETURNS [new: Node] = { size: NAT _ node.size; new _ NEW[NodeRep[size]]; new.properties _ CDProperties.DCopyProps[node.properties]; FOR i: NAT IN [0 .. size) DO new[i] _ node[i]; IF new[i].object.class.composed AND ~new[i].object.immutable THEN childAccessible _ FALSE; ENDLOOP; }; rpo: RoutingSpecific = NARROW[me.specific]; rpn: RoutingSpecific = NEW[RoutingRep[rpo.size]]; childAccessible _ TRUE; new _ NEW[CD.ObjectRep _ [class: routingClass, specific: rpn, bbox: me.bbox, properties: CDProperties.DCopyProps[me.properties]]]; rpn.ir _ rpo.ir; rpn.scaleHint _ rpo.scaleHint; FOR i: NAT IN [0 .. rpn.size) DO rpn[i] _ CopyNode[rpo[i]] ENDLOOP; IF into#NIL THEN { CDDirectory.SetOwner[into, new, FALSE]; IF fromOrNil=into THEN childAccessible _ TRUE; }; }; WriteRO: CD.InternalWriteProc = { WritePO: PROC [h: TokenIO.Handle, po: PlacedObject] = INLINE { CDIO.WriteObject[h, po.object]; CDIO.WritePos[h, po.position]; bbox _ CDBasics.Surround[bbox, CDBasics.MoveRect[po.object.bbox, po.position]]; }; WriteNode: PROC [h: TokenIO.Handle, node: Node] = { size: NAT = node.size; TokenIO.WriteInt[h, size]; CDIO.WriteProperties[h, node.properties]; FOR i: NAT IN [0 .. size) DO WritePO[h, node[i]] ENDLOOP; }; rp: RoutingSpecific _ NARROW[ob.specific]; bbox: CD.Rect _ rp.ir; size: NAT = rp.size; CDIO.WriteRect[h, ob.bbox]; --this is not efficient but it is a good convention to store bbox TokenIO.WriteInt[h, size]; CDIO.WriteRect[h, rp.ir]; TokenIO.WriteReal[h, rp.scaleHint]; FOR i: NAT IN [0 .. size) DO WriteNode[h, rp[i]] ENDLOOP; IF ob.bbox#bbox THEN ERROR; --some fool fooled arround with the object }; ReadRO: CD.InternalReadProc = { ReadPO: PROC [h: TokenIO.Handle] RETURNS [po: PlacedObject] = INLINE { po.object _ CDIO.ReadObject[h]; po.position _ CDIO.ReadPos[h]; }; ReadNode: PROC [h: TokenIO.Handle] RETURNS [node: Node] = { size: NAT _ TokenIO.ReadInt[h]; node _ NEW[NodeRep[size]]; node.properties _ CDIO.ReadProperties[h]; FOR i: NAT IN [0 .. size) DO node[i] _ ReadPO[h] ENDLOOP; }; bbox: CD.Rect _ CDIO.ReadRect[h]; nodeNum: NAT _ TokenIO.ReadInt[h]; rp: RoutingSpecific = NEW[RoutingRep[nodeNum]]; ob: CD.Object _ NEW[CD.ObjectRep _ [class: routingClass, specific: rp, bbox: bbox]]; rp.ir _ CDIO.ReadRect[h]; rp.scaleHint _ TokenIO.ReadReal[h]; FOR i: NAT IN [0 .. nodeNum) DO rp[i] _ ReadNode[h] ENDLOOP; CDDirectory.SetOwner[CDIO.DesignInReadOperation[h], ob]; RETURN [ob]; }; SetSimplificationTreshhold: PUBLIC PROC [ro: CD.Object, val: REAL_-1] = { IF val<=0 THEN val _ 50; WITH ro.specific SELECT FROM rp: RoutingSpecific => IF val<0 THEN rp.scaleHint _ 100.0/MAX[(ro.bbox.y2-ro.bbox.y1)+(ro.bbox.x2-ro.bbox.x1), 2] ELSE rp.scaleHint _ val/MAX[(ro.bbox.y2-ro.bbox.y1), 1]; ENDCASE => NULL; }; routingClass: PUBLIC CD.ObjectClass _ CD.RegisterObjectClass[$RoutingObject, [ drawMe: DrawMeRO, quickDrawMe: QuickDrawMeRO, showMeSelected: DrawSelectionRO, internalRead: ReadRO, internalWrite: WriteRO, interestRect: InterestRectRO, description: "routing object" ]]; [] _ CDDirectory.InstallDirectoryProcs[routingClass, [ enumerateChildObjects: EnumerateChildObjectsRO, another: AnotherRO, replaceDirectChilds: ReplaceDChildsRO, expand: ExpandRO ]]; END.