# mathutils - all the basic math types and functions¶

Most of the names here are coming from the glm module. But the goal is to harvest at one point all the basic math functions and objects that are used all around madcad.

Tip

All the present functions and types are present in the root madcad module.

## Most common glm types¶

all implements the common operators `+ - * / <> ==`

vec3

alias of `glm.dvec3`

mat3

alias of `glm.dmat3x3`

mat4

alias of `glm.dmat4x4`

quat

alias of `glm.dquat`

all glm types exists with several element types and in several precision:

prefix

precision

d

f64 aka double precisin floating point

f

f32 aka for simple precision floating point

i

i32 aka integer

i16

16 bits integer

i8

8 bits integer aka byte

u

unsigned integer (also declines in u16 and u32)

b

bit aka boolean

• precision specification is put as prefix: `dvec3, fvec3, imat4`. Notation without prefix refers to the madcad implementation precision: float64 (prefix ‘d’).

• object dimension is put as suffix.

In this documentation, when we refer to a ‘vector’ without explicit type, we obviously mean a `vec3` aka. `dvec3`.

Note

The default glm precision type is float32 (prefix ‘f’). For convenience, these are overriden in madcad to use float64 for a better precision.

## Common vector operations¶

dot(x: float, y: float) float

Returns the dot product of `x` and `y`, i.e., `result = x * y`. dot(x: vecN, y: vecN) -> float

Returns the dot product of `x` and `y`, i.e., `result = x * y + x * y + ...`

dot(x: quat, y: quat) -> float

Returns dot product of `x` and `y`, i.e., `x * y + x * y + ...` cross(x: vec3, y: vec3) vec3

Returns the cross product of `x` and `y`. cross(x: quat, y: quat) -> quat

Compute a cross product. length(x: float) float

Returns the length of `x`, i.e., `abs(x)`. length(x: vecN) -> float

Returns the length of `x`, i.e., `sqrt(x * x)`.

length(x: quat) -> float

Returns the norm of a quaternion. distance(p0: float, p1: float) float

Returns the distance between `p0` and `p1`, i.e., `length(p0 - p1)`. distance(p0: vecN, p1: vecN) -> float

Returns the distance between `p0` and `p1`, i.e., `length(p0 - p1)`. normalize(x) vecN

Returns `x` normalized. ie. `x / length(x)`

The new vector has the same direction than `x` but with length `1`.

anglebt(x, y) float

angle between two vectors

the result is not sensitive to the lengths of x and y arclength(p1, p2, n1, n2)

length of an arc between p1 and p2, normal to the given vectors in respective points

project(vec, dir) glm.dvec3

component of `vec` along `dir`, equivalent to `dot(vec,dir) / dot(dir,dir) * dir`

the result is not sensitive to the length of `dir` noproject(vec, dir) glm.dvec3

components of `vec` not along `dir`, equivalent to `vec - project(vec,dir)`

the result is not sensitive to the length of `dir` unproject(vec, dir) glm.dvec3

return the vector in the given direction as if `vec` was its projection on it, equivalent to `dot(vec,vec) / dot(vec,dir) * dir`

the result is not sensitive to the length of `dir` perp(v: glm.dvec2) glm.dvec2

perpendicular vector to the given vector norm1(x) float

norm L1 ie. `abs(x) + abs(y) + abs(z)`

Alias to `glm.l1Norm`

norm2(x) float

norm L2 ie. `sqrt(x**2 + y**2 + z**2)` the usual distance also known as manhattan distance

Alias to `glm.l2Norm` alias `glm.length`

norminf(x) float

norm L infinite ie. `max(abs(x), abs(y), abs(z))`

Alias to `glm.lxNorm`

## Transformations¶

transform(*args) glm.dmat4x4

create an affine transformation matrix.

supported inputs:
mat4

obviously returns it unmodified

float

scale using the given ratio

vec3

translation only

quat, mat3, mat4

rotation only

(vec3,vec3), (vec3,mat3), (vec3,quat)

`(o,T)` translation and rotation

(vec3,vec3,vec3)

`(x,y,z)` base of vectors for rotation

(vec3,vec3,vec3,vec3)

`(o,x,y,z)` translation and base of vectors for rotation

