CDBasics.mesa (part of ChipNDale)
Copyright © 1983, 1984 by Xerox Corporation. All rights reserved.
by Christian Jacobi, May 3, 1983 4:26 pm
Last Edited by Christian Jacobi, September 19, 1985 2:32:11 am PDT
DIRECTORY
CD USING [Number, Position, Rect];
CDBasics: CEDAR DEFINITIONS =
BEGIN
--constants
maxnum: CD.Number = LAST[CD.Number]/2;
minnum: CD.Number = FIRST[CD.Number]/2;
highposition: CD.Position = [maxnum, maxnum];
minposition: CD.Position = [minnum, minnum];
empty: CD.Rect = [maxnum, maxnum, minnum, minnum];
universe: CD.Rect = [minnum, minnum, maxnum, maxnum];
--predicats
OrderedIncreasing: PROC [p1, p2: CD.Position] RETURNS [BOOLEAN] =
--p2>=p1
INLINE {RETURN [(p1.x<=p2.x) AND (p1.y<=p2.y)]};
NonEmpty: PROC[r: CD.Rect] RETURNS [BOOLEAN] =
--returns r is not empty
--assumes r normalized
INLINE BEGIN
RETURN [(r.x1<r.x2) AND (r.y1<r.y2)]
END;
Intersect: PROC[r1, r2: CD.Rect] RETURNS [BOOLEAN] =
--returns r1 and r2 have some common points or border; assumes r1, r2 normalized.
--returns TRUE if rect only touches on a single point
INLINE {RETURN [(r1.x1<=r2.x2) AND (r2.x1<=r1.x2) AND (r1.y1<=r2.y2) AND (r2.y1<=r1.y2)]};
Inside: PROC [a, b: CD.Rect] RETURNS [BOOLEAN] =
--returns a inside of b (b inclusive border)
INLINE {RETURN[(a.x1>=b.x1) AND (a.x2<=b.x2) AND (a.y1>=b.y1) AND (a.y2<=b.y2)]};
InsidePos: PROC [p: CD.Position, r: CD.Rect] RETURNS [BOOLEAN] =
--returns p inside of r (or p on border of r)
INLINE {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: CD.Rect] RETURNS [CD.Rect] =
--returns intersection of r1 and r2
INLINE BEGIN
RETURN [CD.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]]]
END;
SizeOfRect: PROCEDURE[r: CD.Rect] RETURNS [CD.Position] =
INLINE BEGIN
IF (r.x2<=r.x1) OR (r.y2<=r.y1) THEN RETURN [CD.Position[x: 0, y: 0]]
ELSE RETURN [CD.Position[x: r.x2-r.x1, y: r.y2-r.y1]]
END;
BaseOfAnyRect: PROCEDURE[r: CD.Rect] RETURNS [CD.Position] =
--returns position of rect, also if non normalized
INLINE {RETURN [CD.Position[x: MIN[r.x2, r.x1], y: MIN[r.y2, r.y1]]]};
BaseOfRect: PROCEDURE[r: CD.Rect] RETURNS [CD.Position] =
--returns position of rect
INLINE {RETURN[CD.Position[x: r.x1, y: r.y1]]};
RectAt: PROC [pos: CD.Position, size: CD.Position] RETURNS [CD.Rect] =
--returns a rect with size "size" at position "pos";
INLINE {RETURN [CD.Rect[x1: pos.x, y1: pos.y, x2: pos.x+size.x, y2: pos.y+size.y]]};
ToRect: PROC [p1, p2: CD.Position] RETURNS [CD.Rect] =
--returns the rect between "pos1" and "pos2"
INLINE BEGIN
RETURN [CD.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]
]]
END;
NormalizeRect: PROC [r: CD.Rect] RETURNS [CD.Rect] =
--r may be not normalized
INLINE BEGIN
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]
END;
SubPoints: PROC [pos, neg: CD.Position] RETURNS [CD.Position] =
--pos displaced by -neg
INLINE {RETURN [CD.Position[x: pos.x-neg.x, y: pos.y-neg.y]]};
AddPoints: PROC [p, s: CD.Position] RETURNS [CD.Position] =
--p displaced by d
INLINE {RETURN [CD.Position[x: p.x+s.x, y: p.y+s.y]]};
AddSize: PROC [p, s: CD.Position] RETURNS [CD.Position] =
--highpoint of rect with size s is at p
INLINE {RETURN [CD.Position[x: p.x+s.x, y: p.y+s.y]]};
MinPoint: PROC[a, b: CD.Position] RETURNS [CD.Position] =
INLINE {RETURN [CD.Position[x: MIN[a.x, b.x], y: MIN[a.y, b.y]]]};
MaxPoint: PROC[a, b: CD.Position] RETURNS [CD.Position] =
INLINE {RETURN [CD.Position[x: MAX[a.x, b.x], y: MAX[a.y, b.y]]]};
NegOffset: PROC [off: CD.Position] RETURNS [CD.Position] =
INLINE {RETURN [CD.Position[x: -off.x, y: -off.y]]};
Surround: PROC [r1, r2: CD.Rect] RETURNS [CD.Rect] =
INLINE BEGIN
RETURN [CD.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]]]
END;
MoveRect: PROC [r: CD.Rect, offset: CD.Position] RETURNS [CD.Rect] =
--returns r move by offset
INLINE BEGIN
RETURN [CD.Rect[
r.x1+offset.x,
r.y1+offset.y,
r.x2+offset.x,
r.y2+offset.y]]
END;
Extend: PROC [r: CD.Rect, ext: CD.Number] RETURNS [CD.Rect] =
--returns r extended by ext in every direction
--if ext<0 it is the callers responsability that ext is not bigger than rect
INLINE {RETURN [CD.Rect[r.x1-ext, r.y1-ext, r.x2+ext, r.y2+ext]]};
Center: PROC [r: CD.Rect] RETURNS [CD.Position] =
--returns center of rect r
INLINE {RETURN[[(r.x1+r.x2)/2, (r.y1+r.y2)/2]]};
--higher level
DecomposeRect: PROC [r, test: CD.Rect, inside, outside: PROC[CD.Rect]←Skip];
--calls inside[part of r inside of test]
--and outside[parts of r outside of test]
Skip: PROC[CD.Rect];
END.