<> <> <> <> <> <> DIRECTORY Real, RealFns, GGAngle; GGAngleImpl: CEDAR PROGRAM IMPORTS Real, RealFns EXPORTS GGAngle = BEGIN Normalize: PUBLIC PROC [anyRange: REAL] RETURNS [range180: REAL] = { <> IF anyRange > 180 THEN { <> realNumberOf360s: REAL _ anyRange/360; fixNumberOf360s: NAT _ Real.Fix[realNumberOf360s];-- FixC truncates numberToSubtract: REAL _ fixNumberOf360s*360.0; RETURN[anyRange-numberToSubtract]; }; IF anyRange <= -180 THEN { <> realNumberOf360s: REAL _ -anyRange/360; fixNumberOf360s: NAT _ Real.Fix[realNumberOf360s];-- FixC truncates numberToAdd: REAL _ (fixNumberOf360s + 1)*360.0; RETURN[anyRange+numberToAdd]; }; range180 _ anyRange }; -- end of Normalize AsSlope: PUBLIC PROC [anyRange: REAL] RETURNS [pos180: REAL] = { <> range180: REAL _ Normalize[anyRange]; -- -180 < theta <= 180 IF range180 < 0.0 THEN range180 _ range180 + 180.0; -- 0 <= theta <= 180 pos180 _ IF range180 = 180.0 THEN 0.0 ELSE range180; -- 0 <= theta < 180.0 }; Add: PUBLIC PROC [position, increment: REAL] RETURNS [finalPosition: REAL] = { <> finalPosition _ position + increment; -- -540 < finalPosition < 540 IF finalPosition > 180 THEN finalPosition _ finalPosition - 360 ELSE IF finalPosition <= -180 THEN finalPosition _ finalPosition + 360; }; -- end of Add ClockwiseAngle: PUBLIC PROC [fromPosition, toPosition: REAL] RETURNS [increment: REAL] = { <> increment _ 0; IF fromPosition < 0 THEN {-- start in lower semi-circle. <> IF -180 < toPosition AND toPosition <= fromPosition THEN RETURN[toPosition - fromPosition] ELSE increment _ increment + (-180 - fromPosition); increment _ increment + (toPosition-180); } ELSE { -- start in upper semi-circle. <> IF fromPosition < toPosition AND toPosition <= 180 THEN RETURN [toPosition - fromPosition - 360] ELSE RETURN[toPosition - fromPosition]; }; }; -- end of ClockwiseAngle CounterClockwiseAngle: PUBLIC PROC [fromPosition, toPosition: REAL] RETURNS [increment: REAL] = { <> <> increment _ 360 + ClockwiseAngle[fromPosition, toPosition]; IF increment = 360 THEN increment _ 0; }; ShortestDifference: PUBLIC PROC [position1, position2: REAL] RETURNS [pos1MinusPos2: REAL] = { <> clockwise: REAL _ ClockwiseAngle[position1, position2]; pos1MinusPos2 _ IF clockwise <= -180 THEN clockwise + 360 ELSE clockwise; }; Scale: PUBLIC PROC [angle: REAL, scalar: REAL] RETURNS [angleTimesScalar: REAL] = { <> angleTimesScalar _ angle*scalar; angleTimesScalar _ Normalize[angleTimesScalar]; }; ArcTan: PUBLIC PROC [numerator, denominator: REAL] RETURNS [degrees: REAL] = { <> degrees _ RealFns.ArcTanDeg[numerator, denominator]; degrees _ Normalize[degrees]; -- Normalize may not be needed. RealFns seems to do the right thing }; IsInCCWInterval: PUBLIC PROC [testPosition: REAL, fromPosition, toPosition: REAL] RETURNS [BOOL] = { <> IF fromPosition <= toPosition THEN -- the angle doesn't cross the -x axis RETURN[fromPosition<= testPosition AND testPosition <= toPosition] ELSE RETURN[ (fromPosition<= testPosition AND testPosition <= 180.0) OR (-180.0 < testPosition AND testPosition <= toPosition)]; }; IsInCCWInterval2: PUBLIC PROC [testPosition: REAL, fromPosition, increment: REAL] RETURNS [BOOL] = { toPosition: REAL; IF increment = 360.0 THEN RETURN[TRUE]; toPosition _ Add[fromPosition, increment]; RETURN[IsInCCWInterval[testPosition, fromPosition, toPosition]]; }; AlmostParallel: PUBLIC PROC [pos1, pos2: REAL, epsilon: REAL] RETURNS [BOOL] = { <> diff: REAL; diff _ ABS[pos1 - pos2]; IF diff < epsilon THEN RETURN[TRUE]; IF ABS[diff - 180.0] < epsilon THEN RETURN[TRUE]; RETURN[FALSE]; }; END.