File: Vectors2dImpl.mesa
Copyright Ó 1986, 1992 by Xerox Corporation. All rights reserved.
Last edited by Bier on June 4, 1985 6:11:29 pm PDT
Author: Eric Bier on September 14, 1987 1:19:47 pm PDT
Contents: Routines for manipulation vectors in two dimensions
Pier, May 30, 1986 5:04:23 pm PDT
DIRECTORY
RealFns, Lines2dTypes, Angles2d, Vectors2d;
Vectors2dImpl:
CEDAR
PROGRAM
IMPORTS RealFns, Angles2d
EXPORTS Vectors2d = BEGIN
Point: TYPE = Lines2dTypes.Point;
Edge: TYPE = Lines2dTypes.Edge;
Vector: TYPE = Lines2dTypes.Vector;
VectorFromPoints:
PUBLIC
PROC [tail, head: Point]
RETURNS [vector: Vector] = {
vector.x ¬ head.x - tail.x;
vector.y ¬ head.y - tail.y;
};
VectorFromAngle:
PUBLIC
PROC [angle:
REAL]
RETURNS [vector: Vector] = {
angle must be in degrees in the range: -180 < angle <= 180.
vector is a unit vector.
vector.x ¬ RealFns.CosDeg[angle];
vector.y ¬ RealFns.SinDeg[angle];
};
VectorPlusAngle:
PUBLIC
PROC [v: Vector, degrees:
REAL]
RETURNS [rotatedV: Vector] = {
Find angle of v. This should be easy. Normalize v and its components will be cos(theta), sin(theta) respectively.
theta: REAL;
angleSum: REAL;
IF degrees = 90.0 THEN {rotatedV[1] ← -v[2]; rotatedV[2] ← v[1]; RETURN};
IF degrees = -90.0 THEN {rotatedV[1] ← v[2]; rotatedV[2] ← -v[1]; RETURN};
theta ¬ RealFns.ArcTanDeg[v.y, v.x];
angleSum ¬ theta + degrees;
IF angleSum<= -180 THEN angleSum ¬ angleSum + 360
ELSE IF angleSum > 180 THEN angleSum ¬ angleSum - 360;
rotatedV ¬ VectorFromAngle[angleSum];
};
AngleFromVector:
PUBLIC
PROC [v: Vector]
RETURNS [position:
REAL] = {
position is a position angle such that -180 < position <= 180
position ¬ Angles2d.ArcTan[v.y, v.x];
};
AngleCCWBetweenVectors:
PUBLIC
PROC [v1, v2: Vector]
RETURNS [difference:
REAL] = {
difference will be in: 0 <= difference < 360. A clockwise angle
angle1, angle2: REAL;
angle1 ¬ AngleFromVector[v1];
angle2 ¬ AngleFromVector[v2];
difference ¬ Angles2d.CounterClockwiseAngle[angle1, angle2];
};
AngleCWBetweenVectors:
PUBLIC
PROC [v1, v2: Vector]
RETURNS [difference:
REAL] = {
difference will be in: 0 <= difference < 360. A counter-clockwise angle
angle1, angle2: REAL;
angle1 ¬ AngleFromVector[v1];
angle2 ¬ AngleFromVector[v2];
difference ¬ Angles2d.ClockwiseAngle[angle1, angle2];
};
SmallestAngleBetweenVectors:
PUBLIC
PROC [v1, v2: Vector]
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 ¬ Angles2d.ShortestDifference[angle1, angle2];
};
Add:
PUBLIC
PROC [v1, v2: Vector]
RETURNS [v1PlusV2: Vector] = {
v1PlusV2.x ¬ v1.x + v2.x;
v1PlusV2.y ¬ v1.y + v2.y;
};
Sub:
PUBLIC
PROC [v1, v2: Vector]
RETURNS [v1MinusV2: Vector] = {
v1MinusV2.x ¬ v1.x - v2.x;
v1MinusV2.y ¬ v1.y - v2.y;
};
Scale:
PUBLIC
PROC[v: Vector, s:
REAL]
RETURNS [vTimesS: Vector] = {
vTimesS.x ¬ v.x*s;
vTimesS.y ¬ v.y*s;
};
Normalize:
PUBLIC
PROC [v: Vector]
RETURNS [normV: Vector] = {
mag: REAL ¬ Magnitude[v];
normV.x ¬ v.x / mag;
normV.y ¬ v.y /mag;
};
Negate:
PUBLIC
PROC [v: Vector]
RETURNS [negV: Vector] = {
negV.x ¬ -v.x;
negV.y ¬ -v.y;
};
ElementwiseProduct:
PUBLIC
PROC [v1, v2: Vector]
RETURNS [v1Timesv2: Vector] = {
v1Timesv2.x ¬ v1.x*v2.x;
v1Timesv2.y ¬ v1.y*v2.y;
};
DotProduct:
PUBLIC
PROC [v1, v2: Vector]
RETURNS [scalar:
REAL] = {
scalar ¬ v1.x*v2.x + v1.y*v2.y;
};
CrossProductScalar:
PUBLIC
PROC [v1, v2: Vector]
RETURNS [scalar:
REAL] = {
scalar ¬ v1.x*v2.y - v1.y*v2.x;
};
Magnitude:
PUBLIC
PROC [v: Vector]
RETURNS [mag:
REAL] = {
mag ¬ RealFns.SqRt[v.x*v.x + v.y*v.y];
};
Distance:
PUBLIC
PROC [p1, p2: Point]
RETURNS [dist:
REAL] = {
dist ¬ Magnitude[Sub[p2, p1]];
};
MagnitudeSquared:
PUBLIC
PROC [v: Vector]
RETURNS [magSquared:
REAL] = {
magSquared ¬ v.x*v.x + v.y*v.y;
};
DistanceSquared:
PUBLIC
PROC [p1, p2: Point]
RETURNS [distSquared:
REAL] = {
distSquared ¬ MagnitudeSquared[Sub[p2, p1]];
};
RightNormalOfEdge:
PUBLIC
PROC [edge: Edge]
RETURNS [normal: Vector] = {
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: Vector;
IF edge.startIsFirst THEN direction ¬ VectorFromPoints[tail: edge.start, head: edge.end]
ELSE direction ¬ VectorFromPoints[tail: edge.end, head: edge.start];
normal.x ¬ direction.y;
normal.y ¬ -direction.x;
};
LeftNormalOfEdge:
PUBLIC
PROC [edge: Edge]
RETURNS [normal: Vector] = {
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: Vector;
IF edge.startIsFirst THEN direction ¬ VectorFromPoints[tail: edge.start, head: edge.end]
ELSE direction ¬ VectorFromPoints[tail: edge.end, head: edge.start];
normal.x ¬ -direction.y;
normal.y ¬ direction.x;
};
END.