On this page:
11.1 Basic Math Utilities
flfrac
flclamp
fxclamp
11.2 Coordinate Systems
11.2.1 Screen Coordinates
11.2.2 Map Coordinates
11.2.3 Transformations in Map Coordinates
11.2.4 Camera Coordinates
11.2.5 Vector Projection
11.3 Generic Linear Algebra
11.3.1 Generic 2D Vectors
flvec2
flvec2-linear
flvec2-values
11.3.2 Generic 3D Vectors
flvec3
flbec3-dot
flvec3-length
flvec3-length^2
flvec3-dist
flvec3-dist^2
flvec3-mul
flvec3-div
flvec3-normalize
flvec3-values
flvec3-linear
flvec3-add
flvec3-neg
flvec3-sub
flvec3-cross
11.4 Normalized Projective 3D Linear Algebra
11.4.1 Normalized Projective 3D Vectors
flvec4
flvec4-x
flvec4-y
flvec4-z
flvec4-w
flvec4-values
flvec4=?
flvec4-add
flvec4-neg
flvec4-sub
flvec4-mul
flvec4-linear
flvec4-project
flvec4-unproject
11.4.2 Normalized 3D Transformation Matrices
flmat4
flmat4-unit
flmat4*flvec4
flmat4-ref
flmat4*flmat4
flmat4*
11.5 Transformations in World/  Camera Coordinates
flmat4-rot  Z
flmat4-rot  X
flmat4-rot  Y
flmat4-translate
flmat4-scale
flmat4-map->camera
flmat4-project-unit
flmat4-project
11.6 Angle Manipulation Helpers
angle-add
angle-subtract
angle-wrap
angle-flvec3
azimuth-name
11.7 2D Integer Vectors
vec2
vec2-add
vec2-neg
vec2-sub
vec2s:  grid
vec2s:  grid+  diagonal
vec2-values
get-vec2-displacement
8.10

11 RRLL: Math

Dominik Pantůček <dominik.pantucek@trustica.cz>

Racket Rogue-Like Library: Math Functions

Common mathematical routines used for many RRLL modules.

11.1 Basic Math Utilities

 (require rrll/math/util) package: rrll-math

Additional math functions for fixnums and flonums.

procedure

(flfrac n)  flonum?

  n : flonum?
Returns the difference between given number and its flfloor.

procedure

(flclamp v min max)  flonum?

  v : flonum?
  min : flonum?
  max : flonum?
Returns a flonum? v clamped between max and min. If v is less than min, returns min, if it is more than max, returns max.

procedure

(fxclamp v min max)  fixnum?

  v : fixnum?
  min : fixnum?
  max : fixnum?
Returns a fixnum? v clamped between max and min. If v is less than min, returns min, if it is more than max, returns max.

11.2 Coordinate Systems

The main coordinate systems used in the project are:

These coordinates and their transformations are used in the rendering pipeline.

A set of functions for working with vectors in affine and projective spaces is implemented throghout the following modules.

11.2.1 Screen Coordinates

The screen – represented by canvas – is a two-dimensional plane with origin in the upper-left corner and the X coordinate growing from left to right and the Y coordinate growing from top to bottom.

image

The screen coordinates are represented as fixnum? values.

11.2.2 Map Coordinates

The world map is represented from the top view with origin – as the screen – with the origin at the top-left corner and the X coordinate growing from left to riht and the Y coordinate growing from top to bottom.

image

The respective compass directions North, East, South and West are shown in the picture as well.

For all practical purposes their respective azimut angles are clockwise from 0 pointing north:

The Z coordinate representing the height on the map grows from below the map up.

image

The inclination starts at \theta=0 for looking north (towards negative Y). Positive inclination goes up to \theta=\frac{\pi}{2} looking straight up in positive Z direction or down to \theta=-\frac{\pi}{2} looking straight down in negative Z direction.

11.2.3 Transformations in Map Coordinates

The simplest transformation is translation by given vector \vec{t} can be represented by the following matrix:

\vec{t}=(x_y,y_t,z_t)

T=\begin{bmatrix} 1 & 0 & 0 & x_t \\ 0 & 1 & 0 & y_t \\ 0 & 0 & 1 & z_t \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}

Rotation around the Z axis counter-clockwise by the angle \theta is:

Z=\begin{bmatrix} \cos\theta & \sin\theta & 0 & 0 \\ -\sin\theta & \cos\theta & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}

image

Rotation around the X axis counter-clockwise by the angle \theta is:

X=\begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos\theta & \sin\theta & 0 \\ 0 & -\sin\theta & \cos\theta & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}

image

