Math
====

Modeling a virtual world requires a good dose of linear algebra, trigonometry, and calculus.  Sly comes with modules for 2D/3D/4D vector math, trigonometry, axis-aligned bounding boxes, quaternions, 4x4 transformation matrices, and interpolation.

Vectors
-------

     (use-modules (sly math vector))

Not to be confused with Guile's vector data structure, Sly provides dedicated data types for 2D, 3D, and 4D vectors in the mathematical sense.  Vector procedures are polymorphic, and will work with any dimensionality that the operation supports.  In some cases, such as v+, v-, and v*, scalar values may be passed as well.

The <vector2>, <vector3>, and <vector4> type descriptors have been exposed for use with Guile's (ice-9 match) pattern matching module.

 -- Record Type: <vector2>
     2D vector data type with fields x and y, in that order.

 -- Record Type: <vector3>
     3D vector data type with fields x, y, and z, in that order.

 -- Record Type: <vector4>
     4D vector data type with fields x, y, z and w, in that order.

 -- Scheme Syntax: vector2 X Y
     Create a new 2D vector with coordinates (X, Y).

 -- Scheme Syntax: vector3 X Y Z
     Create a new 3D vector with coordinates (X, Y, Z).

 -- Scheme Syntax: vector4 X Y Z W
     Create a new 4D vector with coordinates (X, Y, Z, W).

 -- Scheme Syntax: vector2? V
     Return #t if v is a 2D vector.

 -- Scheme Syntax: vector3? V
     Return #t if v is a 3D vector.

 -- Scheme Syntax: vector4? V
     Return #t if v is a 4D vector.

 -- Scheme Procedure: vx V
     Return the x coordinate of the 2D, 3D, or 4D vector V.

 -- Scheme Procedure: vy V
     Return the y coordinate of the 2D, 3D, or 4D vector V.

 -- Scheme Procedure: vz V
     Return the z coordinate of the 3D or 4D vector V.

 -- Scheme Procedure: vw V
     Return the w coordinate of the 4D vector V.

 -- Scheme Procedure: vmap PROC V
     Return a new vector that is the result of applying PROC to each element of the 2D, 3D, or 4D vector V.

 -- Scheme Procedure: v+ . VECTORS
     Return the sum of all VECTORS.  VECTORS may contain scalar values, but it may not contain vectors of mixed dimensions.

 -- Scheme Procedure: v- . VECTORS
     Return the difference of all VECTORS.  VECTORS may contain scalar values, but it may not contain vectors of mixed dimensions.

 -- Scheme Procedure: v* . VECTORS
     Return the product of all VECTORS.  VECTORS may contain scalar values, but it may not contain vectors of mixed dimensions.

 -- Scheme Procedure: vdot V1 V2
     Return the dot product of V1 and V2.  Both vectors must be of the same dimensionality.

 -- Scheme Procedure: vcross V1 V2
     Return the cross product of the 3D vectors V1 and V2.

 -- Scheme Procedure: magnitude V
     Return the magnitude of the vector V.

 -- Scheme Procedure: normalize V
     Return the normalized form of the vector V.

 -- Scheme Procedure: vlerp V1 V2 ALPHA
     Return the linear interpolation of V1 and V2 by the scalar ALPHA.  ALPHA is expected to be in the range [0, 1].

Rectangles
----------

     (use-modules (sly math rect))

Rects are 2D axis-aligned bounding boxes.  They are useful for defining rectangular regions, such as the hitbox of a game entity, or the viewport of a camera.  Because rects are axis-aligned, they provide a cheap means to perform simple collision detection.

