File: AlignmentMarksImpl.mesa   
Copyright © 1984 by Xerox Corporation. All rights reserved.
Created by: Bob Mayo, June 8, 1984 12:28:34 pm PDT
Last Edited by: Mayo, July 30, 1984 3:52:08 pm PDT
DIRECTORY
AlignmentMarks,
TilerMenu USING [Register],
TerminalIO USING [WriteRope, WriteInt, RequestRope],
CDSequencer USING [Command, ImplementCommand],
CD,
TokenIO USING [ReadRope, WriteRope, ReadInt, WriteInt],
CDInline USING [AddPoints],
CDOps USING [AddAnObject],
CDOrient USING [MapPosition],
Rope USING [ROPE, Concat],
Graphics USING [Context, MoveTo, LineTo, DrawArea, NewPath, Path],
Real USING [Fix];
AlignmentMarksImpl: CEDAR PROGRAM    
IMPORTS TilerMenu, CD, TerminalIO, CDOps, CDInline, Rope, CDSequencer, TokenIO, CDOrient, Graphics, Real EXPORTS AlignmentMarks =  
BEGIN OPEN AlignmentMarks;
MarkObj: TYPE = REF MarkObjRec;  -- an object that can be put in a cell or design
MarkObjRec: TYPE = RECORD [
name: Rope.ROPE
];
versionNumber: INT ~ 1;  -- version of file format for alignment marks
markAtom: PUBLIC ATOM ← $AlignmentMark;
myLevel: CD.Level;
objsProcs: REF CD.ObjectProcs;
arrowSize: INT = 2 * CD.lambda;
-- Utilities
-- Given a ChipNDale application that points to an alignment mark, return it's name.
-- Returns some unspecified value if the application contains a different type of object.
FindName: PUBLIC PROC [aptr: CD.ApplicationPtr] RETURNS [Rope.ROPE] = BEGIN
RETURN[ NARROW[aptr.ob.specificRef, MarkObj].name ];
END;
-- find the origin of a mark application relative to the containing cell's origin
FindOrigin: PUBLIC PROC [aptr: CD.ApplicationPtr] RETURNS [CD.Position] = BEGIN
orig: CD.Position;
orig ← CDInline.AddPoints[
CDOrient.MapPosition[
itemInCell: [x1: 0, y1: 0, x2: 0, y2: 0],
cellSize: aptr.ob.size, cellInstOrient: aptr.orientation],
aptr.location];
RETURN[orig];
END;
-- check a command for wierdness as it is possible to screw up the TIP table.
OKCommand: PROC [comm: CDSequencer.Command] RETURNS[BOOL] = BEGIN
IF comm.pos.x > 10000 OR comm.pos.y > 10000 OR comm.pos.x < -10000 OR comm.pos.y < -10000 THEN BEGIN
TerminalIO.WriteRope["Warning: Huge position passed to AlignmentMarks from ChipNDale, maybe the TIP table is screwed up?\n"];
TerminalIO.WriteRope["comm.pos.x ="]; TerminalIO.WriteInt[comm.pos.x];
TerminalIO.WriteRope[" comm.pos.y ="]; TerminalIO.WriteInt[comm.pos.y];
[] ← TerminalIO.RequestRope["\nOperation will be aborted, type return ......"];
RETURN[FALSE];
END;
RETURN[TRUE];
END;
-- routines for interactive editing of marks
-- add a mark to a Design or Cell at absolute coordinates
PlaceMark: PUBLIC PROC [into: CD.Design, markName: Rope.ROPE, markPos: CD.Position] = BEGIN
obj: CD.ObPtr ← NEW[CD.ObjectDefinition];
markObj: MarkObj ← NEW[MarkObjRec];
markObj.name ← markName;
obj.p ← objsProcs;
obj.size ← [arrowSize, arrowSize];
obj.specificRef ← markObj;
obj.level ← myLevel;
CDOps.AddAnObject[design: into, ob: obj, location: markPos];
END;
DrawAlignMark: CD.DrawProc = BEGIN
-- PROC [aptr: ApplicationPtr, pos: DesignPosition, orient: Orientation, pr: REF DrawInformation];
DrawArrow: PROC [context: Graphics.Context] =
BEGIN
-- apply an orientation to a point
MapPoint: PROC [p: CD.Position, cellSize: CD.Position, orient: CD.Orientation] RETURNS [CD.Position] = INLINE BEGIN
RETURN[CDOrient.MapPosition[
itemInCell: [x1: p.x, y1: p.y, x2: p.x, y2: p.y],
cellSize: cellSize, cellInstOrient: orient]];
END;
MapReal: PROC[x, y: REAL] RETURNS [xi, yi: INT] = INLINE BEGIN
orig: CD.Position;
orig.x ← Real.Fix[x]; orig.y ← Real.Fix[y];
orig ← CDInline.AddPoints[MapPoint[orig, aptr.ob.size, orient], pos];
RETURN[orig.x, orig.y];
END;
RealPoint: TYPE = RECORD [x: REAL, y: REAL];
RealPointArray8: TYPE = ARRAY NAT[0..8) OF RealPoint;
x, y: INT;
sx1, sx2, sy1, sy2: INT;
arrow: RealPointArray8 ← [ [0,0], [0,0.75], [0.25,0.5], [0.75,1], [1,0.75], [0.5,0.25], [0.75,0], [0,0] ];
path: Graphics.Path ← Graphics.NewPath[size: 8];
IF context = NIL THEN RETURN;
-- draw the arrow
[sx1, sy1] ← MapReal[0.0, 0.0];
[sx2, sy2] ← MapReal[arrowSize, arrowSize];
[x, y] ← MapReal[arrow[0].x * arrowSize, arrow[0].y * arrowSize];
Graphics.MoveTo[path, x, y, TRUE];
FOR i: INT IN [1..8) DO
[x, y] ← MapReal[arrow[i].x * arrowSize, arrow[i].y * arrowSize];
Graphics.LineTo[path, x , y];
ENDLOOP;
Graphics.DrawArea[self: context, path: path];
END;
DrawName: PROC [context: Graphics.Context] =
BEGIN
name: Rope.ROPENARROW[aptr.ob.specificRef, MarkObj].name;
allr: CD.Rect ← [x1: arrowSize * markScale, y1: 0, x2: markWidth * markScale, y2: markHeight * markScale];
r: CD.Rect;
r ← CDInline.MoveRect[CDOrient.MapRect[allr, aptr.ob.size, orient], pos];
pr.drawComment[r, name, pr];
END;
-- draw the arrow & name
CD.DrawToContext[pr, DrawArrow, aptr.ob.level];
CD.DrawToContext[pr, DrawName, aptr.ob.level];
END;
AddAlignMark: PROC [comm: CDSequencer.Command] = BEGIN
name: Rope.ROPE;
IF ~OKCommand[comm] THEN RETURN[];
name ← TerminalIO.RequestRope["Enter name of new alignment mark: "];
PlaceMark[comm.design, name, comm.pos];
END;
WriteMark: CD.InternalWriteProc -- PROC [me: ObPtr] -- = BEGIN
markObj: MarkObj = NARROW[me.specificRef];
TokenIO.WriteInt[versionNumber];
TokenIO.WriteRope[markObj.name];
END;
ReadMark: CD.InternalReadProc -- PROC [] RETURNS [ObPtr] -- = BEGIN
obj: CD.ObPtr ← NEW[CD.ObjectDefinition];
markObj: MarkObj ← NEW[MarkObjRec];
version: INT;
obj.p ← objsProcs;
obj.size ← [arrowSize, arrowSize];
obj.specificRef ← markObj;
obj.level ← myLevel;
version ← TokenIO.ReadInt[];
SELECT version FROM
1 => markObj.name ← TokenIO.ReadRope[];
ENDCASE => TerminalIO.WriteRope["File contained an unknown version of Alignment Marks\n"];
RETURN[obj];
END;
DescribeMark: CD.DescribeProc -- PROC [me: ObPtr] RETURNS [Rope.ROPE] -- = BEGIN
markObj: MarkObj = NARROW[me.specificRef];
RETURN[Rope.Concat["alignment mark ", markObj.name]];
END;
-- Top-level command routines
Init: PROC[] = BEGIN
error: BOOLFALSE;
tmp: REF CD.ObjectProcs ← NIL;
tmp ← CD.RegisterObjectType[markAtom ! CD.Error => error ← TRUE];
IF tmp = NIL THEN error ← TRUE;
IF ~error THEN {
myLevel ← CD.NewLevel[NIL, $AlignMarkLevel];
objsProcs ← tmp;
}
ELSE {
error ← FALSE;
objsProcs ← CD.FetchObjectProcs[markAtom! CD.Error => {error ← TRUE; CONTINUE}];
myLevel ← CD.FetchLevel[NIL, $AlignMarkLevel ! CD.Error => {error ← TRUE; CONTINUE}];
IF error THEN objsProcs ← NIL;
};
IF objsProcs = NIL THEN {
TerminalIO.WriteRope["Error: Can't register alignment-mark object procs.\n"];
RETURN;
};
objsProcs.drawMe ← DrawAlignMark;
objsProcs.internalWrite ← WriteMark;
objsProcs.internalRead ← ReadMark;
objsProcs.describe ← DescribeMark;
objsProcs.hasChildren ← FALSE;
objsProcs.wireTyped ← FALSE;
CDSequencer.ImplementCommand[$AddAlignMark, AddAlignMark];
TilerMenu.Register["Add Alignment Mark", $AddAlignMark];
END;
-- Main body
Init[];
END.