CDBasics.mesa (part of ChipNDale)
Copyright © 1983, 1984, 1986 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, May 3, 1983 4:26 pm
Last edited by: Christian Jacobi, October 23, 1986 10:03:59 am PDT
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<r.x2 AND r.y1<r.y2]
};
Intersect: PROC [r1, r2: Rect] RETURNS [BOOL] = INLINE {
-- Returns r1 and r2 have some common points or border; [assumes r1, r2 normalized].
-- [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.