The <rect> type descriptor has been exposed for use with Guile's (ice-9 match) pattern matching module.

 -- Scheme Variable: <rect>
     Rectangle data type with fields x, y, width, height, in that order.

 -- Scheme Procedure: make-rect X Y WIDTH HEIGHT
     Create a new rectangle with position (X, Y), and dimensions (WIDTH, HEIGHT).

 -- Scheme Variable: null-rect
     Rectangle with x, y, width, and height of 0.

 -- Scheme Syntax: rect? OBJ
     Return #t if OBJ is a rectangle.

 -- Scheme Syntax: rect-x RECT
     Return the x coordinate of RECT.

 -- Scheme Syntax: rect-y RECT
     Return the x coordinate of RECT.

 -- Scheme Syntax: rect-width RECT
     Return the width of RECT.

 -- Scheme Syntax: rect-height RECT
     Return the height of RECT.

 -- Scheme Procedure: rect-left RECT
     Return the left-hand x coordinate of RECT.

 -- Scheme Procedure: rect-right RECT
     Return the right-hand x coordinate  of RECT.

 -- Scheme Procedure: rect-top RECT
     Return the top y coordinate of RECT

 -- Scheme Procedure: rect-bottom RECT
     Return the bottom y coordinate of RECT.

 -- Scheme Procedure: rect-top-left RECT
     Return the top-left corner of RECT.

 -- Scheme Procedure: rect-top-right RECT
     Return the top-right corner of RECT.

 -- Scheme Procedure: rect-bottom-left RECT
 -- Scheme Procedure: rect-position RECT
     Return the bottom-left corner of RECT

 -- Scheme Procedure: rect-bottom-right RECT
     Return the bottom-right corner of RECT.

 -- Scheme Procedure: rect-center-x RECT
     Return the center x coordinate of RECT.

 -- Scheme Procedure: rect-center-y RECT
     Return the center y coordinate of RECT.

 -- Scheme Procedure: rect-center RECT
     Return the center of RECT.

 -- Scheme Procedure: rect-half-width RECT
     Return the half width of RECT.

 -- Scheme Procedure: rect-half-height RECT
     Return the half height of RECT.

 -- Scheme Procedure: rect-size RECT
     Return the size of RECT.

 -- Scheme Procedure: rect-move RECT V
 -- Scheme Procedure: rect-move RECT X Y
     Create a new rectangle by moving RECT by the given 2D vector offset V, or the coordinates X and Y.

 -- Scheme Procedure: rect-inflate RECT SIZE
 -- Scheme Procedure: rect-inflate RECT WIDTH HEIGHT
     Create a new rectangle by growing RECT by the 2D vector SIZE (or WIDTH and HEIGHT) without changing the center point.

 -- Scheme Procedure: rect-union RECT1 RECT2
     Create a new rectangle that covers the area of both RECT1 and RECT2.

 -- Scheme Procedure: rect-clip RECT1 RECT2
     Create a new rectangle that is the overlapping region of RECT1 and RECT2.  If the rects do not overlap, a rect of size 0 is returned.

 -- Scheme Procedure: rect-clamp RECT V
     Return a new 2D vector by constraining V to the bounds of RECT.

 -- Scheme Procedure: rect-within? RECT1 RECT2
     Return #t if RECT2 is completely within RECT1.

 -- Scheme Procedure: rect-intersects? RECT1 RECT2
     Return #t if RECT2 overlaps RECT1.

 -- Scheme Procedure: rect-contains? RECT V
 -- Scheme Procedure: rect-contains? RECT X Y
     Return #t if the 2D vector V (or the coordinates X and Y) is within RECT.

Transforms
----------

     (use-modules (sly math transform))

Transforms are 4x4 transformation matrices.  Matrices are the fundamental structure for modeling affine transformations such as translation, rotation, and scaling.  Complex transformations are created by composing many simpler ones with the transform* procedure.

It's a good idea to use transforms in a functional manner by treating them as immutable.  This is made easy because almost every procedure in this module returns a new transform rather than mutating an existing one.  However, in some cases it is necessary to use mutable transforms via transform*! for performance reasons.

 -- Scheme Procedure: make-transform AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
     Create a new transform initialized with the given 16 values in column-major format.

 -- Scheme Variable: null-transform
     A transform composed entirely of zeroes.

 -- Scheme Variable: identity-transform
     The multiplicative identity transform.

 -- Scheme Syntax: transform? OBJ
     Return #t if OBJ is a transform.

 -- Scheme Syntax: transform-matrix TRANSFORM
     Return the underlying 4x4 floating point array for TRANSFORM.

 -- Scheme Procedure: transpose TRANSFORM
     Return a transform that is the transpose of TRANSFORM.

 -- Scheme Procedure: transform-vector2 TRANSFORM V
     Apply TRANSFORM to the 2D vector V.

 -- Scheme Procedure: transform-position TRANSFORM
     Return a 3D vector containing the positional data stored in TRANSFORM.

 -- Scheme Procedure: transform+ . TRANSFORMS
     Return the sum of TRANSFORMS.  Return null-transform if called without any arguments.

 -- Scheme Procedure: transform* . TRANSFORMS
     Return the product of TRANSFORMS.  Return identity-transform if called without any arguments.

 -- Scheme Procedure: transform*! DEST A B
     Multiply A and B, storing the result in DEST.

 -- Scheme Procedure: translate V
     Create a new transform that translates by the 2D or 3D vector V.

 -- Scheme Procedure: scale V
 -- Scheme Procedure: scale SCALAR
     Create a new transform that scales by the 2D or 3D vector V, or by SCALAR to scale evenly in all dimensions.

 -- Scheme Procedure: rotate-x ANGLE
     Create a new transform that rotates the x axis by ANGLE radians.

 -- Scheme Procedure: rotate-y ANGLE
     Create a new transform that rotates the y axis by ANGLE radians.

 -- Scheme Procedure: rotate-z ANGLE
     Create a new transform that rotates the z axis by ANGLE radians.

 -- Scheme Procedure: rotate Q
     Convert the quaternion Q into a rotation transform. See Quaternions for more information.

