definition module Math.Geometry

/**
 * This module provides geometry related functions.
 *
 * @property-bootstrap
 *	   import StdReal, StdInt
 *	   import Data.Real
 *	   derive class Gast Angle
 *
 *	   (~~) infix 4
 *	   (~~) x y :== approxEqual (IF_INTERMEDIATE_80BIT_REAL_PRECISION 1.0E-10 1.0E-11) x y
 */

from StdEnv import class ==, class <, class +, class -, class sign, class abs

//* The constant pi.
pi :== 3.14159265359

/**
 * An angle.
 *
 * @invariant angleInvariant: A.angle :: Angle:
 *	   prop (abs (toDeg angle) <= 1.0E6)
 *	   // there is a tradeoff between the largest degree value allowed and the error
 */
:: Angle
  = Deg !Real //* An angle in degree representation
  | Rad !Real //* An angle in radian representation

/**
 * An angle corresponding to the given radian representation.
 *
 * @param the radian representation
 * @result the corresponding angle
 * @property correct angle from radian: A.r :: Real:
 *     not (isNaN r) ==> r =.= toRad (rad r)
 */
rad :: !Real -> Angle

/**
 * An angle corresponding to the given degree representation.
 *
 * @param the degree representation
 * @result the corresponding angle
 * @property correct angle from degrees: A.d :: Real:
 *     not (isNaN d) ==> d =.= toDeg (deg d)
 */
deg :: !Real -> Angle

/**
 * The degree representation of a given angle.
 *
 * @param the angle
 * @result the angle's degree representation
 * @property degrees from angle agree with radians: A.angle :: Angle:
 *     toDeg angle ~~ toDeg (rad (toRad angle))
 * @precondition angleInvariant angle
 */
toDeg :: !Angle -> Real

/**
 * The radian representation of a given angle.
 *
 * @param the angle
 * @result the angle's radian representation
 * @property radians from angle agree with degrees: A.angle :: Angle:
 *     toRad angle ~~ toRad (deg (toDeg angle))
 * @precondition angleInvariant angle
 */
toRad :: !Angle -> Real

/**
 * Normalizes an angle.
 *
 * @param the angle to normalize
 * @result the normalized angle
 * @property normalized degree range: A.angle :: Angle:
 *     0.0 <=. degNorm /\ degNorm <=. 360.0
 *     with
 *         degNorm = toDeg (normalize angle)
 * @property normalized radian range: A.angle :: Angle:
 *     0.0 <=. radNorm /\ radNorm <=. 2.0 * pi
 *     with
 *         radNorm = toRad (normalize angle)
 * @property idempotence: A.angle :: Angle:
 *     normalize angle =.= normalize (normalize angle)
 * @precondition angleInvariant angle
 */
normalize :: !Angle -> Angle

instance == Angle
instance < Angle
instance + Angle
instance - Angle
instance sign Angle
