CDSymbolicObjectsImpl.mesa (part of ChipNDale)
Copyright © 1984, 1986 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, August 8, 1984 12:41:50 pm PDT
Last Edited by: Christian Jacobi, October 30, 1986 3:18:24 pm PST
DIRECTORY
CD,
CDInstances,
CDBasics,
CDCells,
CDLayers USING [MakeAbstract, AbstractToPaint],
CDImports,
CDIO,
CDOps,
CDSymbolicObjects,
CDPrivate,
CDProperties,
CDRects,
Imager,
ImagerPath,
LRUCache,
Rope;
CDSymbolicObjectsImpl:
CEDAR
MONITOR
IMPORTS CD, CDInstances, CDBasics, CDCells, CDLayers, CDIO, CDOps, CDPrivate, CDProperties, CDRects, Imager, ImagerPath, LRUCache, Rope
EXPORTS CDSymbolicObjects
SHARES CDLayers =
BEGIN
symNameProp: ATOM = $SignalName;
symLayerProp: ATOM = $layerOfPin;
symOwnerProp: ATOM = $ownerOfPin;
markObject:
CD.Object;
markObjectPath: ImagerPath.Trajectory = CreateMarkObjectPath[];
dummySpecific:
REF SymRec =
NEW[SymRec];
SymRec: TYPE = RECORD [dummy: INT ← 17];
pinLayer: PUBLIC CD.Layer ← CD.NewLayer[NIL, $pinRepresentation];
segmentLayer: PUBLIC CD.Layer ← CD.NewLayer[NIL, $segmentRepresentation];
markLayer: CD.Layer ← CD.undefLayer;
lruQueue: LRUCache.Handle ← LRUCache.Create[87, CDPrivate.Hash, Equal];
freePin: CD.Object ← NIL; --reduces the allocators work
freeSegment: CD.Object ← NIL;
GivePin:
ENTRY
PROC []
RETURNS [ob:
CD.Object] =
INLINE {
ob ← freePin; freePin ← NIL;
IF ob=
NIL
THEN
ob ← NEW[CD.ObjectRep←[class: pinClass, specific: dummySpecific, layer: pinLayer]];
};
GiveSegment:
ENTRY
PROC []
RETURNS [ob:
CD.Object] =
INLINE {
ob ← freeSegment; freeSegment ← NIL;
IF ob=
NIL
THEN
ob ← NEW[CD.ObjectRep←[class: segmentClass, specific: dummySpecific, layer: segmentLayer]];
};
Equal:
PROC[x, y:
REF]
RETURNS [
BOOL] = {
ob1: CD.Object = NARROW[x];
ob2: CD.Object = NARROW[y];
RETURN [ob1.class=ob2.class AND ob1.bbox=ob2.bbox AND ob1.layer=ob2.layer]
};
pinClass:
PUBLIC
CD.ObjectClass ←
CD.RegisterObjectClass[$PinOb0, [
drawMe: DrawPin,
quickDrawMe: DrawPin,
showMeSelected: ShowSelectedSymRL,
internalRead: ReadPin,
internalWrite: WritePinOrSegment,
wireTyped: TRUE,
symbolic: TRUE,
description: "pin",
describeInst: DescribeInstance,
newLayer: ChangePinLayer
]];
segmentClass:
PUBLIC
CD.ObjectClass ←
CD.RegisterObjectClass[$SymbolicSegment, [
drawMe: DrawSegment,
quickDrawMe: DrawSegment,
showMeSelected: ShowSelectedSymRL,
internalRead: ReadSegment,
internalWrite: WritePinOrSegment,
wireTyped: TRUE,
symbolic: TRUE,
description: "segment",
describeInst: DescribeInstance,
newLayer: ChangePinLayer
]];
markClass:
PUBLIC
CD.ObjectClass ←
CD.RegisterObjectClass[$AlignmentMarkOb, [
drawMe: DrawMark,
quickDrawMe: DrawMark,
internalRead: ReadMark,
internalWrite: WriteMark,
symbolic: TRUE,
description: "mark",
newLayer: ChangePinLayer
]];
CreateMarkObjectPath:
PROC []
RETURNS [markObjectPath: ImagerPath.Trajectory] = {
markObjectPath ← ImagerPath.MoveTo[[0, 0]];
markObjectPath ← ImagerPath.LineTo[markObjectPath, [0, 3]];
markObjectPath ← ImagerPath.LineTo[markObjectPath, [1, 2]];
markObjectPath ← ImagerPath.LineTo[markObjectPath, [3, 4]];
markObjectPath ← ImagerPath.LineTo[markObjectPath, [4, 3]];
markObjectPath ← ImagerPath.LineTo[markObjectPath, [2, 1]];
markObjectPath ← ImagerPath.LineTo[markObjectPath, [3, 0]];
markObjectPath ← ImagerPath.LineTo[markObjectPath, [0, 0]];
};
Init:
PROC [] = {
--rects
CDLayers.MakeAbstract[pinLayer];
CDRects.UseAsCreateRect[pinLayer, RCreatePin, pinClass];
--lines
CDLayers.MakeAbstract[segmentLayer];
CDRects.UseAsCreateRect[segmentLayer, RCreateSegment, segmentClass];
--points
markObject ←
NEW[
CD.ObjectRep ← [
class: markClass,
bbox: [0, 0, 4, 4],
layer: markLayer,
specific: $AlignmentMarkOb
]];
--common
[] ← CDProperties.RegisterProperty[symLayerProp, $layer];
[] ← CDProperties.RegisterProperty[symOwnerProp, $atom];
CDProperties.InstallProcs[prop: symOwnerProp, procs: [makeCopy: CDProperties.CopyVal]];
CDProperties.InstallProcs[prop: symLayerProp, procs: [makeCopy: CDProperties.CopyVal]];
};
CreateMark:
PUBLIC
PROC [dummySize:
CD.Number𡤀]
RETURNS [
CD.Object] = {
RETURN [markObject]
};
CreateSegment:
PUBLIC
PROC [length:
CD.Number, dummyWidth:
CD.Number𡤀]
RETURNS [ob:
CD.Object] = {
used: REF; insert: BOOL;
ob ← GiveSegment[];
IF dummyWidth<=0 THEN dummyWidth ← 8;
ob.bbox ← CDPrivate.MinBBox[[dummyWidth, length]];
[insert: insert, used: used] ← LRUCache.Include[lruQueue, ob];
IF ~insert
THEN {
freeSegment ← ob;
ob ← NARROW[used];
};
};
RCreateSegment:
PROC [size:
CD.Position, l:
CD.Layer]
RETURNS [
CD.Object] = {
RETURN [CreateSegment[size.y, size.x]]
};
CreatePin:
PUBLIC
PROC [size:
CD.Position]
RETURNS [ob:
CD.Object] = {
used: REF; insert: BOOL;
ob ← GivePin[];
ob.bbox ← CDPrivate.MinBBox[size];
[insert: insert, used: used] ← LRUCache.Include[lruQueue, ob];
IF ~insert THEN {freePin ← ob; ob ← NARROW[used]};
};
RCreatePin:
PROC [size:
CD.Position, l:
CD.Layer]
RETURNS [
CD.Object] = {
--has the right form for CDRects type
RETURN [CreatePin[size]]
};
IsSymbolicOb:
PUBLIC
PROC [ob:
CD.Object]
RETURNS [
BOOL] = {
RETURN [ob.class=markClass OR ob.class=segmentClass OR ob.class=pinClass]
};
IsMark:
PUBLIC
PROC [ob:
CD.Object]
RETURNS [
BOOL] = {
RETURN [ob.class=markClass]
};
IsSegment:
PUBLIC
PROC [ob:
CD.Object]
RETURNS [
BOOL] = {
RETURN [ob.class=segmentClass]
};
IsPin:
PUBLIC
PROC [ob:
CD.Object]
RETURNS [
BOOL] = {
RETURN [ob.class=pinClass]
};
SymbolicKind:
PUBLIC
PROC [ob:
CD.Object]
RETURNS [k: CDSymbolicObjects.Kind] = {
SELECT
TRUE
FROM
ob.class=pinClass => k ← pin;
ob.class=segmentClass => k ← segment;
ob.class=markClass => k ← mark;
ENDCASE => k ← notSymbolic
};
SetOwner:
PUBLIC PROC [symInst:
CD.Instance, owner:
ATOM←
NIL] = {
IF IsSymbolicOb[symInst.ob]
THEN
CDProperties.PutInstanceProp[symInst, symOwnerProp, owner]
};
GetOwner:
PUBLIC PROC [symInst:
CD.Instance]
RETURNS [at:
ATOM] = {
WITH CDProperties.GetInstanceProp[symInst, symOwnerProp]
SELECT
FROM
a: ATOM => at ← a
ENDCASE => at ← NIL
};
SetName:
PUBLIC
PROC [symInst:
CD.Instance, name: Rope.
ROPE] = {
IF IsSymbolicOb[symInst.ob]
THEN
CDProperties.PutInstanceProp[symInst, symNameProp, name]
};
GetName:
PUBLIC
PROC [symInst:
CD.Instance]
RETURNS [r: Rope.
ROPE ←
NIL] = {
WITH CDProperties.GetInstanceProp[symInst, symNameProp]
SELECT
FROM
n: Rope.ROPE => r ← n;
rt: REF READONLY TEXT => r ← Rope.FromRefText[rt];
ENDCASE => NULL;
};
SetLayer:
PUBLIC
PROC [symInst:
CD.Instance, layer:
CD.Layer] = {
IF IsSymbolicOb[symInst.ob]
THEN
CDProperties.PutInstanceProp[symInst, symLayerProp, CDPrivate.layers[layer]]
};
GetLayer:
PUBLIC
PROC [symInst:
CD.Instance]
RETURNS [layer:
CD.Layer] = {
WITH CDProperties.GetInstanceProp[symInst, symLayerProp]
SELECT
FROM
lp: CDPrivate.LayerRef => layer ← lp^.number
ENDCASE => layer ← CD.undefLayer
};
DirectionFromOrient:
PUBLIC
PROC [o:
CD.Orientation]
RETURNS [dir: CDSymbolicObjects.Direction] = {
SELECT o
FROM
original, rotate180X => dir ← west;
rotate90, rotate90X => dir ← south;
rotate180, mirrorX => dir ← east;
rotate270, rotate270X => dir ← north;
ENDCASE => ERROR;
};
OrientFromDirection:
PUBLIC
PROC [dir: CDSymbolicObjects.Direction]
RETURNS [o:
CD.Orientation] = {
SELECT dir
FROM
west => o ← original;
south => o ← rotate90;
east => o ← rotate180;
north => o ← rotate270;
ENDCASE => ERROR;
};
OrderRect:
PROC [r:
CD.Rect]
RETURNS [
CD.Rect] = {
t: CD.Number;
IF r.x1>r.x2 THEN {t←r.x1; r.x1←r.x2; r.x2←t};
IF r.y1>r.y2 THEN {t←r.y1; r.y1←r.y2; r.y2←t};
RETURN [r]
};
CreateSymInst:
PUBLIC
PROC [name: Rope.
ROPE, denotes:
CD.Rect, dummySize:
CD.Number, layer:
CD.Layer, owner:
ATOM, approachFrom: CDSymbolicObjects.Direction]
RETURNS [symInst:
CD.Instance] = {
symOb: CD.Object;
orient: CD.Orientation ← OrientFromDirection[approachFrom];
loc: CD.Position;
denotes ← OrderRect[denotes];
IF denotes.x1#denotes.x2
AND denotes.y1#denotes.y2
THEN {
--pin
loc ← CDBasics.BaseOfRect[denotes];
symOb ← CreatePin[CDBasics.OrientedSize[CDBasics.SizeOfRect[denotes], orient]];
}
ELSE
IF denotes.x1=denotes.x2
AND denotes.y1=denotes.y2
THEN {
--mark
symOb ← CreateMark[dummySize];
loc ← [x: denotes.x1, y: denotes.y1];
}
ELSE {
--segment
l: CD.Number;
IF denotes.x1=denotes.x2
THEN {
l ← denotes.y2-denotes.y1;
IF approachFrom=south
OR approachFrom=north
THEN {
-- erroneous parameters..
approachFrom ← west;
orient ← OrientFromDirection[approachFrom];
}
}
ELSE {
l ← denotes.x2-denotes.x1;
IF approachFrom=west
OR approachFrom=east
THEN {
-- erroneous parameters..
approachFrom ← south;
orient ← OrientFromDirection[approachFrom];
}
};
symOb ← CreateSegment[length: l, dummyWidth: dummySize];
loc ← CDBasics.BaseOfRect[denotes];
SELECT approachFrom
FROM
west => NULL;
south => loc.x ← loc.x+symOb.bbox.y2;
east => loc.y ← loc.y+symOb.bbox.y2;
north => NULL;
ENDCASE => ERROR;
};
layer ← CDLayers.AbstractToPaint[layer];
symInst ← CDInstances.NewInst[ob: symOb, trans: [loc, orient]];
IF name#NIL THEN SetName[symInst, name];
IF layer#CD.undefLayer THEN SetLayer[symInst, layer];
IF owner#NIL THEN SetOwner[symInst, owner];
};
ObDenotes:
PROC [ob:
CD.Object]
RETURNS [
CD.Rect] = {
RETURN [
SELECT
TRUE
FROM
ob.class=pinClass => ob.bbox,
ob.class=segmentClass => [x1: 0, y1: 0, x2: 0, y2: ob.bbox.y2],
ob.class=markClass => [0, 0, 0, 0],
ENDCASE => CD.InterestRect[ob]]
};
Denotes:
PUBLIC
PROC [symInst:
CD.Instance]
RETURNS [
CD.Rect] = {
RETURN [CDBasics.MapRect[ObDenotes[symInst.ob], symInst.trans]]
};
EnumerateSymbolicObs:
PUBLIC
PROC [cellOb:
CD.Object←
NIL, eachInst: CDSymbolicObjects.InstEnumerator]
RETURNS [quit:
BOOL←
FALSE] = {
WITH cellOb.specific
SELECT
FROM
c:
CD.CellSpecific => {
EachInst: CDCells.InstEnumerator = {
IF IsSymbolicOb[inst.ob]
THEN
quit ← eachInst[inst]; -- do NOT catch errors
};
quit ← CDCells.EnumerateInstances[cellOb, EachInst];
};
ip: CDImports.ImportSpecific => {
-- HACK? until imports handle symbolic objects more reasonably
IF ip.boundInstance=NIL THEN RETURN [TRUE];
quit ← EnumerateSymbolicObs[ip.boundInstance.ob, eachInst];
RETURN
};
ENDCASE => RETURN [TRUE];
};
FindSymbolicObs:
PUBLIC
PROC [cellOb:
CD.Object←
NIL, name: Rope.
ROPE]
RETURNS [il:
CD.InstanceList←
NIL] = {
Enumerate: CDSymbolicObjects.InstEnumerator = {
IF Rope.Equal[GetName[inst], name] THEN il ← CONS[inst, il];
};
[] ← EnumerateSymbolicObs[cellOb, Enumerate];
};
WritePinOrSegment:
CD.InternalWriteProc = {
CDIO.WritePos[h, CDBasics.SizeOfRect[ob.bbox]];
};
WriteMark:
CD.InternalWriteProc = {
};
ReadPin:
CD.InternalReadProc = {
RETURN [CreatePin[CDIO.ReadPos[h]]]
};
ReadSegment:
CD.InternalReadProc = {
p: CD.Position ← CDIO.ReadPos[h];
RETURN [CreateSegment[p.y, p.x]]
};
ReadMark:
CD.InternalReadProc = {
RETURN [markObject]
};
DescribeInstance:
PROC[i:
CD.Instance]
RETURNS [Rope.
ROPE] = {
RETURN [Rope.Cat[CDOps.LayerRope[GetLayer[i]], " ", i.ob.class.description]];
};
ShowSelectedSymRL:
PROC [inst:
CD.Instance, trans:
CD.Transformation, pr:
CD.DrawRef] = {
pr.drawRect[CDBasics.MapRect[inst.ob.bbox, trans], CD.shadeLayer, pr]
};
DrawPin:
PROC [inst:
CD.Instance, trans:
CD.Transformation, pr:
CD.DrawRef] = {
DrawPinInContext:
PROC [context: Imager.Context, ob:
CD.Object, layer:
CD.Layer] = {
Imager.MaskVector[context, [0, 0], [ob.bbox.x2, ob.bbox.y2]];
Imager.MaskVector[context, [0, ob.bbox.y2], [ob.bbox.x2, 0]];
};
IF pr.symbolics
AND (pr.scaleHint*
MIN[inst.ob.bbox.y2, inst.ob.bbox.x2]>3
OR pr.scaleHint<=0)
THEN {
pr.drawContext[pr, DrawPinInContext, inst.ob, trans, pinLayer];
pr.drawComment[r: CDBasics.MapRect[inst.ob.bbox, trans], comment: GetName[inst], pr: pr]
};
};
DrawSegment:
PROC [inst:
CD.Instance, trans:
CD.Transformation, pr:
CD.DrawRef] = {
DrawSegmentInContext:
PROC [context: Imager.Context, ob:
CD.Object, layer:
CD.Layer] = {
Imager.MaskVector[context, [0, 0], [0, ob.bbox.y2]];
Imager.MaskVector[context, [0, 0], [ob.bbox.x2, ob.bbox.y2/2]];
Imager.MaskVector[context, [0, ob.bbox.y2], [ob.bbox.x2, ob.bbox.y2/2]];
};
IF pr.symbolics
AND (pr.scaleHint*inst.ob.bbox.y2>3
OR pr.scaleHint<=0)
THEN {
pr.drawContext[pr, DrawSegmentInContext, inst.ob, trans, segmentLayer];
pr.drawComment[r: CDBasics.MapRect[inst.ob.bbox, trans], comment: GetName[inst], pr: pr]
}
};
DrawMark:
PROC [inst:
CD.Instance, trans:
CD.Transformation, pr:
CD.DrawRef] = {
DrawPath:
PROC [context: Imager.Context, ob:
CD.Object, layer:
CD.Layer] = {
Imager.MaskFillTrajectory[context, markObjectPath];
};
IF pr.symbolics
AND (pr.scaleHint*inst.ob.bbox.y2>2
OR pr.scaleHint<=0)
THEN {
pr.drawContext[pr, DrawPath, markObject, trans, markLayer]
}
};
ChangePinLayer:
CD.ChangeLayerProc = {
layer ← CDLayers.AbstractToPaint[layer];
SetLayer[inst, layer];
};
Init[];
END.