<> <> <<>> <> <<>> DIRECTORY Graphics, RealFns, Geom2D; Geom2DImpl: CEDAR PROGRAM IMPORTS RealFns EXPORTS Geom2D = BEGIN OPEN Geom2D; Singularity: PUBLIC SIGNAL = CODE; Plus: PUBLIC PROC [a, b: Vec] RETURNS [Vec] = {RETURN [[a.x+b.x, a.y+b.y]]}; Minus: PUBLIC PROC [a, b: Vec] RETURNS [Vec] = {RETURN [[a.x-b.x, a.y-b.y]]}; Project: PUBLIC PROC [on, what: Vec] RETURNS [Vec] = {l2, d: Number; l2 _ on.x * on.x + on.y * on.y; IF l2 = 0 THEN SIGNAL Singularity[]; d _ on.x * what.x + on.y * what.y; RETURN [[(on.x * d)/l2, (on.y * d)/l2]]}; Normalize: PUBLIC PROC [p: Vec] RETURNS [Vec] = {l: REAL _ Length[p]; IF l = 0 THEN SIGNAL Singularity[]; RETURN [[p.x/l, p.y/l]]}; Displace: PUBLIC PROC [p: Vec, a: Area] RETURNS [Area] = {RETURN [[a.xmin+p.x, a.ymin+p.y, a.xmax+p.x, a.ymax+p.y]]}; Scale: PUBLIC PROC [p: Vec, s: Number] RETURNS [Vec] = {RETURN [[p.x*s, p.y*s]]}; Dot: PUBLIC PROC [a, b: Vec] RETURNS [Number] = {RETURN [a.x*b.x + a.y*b.y]}; Length: PUBLIC PROC [p: Vec] RETURNS [Number] = {dx: Number _ ABS[p.x]; dy: Number _ ABS[p.y]; RETURN[IF dx = 0 THEN dy ELSE IF dy = 0 THEN dx ELSE RealFns.SqRt[p.x*p.x + p.y*p.y]]}; DirectionOf: PUBLIC PROC [p: Vec] RETURNS [Direction] = {IF Length[p] = 0 THEN SIGNAL Singularity[]; RETURN [IF p.x = 0 THEN [Y, SGN[p.y]] ELSE IF p.y = 0 THEN [X, SGN[p.x]] ELSE ERROR]}; SGN: PROC [n: Number] RETURNS [Dir] = {RETURN [IF n < 0 THEN -1 ELSE IF n > 0 THEN 1 ELSE 0]}; BloatLine: PUBLIC PROC [l: Line, by: Number] RETURNS [a: Area] = {[a.xmin, a.xmax] _ MinMax[l.from.x, l.to.x]; a.xmin _ a.xmin - by; a.xmax _ a.xmax + by; [a.ymin, a.ymax] _ MinMax[l.from.y, l.to.y]; a.ymin _ a.ymin - by; a.ymax _ a.ymax + by}; MinMax: PROC [a, b: Number] RETURNS [min, max: Number] = {IF b < a THEN RETURN[b, a] ELSE RETURN[a, b]}; BloatVec: PUBLIC PROC [p: Vec, by: Number] RETURNS [Area] = {RETURN [[p.x-by, p.y-by, p.x+by, p.y+by]]}; UnitNormalToward: PUBLIC PROC [l: Line, p: Vec] RETURNS [u: Vec] = {dx, dy: Number; e: Number _ (p.x - l.from.x) * (dy _ l.to.y - l.from.y) - (dx _ l.to.x - l.from.x) * (p.y - l.from.y); IF e = 0 THEN SIGNAL Singularity[] ELSE RETURN [IF e > 0 THEN Normalize[[dy, -dx]] ELSE IF e < 0 THEN Normalize[[-dy, dx]] ELSE ERROR]}; In: PUBLIC PROC [p: Vec, a: Area] RETURNS [BOOLEAN] = {RETURN [IF p.x < a.xmin THEN FALSE ELSE IF p.x > a.xmax THEN FALSE ELSE IF p.y < a.ymin THEN FALSE ELSE IF p.y > a.ymax THEN FALSE ELSE TRUE]}; SweepBounds: PUBLIC PROC [a, b: Area] RETURNS [Area] = {RETURN [[a.xmin+b.xmin, a.ymin+b.ymin, a.xmax+b.xmax, a.ymax+b.ymax]]}; UpdateBounds: PUBLIC PROC [a, b: Area] RETURNS [Area] = {RETURN [[MIN[a.xmin, b.xmin], MIN[a.ymin, b.ymin], MAX[a.xmax, b.xmax], MAX[a.ymax, b.ymax]]]}; UpdateFBounds: PUBLIC PROC [a: Area, f: FBounds] RETURNS [FBounds] = {RETURN [[TRUE, IF f.defined THEN [MIN[a.xmin, f.area.xmin], MIN[a.ymin, f.area.ymin], MAX[a.xmax, f.area.xmax], MAX[a.ymax, f.area.ymax]] ELSE a]]}; Parallel: PUBLIC PROC [a, b: Vec] RETURNS [BOOLEAN] = {RETURN [ABS[a.x * b.y - a.y * b.x] = 0]}; Translate: PUBLIC PROC [t: Transform, dx, dy: Number] RETURNS [Transform] = {RETURN [[t.a, t.b, t.c, t.d, t.e+dx, t.f+dy]]}; TranslateV: PUBLIC PROC [t: Transform, d: Vec] RETURNS [Transform] = {RETURN [[t.a, t.b, t.c, t.d, t.e+d.x, t.f+d.y]]}; ScaleT: PUBLIC PROC [t: Transform, s: Number] RETURNS [Transform] = {RETURN [[s*t.a, s*t.b, s*t.c, s*t.d, s*t.e, s*t.f]]}; ScaleTXY: PUBLIC PROC [t: Transform, sx, sy: Number] RETURNS [Transform] = {RETURN [[sx*t.a, sy*t.b, sx*t.c, sy*t.d, sx*t.e, sy*t.f]]}; RotateBy90s: PUBLIC PROC [t: Transform, i: INTEGER] RETURNS [Transform] = {RETURN [SELECT ((i MOD 4) + 4) MOD 4 FROM 0 => t, 2 => [-t.a, -t.b, -t.c, -t.d, -t.e, -t.f], 1 => [-t.b, t.a, -t.d, t.c, -t.f, t.e], 3 => [t.b, -t.a, t.d, -t.c, t.f, -t.e], ENDCASE => ERROR]}; RotateDegrees: PUBLIC PROC [t: Transform, deg: Number] RETURNS [Transform] = BEGIN c, s: Number; s _ RealFns.SinDeg[deg]; c _ RealFns.CosDeg[deg]; RETURN [[t.a*c - t.b*s, t.a*s + t.b*c, t.c*c - t.d*s, t.c*s + t.d*c, t.e*c - t.f*s, t.e*s + t.f*c]]; END; Inverse: PUBLIC PROC [t: Transform] RETURNS [Transform] = {det: Number _ t.a*t.d - t.b*t.c; IF ABS[det] = 0 THEN {SIGNAL Singularity[]; RETURN [id]} ELSE RETURN [[t.d/det, -t.b/det, -t.c/det, t.a/det, (t.f*t.c - t.e*t.d)/det, (t.e*t.b - t.f*t.a)/det]]}; MapVec: PUBLIC PROC [t: Transform, v: Vec] RETURNS [Vec] = {RETURN [[t.a*v.x + t.c*v.y + t.e, t.b*v.x + t.d*v.y + t.f]]}; MapVecs: PUBLIC PROC [t: Transform, l: VecList] RETURNS [n: VecList] = {prev: VecList _ n _ NIL; FOR l _ l, l.rest WHILE l # NIL DO cur: VecList _ CONS[[t.a * l.first.x + t.c * l.first.y + t.e, t.b * l.first.x + t.d * l.first.y + t.f], NIL]; IF prev = NIL THEN n _ cur ELSE prev.rest _ cur; prev _ cur; ENDLOOP}; MapArea: PUBLIC PROC [t: Transform, a: Area] RETURNS [b: Area] = {ll: Vec _ MapVec[t, [a.xmin, a.ymin]]; ur: Vec _ MapVec[t, [a.xmax, a.ymax]]; [b.xmin, b.xmax] _ MinMax[ll.x, ur.x]; [b.ymin, b.ymax] _ MinMax[ll.y, ur.y]}; MapAreas: PUBLIC PROC [t: Transform, l: AreaList] RETURNS [n: AreaList] = BEGIN prev: AreaList _ n _ NIL; FOR l _ l, l.rest WHILE l # NIL DO cur: AreaList _ CONS[MapArea[t, l.first], NIL]; IF prev = NIL THEN n _ cur ELSE prev.rest _ cur; prev _ cur; ENDLOOP; END; Concat: PUBLIC PROC [left, right: Transform] RETURNS [prod: Transform] = BEGIN prod.a _ left.a*right.a + left.b*right.c; prod.b _ left.a*right.b + left.b*right.d; prod.c _ left.c*right.a + left.d*right.c; prod.d _ left.c*right.b + left.d*right.d; prod.e _ left.e*right.a + left.f*right.c + right.e; prod.f _ left.e*right.b + left.f*right.d + right.f; END; END.