CDRoutingObjectsImpl.mesa
Copyright © 1987 by Xerox Corporation. All rights reversed.
Created by: Christian Jacobi, March 16, 1987 4:50:53 pm PST
Last edited by: Christian Jacobi, April 17, 1987 10:51:07 am PDT
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.scaleHint<rp.scaleHint AND pr.scaleHint>0 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.scaleHint<rp.scaleHint AND pr.scaleHint>0 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.