-- File: SVVector2dImpl.mesa
-- Last edited by Bier on December 18, 1982 1:08 am
-- Author: Eric Bier on August 12, 1983 9:26 pm
-- Contents: Routines for manipulation vectors in two dimensions

DIRECTORY
 RealFns,
 SV2d,
 SVAngle,
 SVVector2d;

SVVector2dImpl: PROGRAM
IMPORTS RealFns, SVAngle
EXPORTS SVVector2d =

BEGIN

Point2d: TYPE = SV2d.Point2d;
TrigLineSeg: TYPE = SV2d.TrigLineSeg;
Vector2d: TYPE = SV2d.Vector2d;

VectorFromAngle: PUBLIC PROC [angle: REAL] RETURNS [vector: Vector2d] = {
-- angle must be in degrees in the range: -180 < angle <= 180.
-- vector is a unit vector.
 vector[1] ← RealFns.CosDeg[angle];
 vector[2] ← RealFns.SinDeg[angle];
 };

VectorPlusAngle: PUBLIC PROC [v: Vector2d, degrees: REAL] RETURNS [rotatedV: Vector2d] = {
-- Find angle of v. This should be easy. Normalize v and its components will be cos(theta), sin(theta) respectively.
 theta: REAL ← RealFns.ArcTanDeg[v[2], v[1]];
 angleSum: REAL ← theta + degrees;
IF angleSum<= -180 THEN angleSum ← angleSum + 360
ELSE IF angleSum > 180 THEN angleSum ← angleSum - 360;
 rotatedV ← VectorFromAngle[angleSum];
 };

AngleFromVector: PUBLIC PROC [v: Vector2d] RETURNS [position: REAL] = {
-- position is a position angle such that -180 < position <= 180
 position ← SVAngle.ArcTan[v[2], v[1]];
 };

AngleCCWBetweenVectors: PUBLIC PROC [v1, v2: Vector2d] RETURNS [difference: REAL] = {
-- difference will be in: 0 <= difference < 360. A clockwise angle
 angle1, angle2: REAL;
 angle1 ← AngleFromVector[v1];
 angle2 ← AngleFromVector[v2];
 difference ← SVAngle.CounterClockwiseAngle[angle1, angle2];
 };

AngleCWBetweenVectors: PUBLIC PROC [v1, v2: Vector2d] RETURNS [difference: REAL] = {
-- difference will be in: 0 <= difference < 360. A counter-clockwise angle
 angle1, angle2: REAL;
 angle1 ← AngleFromVector[v1];
 angle2 ← AngleFromVector[v2];
 difference ← SVAngle.ClockwiseAngle[angle1, angle2];
 };

SmallestAngleBetweenVectors: PUBLIC PROC [v1, v2: Vector2d] RETURNS [difference: REAL] = {
-- all angles in degrees. RETURNS ClockwiseAngle or CounterClockwiseAngle. Whichever is smaller. -180 < difference <= 180.
 angle1, angle2: REAL;
 angle1 ← AngleFromVector[v1];
 angle2 ← AngleFromVector[v2];
 difference ← SVAngle.ShortestDifference[angle1, angle2];
 };

Difference: PUBLIC PROC [v1, v2: Vector2d] RETURNS [v1MinusV2: Vector2d] = {
 v1MinusV2[1] ← v1[1] - v2[1];
 v1MinusV2[2] ← v1[2] - v2[2];
 };

Sum: PUBLIC PROC [v1, v2: Vector2d] RETURNS [v1PlusV2: Vector2d] = {
 v1PlusV2[1] ← v1[1] + v2[1];
 v1PlusV2[2] ← v1[2] + v2[2];
 };

Scale: PUBLIC PROC[v: Vector2d, s: REAL] RETURNS [vTimesS: Vector2d] = {
 vTimesS[1] ← v[1]*s;
 vTimesS[2] ← v[2]*s;
 };

Normalize: PUBLIC PROC [v: Vector2d] RETURNS [normV: Vector2d] = {
 mag: REAL ← Magnitude[v];
 normV[1] ← v[1] / mag;
 normV[2] ← v[2] /mag;
 };

ElementwiseProduct: PUBLIC PROC [v1, v2: Vector2d] RETURNS [v1Timesv2: Vector2d] = {
 v1Timesv2[1] ← v1[1]*v2[1];
 v1Timesv2[2] ← v1[2]*v2[2];
 };

DotProduct: PUBLIC PROC [v1, v2: Vector2d] RETURNS [scalar: REAL] = {
 scalar ← v1[1]*v2[1] + v1[2]*v2[2];
 };

Magnitude: PUBLIC PROC [v: Vector2d] RETURNS [mag: REAL] = {
 mag ← RealFns.SqRt[v[1]*v[1] + v[2]*v[2]];
 };

MagnitudeSquared: PUBLIC PROC [v: Vector2d] RETURNS [magSquared: REAL] = {
 magSquared ← v[1]*v[1] + v[2]*v[2];
 };

VectorFromPoints: PUBLIC PROC [tail, head: Point2d] RETURNS [vector: Vector2d] = {
 vector[1] ← head[1] - tail[1];
 vector[2] ← head[2] - tail[2];
 };

RightNormalOfTrigLineSeg: PUBLIC PROC [seg: TrigLineSeg] RETURNS [normal: Vector2d] = {
-- Given the ordered points of the line segment, we can find the vector from the first to the second. If this vector is [a, b] then the vector 90 degrees to the right is [b, -a];
 direction: Vector2d;
IF seg.pLoIsFirst THEN direction ← VectorFromPoints[tail: seg.pLo, head: seg.pHi]
      ELSE direction ← VectorFromPoints[tail: seg.pHi, head: seg.pLo];
 normal[1] ← direction[2];
 normal[2] ← -direction[1];
 };

LeftNormalOfTrigLineSeg: PUBLIC PROC [seg: TrigLineSeg] RETURNS [normal: Vector2d] = {
-- Given the ordered points of the line segment, we can find the vector from the first to the second. If this vector is [a, b] then the vector 90 degrees to the left is [-b, a];
 direction: Vector2d;
IF seg.pLoIsFirst THEN direction ← VectorFromPoints[tail: seg.pLo, head: seg.pHi]
      ELSE direction ← VectorFromPoints[tail: seg.pHi, head: seg.pLo];
 normal[1] ← -direction[2];
 normal[2] ← direction[1];
 };


END.