<> <> <> <> 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> <<--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.