<> <> <> <> DIRECTORY Basics USING [BITAND], CD USING [Number, Orientation, Position, Rect, Transformation], Imager USING [Transformation]; CDBasics: CEDAR DEFINITIONS IMPORTS Basics = BEGIN Number: TYPE = CD.Number; Orientation: TYPE = CD.Orientation; Position: TYPE = CD.Position; Rect: TYPE = CD.Rect; Transformation: TYPE = CD.Transformation; <<--constants>> maxnum: Number = LAST[Number]/2; --/2: poor man's arithmetic overflow protection minnum: Number = FIRST[Number]/2; highposition: Position = [maxnum, maxnum]; minposition: Position = [minnum, minnum]; empty: Rect = [maxnum, maxnum, minnum, minnum]; universe: Rect = [minnum, minnum, maxnum, maxnum]; <<--predicats>> OrderedIncreasing: PROC [p1, p2: Position] RETURNS [BOOL] = INLINE { <<-- Returns p2>=p1>> RETURN [p1.x<=p2.x AND p1.y<=p2.y] }; Degenerated: PROC [r: Rect] RETURNS [BOOL] = INLINE { <<-- Returns r is degenerated [contains not even a single point or border]>> RETURN [r.x1>r.x2 OR r.y1>r.y2] }; NonEmpty: PROC [r: Rect] RETURNS [BOOL] = INLINE { <<-- Returns r is not empty [contains more points than the border]>> <<-- This is NOT the inverse of Degenerated >> RETURN [r.x1> <<-- [TRUE if rects touch on a single point]>> RETURN [r1.x1<=r2.x2 AND r2.x1<=r1.x2 AND r1.y1<=r2.y2 AND r2.y1<=r1.y2] }; Inside: PROC [a, b: Rect] RETURNS [BOOL] = INLINE { <<-- Returns a inside of b (b inclusive border)>> RETURN[a.x1>=b.x1 AND a.x2<=b.x2 AND a.y1>=b.y1 AND a.y2<=b.y2] }; InsidePos: PROC [p: Position, r: Rect] RETURNS [BOOL] = INLINE { <<-- Returns p inside of r (or p on border of r)>> RETURN[p.x>=r.x1 AND p.x<=r.x2 AND p.y>=r.y1 AND p.y<=r.y2] }; <<--functions>> Intersection: PROC [r1, r2: Rect] RETURNS [Rect] = INLINE { <<-- Returns intersection of r1 and r2>> RETURN [Rect[ x1: MAX[r1.x1, r2.x1], y1: MAX[r1.y1, r2.y1], x2: MIN[r1.x2, r2.x2], y2: MIN[r1.y2, r2.y2]]] }; SizeOfRect: PROC [r: Rect] RETURNS [Position] = INLINE { IF (r.x2<=r.x1) OR (r.y2<=r.y1) THEN RETURN [Position[x: 0, y: 0]] ELSE RETURN [Position[x: r.x2-r.x1, y: r.y2-r.y1]] }; BaseOfRect: PROC [r: Rect] RETURNS [Position] = INLINE { <<-- Returns position of rect>> RETURN[Position[x: r.x1, y: r.y1]] }; RectAt: PROC [pos: Position, size: Position] RETURNS [Rect] = INLINE { <<-- Returns a rect with size "size" at position "pos"; >> RETURN [Rect[x1: pos.x, y1: pos.y, x2: pos.x+size.x, y2: pos.y+size.y]] }; ToRect: PROC [p1, p2: Position] RETURNS [Rect] = INLINE { <<-- Returns the rect between "pos1" and "pos2">> RETURN [Rect[ x1: MIN[p1.x, p2.x], y1: MIN[p1.y, p2.y], x2: MAX[p1.x, p2.x], y2: MAX[p1.y, p2.y] ]] }; SubPoints: PROC [pos, neg: Position] RETURNS [Position] = INLINE { <<-- pos displaced by -neg>> RETURN [Position[x: pos.x-neg.x, y: pos.y-neg.y]] }; AddPoints: PROC [p, s: Position] RETURNS [Position] = INLINE { <<-- p displaced by d>> RETURN [Position[x: p.x+s.x, y: p.y+s.y]] }; MinPoint: PROC[a, b: Position] RETURNS [Position] = INLINE { RETURN [Position[x: MIN[a.x, b.x], y: MIN[a.y, b.y]]] }; MaxPoint: PROC[a, b: Position] RETURNS [Position] = INLINE { RETURN [Position[x: MAX[a.x, b.x], y: MAX[a.y, b.y]]] }; NegOffset: PROC [off: Position] RETURNS [Position] = INLINE { RETURN [Position[x: -off.x, y: -off.y]] }; Surround: PROC [r1, r2: Rect] RETURNS [Rect] = INLINE { RETURN [Rect[ x1: MIN[r1.x1, r2.x1], y1: MIN[r1.y1, r2.y1], x2: MAX[r1.x2, r2.x2], y2: MAX[r1.y2, r2.y2]]] }; MoveRect: PROC [r: Rect, offset: Position] RETURNS [Rect] = INLINE { <<-- Returns r move by offset>> RETURN [Rect[ r.x1+offset.x, r.y1+offset.y, r.x2+offset.x, r.y2+offset.y]] }; Extend: PROC [r: Rect, ext: Number] RETURNS [Rect] = INLINE { <<-- Returns r extended by ext in every direction>> <<-- If ext<0 it is the callers responsability that ext is not bigger than rect>> RETURN [Rect[r.x1-ext, r.y1-ext, r.x2+ext, r.y2+ext]] }; Center: PROC [r: Rect] RETURNS [Position] = INLINE { <<-- Returns center of rect r>> RETURN[[(r.x1+r.x2)/2, (r.y1+r.y2)/2]] }; ReInterpreteRect: PROC [r: CD.Rect] RETURNS [CD.Rect] = INLINE { <<-- Changes coordinates to make rect not degenerated>> 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] }; <<>> <<>> <<--higher level>> <<>> DecomposeRect: PROC [r, test: Rect, inside, outside: PROC [Rect] _ Skip]; <<-- Calls inside [part of r inside of test] and outside [parts of r outside of test]>> <<-- [border points might be part of both calls]>> Skip: PROC [Rect]; <<>> <<--Orientations>> MapRect: PROC [itemInCell: Rect, cellInWorld: Transformation] RETURNS [itemInWorld: Rect]; <<-- Given an item in a cell [in "cell" coordinates], >> <<-- the position and orientation of an instance of that cell in "world" coordinates,>> <<-- returns the world coordinates of the item>> DeMapRect: PROC [itemInWorld: Rect, cellInWorld: Transformation] RETURNS [itemInCell: Rect]; <<-- Given an item in world coordinates, the size of a cell,>> <<-- the position and orientation of an instance of that cell in "world" coordinates,>> <<-- returns the cell coordinates of that item.>> MapPoint: PROC [pointInCell: Position, cellInWorld: Transformation] RETURNS [pointInWorld: Position]; <<-- Given an point in a cell, >> <<-- the position and orientation of an instance of the cell in "world" coordinates,>> <<-- returns the world coordinates of the point.>> DeMapPoint: PROC [pointInWorld: Position, cellInWorld: Transformation] RETURNS [pointInCell: Position]; <<-- Given a point in world co-ordinates,>> <<-- the position and orientation of an instance of the cell in "world" coordinates,>> <<-- returns the cell coordinates of the point.>> OrientedPoint: PROC [pos: Position, orient: Orientation] RETURNS [Position]; <<--Maps a point on a transformation [[0,0], orient]>> OrientedSize: PROC [size: Position, orient: Orientation] RETURNS [Position] = INLINE { <<-- Returns the size transformed by transformation "orient" >> RETURN [IF IncludesOddRot90[orient] THEN [x: size.y, y: size.x] ELSE size] }; ComposeTransform: PROC [itemInCell, cellInWorld: Transformation] RETURNS [itemInWorld: Transformation]; <<-- composes transformations>> InverseTransform: PROC [trans: Transformation] RETURNS [Transformation]; <<-- Returns the inverse transformation>> DecomposeTransform: PROC [itemInWorld, cellInWorld: Transformation] RETURNS [itemInCell: Transformation]; <<-- de-composes transformations>> ImagerTransform: PROC [trans: CD.Transformation] RETURNS [Imager.Transformation]; <<-- Converts a ChipNDale Transformation into a corresponding Imager Transformation>> ComposeOrient: PROC [itemInCell, cellInWorld: Orientation] RETURNS [itemInWorld: Orientation]; <<-- Returns the composite orientation obtained by first doing>> <<-- itemInCell and then cellInWorld>> InverseOrient: PROC [orient: Orientation] RETURNS [inverse: Orientation]; <<-- For all orientations o1, ComposeOrient[o1, InverseOrient[o1]] = original.>> <<>> DecomposeOrient: PROC [itemInWorld, cellInWorld: Orientation] RETURNS [itemInCell: Orientation]; <<-- For all orientations o1 and o2,>> <<-- DecomposeOrient[>> <<-- cellInWorld: o1, >> <<-- itemInWorld: ComposeOrient[cellInWorld: o1, itemInCell: o2]>> <<-- ] = o2.>> IncludesOddRot90: PROC [orient: Orientation] RETURNS [BOOLEAN] = INLINE { <<-- Returns orient includes an odd multiple of 90 degree >> RETURN [Basics.BITAND[ORD[orient], ORD[Orientation[rotate90]]]#0] }; IncludesMirrorX: PROC [orient: Orientation] RETURNS [BOOLEAN] = INLINE { <<-- Returns orient includes some mirroring >> RETURN [Basics.BITAND[ORD[orient], ORD[Orientation[mirrorX]]]#0] }; ConcentrateOnRotate90: PROC [orient: Orientation] RETURNS [Orientation] = INLINE { <<-- Discard mirroring >> RETURN [VAL[Basics.BITAND[ORD[orient], 6]]] }; END.