degree x = rad (toReal x * pi / 180.0)
normalize_radian :: !Real -> Real
-normalize_radian r
-| r < (~cycle) = normalize_radian (r + cycle)
-| r > cycle = normalize_radian (r - cycle)
-| otherwise = r
-where
- cycle = 2.0 * pi
+normalize_radian r = normalize r 100
+where
+ normalize r 0 = abort "Loop in normalize_radian. Mail p.achten@cs.ru.nl"
+ normalize r n
+ | r < ~pi = normalize (r + 2.0*pi) (n-1)
+ | r > pi = normalize (r - 2.0*pi) (n-1)
+ | otherwise = r
+
instance zero Angle where zero = Radian zero
instance + Angle where + (Radian r1) (Radian r2) = Radian (normalize_radian (r1 + r2))
px_bearing :: !base !target -> Angle | toPosition base & toPosition target
px_bearing base target
+| abs ratio > 1.0 = Radian zero // Corner-cases: d==0 and "large values of 1.0"
| v.dx >= zero && v.dy >= zero = Radian base_angle // 1st quadrant
| v.dx <= zero && v.dy >= zero = Radian (pi-base_angle) // 2nd quadrant
| v.dx <= zero && v.dy <= zero = Radian (base_angle-pi) // 3rd quadrant
ptarget = toPosition target
v = {dx = ptarget.px - pbase.px, dy = ptarget.py - pbase.py}
d = toReal (dist pbase ptarget)
- base_angle = acos ((toReal (abs v.dx)) / d)
+ ratio = toReal (abs v.dx) / d
+ base_angle = acos ratio
bearing :: !Angle !base !target -> Angle | toPosition base & toPosition target
bearing angle base target = px_bearing base target - angle