dirbase(dir, align=dvec3(1, 0, 0))

returns a base using the given direction as z axis (and the nearer vector to align as x)

scaledir(dir, factor=None) glm.dmat3x3

return a mat3 scaling in the given direction, with the given factor (1 means original scale) if factor is None, the length of dir is used, but it can leads to precision loss on direction when too small.

rotatearound(angle, *args) glm.dmat4x4

return a transformation matrix for a rotation around an axis

rotatearound(angle, axis) rotatearound(angle, origin, dir)

transpose(x: matNxM) matMxN

Returns the transposed matrix of `x`.

inverse(m: matSxS) matSxS

Return the inverse of a squared matrix. inverse(q: quat) -> quat

Return the inverse of a quaternion.

affineInverse(m: matSxS) matSxS

Fast matrix inverse for affine matrix.

angle(x: quat) float

Returns the quaternion rotation angle.

axis(x: quat) vec3

Returns the `q` rotation axis.

angleAxis(angle: float, axis: vec3) quat

Build a quaternion from an angle and a normalized axis.

lerp(x: quat, y: quat, a: float) quat

Linear interpolation of two quaternions. The interpolation is oriented.

slerp(x: quat, y: quat, a: float) quat
Spherical linear interpolation of two quaternions. The interpolation always take the short

path and the rotation is performed at constant speed.

slerp(x: vec3, y: vec3, a: float) -> vec3

Returns Spherical interpolation between two vectors.

## Scalar functions¶

mix(x: number, y: number, a: float) number
Returns `x * (1.0 - a) + y * a`, i.e., the linear blend of `x` and `y` using the floating-point

value `a`. The value for `a` is not restricted to the range `[0, 1]`.

mix(x: number, y: number, a: bool) -> number

Returns `y` if `a` is `True` and `x` otherwise.

mix(x: vecN, y: vecN, a: fvecN) -> vecN

Returns `x * (1.0 - a) + y * a`, i.e., the linear blend of `x` and `y` using the floating-point value `a`. The value for `a` is not restricted to the range `[0, 1]`.

mix(x: vecN, y: vecN, a: bvecN) -> vecN

For each component index `i`: Returns `y[i]` if `a[i]` is `True` and `x[i]` otherwise.

mix(x: matNxM, y: matNxM, a: fmatNxM) -> matNxM

Returns `x * (1.0 - a) + y * a`, i.e., the linear blend of `x` and `y` using the floating-point value `a` for each component. The value for `a` is not restricted to the range `[0, 1]`.

mix(x: matNxM, y: matNxM, a: float) -> matNxM

Returns `x * (1.0 - a) + y * a`, i.e., the linear blend of `x` and `y` using the floating-point value `a` for each component. The value for `a` is not restricted to the range `[0, 1]`.

mix(x: quat, y: quat, a: float) -> quat

Spherical linear interpolation of two quaternions. The interpolation is oriented and the rotation is performed at constant speed. For short path spherical linear interpolation, use the `slerp` function. hermite(a, b, x)

3rd order polynomial interpolation a and b are iterable of successive derivatives of a and b step(edge: number, x: number) float

Returns `0.0` if `x < edge`, otherwise it returns `1.0`. step(edge: number, x: vecN) -> vecN

For every component `c` of `x`: Returns `0.0` if `c < edge`, otherwise it returns `1.0`.

step(edge: vecN, x: vecN) -> vecN

For every index `i`: Returns `0.0` if `x[i] < edge[i]`, otherwise it returns `1.0`. smoothstep(edge0: number, edge1: number, x: number) float
Returns `0.0` if `x <= edge0` and `1.0` if `x >= edge1` and performs smooth Hermite interpolation

between `0` and `1` when `edge0 < x < edge1`. This is useful in cases where you would want a threshold function with a smooth transition. This is equivalent to : `t = clamp((x - edge0) / (edge1 - edge0), 0, 1)` `return t * t * (3 - 2 * t)` Results are undefined if `edge0 >= edge1`.

smoothstep(edge0: number, edge1: number, x: vecN) -> vecN

