-- Copyright (C) 1983 by Xerox Corporation. All rights reserved. -- IVectorImpl.mesa - last edited by -- Poskanzer 23-May-83 20:23:59 DIRECTORY IVector USING [Angle, IPoint, IVec], Real USING [RoundI], RealFns USING [ArcTanDeg, SqRt]; IVectorImpl: PROGRAM IMPORTS Real, RealFns EXPORTS IVector = BEGIN IVec: TYPE = IVector.IVec; IPoint: TYPE = IVector.IPoint; Angle: TYPE = IVector.Angle; ArcTan: PUBLIC PROCEDURE [y, x: INTEGER] RETURNS [Angle] = BEGIN RETURN[RealFns.ArcTanDeg[y, x]]; END; Sqrt: PUBLIC PROCEDURE [i: LONG INTEGER] RETURNS [INTEGER] = BEGIN RETURN[Real.RoundI[RealFns.SqRt[i]]]; END; Sign: PUBLIC PROCEDURE [a: INTEGER] RETURNS [INTEGER] = BEGIN RETURN[IF a < 0 THEN -1 ELSE 1]; END; Go: PUBLIC PROCEDURE [from, to: IPoint] RETURNS [IVec] = BEGIN RETURN[[to.x - from.x, to.y - from.y]]; END; Add: PUBLIC PROCEDURE [v1, v2: IVec] RETURNS [IVec] = BEGIN RETURN[[v1.x + v2.x, v1.y + v2.y]]; END; Dot: PUBLIC PROCEDURE [v1, v2: IVec] RETURNS [LONG INTEGER] = BEGIN RETURN[LONG[v1.x]*LONG[v2.x] + LONG[v1.y]*LONG[v2.y]]; END; Sub: PUBLIC PROCEDURE [v1, v2: IVec] RETURNS [IVec] = BEGIN RETURN[[v1.x - v2.x, v1.y - v2.y]]; END; -- angle stuff AngleOf: PUBLIC PROCEDURE [v: IVec] RETURNS [REAL] = BEGIN RETURN[ArcTan[v.y, v.x]]; END; -- comarision stuff BetweenVector: PUBLIC PROCEDURE [cw, ccw, test: IVec] RETURNS [BOOLEAN] = BEGIN leftOfCw: BOOLEAN = LeftOf[ref: cw, test: test]; rightOfCcw: BOOLEAN = RightOf[ref: ccw, test: test]; RETURN[ SELECT Det[cw: cw, ccw: ccw] FROM > 0 => leftOfCw AND rightOfCcw, < 0 => leftOfCw OR rightOfCcw, ENDCASE => (Dot[cw, ccw] < 0 OR Dot[cw, test] > 0) AND leftOfCw AND rightOfCcw]; END; LeftOf: PUBLIC PROCEDURE [ref, test: IVec] RETURNS [BOOLEAN] = BEGIN RETURN[Det[cw: ref, ccw: test] >= 0]; END; RightOf: PUBLIC PROCEDURE [ref, test: IVec] RETURNS [BOOLEAN] = BEGIN RETURN[Det[ccw: ref, cw: test] >= 0]; END; SameDirection: PUBLIC PROCEDURE [v1, v2: IVec] RETURNS [BOOLEAN] = BEGIN RETURN[Dot[v1, v2] >= 0]; END; RLength: PROCEDURE [v: IVec] RETURNS [REAL] = BEGIN RETURN[RealFns.SqRt[LenSqrd[v]]]; END; Length: PUBLIC PROCEDURE [v: IVec] RETURNS [INTEGER] = BEGIN RETURN[Real.RoundI[RLength[v]]]; END; LenSqrd: PUBLIC PROCEDURE [v: IVec] RETURNS [LONG INTEGER] = BEGIN RETURN[LONG[v.x]*LONG[v.x] + LONG[v.y]*LONG[v.y]]; END; Scale: PUBLIC PROCEDURE [v: IVec, scale: REAL] RETURNS [IVec] = BEGIN RETURN[[Real.RoundI[v.x*scale], Real.RoundI[v.y*scale]]]; END; VectorOfLength: PUBLIC PROCEDURE [v: IVec, l: INTEGER] RETURNS [IVec] = BEGIN RETURN[Scale[v, REAL[l]/RLength[v]]]; END; Minus: PUBLIC PROCEDURE [v: IVec] RETURNS [IVec] = BEGIN RETURN[[-v.x, -v.y]]; END; Rotate90CCW: PUBLIC PROCEDURE [v: IVec] RETURNS [IVec] = BEGIN RETURN[[-v.y, v.x]]; END; Rotate90CW: PUBLIC PROCEDURE [v: IVec] RETURNS [IVec] = BEGIN RETURN[[v.y, -v.x]]; END; AddPoint: PUBLIC PROCEDURE [p: IPoint, v: IVec] RETURNS [IPoint] = BEGIN RETURN[[p.x + v.x, p.y + v.y]]; END; SubPoint: PUBLIC PROCEDURE [p: IPoint, v: IVec] RETURNS [IPoint] = BEGIN RETURN[[p.x - v.x, p.y - v.y]]; END; Between: PUBLIC PROCEDURE [cw, ccw, test: IVec] RETURNS [BOOLEAN] = BEGIN RETURN[(Dot[test, Rotate90CCW[cw]] > 0) = (Dot[test, Rotate90CW[ccw]] > 0)]; END; Combine: PUBLIC PROCEDURE [v1: IVec, s1: INTEGER, v2: IVec, s2: INTEGER] RETURNS [IVec] = BEGIN RETURN[[s1*v1.x + s2*v2.x, s1*v1.y + s2*v2.y]]; END; Det: PUBLIC PROCEDURE [cw, ccw: IVec] RETURNS [LONG INTEGER] = BEGIN RETURN[Dot[cw, Rotate90CW[ccw]]]; END; Colinear: PUBLIC PROCEDURE [p1, p2, p3: IPoint] RETURNS [BOOLEAN] = BEGIN IF p1 = p2 OR p2 = p3 OR p3 = p1 THEN RETURN[TRUE] ELSE RETURN[Parallel[Go[p1, p2], Go[p2, p3]]]; END; Parallel: PUBLIC PROCEDURE [v1, v2: IVec] RETURNS [BOOLEAN] = BEGIN RETURN[v1.x*v2.y = v2.x*v1.y]; END; -- Coeffs: computes c1 and c2 such that v = c1*basis1 + c2*basis2. Coeffs: PUBLIC PROCEDURE [basis1, basis2, v: IVec] RETURNS [c1, c2: REAL] = BEGIN det: REAL = Det[basis1, basis2]; c1 ← REAL[Det[v, basis2]]/det; c2 ← REAL[Det[basis1, v]]/det; END; -- Intersect: finds the intersection point of two rooted vectors. Intersect: PUBLIC PROCEDURE [v1: IVec, p1: IPoint, v2: IVec, p2: IPoint] RETURNS [p: IPoint] = BEGIN v: IVec; c1, c2: REAL; IF Parallel[v1, v2] THEN RETURN[p1] -- p1 is as good as any other point ELSE BEGIN v ← Go[p1, p2]; [c1, c2] ← Coeffs[basis1: v1, basis2: v2, v: v]; RETURN[AddPoint[p1, Scale[v1, c1]]]; END; END; END.