<> <> <> <> DIRECTORY AlignmentMarks, TilerMenu USING [Register], TerminalIO USING [WriteRope, RequestRope], CDSequencer USING [Command, ImplementCommand], CD, TokenIO USING [ReadRope, WriteRope, ReadInt, WriteInt], CDBasics USING [AddPoints, SubPoints], CDOps USING [IncludeApplication], CDOrient USING [MapPosition], CDApplications USING [NewApplicationI], Rope USING [ROPE, Concat, Equal], Graphics USING [Context, MoveTo, LineTo, DrawArea, NewPath, Path], Real USING [Fix]; AlignmentMarksImpl: CEDAR PROGRAM IMPORTS TilerMenu, CD, TerminalIO, CDOps, CDBasics, Rope, CDSequencer, TokenIO, CDOrient, CDApplications, 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 objAtom: PUBLIC ATOM _ $AlignmentMark; myLevel: CD.Level; objsProcs: REF CD.ObjectProcs; arrowSize: INT = 2 * CD.lambda; <<-- Utilities>> <<>> <<>> AptrToMark: PUBLIC PROC [aptr: CD.ApplicationPtr] RETURNS [REF Mark] = BEGIN mark: REF Mark _ NEW[Mark]; IF aptr.ob.p.objectType # objAtom THEN RETURN[NIL]; mark.name _ NARROW[aptr.ob.specificRef, MarkObj].name; mark.pos _ CDBasics.AddPoints[ CDOrient.MapPosition[ itemInCell: [x1: 0, y1: 0, x2: 0, y2: 0], cellSize: aptr.ob.size, cellInstOrient: aptr.orientation], aptr.location]; RETURN[mark]; END; <<>> <<-- Make an application for a mark, but don't place it>> MakeMarkAptr: PUBLIC PROC [mark: Mark, orient: CD.Orientation _ CD.original] RETURNS [CD.ApplicationPtr]= BEGIN aptr: CD.ApplicationPtr; pos: CD.Position _ mark.pos; obj: CD.ObPtr _ NEW[CD.ObjectDefinition]; markObj: MarkObj _ NEW[MarkObjRec]; markObj.name _ mark.name; obj.p _ objsProcs; obj.size _ [arrowSize, arrowSize]; obj.specificRef _ markObj; obj.level _ myLevel; aptr _ CDApplications.NewApplicationI[obj, pos, orient]; <<-- adjust location of mark for the orientation>> aptr.location _ CDBasics.SubPoints[aptr.location, CDBasics.SubPoints[AptrToMark[aptr].pos, aptr.location]]; RETURN[aptr]; END; FindList: PUBLIC PROC [ob: CD.ObPtr] RETURNS [LIST OF Mark] = BEGIN list: CD.ApplicationList; marks: LIST OF Mark _ NIL; SELECT ob.p.objectType FROM $Cell => list _ NARROW[ob.specificRef, CD.CellPtr].contents; ENDCASE => RETURN[NIL]; FOR a: CD.ApplicationList _ list, a.rest WHILE a # NIL DO IF a.first.ob.p.objectType = objAtom THEN { marks _ CONS[AptrToMark[a.first]^, marks]; }; ENDLOOP; RETURN[marks]; END; <<>> Find: PUBLIC PROC [ob: CD.ObPtr, name: Rope.ROPE] RETURNS [REF Mark] = BEGIN FOR a: LIST OF Mark _ FindList[ob], a.rest WHILE a # NIL DO IF Rope.Equal[a.first.name, name] THEN { RETURN[NEW[Mark _ a.first]]; }; ENDLOOP; RETURN[NIL]; END; <<>> <<-- routines for interactive editing of marks>> <<>> <<-- Place a mark into a design.>> Place: PUBLIC PROC [into: CD.Design, mark: Mark, orient: CD.Orientation _ CD.original] = BEGIN CDOps.IncludeApplication[into, MakeMarkAptr[mark, orient]]; 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 _ CDBasics.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; <<-- draw the arrow & name>> CD.DrawToContext[pr, DrawArrow, aptr.ob.level]; <> END; AddAlignMark: PROC [comm: CDSequencer.Command] = BEGIN mark: Mark; mark.name _ TerminalIO.RequestRope["Enter name of new alignment mark: "]; mark.pos _ comm.pos; Place[comm.design, mark]; 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: BOOL _ FALSE; tmp: REF CD.ObjectProcs _ NIL; tmp _ CD.RegisterObjectType[objAtom ! 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[objAtom! 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.inDirectory _ FALSE; objsProcs.wireTyped _ FALSE; CDSequencer.ImplementCommand[$AddAlignMark, AddAlignMark]; TilerMenu.Register["Add Alignment Mark", $AddAlignMark]; END; <<-- Main body>> <<>> Init[]; END.