Returns `0.0` if `x <= edge0` and `1.0` if `x >= edge1` and performs smooth Hermite interpolation between `0` and `1` when `edge0 < x < edge1`. This is useful in cases where you would want a threshold function with a smooth transition. This is equivalent to : `t = clamp((x - edge0) / (edge1 - edge0), 0, 1)` `return t * t * (3 - 2 * t)` Results are undefined if `edge0 >= edge1`.

smoothstep(edge0: vecN, edge1: vecN, x: vecN) -> vecN

Returns `0.0` if `x <= edge0` and `1.0` if `x >= edge1` and performs smooth Hermite interpolation between `0` and `1` when `edge0 < x < edge1`. This is useful in cases where you would want a threshold function with a smooth transition. This is equivalent to : `t = clamp((x - edge0) / (edge1 - edge0), 0, 1)` `return t * t * (3 - 2 * t)` Results are undefined if `edge0 >= edge1`. clamp(x: number, minVal: number, maxVal: number) number

Returns `min(max(x, minVal), maxVal)`. clamp(x: vecN, minVal: number, maxVal: number) -> vecN

Returns `min(max(x, minVal), maxVal)` for each component in `x` using the floating-point values `minVal` and `maxVal`.

clamp(x: vecN, minVal: vecN, maxVal: vecN) -> vecN

Returns `min(max(x, minVal), maxVal)` for each component in `x` using the floating-point values `minVal` and `maxVal`. intri_smooth(pts, ptangents, a, b)

cubic interpolation over a triangle, edges are guaranteed to fit an interpol2 curve using the edge tangents

Note

if the tangents lengths are set to the edge lenghts, that version gives a result that only blends between the curved edges, a less bulky result than `intri_sphere`

intri_sphere(pts, ptangents, a, b, etangents=None)

cubic interpolation over a triangle (2 dimension space), edges are guaranteed to fit an interpol2 curve using the edge tangents

Note

if the tangents lengths are set to the edge lenghts, that version gives a result close to a sphere surface

intri_parabolic(pts, ptangents, a, b, etangents=None)

quadratic interpolation over a triangle, edges are NOT fitting an interpol2 curve

## Distances¶

distance_pa(pt, axis)

point - axis distance

distance_pe(pt, edge)

point - edge distance

distance_aa(a1, a2)

axis - axis distance

distance_ae(axis, edge)

axis - edge distance

## Constants¶

NUMPREC

Numeric precision of a unit float (using the default precision)

COMPREC

unit complement of NUMPREC for convenience: `1 - NUMPREC`

## Localy defined data types¶

class Box(min=None, max=None, center=dvec3(0, 0, 0), width=dvec3(- inf, - inf, - inf))

This class describes a box always orthogonal to the base axis, used as convex for area delimitations

This class is independent from the dimension or number precision of the used vectors. You can for instance have a `Box` of `vec2` as well as a box of `vec3`. however boxes with different vector types cannot interperate.

min

vector of minimum coordinates of the box (usually bottom left corner)

max

vector of maximum coordinates of the box (usually top right corner)

property center: glm.dvec3

mid coordinates of the box

property width: glm.dvec3

diagonal vector of the box

corners() [vec3]

create a list of the corners of the box

volume() float

volume inside

isvalid()

return True if the box defines a valid space (min coordinates <= max coordinates)

isempty()

return True if the box contains a non null volume

contain(point)

return True if the given point is inside or on the surface of the box

inside(point)

return True if the given point is strictly inside the box

intersection(other)

return a box for the volume common to the current and the given box

Example

```>>> Box(vec2(-1,2), vec2(2,3)) .intersection(Box(vec3(1,-4), vec3(2,8)))
Box(vec2(1,2), vec3(2,3))
```
union(other)

return a box containing the current and the given box (or point)

Example

```>>> Box(vec2(1,2), vec2(2,3)) .union(vec3(1,4))
Box(vec2(1,2), vec2(2,4))
```
```>>> Box(vec2(1,2), vec2(2,3)) .union(Box(vec3(1,-4), vec3(2,8)))
Box(vec2(1,-4), vec3(2,8))
```
intersection_update(other) self

reduce the volume of the current box to the intersection between the 2 boxes

union_update(other) self

extend the volume of the current box to bound the given point or box

transform(trans)

box bounding the current one in a transformed space