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. *File: GGAngleImpl.mesa Last edited by Bier on June 4, 1985 6:15:52 pm PDT Author: Eric Bier on February 10, 1987 1:33:38 pm PST Contents: Gargoyle requires a precise set of angle operations defined with angle "theta" in the range -180 < theta <= 180. "theta" is an absolute angle (ie a position around the circle). Given two positions angles T1 and T2 we can find the incremental clockwise angle CT between them or the incremental counter-clockwise angle CCT where -360 < CT <= 0 and 0 <= CCT < 360. When we add two angles, we are adding an incremental angle to a position angle to get a new position angle. We subtract two position angles to get an incremental angle. Pier, December 6, 1985 10:06:16 am PST Kurlander August 25, 1986 4:45:40 pm PDT Takes an angle in degrees and puts it in -180 < theta <= 180 form. Find the integer number of times 360 goes into it and subtract that many 360's. Find the integer number of times 360 goes into its negative and add (that many + 1) 360's. Takes an angle in degrees and puts it in 0 <= theta < 180 form. This may require adding 180 degrees for negative angles. All angles in degrees All angles in degrees. -360 < increment <= 0 Proceed clockwise until you encounter theta = 180 or "toPostion". Proceed clockwise until you encounter "toPostion" or theta = 180 All angles in degrees. 0 <= increment < 360. For example, if the clockwise angle is -90, the counter-clockwise angle will be 270. All angles in degrees. RETURNS ClockwiseAngle or CounterClockwiseAngle. Whichever is smaller. -180< pos1MinusPos2 <= 180. All angles in degrees. Think of angle as the increment from 0 degrees to angle degrees. Scale this and normalize. Has the effect of calling RealFns.ArcTanDegrees and normalizing the result. Consider the set of angles encountered when traveling counterclockwise from angle "fromPosition" to angle "toPosition" around a circle. Is testPosition one of the angles encountered? pos1 and pos2 are assumed to be in -180 < theta <= 180. Return TRUE if they are the same angle +- epsilon or if they differ by 180+- epsilon. Κ˜Icodešœ™Kšœ2™2Kšœ5™5šœ ™ K™&K™(—K˜šΟk ˜ Kšœ˜—K˜šœ œ˜Kšœ˜Kšœ ˜—Kš˜K˜š Οn œœœ œœ œ˜DKšœB™Bšœœ˜KšœO™OKšœœ˜&KšœœΟc˜CKšœœ˜/Kšœ˜"Kšœ˜—šœœ˜KšœZ™ZKšœœ˜'KšœœŸ˜CKšœ œ˜0Kšœ˜Kšœ˜—Kšœ˜KšœŸ˜—K˜š žœœœ œœ œ˜@Kšœy™yKšœ œ0˜>KšœI˜IKšœ œœœ ˜JK˜K˜—š žœœœœœœ˜NKšœ™Kšœ&Ÿ˜CKšœœ$˜?Kšœœœ%˜GKšœŸ ˜—K˜š žœœœœœ œ˜ZKšœ,™,Kšœ˜šœœŸ˜8KšœA™AKšœœœœ˜ZKšœ/˜3Kšœ œ˜)Kšœ˜—šœŸ˜%Kšœ@™@Kšœœœœ"˜`Kšœœ˜'Kšœ˜—KšœŸ˜K˜—š žœœœœœ œ˜aKšœ,™,KšœT™TKšœ;˜;Kšœœ˜&Kšœ˜—K˜š žœœœœœœ˜_Kšœ{™{Kšœ œ(˜7Kšœœœœ ˜IKšœ˜—K˜šžœœœ œ œœœ˜SKšœr™rKšœ ˜ Kšœ/˜/Kšœ˜—K˜š žœœœœœ œ˜NšœK™KKšœ4˜4KšœŸD˜bKšœ˜K˜——šžœœœœœœœ˜dKšœ·™·šœI˜IKšœB˜B—˜šœ˜Kšœ;˜;Kšœ8˜8——Kšœ˜K˜—šžœœœœœœœ˜dKšœ œ˜Kšœœœœ˜'Kšœ*˜*Kšœ:˜@K˜—K˜šžœœœœ œœœ˜PKšœ@œJ™ŽKšœœ˜ Kšœœ˜Kšœœœœ˜$Kš œœœœœ˜1Kšœœ˜K˜K˜—Kšœ˜K˜—…— Άο