Rotation around the Y axis counter-clockwise by the angle \theta is:

Y=\begin{bmatrix} \cos\theta & 0 & -\sin\theta & 0 \\ 0 & 1 & 0 & 0 \\ \sin\theta & 0 & \cos\theta & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}

image

11.2.4 Camera Coordinates

The 3D coordinates used for populating the world with polygons from the map and the camera coordinates share a similar same coordinate system.

The X coordinate grows from left to right, the Y coordinate grows from top to bottom and the Z coordinate grows into the screen.

image

After applying camera translation and all rotations, the axis are flipped to represent the point in camera coordinate axes using the following matrix:

M=\begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & -1 & 0 \\ 0 & -1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}

It switches the axes as follows:

x_w=x_m y_w=-z_m z_w=-y_m w_w=w_m

With camera axes in place the projective transformation to camera projective coordinates is performed using the projection matrix. The following parameters are used:

Because of limitations of the 24-bit fixed-point w-buffer (TODO), the near-plane distance has to be fixed:

n=0.1

The far-plane distance can be almost anything but for all practical purposes the following is used:

n=100

The projection assumes 90^\circ viewing angle in the smaller canvas dimension and slightly bigger viewing angle in the other dimension that gets calculated from the camera canvas width and height.

First, primary lens size is calculated:

w<=h\Rightarrow l=w w>h\Rightarrow l=h

Then width and height aspect ratio is computed:

r_w=\frac{w}{l} r_h=\frac{h}{l}

The projection matrix is then as follows:

P=\begin{bmatrix} \frac{2\cdot n\cdot r}{r_w} & 0 & 0 & 0 \\ 0 & \frac{2\cdot n}{r_h} & 0 & 0 \\ 0 & 0 & \frac{f+n}{f-n} & 1 \\ 0 & 0 & \frac{2\cdot f\cdot n}{f-n} & 0 \\ \end{bmatrix}

After applying the projection matrix the vertices are in camera projective coordinates. Clipping against frustum is performed in these coordinates.

11.2.5 Vector Projection

Any point in camera projective coordinates can be represented as:

P=(x_p,y_p,z_p,w_p)

A screen vector then is:

S=(x_s,y_s,w_s)

The projection is as follows:

x_s=w\cdot\frac{x_p+1}{2\cdot w_p} y_s=w\cdot\frac{y_p+1}{2\cdot w_p} w_s=w_p

The screen coordinates must be rounded to the nearest integer.

11.3 Generic Linear Algebra

11.3.1 Generic 2D Vectors

 (require rrll/math/algebra2) package: rrll-math

These procedures help with basic map vector handling.

procedure

(flvec2 [a b])  flvector?

  a : flonum? = 0.0
  b : flonum? = 0.0
Creates new flvector of two elements.

procedure

(flvec2-linear A B v)  flvector?

  A : flvector?
  B : flvector?
  v : flonum?
Computes linear interpolation between given vectors:

C=A+v\cdot(B-A)

procedure

(flvec2-values A)  
flonum? flonum?
  A : flvector?
Returns the two components as separate values.

11.3.2 Generic 3D Vectors

 (require rrll/math/algebra3) package: rrll-math

procedure

(flvec3 [a b c])  flvector?

  a : flonum? = 0.0
  b : flonum? = 0.0
  c : flonum? = 0.0
Returns a three-element flvector?.

procedure

(flbec3-dot v1 v2)  flonum?

  v1 : flvector?
  v2 : flvector?
Returns a dot-product of the two 3D vectors given:

d=\vec{v_1}\cdot\vec{v_2} d=x_{v_1}\cdot x_{v_2}+y_{v_1}\cdot y_{v_2}+z_{v_1}\cdot z_{v_2}

procedure

(flvec3-length v)  flonum?

  v : flvector?
Returns the length of given three-element flvector?:

l=\sqrt{\vec{v}\cdot \vec{v}} l=\sqrt{x_v^2+y_v^2+z_v^2}

procedure

(flvec3-length^2 v)  flonum?

  v : flvector?
Returns the square of given vector length.

l^2=x_v^2+y_v^2+z_v^2

procedure

(flvec3-dist A B)  flonum?

  A : flvector?
  B : flvector?
Returns the distance between the two vectors.

d=\sqrt{(x_A-x_B)^2+(y_A-y_B)^2+(z_A-z_B)^2}

procedure

(flvec3-dist^2 A B)  flonum?

  A : flvector?
  B : flvector?
Returns the square of the distance between the two vectors.

d^2=(x_A-x_B)^2+(y_A-y_B)^2+(z_A-z_B)^2

procedure

