<<>> <> <> <> <> <> <> 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] = { <> <> vector.x ¬ RealFns.CosDeg[angle]; vector.y ¬ RealFns.SinDeg[angle]; }; VectorPlusAngle: PUBLIC PROC [v: Vector, degrees: REAL] RETURNS [rotatedV: Vector] = { <> theta: REAL; angleSum: REAL; <> <> 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 ¬ Angles2d.ArcTan[v.y, v.x]; }; AngleCCWBetweenVectors: PUBLIC PROC [v1, v2: Vector] RETURNS [difference: REAL] = { <> angle1, angle2: REAL; angle1 ¬ AngleFromVector[v1]; angle2 ¬ AngleFromVector[v2]; difference ¬ Angles2d.CounterClockwiseAngle[angle1, angle2]; }; AngleCWBetweenVectors: PUBLIC PROC [v1, v2: Vector] RETURNS [difference: REAL] = { <> angle1, angle2: REAL; angle1 ¬ AngleFromVector[v1]; angle2 ¬ AngleFromVector[v2]; difference ¬ Angles2d.ClockwiseAngle[angle1, angle2]; }; SmallestAngleBetweenVectors: PUBLIC PROC [v1, v2: Vector] RETURNS [difference: REAL] = { <> 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] = { <> 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] = { <> 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.