Geom2DImpl.Mesa
Last Edited by: Spreitzer, April 16, 1983 1:18 pm
some two dimensional geometry, with real numbers
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.