One of the most common composite transformations is a translation multiplied by a scale multiplied by a rotation.  The build-transform procedure is a convenience procedure for this case.

 -- Scheme Procedure: build-transform [#:POSITION=(VECTOR3 0 0 0)] [#:SCALE=1] [#:ROTATION=NULL-QUATERNION]
     Build a transform by multiplying the following transforms:

       * translation by POSITION

       * rotation by ROTATION

       * scaling by SCALE

The procedures below are useful for creating projection and view matrices for cameras. See Cameras for more details.

 -- Scheme Procedure: orthographic-projection left right top bottom near far
     Create a new transform that represents an orthographic projection for the vertical clipping plane LEFT and RIGHT, the horizontal clipping plane TOP and BOTTOM, and the depth clipping plane NEAR and FAR.

 -- Scheme Procedure: perspective-projection FIELD-OF-VISION ASPECT-RATIO NEAR FAR
     Create a new transform that represents a perspective projection with a FIELD-OF-VISION in degrees, the desired ASPECT-RATIO, and the depth clipping plane NEAR and FAR.

 -- Scheme Procedure: look-at EYE CENTER [UP=(VECTOR3 0 1 0)]
     Create a view transform that looks from 3D vector EYE at the 3D vector CENTER, with the 3D vector UP indicating which direction points up.

Tweens
------

     (use-modules (sly math tween))

Tweening is the process of interpolating between two key values to create the illusion of smooth animation.  There are many different ways to alter the rate of change, or ``ease'', one value to another.

When tween functions are combined with Signals, the result is animation!

Easings
.......

Easing procedures specify the rate of change of a value ALPHA over time.  Easings may be composed to form complex animation.

The following procedures are used to control repitition by clamping ALPHA to the range [0, 1] in different ways.

 -- Scnheme Procedure: ease-loop ALPHA
     When ALPHA reaches 1, start over from 0.

 -- Scheme Procedure: ease-reflect ALPHA
     When ALPHA reaches 1, work backwards to 0.  When ALPHA reaches 0, work forwards to 1.

The following easing functions control the rate of change of an animation:

 -- Scheme Procedure: ease-linear ALPHA

 -- Scheme Procedure: ease-in-sine ALPHA

 -- Scheme Procedure: ease-out-sine ALPHA

 -- Scheme Procedure: ease-in-out-sine ALPHA

 -- Scheme Procedure: ease-in-quad ALPHA

 -- Scheme Procedure: ease-out-quad ALPHA

 -- Scheme Procedure: ease-in-out-quad ALPHA

Tweening
........

The tween procedure creates new procedures to be used for animation.  For example, the code below creates a tween procedure that linearly interpolates (0, 0) to (10, 10) over the course of ten ticks.

     (define t (tween vlerp ease-linear (vector2 0 0) (vector2 10 0) 10))

     (t 5) ;; => (vector2 5 5)

 -- Scheme Procedure: tween INTERPOLATOR EASE START END DURATION
     Return a procedure that interpolates from START to END in DURATION ticks.  The value returned for a given time is determined by applying EASE with the time ratio to acquire an ALPHA value, and then applying INTERPOLATOR with START, END, and ALPHA.  ALPHA is a rational number in the range [0, 1].

Quaternions
-----------

     (use-modules (sly math quaternion))

Quaternions are used to express rotations about an arbitrary axis in a way that avoids ``gimbal lock'' and allows for useful interpolation, unlike matrices or Euler angles.

Quaternions can be used in rotation transformations (see Transforms), as well as converted to and from Vectors.

 -- Record Type: <quaternion>
     Data type with 4 fields: w, x, y, z, in that order.  This type descriptor has been exposed for destructuring via Guile's (ice-9 match) module.

 -- Scheme Procedure: make-quaternion V THETA
 -- Scheme Procedure: make-quaternion W X Y Z
     Create a new quaternion from an axis angle (a 3D vector V plus an angle THETA) or from individual coordinates W, X, Y, and Z.

 -- Scheme Procedure: quaternion V THETA
 -- Scheme Procedure: quaternion W X Y Z
     Alternate spelling of make-quaternion.

 -- Scheme Syntax: quaternion? OBJ
     Return #t if OBJ is a quaternion.

 -- Scheme Syntax: quaternion-w Q
     Return the w coordinate of the quaternion Q.

 -- Scheme Syntax: quaternion-x Q
     Return the x coordinate of the quaternion Q.

 -- Scheme Syntax: quaternion-y Q
     Return the y coordinate of the quaternion Q.

 -- Scheme Syntax: quaternion-z Q
     Return the z coordinate of the quaternion Q.

 -- Scheme Variable: identity-quaternion
     The multiplicative identity quaternion.

 -- Scheme Variable: null-quaternion
     A quaternion with all fields set to zero.

 -- Scheme Procedure: quaternion* . QUATERNIONS
     Return the product of all QUATERNIONS.  Return identity-quaternion if called without arguments.

 -- Scheme Procedure: quaternion-slerp Q1 Q2 DELTA
     Perform a spherical linear interpolation of the quaternions Q1 and Q2 and blending factor DELTA.

 -- Scheme Procedure: quaternion-magnitude Q
     Return the magnitude of the quaternion Q.

 -- Scheme Procedure: quaternion-normalize Q
     Return the normalized form of the quaternion Q.

 -- Scheme Procedure: vector->quaternion V
     Convert the 4D vector V to a quaternion.

 -- Scheme Procedure: quaternion->vector Q
     Convert the quaternion Q to a 4D vector.

Miscellaneous
-------------

     (use-modules (sly math))

A grab bag of commonly used math functions and constants.

 -- Scheme Variable: pi
     An approximation of \pi, the ratio of a circle's circumference to its diameter.

 -- Scheme Variable: 2pi
     2\pi

 -- Scheme Variable: pi/2
     \pi/2

 -- Scheme Procedure: degrees->radians ANGLE
     Convert ANGLE from degrees to radians.

 -- Scheme Procedure: radians->degrees ANGLE
     Convert ANGLE from radians to degrees.

 -- Scheme Procedure: sin-degrees ANGLE
     Return the sine of ANGLE, where ANGLE is measured in degrees.

 -- Scheme Procedure: cos-degrees ANGLE
     Return the cosine of ANGLE, where ANGLE is measured in degrees.

 -- Scheme Procedure: tan-degrees ANGLE
     Return the tangent of ANGLE, where ANGLE is measured in degrees.

 -- Scheme Procedure: atan-degrees Y X
     Return the arctangent of Y and X, where Y and X are measured in degrees.

 -- Scheme Procedure: cotan Z
     Return the cotangent of Z.

 -- Scheme Procedure: clamp MIN MAX X
     Restrict X to the range [MIN, MAX], assuming that MIN is actually less than MAX.

 -- Scheme Procedure: linear-scale MIN MAX A B N
     Map N in the range [MIN, MAX] to the range [A, B].

 -- Scheme Procedure: half X
     Return X / 2.

 -- Scheme Procedure: square X
     Return X^2.

 -- Scheme Procedure: make-lerp + *
     Return a new procedure that accepts three arguments: START, END, and ALPHA.  The returned procedure uses the procedures + and * to linearly interpolate a value between START and END.  ALPHA should always be in the range [0, 1].

 -- Scheme Procedure: lerp START END ALPHA
     Return the linear interpolation between the numbers START and END with scalar factor ALPHA.

 -- Scheme Procedure: modulo* X Y
     Return the remainder of X / Y.  Works like regular modulo, except that X and Y may be rational numbers or inexact numbers.