(flvec3-mul v n)  flvector?

  v : flvector?
  n : flonum?
Multiplies given vector by scalar:

\vec{v{}’}=n\cdot \vec{v} \vec{v}=(x_v,y_v,z_v) \vec{v{}’}=(x_v{}’,y_v{}’,z_v{}’) \vec{v{}’}=(n\cdot x_v,n\cdot y_v,n\cdot z_v)

procedure

(flvec3-div v n)  flvector?

  v : flvector?
  n : flonum?
Divides given flvector by scalar.

\vec{v{}’}=\frac{v}{n} \vec{v{}’}=\frac{1}{n}\cdot \vec{v}

procedure

(flvec3-normalize v)  flvector?

  v : flvector?
Returns the given vector divided by its size resulting in a vector of the same direction but unit size.

procedure

(flvec3-values v)  
flonum? flonum? flonum?
  v : flvector?
Returns the three components as separate values.

procedure

(flvec3-linear A B v)  flvector?

  A : flvector?
  B : flvector?
  v : flonum?
Computes linear interpolation between given vectors:

C=A+v\cdot(B-A)

procedure

(flvec3-add A B)  flvector?

  A : flvector?
  B : flvector?
Computes the sum of two three-dimensional vector by summing its components.

procedure

(flvec3-neg A)  flvector?

  A : flvector?
Computes the negation of given three-dimensional vector by negating its components. The resulting vector has opposite direction and the same size as the original vector.

procedure

(flvec3-sub A B)  flvector?

  A : flvector?
  B : flvector?
Computes the difference of the two three-dimensional vectors given by subtracting the components of the latter from the components of the former.

procedure

(flvec3-cross A B)  flvector?

  A : flvector?
  B : flvector?
Computes the cross product of the two three-dimensional vectors given. The resulting vector is perpendicular to both original vectors and its length is equal to the area of parallelogram delimited by them:

C=A\times B A=(x_A,y_A,z_A) B=(x_B,y_B,z_B) C=(x_C,y_C,z_C) x_C=y_A\cdot z_B-z_A\cdot y_B y_C=z_A\cdot x_B-x_A\cdot z_B z_C=x_A\cdot y_B-y_A\cdot x_B

11.4 Normalized Projective 3D Linear Algebra

 (require rrll/math/algebra4) package: rrll-math

This module handles the basic vector transformation in 4D affine vector space representing 3D projective vector space.

11.4.1 Normalized Projective 3D Vectors

The first part of this module implements the basic affine 4D vector operations.

procedure

(flvec4 [a b c d])  flvector?

  a : flonum? = 0.0
  b : flonum? = 0.0
  c : flonum? = 0.0
  d : flonum? = 1.0
Creates a new 4D vector with the w coordinate defaulting 1.0 to represent projective 3D vectors easily.

procedure

(flvec4-x v)  flonum?

  v : flvector?
Returns the 0th (x) coordinate of given flvec4.

procedure

(flvec4-y v)  flonum?

  v : flvector?
Returns the 1st (y) coordinate of given flvec4.

procedure

(flvec4-z v)  flonum?

  v : flvector?
Returns the 2nd (z) coordinate of given flvec4.

procedure

(flvec4-w v)  flonum?

  v : flvector?
Returns the 3rd (w) coordinate of given flvec4.

procedure

(flvec4-values v)  
flonum? flonum? flonum? flonum?
  v : flvector?
Returns the four separated components of the 4D affine vector representing a vector in the 3D projective vector space.

procedure

