File: GGVectorImpl.mesa
Last edited by Bier on June 4, 1985 6:11:29 pm PDT
Author: Eric Bier on June 21, 1985 5:53:16 pm PDT
Contents: Routines for manipulation vectors in two dimensions
DIRECTORY
RealFns,
GGModelTypes,
GGAngle,
GGVector;
GGVectorImpl:
CEDAR
PROGRAM
IMPORTS RealFns, GGAngle
EXPORTS GGVector =
BEGIN
Point: TYPE = GGModelTypes.Point;
Edge: TYPE = GGModelTypes.Edge;
Vector: TYPE = GGModelTypes.Vector;
VectorFromPoints:
PUBLIC PROC [tail, head: Point]
RETURNS [vector: Vector] =
CHECKED {
vector[1] ← head[1] - tail[1];
vector[2] ← head[2] - tail[2];
};
VectorFromAngle:
PUBLIC PROC [angle:
REAL]
RETURNS [vector: Vector] =
CHECKED {
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: Vector, degrees:
REAL]
RETURNS [rotatedV: Vector] =
CHECKED {
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: Vector]
RETURNS [position:
REAL] =
CHECKED {
position is a position angle such that -180 < position <= 180
position ← GGAngle.ArcTan[v[2], v[1]];
};
AngleCCWBetweenVectors:
PUBLIC PROC [v1, v2: Vector]
RETURNS [difference:
REAL] =
CHECKED {
difference will be in: 0 <= difference < 360. A clockwise angle
angle1, angle2: REAL;
angle1 ← AngleFromVector[v1];
angle2 ← AngleFromVector[v2];
difference ← GGAngle.CounterClockwiseAngle[angle1, angle2];
};
AngleCWBetweenVectors:
PUBLIC PROC [v1, v2: Vector]
RETURNS [difference:
REAL] =
CHECKED {
difference will be in: 0 <= difference < 360. A counter-clockwise angle
angle1, angle2: REAL;
angle1 ← AngleFromVector[v1];
angle2 ← AngleFromVector[v2];
difference ← GGAngle.ClockwiseAngle[angle1, angle2];
};
SmallestAngleBetweenVectors:
PUBLIC PROC [v1, v2: Vector]
RETURNS [difference:
REAL] =
CHECKED {
all angles in degrees. RETURNS ClockwiseAngle or CounterClockwiseAngle. Whichever is smaller. -180 < difference <= 180.
angle1, angle2: REAL;
angle1 ← AngleFromVector[v1];
angle2 ← AngleFromVector[v2];
difference ← GGAngle.ShortestDifference[angle1, angle2];
};
Add:
PUBLIC PROC [v1, v2: Vector]
RETURNS [v1PlusV2: Vector] =
CHECKED {
v1PlusV2[1] ← v1[1] + v2[1];
v1PlusV2[2] ← v1[2] + v2[2];
};
Sub:
PUBLIC PROC [v1, v2: Vector]
RETURNS [v1MinusV2: Vector] =
CHECKED {
v1MinusV2[1] ← v1[1] - v2[1];
v1MinusV2[2] ← v1[2] - v2[2];
};
Scale:
PUBLIC PROC[v: Vector, s:
REAL]
RETURNS [vTimesS: Vector] =
CHECKED {
vTimesS[1] ← v[1]*s;
vTimesS[2] ← v[2]*s;
};
Normalize:
PUBLIC PROC [v: Vector]
RETURNS [normV: Vector] =
CHECKED {
mag: REAL ← Magnitude[v];
normV[1] ← v[1] / mag;
normV[2] ← v[2] /mag;
};
Negate:
PUBLIC PROC [v: Vector]
RETURNS [negV: Vector] =
CHECKED {
negV[1] ← -v[1];
negV[2] ← -v[2];
};
ElementwiseProduct:
PUBLIC PROC [v1, v2: Vector]
RETURNS [v1Timesv2: Vector] =
CHECKED {
v1Timesv2[1] ← v1[1]*v2[1];
v1Timesv2[2] ← v1[2]*v2[2];
};
DotProduct:
PUBLIC PROC [v1, v2: Vector]
RETURNS [scalar:
REAL] =
CHECKED {
scalar ← v1[1]*v2[1] + v1[2]*v2[2];
};
Magnitude:
PUBLIC PROC [v: Vector]
RETURNS [mag:
REAL] =
CHECKED {
mag ← RealFns.SqRt[v[1]*v[1] + v[2]*v[2]];
};
Distance:
PUBLIC PROC [p1, p2: Point]
RETURNS [dist:
REAL] =
CHECKED {
dist ← Magnitude[Sub[p2, p1]];
};
MagnitudeSquared:
PUBLIC PROC [v: Vector]
RETURNS [magSquared:
REAL] =
CHECKED {
magSquared ← v[1]*v[1] + v[2]*v[2];
};
DistanceSquared:
PUBLIC PROC [p1, p2: Point]
RETURNS [distSquared:
REAL] =
CHECKED {
distSquared ← MagnitudeSquared[Sub[p2, p1]];
};
RightNormalOfEdge:
PUBLIC PROC [edge: Edge]
RETURNS [normal: Vector] =
CHECKED {
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[1] ← direction[2];
normal[2] ← -direction[1];
};
LeftNormalOfEdge:
PUBLIC PROC [edge: Edge]
RETURNS [normal: Vector] =
CHECKED {
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[1] ← -direction[2];
normal[2] ← direction[1];
};
END.