(flvec4=? v1 v2 [#:precision precision])  boolean?

  v1 : flvector?
  v2 : flvector?
  precision : flonum? = 0.0001
Compares all elements of two flvec4s with given arbitrary precision.

procedure

(flvec4-add v1 v2)  flvector?

  v1 : flvector?
  v2 : flvector?
Adds respective components of two flvec4s and returns the result as new one.

procedure

(flvec4-neg v)  flvector?

  v : flvector?
Negates all components of given flvec4 and returns the result as new one.

procedure

(flvec4-sub v1 v2)  flvector?

  v1 : flvector?
  v2 : flvector?
Subtracts respective components of two flvec4s and returns the result as new one.

procedure

(flvec4-mul v n)  flvector?

  v : flvector?
  n : flonum?
Multiplies all components of given flvec4 by specified number.

procedure

(flvec4-linear A B v)  flvector?

  A : flvector?
  B : flvector?
  v : flonum?
Performs linear interpolation of the two vectors given.

procedure

(flvec4-project v)  flvector?

  v : flvector?
Performs the projection of given vector \vec{v} and returns the result \vec{v}{}’.

\vec{v}=(x_v,y_v,z_v,w_v) \vec{v}{}’=(x_v{}’,y_v{}’,z_v{}’,w_v{}’) x_v{}’=\frac{x_v}{w_v} y_v{}’=\frac{y_v}{w_v} z_v{}’=\frac{z_v}{w_v} w_v{}’=w_v

procedure

(flvec4-unproject v)  flvector?

  v : flvector?
Performs the reverse of projection of given vector \vec{v} and returns the result \vec{v}{}’.

\vec{v}=(x_v,y_v,z_v,w_v) \vec{v}{}’=(x_v{}’,y_v{}’,z_v{}’,w_v{}’) x_v{}’=x_v\cdot w_v y_v{}’=y_v\cdot w_v z_v{}’=z_v\cdot w_v w_v{}’=w_v

11.4.2 Normalized 3D Transformation Matrices

These functions implement construction and application of 4\times 4 matrices.

procedure

(flmat4 [r0c0    
  r0c1    
  r0c2    
  r0c3    
  r1c0    
  r1c1    
  r1c2    
  r1c3    
  r2c0    
  r2c1    
  r2c2    
  r2c3    
  r3c0    
  r3c1    
  r3c2    
  r3c3])  flvector?
  r0c0 : flonum? = 0.0
  r0c1 : flonum? = 0.0
  r0c2 : flonum? = 0.0
  r0c3 : flonum? = 0.0
  r1c0 : flonum? = 0.0
  r1c1 : flonum? = 0.0
  r1c2 : flonum? = 0.0
  r1c3 : flonum? = 0.0
  r2c0 : flonum? = 0.0
  r2c1 : flonum? = 0.0
  r2c2 : flonum? = 0.0
  r2c3 : flonum? = 0.0
  r3c0 : flonum? = 0.0
  r3c1 : flonum? = 0.0
  r3c2 : flonum? = 0.0
  r3c3 : flonum? = 0.0
Creates a 4\times 4 matrix:

M=\begin{bmatrix} r0c0 & r0c1 & r0c2 & r0c3 \\ r1c0 & r1c1 & r1c2 & r1c3 \\ r2c0 & r2c1 & r2c2 & r2c3 \\ r3c0 & r3c1 & r3c2 & r3c3 \\ \end{bmatrix}

procedure

(flmat4-unit)  flvector?

Creates a 4\times 4 unit matrix:

M=\begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix}

procedure

(flmat4*flvec4 M v)  flvector?

  M : flvector?
  v : flvector?
Multiplies given vector \vec{v} by matrix M, returning the result \vec{v}{}’

M=\begin{bmatrix} M_{0,0} & M_{0,1} & M_{0,2} & M_{0,3} \\ M_{1,0} & M_{1,1} & M_{1,2} & M_{1,3} \\ M_{2,0} & M_{2,1} & M_{2,2} & M_{2,3} \\ M_{3,0} & M_{3,1} & M_{3,2} & M_{3,3} \\ \end{bmatrix}

\vec{v}=(x_v,y_v,z_v,w_v) \vec{v}{}’=(x_v{}’,y_v{}’,z_v{}’,w_v{}’) x_v{}’=M_{0,0}\cdot x_v+M_{0,1}\cdot y_v+M_{0,2}\cdot z_v+M_{0,3}\cdot w_v y_v{}’=M_{1,0}\cdot x_v+M_{1,1}\cdot y_v+M_{1,2}\cdot z_v+M_{1,3}\cdot w_v z_v{}’=M_{2,0}\cdot x_v+M_{2,1}\cdot y_v+M_{2,2}\cdot z_v+M_{2,3}\cdot w_v w_v{}’=M_{3,0}\cdot x_v+M_{3,1}\cdot y_v+M_{3,2}\cdot z_v+M_{3,3}\cdot w_v

\begin{bmatrix}x_v{}’\\y_v{}’\\z_v{}’\\w_v{}’\end{bmatrix}= \begin{bmatrix} M_{0,0} & M_{0,1} & M_{0,2} & M_{0,3} \\ M_{1,0} & M_{1,1} & M_{1,2} & M_{1,3} \\ M_{2,0} & M_{2,1} & M_{2,2} & M_{2,3} \\ M_{3,0} & M_{3,1} & M_{3,2} & M_{3,3} \\ \end{bmatrix}\cdot \begin{bmatrix}x_v\\y_v\\z_v\\w_v\end{bmatrix}

procedure

(flmat4-ref m r c)  flonum?

  m : flvector?
  r : fixnum?
  c : fixnum?
Returns a value found in column c, row r of given matrix m.

procedure

(flmat4*flmat4 m1 m2)  flvector?

  m1 : flvector?
  m2 : flvector?
Performs matrix multiplication.

procedure

(flmat4* mat ...)  flvector?

  mat : flvector?
Performs chained matrix multiplication from right to left.

11.5 Transformations in World/Camera Coordinates

 (require rrll/math/transform4) package: rrll-math

This module contains useful matrices for working in world/camera coordinates.

procedure

(flmat4-rotZ theta)  flvector?

  theta : flonum?
Returns a rotation matrix that rotates counter-clockwise around the Z axis by given angle.

procedure

(flmat4-rotX theta)  flvector?

  theta : flonum?
Returns a rotation matrix that rotates counter-clockwise around the X axis by given angle.

procedure

(flmat4-rotY theta)  flvector?

  theta : flonum?
Returns a rotation matrix that rotates counter-clockwise around the Y axis by given angle.

procedure

(flmat4-translate x y z)  flvector?

  x : flonum?
  y : flonum?
  z : flonum?
Returns a translation matrix that translates by given amount along all axes.

procedure

(flmat4-scale [x y z])  flvector?

  x : flonum? = 1.0
  y : flonum? = 1.0
  z : flonum? = 1.0
Returns a scaling matrix.

procedure

(flmat4-map->camera)  flvector?

Creates a transformation matrix that maps from map to world/camera coordinates.

procedure

(flmat4-project-unit near    
  far    
  width    
  height    
  [pixel-aspect])  flvector?
  near : flonum?
  far : flonum?
  width : (or/c fixnum? flonum?)
  height : (or/c fixnum? flonum?)
  pixel-aspect : (or/c #f flonum?) = #f
Constructs a standard projection matrix for the world/camera coordinate system. The screen size is measured from -1 to 1 in both directions.

procedure

(flmat4-project near    
  far    
  width    
  height    
  [pixel-aspect])  flvector?
  near : flonum?
  far : flonum?
  width : (or/c fixnum? flonum?)
  height : (or/c fixnum? flonum?)
  pixel-aspect : (or/c #f flonum?) = #f
Constructs a standard projection matrix for the world/camera coordinate system.

11.6 Angle Manipulation Helpers

 (require rrll/math/angles) package: rrll-math

This module contains simple functions for working with angles in the range \langle 0;2\pi\rangle.

Angles in this module and other related modules represented in 2D map coordinates point in the north direction for zero angle rotating clockwise as the angle increases.

image

procedure

(angle-add a1 a2)  flonum?

  a1 : flonum?
  a2 : flonum?
Adds two angles and clips the result within the 2\pi.

procedure

(angle-subtract a1 a2)  flonum?

  a1 : flonum?
  a2 : flonum?
Subtracts the second angle from the first returning a nonnegative result smaller than 2\pi.

procedure

(angle-wrap theta)  flonum?

  theta : flonum?
Makes sure given angle is within the \langle 0;2\pi\rangle range.

procedure

(angle-flvec3 theta)  flvector?

  theta : flonum?
Returns a unit vector pointing in the direction of given theta azimuth within the plane z=0.

procedure

(azimuth-name theta)  string?

  theta : flonum?
Returns the nearest name for given azimuth angle. All eight major and semi-major directions are handled.

11.7 2D Integer Vectors

 (require rlgrid/vec2)

A convenience structure for representing 2D coordinates in the grid. The x and y values can only be fixnum?s.

struct

(struct vec2 (x y))

  x : fixnum?
  y : fixnum?
Represents a single cell in a 2D grid - usually implemented as gen:rlgrid: tgrid, stgrid, and vgrid.

procedure

(vec2-add v1 v2)  vec2?

  v1 : vec2?
  v2 : vec2?
Returns the sum of two vec2s.

procedure

(vec2-neg v)  vec2?

  v : vec2?
Returns a vec2 with both coordinates negated.

procedure

(vec2-sub v1 v2)  vec2?

  v1 : vec2?
  v2 : vec2?
Subtracts v2 from v1 in both coordinates and returns the result.

value

vec2s:grid : (listof vec2?)

List of orthogonal grid directions: north, east, south, west.

image

value

vec2s:grid+diagonal : (lisof vec2?)

List of orthogonal and diagonal grid directions like vec2s:grid but also including: northeast, southeast, southwest, northwest.

image

procedure

(vec2-values v)  
fixnum? fixnum?
  v : vec2?
Deconstructs vector value.

procedure

(get-vec2-displacement d)  vec2?

  d : (or/c 'left 'right 'up 'down)
Returns vec2? displacement for 'left, 'right, 'up and 'down.