moonmath the arithmetic of space

Every public name

One entry per type, field, variant, method and value, in the words the source wrote for it. Grouped by what the thing is for; the page is generated from the interfaces and the doc comments, so it cannot drift from the code without the build saying so.

Values

18

Scalars, angles and the easing functions, which belong to no type.

approxfunction

pub fn approx(Float, Float, eps? : Float) -> Bool

Whether two numbers are the same to within eps.

Without an epsilon the comparison uses default_epsilon, scaled up for values whose magnitude would swamp an absolute tolerance. Equality itself is exact — == on two numbers that took different paths to the same place rarely holds — so this is the test callers want for results of arithmetic.

mbt check
test {
let a : Float = 0.1 + 0.2
assert_true(@moonmath.approx(a, 0.3))
assert_false(@moonmath.approx(a, 0.31))
assert_true(@moonmath.approx(a, 0.31, eps=0.02))
}

approx_anglefunction

pub fn approx_angle(Float, Float, eps? : Float) -> Bool

Whether two angles — in radians, wrapping at tau — point the same way.

0 and tau are the same direction, and so are -pi and pi; comparing them as plain numbers says otherwise.

clamp01function

pub fn clamp01(Float) -> Float

value pinned to 0..1.

default_epsilonvalue

pub let default_epsilon : Float

The absolute tolerance approx falls back on when the caller gives none.

It is a compromise: large enough to cover the rounding of a handful of operations at this precision, small enough that values a user would call different do not compare equal.

half_pivalue

pub let half_pi : Float

Half a turn in radians: pi / 2. A quarter of tau.

hsv_to_rgbfunction

pub fn hsv_to_rgb(Color3) -> Color3

The colour a hue, saturation and value describe, read the way rgb_to_hsv writes them.

inverse_lerpfunction

pub fn inverse_lerp(Float, Float, Float) -> Float

Where value sits between start and end, as a fraction: the inverse of lerp.

Returns zero when the two ends are equal — there is no fraction between them, and zero is the answer that keeps lerp from producing a NaN.

lerpfunction

pub fn lerp(Float, Float, Float) -> Float

The point t of the way from a to b: a at zero, b at one.

t outside 0..1 extrapolates, which is what callers building animation curves usually want; clamp the result if it is not.

pivalue

pub let pi : Float

The ratio of a circle's circumference to its diameter.

quarter_pivalue

pub let quarter_pi : Float

A quarter turn in radians: pi / 4, the angle whose tangent is one.

remapfunction

pub fn remap(Float, Float, Float, Float, Float) -> Float

value taken from the range from_start..from_end and placed in to_start..to_end.

It is lerp(to_start, to_end, inverse_lerp(from_start, from_end, value)): the value keeps its position within the range, and values outside the source range land outside the destination range by the same proportion.

rgb_to_hsvfunction

pub fn rgb_to_hsv(Color3) -> Color3

The hue, saturation and value of a colour, packed into a Color3 as r the hue, g the saturation and b the value.

The hue is a fraction of a turn in 0..1 — a turn rather than degrees or radians, so it lines up with the rest of a graphics pipeline — and the other two are in 0..1. A grey has no hue and comes back as zero.

smoothstepfunction

pub fn smoothstep(Float, Float, Float) -> Float

A smooth step from zero at start to one at end, zero slope at both ends.

The curve is 3t² - 2t³ over the normalised position, which is the cheapest easing whose first derivative vanishes at both ends — no visible corner where the animation starts or stops.

A zero-width range has no slope to smooth: it steps at start.

tauvalue

pub let tau : Float

A full turn in radians: 2 * pi. The period of every angle here.

to_degreesfunction

pub fn to_degrees(Float) -> Float

radians converted to degrees.

to_radiansfunction

pub fn to_radians(Float) -> Float

degrees converted to radians.

wrapfunction

pub fn wrap(Float, Float) -> Float

value folded into 0..span.

Angles and texture coordinates repeat, and a value that has run past the end of its range has to come back to the start rather than stop there. A span of zero or less has nothing to fold into and gives zero.

mbt check
test {
assert_eq(@moonmath.wrap(7.5, 5.0), 2.5)
assert_eq(@moonmath.wrap(-1.0, 5.0), 4.0)
}

wrap_rangefunction

pub fn wrap_range(Float, Float, Float) -> Float

value folded into start..end.

wrap(value - start, end - start) + start, with the same half-open result.

Half precision

1

A 16-bit float, the storage format a texture or a packed vertex uses.

Halfstruct

pub struct Half

A 16-bit IEEE 754 binary16 value: the half precision a texture, a packed vertex or a GPU buffer carries when thirty-two bits are more than the data needs and sixteen are enough.

The value is the sixteen bits themselves, so a half read from a buffer is from_bits and one written back is to_bits. Arithmetic runs at Float, the precision the rest of this library works in: a half is a storage format, not a second arithmetic. Conversion rounds to nearest with ties to even, as the standard and the graphics formats do, and the special values — signed zeros, the two infinities, a quiet NaN and the subnormals — survive the round trip.

Fixed at sixteen bits, this type has no double-precision counterpart; it lives only in the single-precision package.

Fields
bits : UInt16

The sixteen bits, sign, exponent and fraction, in that order.

CarriesDebug, Show

approx

pub fn Half::approx(Self, Self, eps? : Float) -> Bool

Whether the two halves hold the same value to within eps, compared at Float precision.

denorm_min

pub fn Half::denorm_min() -> Self

The smallest positive subnormal, 2^-24.

epsilon

pub fn Half::epsilon() -> Self

The smallest number that, added to one, gives a half different from one: 2^-10.

from_bits

pub fn Half::from_bits(UInt16) -> Self

The half made of the sixteen raw bits, as a buffer holds it.

from_float

pub fn Half::from_float(Float) -> Self

The 16-bit encoding of value, rounded to the nearest representable half, ties to even.

Values beyond the largest finite half become an infinity of the same sign; values below the smallest subnormal become a signed zero; a NaN stays a NaN.

is_denormal

pub fn Half::is_denormal(Self) -> Bool

Whether the half is a subnormal: non-zero, smaller than the smallest normal.

is_finite

pub fn Half::is_finite(Self) -> Bool

Whether the half is neither an infinity nor a NaN.

is_inf

pub fn Half::is_inf(Self) -> Bool

Whether the half is an infinity, of either sign.

is_nan

pub fn Half::is_nan(Self) -> Bool

Whether the half is a NaN.

is_normal

pub fn Half::is_normal(Self) -> Bool

Whether the half is a normal number: not zero, not subnormal, not infinite.

lowest

pub fn Half::lowest() -> Self

The most negative finite half, -65504.

max

pub fn Half::max() -> Self

The largest finite half, 65504.

min

pub fn Half::min() -> Self

The smallest positive normal, 2^-14.

nan

pub fn Half::nan() -> Self

A quiet NaN.

neg_infinity

pub fn Half::neg_infinity() -> Self

Negative infinity.

one

pub fn Half::one() -> Self

One.

pos_infinity

pub fn Half::pos_infinity() -> Self

Positive infinity.

to_bits

pub fn Half::to_bits(Self) -> UInt16

The sixteen raw bits, in the order a buffer expects.

to_float

pub fn Half::to_float(Self) -> Float

The Float the half stands for.

Exact: every half is a Float, though not every Float is a half.

zero

pub fn Half::zero() -> Self

Positive zero.

Vectors

3

Points and directions, and the arithmetic between them.

Vec2struct

pub(all) struct Vec2

A point or a direction in the plane.

Two scalars side by side, in the order the plane's axes are named: x runs east, y runs north. Nothing here knows whether +y points up the screen or down it — that is a convention of the canvas, not of the arithmetic.

Values are immutable; every operation returns a new one.

The operators take two vectors of the same type. There is no Vec2 * Float, because a value can only carry one Mul implementation here: scalar scaling is scale, its inverse divide.

Fields
x : Float

The x component: east.

y : Float

The y component: north.

CarriesAdd, Debug, Div, Mul, Neg, Show, Sub

abs

pub fn Vec2::abs(Self) -> Self

The vector with every component replaced by its absolute value.

angle_between

pub fn Vec2::angle_between(Self, Self) -> Float

The angle from self to other, in radians, positive counter-clockwise.

Signed, because in the plane there are only two ways to turn and the sign says which. The result is in -pi..pi, and is zero when either vector has no direction.

mbt check
test {
let x : @moonmath.Vec2 = @moonmath.Vec2::unit_x()
let y = @moonmath.Vec2::unit_y()
assert_true(@moonmath.approx(x.angle_between(y), @moonmath.half_pi))
}

approx

pub fn Vec2::approx(Self, Self, eps? : Float) -> Bool

Whether the two vectors agree to within eps component by component.

Without an epsilon this uses default_epsilon.

ceil

pub fn Vec2::ceil(Self) -> Self

The vector with every component rounded up to a whole number.

clamp

pub fn Vec2::clamp(Self, Self, Self) -> Self

The vector with every component pinned between low and high.

clamp_length

pub fn Vec2::clamp_length(Self, Float, Float) -> Self

The vector shortened to at most high and lengthened to at least low.

The direction is kept, and a vector with no direction is left as it is: there is no length to bring into range. The two bounds may be given in either order.

cross

pub fn Vec2::cross(Self, Self) -> Float

The 2D cross product: the signed area of the parallelogram the two span.

Positive when other lies counter-clockwise of self, which is the sign a winding test reads.

distance

pub fn Vec2::distance(Self, Self) -> Float

The distance between the two points.

distance_squared

pub fn Vec2::distance_squared(Self, Self) -> Float

The square of the distance between the two points.

divide

pub fn Vec2::divide(Self, Float) -> Self

The vector divided by divisor, component by component.

Dividing by zero gives an infinity or a NaN, as the scalar division does; no check is made here.

dot

pub fn Vec2::dot(Self, Self) -> Float

The dot product: length * other.length * cos(angle) between them.

Positive when they point the same way, negative when they oppose, zero when they are perpendicular. It is also what a shader's dot computes, so the two agree bit for bit when the operands do.

floor

pub fn Vec2::floor(Self) -> Self

The vector with every component rounded down to a whole number.

fract

pub fn Vec2::fract(Self) -> Self

The vector with every component replaced by its fractional part, x - floor(x).

is_finite

pub fn Vec2::is_finite(Self) -> Bool

Whether both components are finite — neither an infinity nor a NaN.

length

pub fn Vec2::length(Self) -> Float

The length of the vector: its distance from the origin.

length_squared

pub fn Vec2::length_squared(Self) -> Float

The square of the length.

Comparing squared lengths orders vectors the same way length does without the square root, which is why range checks in hot loops use it.

lerp

pub fn Vec2::lerp(Self, Self, Float) -> Self

The point a fraction of the way from self to other.

max

pub fn Vec2::max(Self, Self) -> Self

The component-wise larger of the two.

max_element

pub fn Vec2::max_element(Self) -> Float

The largest of the two components.

midpoint

pub fn Vec2::midpoint(Self, Self) -> Self

The point half way between the two.

min

pub fn Vec2::min(Self, Self) -> Self

The component-wise smaller of the two.

min_element

pub fn Vec2::min_element(Self) -> Float

The smallest of the two components.

move_towards

pub fn Vec2::move_towards(Self, Self, Float) -> Self

The vector moved towards target by at most max_delta, without passing it.

A step of a steering pass: the distance covered is max_delta however far away the target is, and the target itself once it is nearer than that.

new

pub fn Vec2::new(Float, Float) -> Self

The vector from x and y.

normalize

pub fn Vec2::normalize(Self) -> Self

The vector scaled to length one, pointing the way it did.

The zero vector has no direction, and this returns zero rather than a NaN or a division by zero: Vec2::zero() is the named answer for "no direction". Callers that need to tell the case apart use try_normalize.

normalize_or

pub fn Vec2::normalize_or(Self, Self) -> Self

The vector scaled to length one, or fallback if it has no direction.

one

pub fn Vec2::one() -> Self

The vector with one in both components.

perp

pub fn Vec2::perp(Self) -> Self

The vector turned a quarter turn counter-clockwise: (-y, x).

project

pub fn Vec2::project(Self, Self) -> Self

The component of self along onto: the shadow it casts on that direction.

onto need not be a unit vector; the result lies along it either way. A zero onto has no direction to project onto and gives zero.

reflect

pub fn Vec2::reflect(Self, Self) -> Self

The direction self takes after bouncing off a surface with normal normal.

self is the incoming direction, and normal points out of the surface against it — the result leaves at the mirror angle with the same length. A zero normal returns self unchanged.

refract

pub fn Vec2::refract(Self, Self, Float) -> Self?

The direction self takes after entering a medium with normal normal and index ratio eta, or None when it does not enter at all.

self and normal are taken to be unit length, normal pointing against the incoming direction, and eta the ratio of the indices of refraction on the two sides. Past the critical angle the ray is reflected instead of refracted, and there is no refracted direction to return — that is the None, and it is the caller's job to reflect.

reject

pub fn Vec2::reject(Self, Self) -> Self

The component of self perpendicular to onto: what is left after the projection is taken away.

round

pub fn Vec2::round(Self) -> Self

The vector with every component rounded to the nearest whole number, a half going up: 2.5 becomes 3 and -1.5 becomes -1. This is the rounding Float::round does, in both units and sign.

scale

pub fn Vec2::scale(Self, Float) -> Self

The vector multiplied by factor.

This is the scalar product the * operator cannot express, since * on two vectors is the component-wise one.

splat

pub fn Vec2::splat(Float) -> Self

The same value in both components.

to_array

pub fn Vec2::to_array(Self) -> FixedArray[Float]

The components in order, [x, y], for handing to a buffer.

to_vec3

pub fn Vec2::to_vec3(Self, Float) -> Vec3

The same vector with z appended, for a point being lifted into 3D.

to_vec4

pub fn Vec2::to_vec4(Self, Float, Float) -> Vec4

The same vector with z and w appended.

try_normalize

pub fn Vec2::try_normalize(Self) -> Self?

The vector scaled to length one, or None if it has no direction.

unit_x

pub fn Vec2::unit_x() -> Self

The unit vector along +x.

unit_y

pub fn Vec2::unit_y() -> Self

The unit vector along +y.

with_x

pub fn Vec2::with_x(Self, Float) -> Self

The same vector with a new x component.

with_y

pub fn Vec2::with_y(Self, Float) -> Self

The same vector with a new y component.

yx

pub fn Vec2::yx(Self) -> Self

The components the other way round: (y, x).

zero

pub fn Vec2::zero() -> Self

The zero vector: the origin, and the one vector with no direction.

Vec3struct

pub(all) struct Vec3

A point or a direction in space.

Right-handed: x and y as in the plane, z towards the viewer in the usual camera setup, so that cross(x, y) == z.

Values are immutable; every operation returns a new one.

The operators take two vectors of the same type. Scalar scaling is scale and divide, not * and /, which belong to the component-wise product.

Fields
x : Float

The x component: east.

y : Float

The y component: north.

z : Float

The z component: towards the viewer.

CarriesAdd, Debug, Div, Mul, Neg, Show, Sub

abs

pub fn Vec3::abs(Self) -> Self

The vector with every component replaced by its absolute value.

angle_between

pub fn Vec3::angle_between(Self, Self) -> Float

The angle between the two directions, in radians, in 0..pi.

Unsigned: in space there is no counter-clockwise, so the answer is just how far apart they point. Computed from the normalized dot product, clamped so that rounding cannot push it out of the arc cosine's domain. Zero when either vector has no direction.

mbt check
test {
let x : @moonmath.Vec3 = @moonmath.Vec3::unit_x()
let y = @moonmath.Vec3::unit_y()
assert_true(@moonmath.approx(x.angle_between(y), @moonmath.half_pi))
assert_true(@moonmath.approx(x.angle_between(-x), @moonmath.pi))
}

any_orthonormal_pair

pub fn Vec3::any_orthonormal_pair(Self) -> (Self, Self)

Two unit vectors that, with this one, form a right-handed frame.

The first is any_orthonormal_vector; the second is this vector crossed with it, so u.cross(v) == self.normalize(). What a tangent frame for a normal map or a tube around a curve is built from. A vector with no direction answers the x and y axes.

any_orthonormal_vector

pub fn Vec3::any_orthonormal_vector(Self) -> Self

A unit vector perpendicular to this one.

The choice is fixed rather than arbitrary: the axis this vector leans on least is crossed with it, which is never near a zero-length product, and the same input always gives the same answer. A vector with no direction answers unit_x, there being no perpendicular to prefer.

approx

pub fn Vec3::approx(Self, Self, eps? : Float) -> Bool

Whether the two vectors agree to within eps component by component.

ceil

pub fn Vec3::ceil(Self) -> Self

The vector with every component rounded up to a whole number.

clamp

pub fn Vec3::clamp(Self, Self, Self) -> Self

The vector with every component pinned between low and high.

clamp_length

pub fn Vec3::clamp_length(Self, Float, Float) -> Self

The vector shortened to at most high and lengthened to at least low.

The direction is kept, and a vector with no direction is left as it is: there is no length to bring into range. The two bounds may be given in either order.

cross

pub fn Vec3::cross(Self, Self) -> Self

The cross product: the vector perpendicular to both, right-handed.

Its length is the area of the parallelogram they span, so the two are parallel exactly when it is zero. cross(x, y) is z.

distance

pub fn Vec3::distance(Self, Self) -> Float

The distance between the two points.

distance_squared

pub fn Vec3::distance_squared(Self, Self) -> Float

The square of the distance between the two points.

divide

pub fn Vec3::divide(Self, Float) -> Self

The vector divided by divisor, component by component.

Dividing by zero gives an infinity or a NaN, as the scalar division does.

dot

pub fn Vec3::dot(Self, Self) -> Float

The dot product: length * other.length * cos(angle) between them.

floor

pub fn Vec3::floor(Self) -> Self

The vector with every component rounded down to a whole number.

fract

pub fn Vec3::fract(Self) -> Self

The vector with every component replaced by its fractional part.

is_finite

pub fn Vec3::is_finite(Self) -> Bool

Whether every component is finite.

length

pub fn Vec3::length(Self) -> Float

The length of the vector: its distance from the origin.

length_squared

pub fn Vec3::length_squared(Self) -> Float

The square of the length, without the square root.

lerp

pub fn Vec3::lerp(Self, Self, Float) -> Self

The point a fraction of the way from self to other.

max

pub fn Vec3::max(Self, Self) -> Self

The component-wise larger of the two.

max_element

pub fn Vec3::max_element(Self) -> Float

The largest of the three components.

midpoint

pub fn Vec3::midpoint(Self, Self) -> Self

The point half way between the two.

min

pub fn Vec3::min(Self, Self) -> Self

The component-wise smaller of the two.

min_element

pub fn Vec3::min_element(Self) -> Float

The smallest of the three components.

move_towards

pub fn Vec3::move_towards(Self, Self, Float) -> Self

The vector moved towards target by at most max_delta, without passing it.

A step of a steering or an inverse-kinematics pass: the distance covered is max_delta however far away the target is, and the target itself once it is nearer than that.

new

pub fn Vec3::new(Float, Float, Float) -> Self

The vector from its three components.

normalize

pub fn Vec3::normalize(Self) -> Self

The vector scaled to length one, pointing the way it did.

The zero vector has no direction, and this returns Vec3::zero() rather than a NaN: the named answer is "no direction", not "undefined". Use try_normalize where the case needs telling apart.

normalize_or

pub fn Vec3::normalize_or(Self, Self) -> Self

The vector scaled to length one, or fallback if it has no direction.

one

pub fn Vec3::one() -> Self

The vector with one in every component.

project

pub fn Vec3::project(Self, Self) -> Self

The component of self along onto.

onto need not be a unit vector. A zero onto gives zero.

random_in_ball

pub fn Vec3::random_in_ball(Float, Float, Float) -> Self

A point uniformly distributed through the unit ball.

u1, u2 and u3 are independent uniform samples in [0, 1). The radius is the cube root of u3, not u3 itself: the volume grows as the cube of the radius, so a linear radius would pile the points near the centre.

random_on_sphere

pub fn Vec3::random_on_sphere(Float, Float) -> Self

A point uniformly distributed over the surface of the unit sphere.

u1 and u2 are independent uniform samples in [0, 1). The height is sampled uniformly rather than the polar angle, which is what keeps the distribution even: sampling the angle uniformly would crowd the poles.

reflect

pub fn Vec3::reflect(Self, Self) -> Self

The direction self takes after bouncing off a surface with normal normal.

self is the incoming direction and normal points out of the surface against it. Both are taken to be unit length, as they are in a shader; the result has the same length as self.

refract

pub fn Vec3::refract(Self, Self, Float) -> Self?

The direction self takes after entering a medium with normal normal and index ratio eta, or None past the critical angle.

self and normal are taken to be unit length, normal pointing against the incoming direction, and eta the ratio of the indices of refraction on the two sides. Past the critical angle the ray is reflected whole and there is no refracted direction: None says so, and reflecting is the caller's business.

mbt check
test {
let down : @moonmath.Vec3 = @moonmath.Vec3::new(0.0, -1.0, 0.0)
let up = @moonmath.Vec3::new(0.0, 1.0, 0.0)
// Straight down onto a surface and straight on through.
let through = down.refract(up, 0.5).unwrap()
assert_true(through.approx(down))
}

reject

pub fn Vec3::reject(Self, Self) -> Self

The component of self perpendicular to onto.

rotate_axis

pub fn Vec3::rotate_axis(Self, Self, Float) -> Self

The vector turned about axis by radians, by the right-hand rule.

axis is normalized first, and a zero axis turns nothing.

rotate_x

pub fn Vec3::rotate_x(Self, Float) -> Self

The vector turned about +x by radians, by the right-hand rule.

The turn looks from +x towards the origin: unit_y goes to unit_z for a quarter turn, as a rotation about x does everywhere else in the library.

mbt check
test {
let quarter : @moonmath.Vec3 = @moonmath.Vec3::unit_y().rotate_x(
@moonmath.half_pi,
)
assert_true(quarter.approx(@moonmath.Vec3::unit_z()))
}

rotate_y

pub fn Vec3::rotate_y(Self, Float) -> Self

The vector turned about +y by radians, by the right-hand rule.

rotate_z

pub fn Vec3::rotate_z(Self, Float) -> Self

The vector turned about +z by radians, by the right-hand rule.

round

pub fn Vec3::round(Self) -> Self

The vector with every component rounded to the nearest whole number, a half going up.

scale

pub fn Vec3::scale(Self, Float) -> Self

The vector multiplied by factor.

slerp

pub fn Vec3::slerp(Self, Self, Float) -> Self

The direction a fraction t of the way from this one to other, along the great circle.

Both are read as directions and normalized first, so the result is a unit vector and the length of the inputs does not matter. Directions that are the same give the same answer for every t; opposite ones have no single arc between them, and the start is returned. A vector with no direction falls back to the straight line, there being no arc to take.

mbt check
test {
let x : @moonmath.Vec3 = @moonmath.Vec3::unit_x()
let y = @moonmath.Vec3::unit_y()
let half_way = x.slerp(y, 0.5)
let diagonal = @moonmath.Vec3::new(1.0, 1.0, 0.0).normalize()
assert_true(half_way.approx(diagonal))
}

splat

pub fn Vec3::splat(Float) -> Self

The same value in all three components.

to_array

pub fn Vec3::to_array(Self) -> FixedArray[Float]

The components in order, [x, y, z], for handing to a buffer.

to_vec4

pub fn Vec3::to_vec4(Self, Float) -> Vec4

The same vector with w appended, for a point being lifted into 4D.

try_normalize

pub fn Vec3::try_normalize(Self) -> Self?

The vector scaled to length one, or None if it has no direction.

unit_x

pub fn Vec3::unit_x() -> Self

The unit vector along +x.

unit_y

pub fn Vec3::unit_y() -> Self

The unit vector along +y.

unit_z

pub fn Vec3::unit_z() -> Self

The unit vector along +z.

with_x

pub fn Vec3::with_x(Self, Float) -> Self

The same vector with a new x component.

with_y

pub fn Vec3::with_y(Self, Float) -> Self

The same vector with a new y component.

with_z

pub fn Vec3::with_z(Self, Float) -> Self

The same vector with a new z component.

xy

pub fn Vec3::xy(Self) -> Vec2

The first two components: the vector projected onto the xy plane.

xz

pub fn Vec3::xz(Self) -> Vec2

The first and third components: the projection onto the xz plane.

xzy

pub fn Vec3::xzy(Self) -> Self

The components in the order (x, z, y), swapping the last two.

yxz

pub fn Vec3::yxz(Self) -> Self

The components in the order (y, x, z), swapping the first two.

yz

pub fn Vec3::yz(Self) -> Vec2

The last two components: the projection onto the yz plane.

yzx

pub fn Vec3::yzx(Self) -> Self

The components in the order (y, z, x), a third of a turn of the axes.

zero

pub fn Vec3::zero() -> Self

The zero vector: the origin, and the one vector with no direction.

zxy

pub fn Vec3::zxy(Self) -> Self

The components in the order (z, x, y), the other third of a turn.

zyx

pub fn Vec3::zyx(Self) -> Self

The components backwards: (z, y, x), which turns a lookup into its mirror.

Vec4struct

pub(all) struct Vec4

Four components: a point in homogeneous coordinates, a colour with alpha, or four numbers that travel together.

A Vec4 is what a Mat4 multiplies, and what a shader writes into a vertex buffer: to_array gives the four in the order the buffer wants them.

Values are immutable; every operation returns a new one.

Fields
x : Float

The x component: east.

y : Float

The y component: north.

z : Float

The z component: towards the viewer.

w : Float

The fourth component: one for a point, zero for a direction.

CarriesAdd, Debug, Div, Mul, Neg, Show, Sub

abs

pub fn Vec4::abs(Self) -> Self

The vector with every component replaced by its absolute value.

approx

pub fn Vec4::approx(Self, Self, eps? : Float) -> Bool

Whether the two vectors agree to within eps component by component.

ceil

pub fn Vec4::ceil(Self) -> Self

The vector with every component rounded up to a whole number.

clamp

pub fn Vec4::clamp(Self, Self, Self) -> Self

The vector with every component pinned between low and high.

clamp_length

pub fn Vec4::clamp_length(Self, Float, Float) -> Self

The vector shortened to at most high and lengthened to at least low.

The direction is kept, and a vector with no direction is left as it is: there is no length to bring into range. The two bounds may be given in either order.

distance

pub fn Vec4::distance(Self, Self) -> Float

The distance between the two points, in four dimensions.

distance_squared

pub fn Vec4::distance_squared(Self, Self) -> Float

The square of the distance between the two points.

divide

pub fn Vec4::divide(Self, Float) -> Self

The vector divided by divisor, component by component.

dot

pub fn Vec4::dot(Self, Self) -> Float

The dot product, over all four components.

In homogeneous coordinates this is what a plane's dot does with a point, and what the w component of a transformed vector carries.

floor

pub fn Vec4::floor(Self) -> Self

The vector with every component rounded down to a whole number.

fract

pub fn Vec4::fract(Self) -> Self

The vector with every component replaced by its fractional part.

is_finite

pub fn Vec4::is_finite(Self) -> Bool

Whether every component is finite.

length

pub fn Vec4::length(Self) -> Float

The length of the vector, in four dimensions.

length_squared

pub fn Vec4::length_squared(Self) -> Float

The square of the length, without the square root.

lerp

pub fn Vec4::lerp(Self, Self, Float) -> Self

The point a fraction of the way from self to other, all four components.

max

pub fn Vec4::max(Self, Self) -> Self

The component-wise larger of the two.

max_element

pub fn Vec4::max_element(Self) -> Float

The largest of the four components.

min

pub fn Vec4::min(Self, Self) -> Self

The component-wise smaller of the two.

min_element

pub fn Vec4::min_element(Self) -> Float

The smallest of the four components.

move_towards

pub fn Vec4::move_towards(Self, Self, Float) -> Self

The vector moved towards target by at most max_delta, without passing it.

A step of a solver on four unknowns: the distance covered is max_delta however far away the target is, and the target itself once it is nearer than that.

new

pub fn Vec4::new(Float, Float, Float, Float) -> Self

The vector from its four components.

normalize

pub fn Vec4::normalize(Self) -> Self

The vector scaled to length one, or Vec4::zero() if it has no direction.

normalize_or

pub fn Vec4::normalize_or(Self, Self) -> Self

The vector scaled to length one, or fallback if it has no direction.

one

pub fn Vec4::one() -> Self

The vector with one in every component.

round

pub fn Vec4::round(Self) -> Self

The vector with every component rounded to the nearest whole number, a half going up.

scale

pub fn Vec4::scale(Self, Float) -> Self

The vector multiplied by factor.

This is how a homogeneous position is taken out of projective space: divide by w with divide, or scale by its reciprocal.

splat

pub fn Vec4::splat(Float) -> Self

The same value in all four components.

to_array

pub fn Vec4::to_array(Self) -> FixedArray[Float]

The components in order, [x, y, z, w], for handing to a buffer.

try_normalize

pub fn Vec4::try_normalize(Self) -> Self?

The vector scaled to length one, or None if it has no direction.

unit_w

pub fn Vec4::unit_w() -> Self

The unit vector along +w.

unit_x

pub fn Vec4::unit_x() -> Self

The unit vector along +x.

unit_y

pub fn Vec4::unit_y() -> Self

The unit vector along +y.

unit_z

pub fn Vec4::unit_z() -> Self

The unit vector along +z.

with_w

pub fn Vec4::with_w(Self, Float) -> Self

The same vector with a new w component.

with_x

pub fn Vec4::with_x(Self, Float) -> Self

The same vector with a new x component.

with_y

pub fn Vec4::with_y(Self, Float) -> Self

The same vector with a new y component.

with_z

pub fn Vec4::with_z(Self, Float) -> Self

The same vector with a new z component.

wzyx

pub fn Vec4::wzyx(Self) -> Self

All four components backwards: (w, z, y, x).

xy

pub fn Vec4::xy(Self) -> Vec2

The first two components.

xyz

pub fn Vec4::xyz(Self) -> Vec3

The first three components: the position a homogeneous point names, before the division by w.

zero

pub fn Vec4::zero() -> Self

The zero vector.

Integer vectors

6

For grid cells, pixels and indices, where a half is not a position.

IVec2struct

pub(all) struct IVec2

Two whole numbers: a grid cell or a pixel coordinate.

Division is integer division and truncates towards zero, and dividing by zero aborts, as it does for Int itself.

Fields
x : Int32

The x component.

y : Int32

The y component.

CarriesAdd, Debug, Div, Mul, Neg, Show, Sub

abs

pub fn IVec2::abs(Self) -> Self

The pair with every component replaced by its absolute value.

as_vec2

pub fn IVec2::as_vec2(Self) -> Vec2

The same cell as a floating-point vector, exactly.

clamp

pub fn IVec2::clamp(Self, Self, Self) -> Self

The pair with every component pinned between low and high, inclusive.

dot

pub fn IVec2::dot(Self, Self) -> Int32

The dot product, in whole numbers.

from_vec2

pub fn IVec2::from_vec2(Vec2) -> Self

The cell a floating-point position falls in, truncated towards zero.

Truncation rather than rounding, because a pixel coordinate of -0.5 is in cell 0 when the cell is counted from the point, and the caller that wants the floor asks for floor first.

max

pub fn IVec2::max(Self, Self) -> Self

The component-wise larger of the two.

min

pub fn IVec2::min(Self, Self) -> Self

The component-wise smaller of the two.

new

pub fn IVec2::new(Int32, Int32) -> Self

The pair (x, y).

one

pub fn IVec2::one() -> Self

One in both components: the step between neighbouring cells.

splat

pub fn IVec2::splat(Int32) -> Self

The same value in both components.

to_array

pub fn IVec2::to_array(Self) -> FixedArray[Int32]

The components in order, [x, y].

zero

pub fn IVec2::zero() -> Self

The origin of the grid.

IVec3struct

pub(all) struct IVec3

Three whole numbers: a cell in a voxel grid.

Fields
x : Int32

The x component.

y : Int32

The y component.

z : Int32

The z component.

CarriesAdd, Debug, Div, Mul, Neg, Show, Sub

abs

pub fn IVec3::abs(Self) -> Self

The triple with every component replaced by its absolute value.

as_vec3

pub fn IVec3::as_vec3(Self) -> Vec3

The same cell as a floating-point vector, exactly.

clamp

pub fn IVec3::clamp(Self, Self, Self) -> Self

The triple with every component pinned between low and high, inclusive.

dot

pub fn IVec3::dot(Self, Self) -> Int32

The dot product, in whole numbers.

from_vec3

pub fn IVec3::from_vec3(Vec3) -> Self

The cell a floating-point position falls in, truncated towards zero.

max

pub fn IVec3::max(Self, Self) -> Self

The component-wise larger of the two.

min

pub fn IVec3::min(Self, Self) -> Self

The component-wise smaller of the two.

new

pub fn IVec3::new(Int32, Int32, Int32) -> Self

The triple (x, y, z).

one

pub fn IVec3::one() -> Self

One in every component.

splat

pub fn IVec3::splat(Int32) -> Self

The same value in all three components.

to_array

pub fn IVec3::to_array(Self) -> FixedArray[Int32]

The components in order, [x, y, z].

zero

pub fn IVec3::zero() -> Self

The origin of the grid.

IVec4struct

pub(all) struct IVec4

Four whole numbers.

Fields
x : Int32

The x component.

y : Int32

The y component.

z : Int32

The z component.

w : Int32

The fourth component.

CarriesAdd, Debug, Div, Mul, Neg, Show, Sub

abs

pub fn IVec4::abs(Self) -> Self

The quadruple with every component replaced by its absolute value.

as_vec4

pub fn IVec4::as_vec4(Self) -> Vec4

The same values as a floating-point vector, exactly.

clamp

pub fn IVec4::clamp(Self, Self, Self) -> Self

The quadruple with every component pinned between low and high.

dot

pub fn IVec4::dot(Self, Self) -> Int32

The dot product, in whole numbers.

from_vec4

pub fn IVec4::from_vec4(Vec4) -> Self

The values a floating-point vector carries, truncated towards zero.

max

pub fn IVec4::max(Self, Self) -> Self

The component-wise larger of the two.

min

pub fn IVec4::min(Self, Self) -> Self

The component-wise smaller of the two.

new

pub fn IVec4::new(Int32, Int32, Int32, Int32) -> Self

The quadruple (x, y, z, w).

one

pub fn IVec4::one() -> Self

One in every component.

splat

pub fn IVec4::splat(Int32) -> Self

The same value in all four components.

to_array

pub fn IVec4::to_array(Self) -> FixedArray[Int32]

The components in order, [x, y, z, w].

zero

pub fn IVec4::zero() -> Self

The zero vector.

UVec2struct

pub(all) struct UVec2

Two unsigned whole numbers: a size, a count, a pixel coordinate that cannot be negative.

There is no Neg here for the obvious reason: a negative size is not a size. Subtraction is present and wraps, as UInt subtraction does.

Fields
x : UInt32

The x component.

y : UInt32

The y component.

CarriesAdd, Debug, Div, Mul, Show, Sub

as_vec2

pub fn UVec2::as_vec2(Self) -> Vec2

The same size as a floating-point vector, exactly.

clamp

pub fn UVec2::clamp(Self, Self, Self) -> Self

The pair with every component pinned between low and high, inclusive.

dot

pub fn UVec2::dot(Self, Self) -> UInt32

The dot product.

max

pub fn UVec2::max(Self, Self) -> Self

The component-wise larger of the two.

min

pub fn UVec2::min(Self, Self) -> Self

The component-wise smaller of the two.

new

pub fn UVec2::new(UInt32, UInt32) -> Self

The pair (x, y).

one

pub fn UVec2::one() -> Self

One in both components.

splat

pub fn UVec2::splat(UInt32) -> Self

The same value in both components.

to_array

pub fn UVec2::to_array(Self) -> FixedArray[UInt32]

The components in order, [x, y].

zero

pub fn UVec2::zero() -> Self

Zero in both components: an empty size.

UVec3struct

pub(all) struct UVec3

Three unsigned whole numbers.

Fields
x : UInt32

The x component.

y : UInt32

The y component.

z : UInt32

The z component.

CarriesAdd, Debug, Div, Mul, Show, Sub

as_vec3

pub fn UVec3::as_vec3(Self) -> Vec3

The same values as a floating-point vector, exactly.

clamp

pub fn UVec3::clamp(Self, Self, Self) -> Self

The triple with every component pinned between low and high, inclusive.

dot

pub fn UVec3::dot(Self, Self) -> UInt32

The dot product.

max

pub fn UVec3::max(Self, Self) -> Self

The component-wise larger of the two.

min

pub fn UVec3::min(Self, Self) -> Self

The component-wise smaller of the two.

new

pub fn UVec3::new(UInt32, UInt32, UInt32) -> Self

The triple (x, y, z).

one

pub fn UVec3::one() -> Self

One in every component.

splat

pub fn UVec3::splat(UInt32) -> Self

The same value in all three components.

to_array

pub fn UVec3::to_array(Self) -> FixedArray[UInt32]

The components in order, [x, y, z].

zero

pub fn UVec3::zero() -> Self

Zero in every component.

UVec4struct

pub(all) struct UVec4

Four unsigned whole numbers.

Fields
x : UInt32

The x component.

y : UInt32

The y component.

z : UInt32

The z component.

w : UInt32

The fourth component.

CarriesAdd, Debug, Div, Mul, Show, Sub

as_vec4

pub fn UVec4::as_vec4(Self) -> Vec4

The same values as a floating-point vector, exactly.

clamp

pub fn UVec4::clamp(Self, Self, Self) -> Self

The quadruple with every component pinned between low and high.

dot

pub fn UVec4::dot(Self, Self) -> UInt32

The dot product.

max

pub fn UVec4::max(Self, Self) -> Self

The component-wise larger of the two.

min

pub fn UVec4::min(Self, Self) -> Self

The component-wise smaller of the two.

new

pub fn UVec4::new(UInt32, UInt32, UInt32, UInt32) -> Self

The quadruple (x, y, z, w).

one

pub fn UVec4::one() -> Self

One in every component.

splat

pub fn UVec4::splat(UInt32) -> Self

The same value in all four components.

to_array

pub fn UVec4::to_array(Self) -> FixedArray[UInt32]

The components in order, [x, y, z, w].

zero

pub fn UVec4::zero() -> Self

Zero in every component.

Matrices

4

Linear maps, and the four cameras: look_at, perspective, orthographic, frustum.

Mat2struct

pub(all) struct Mat2

A 2×2 matrix, stored as two column vectors.

Column-major, like every matrix here: c0 is the first column, so the matrix that maps x to (a, c) and y to (b, d) is c0 = (a, c), c1 = (b, d), and its x and y are the first and second rows. WGSL writes a mat2x2<f32> in the same order, so to_array goes straight into a buffer.

Values are immutable.

Fields
c0 : Vec2

The first column.

c1 : Vec2

The second column.

CarriesAdd, Debug, Div, Mul, Neg, Show, Sub

approx

pub fn Mat2::approx(Self, Self, eps? : Float) -> Bool

Whether the two matrices agree to within eps element by element.

col

pub fn Mat2::col(Self, Int32) -> Vec2

Column index, counted from zero.

determinant

pub fn Mat2::determinant(Self) -> Float

The signed area the matrix scales by: zero exactly when it is singular.

from_angle

pub fn Mat2::from_angle(Float) -> Self

The matrix that rotates counter-clockwise by radians.

from_array

pub fn Mat2::from_array(FixedArray[Float]) -> Self

The matrix from four values in column-major order: [c0.x, c0.y, c1.x, c1.y].

This is the order a mat2x2<f32> sits in a GPU buffer in, so a matrix read back out of one goes in here unchanged. Aborts if the array does not hold four values.

from_cols

pub fn Mat2::from_cols(Vec2, Vec2) -> Self

The matrix with c0 and c1 as its columns.

from_rows

pub fn Mat2::from_rows(Vec2, Vec2) -> Self

The matrix with r0 and r1 as its rows.

from_scale

pub fn Mat2::from_scale(Vec2) -> Self

The matrix that scales x by s.x and y by s.y.

get

pub fn Mat2::get(Self, Int32, Int32) -> Float

The element at row and column, both counted from zero.

identity

pub fn Mat2::identity() -> Self

The identity: the matrix that changes nothing.

inverse

pub fn Mat2::inverse(Self) -> Self?

The matrix that undoes this one, or None when there is none.

A singular matrix — one with a zero determinant — flattens the plane onto a line or a point, and nothing undoes that. None is the honest answer; the caller decides whether that is an error or a case to handle.

is_finite

pub fn Mat2::is_finite(Self) -> Bool

Whether every element is finite.

mul_vec2

pub fn Mat2::mul_vec2(Self, Vec2) -> Vec2

The vector the matrix takes v to.

Written as one expression per component rather than as the sum of two scaled columns: a Vec2 is a heap value in the native backend, so every intermediate column is an allocation, and there are two of them here for each result.

row

pub fn Mat2::row(Self, Int32) -> Vec2

Row index, counted from zero.

to_angle

pub fn Mat2::to_angle(Self) -> Float

The angle, in radians, the matrix rotates x by.

Only meaningful for a rotation matrix — one built by from_angle, or a linear part that happens to be one; on anything else it reads the direction of the first column.

to_array

pub fn Mat2::to_array(Self) -> FixedArray[Float]

The elements in column-major order, [c0.x, c0.y, c1.x, c1.y], ready for a buffer.

transpose

pub fn Mat2::transpose(Self) -> Self

The matrix with rows and columns exchanged.

zero

pub fn Mat2::zero() -> Self

The zero matrix: the one that sends everything to the origin.

Mat3struct

pub(all) struct Mat3

A 3×3 matrix: a linear map of space, or the upper-left block of a 4×4 one.

Column-major, as mat3x3<f32> is in a buffer: c0 is the first column, and the rows are read across the columns. Rotations, scalings and shears are linear maps, so they need no translation column and live here rather than in Affine3.

Values are immutable.

Fields
c0 : Vec3

The first column.

c1 : Vec3

The second column.

c2 : Vec3

The third column.

CarriesAdd, Debug, Div, Mul, Neg, Show, Sub

approx

pub fn Mat3::approx(Self, Self, eps? : Float) -> Bool

Whether the two matrices agree to within eps element by element.

col

pub fn Mat3::col(Self, Int32) -> Vec3

Column index, counted from zero.

determinant

pub fn Mat3::determinant(Self) -> Float

The signed volume the matrix scales by: zero exactly when it is singular.

from_array

pub fn Mat3::from_array(FixedArray[Float]) -> Self

The matrix from nine values in column-major order.

Aborts if the array does not hold nine values.

from_axis_angle

pub fn Mat3::from_axis_angle(Vec3, Float) -> Self

The rotation of radians about axis, by the right-hand rule.

axis is normalized first; a zero axis has no direction to turn about and gives the identity.

from_cols

pub fn Mat3::from_cols(Vec3, Vec3, Vec3) -> Self

The matrix with the three vecs as its columns.

from_euler

pub fn Mat3::from_euler(EulerOrder, Vec3) -> Self

The rotation the three angles describe, taken in order, read by axis.

The components are the turns about x, y and z, in radians, wherever in the order those axes turn up; see Quat::from_euler, which also says which orders this reading cannot express. from_euler_turns takes the turns in the order the order names them and covers all twelve.

from_euler_turns

pub fn Mat3::from_euler_turns(EulerOrder, Turns) -> Self

The rotation the three turns describe, in the order the order names them.

from_mat4

pub fn Mat3::from_mat4(Mat4) -> Self

The upper-left 3×3 block of a 4×4 matrix: the linear part, without the translation.

from_quat

pub fn Mat3::from_quat(Quat) -> Self

The rotation the quaternion holds.

from_rows

pub fn Mat3::from_rows(Vec3, Vec3, Vec3) -> Self

The matrix with the three vecs as its rows.

from_scale

pub fn Mat3::from_scale(Vec3) -> Self

The matrix that scales each axis by the matching component of s.

get

pub fn Mat3::get(Self, Int32, Int32) -> Float

The element at row and column, both counted from zero.

identity

pub fn Mat3::identity() -> Self

The identity: the matrix that changes nothing.

inverse

pub fn Mat3::inverse(Self) -> Self?

The matrix that undoes this one, or None when there is none.

is_finite

pub fn Mat3::is_finite(Self) -> Bool

Whether every element is finite.

mul_vec3

pub fn Mat3::mul_vec3(Self, Vec3) -> Vec3

The vector the matrix takes v to.

One expression per component, for the reason given at Mat2::mul_vec2: the three scaled columns a sum would build are three allocations on the native backend.

row

pub fn Mat3::row(Self, Int32) -> Vec3

Row index, counted from zero.

to_array

pub fn Mat3::to_array(Self) -> FixedArray[Float]

The elements in column-major order, ready for a buffer.

transpose

pub fn Mat3::transpose(Self) -> Self

The matrix with rows and columns exchanged.

This is also the inverse of a rotation matrix, which is the cheapest way to undo one.

zero

pub fn Mat3::zero() -> Self

The zero matrix: the one that sends everything to the origin.

Mat4struct

pub(all) struct Mat4

A 4×4 matrix: everything a 3×3 matrix does, plus the translation a transformation of space needs.

Column-major, so c3 is the translation column and to_array is exactly the sixteen floats a mat4x4<f32> occupies in a storage or uniform buffer. A point is a Vec4 with w = 1, a direction one with w = 0, and the fourth row of a projection matrix puts the perspective divide into w.

Values are immutable.

Fields
c0 : Vec4

The first column.

c1 : Vec4

The second column.

c2 : Vec4

The third column.

c3 : Vec4

The fourth column: the translation, for an affine matrix.

CarriesAdd, Debug, Div, Mul, Neg, Show, Sub

approx

pub fn Mat4::approx(Self, Self, eps? : Float) -> Bool

Whether the two matrices agree to within eps element by element.

col

pub fn Mat4::col(Self, Int32) -> Vec4

Column index, counted from zero.

determinant

pub fn Mat4::determinant(Self) -> Float

The signed hypervolume the matrix scales by: zero exactly when it is singular.

from_array

pub fn Mat4::from_array(FixedArray[Float]) -> Self

The matrix from sixteen values in column-major order — the order a mat4x4<f32> sits in a buffer in.

Aborts if the array does not hold sixteen values.

from_axis_angle

pub fn Mat4::from_axis_angle(Vec3, Float) -> Self

The rotation of radians about axis, by the right-hand rule.

from_cols

pub fn Mat4::from_cols(Vec4, Vec4, Vec4, Vec4) -> Self

The matrix with the four vecs as its columns.

from_euler

pub fn Mat4::from_euler(EulerOrder, Vec3) -> Self

The rotation the three angles describe, taken in order, in radians, read by axis. See Quat::from_euler for how the components are read and which orders that reading cannot express.

from_euler_turns

pub fn Mat4::from_euler_turns(EulerOrder, Turns) -> Self

The rotation the three turns describe, in the order the order names them.

from_mat3

pub fn Mat4::from_mat3(Mat3) -> Self

The matrix that does what the 3×3 matrix does to x, y and z, and leaves w alone.

from_quat

pub fn Mat4::from_quat(Quat) -> Self

The rotation the quaternion holds.

from_rows

pub fn Mat4::from_rows(Vec4, Vec4, Vec4, Vec4) -> Self

The matrix with the four vecs as its rows.

from_scale

pub fn Mat4::from_scale(Vec3) -> Self

The matrix that scales each axis by the matching component of s.

from_translation

pub fn Mat4::from_translation(Vec3) -> Self

The matrix that moves every point by t.

from_trs

pub fn Mat4::from_trs(Trs) -> Self

The matrix that scales by scale, then rotates by rotation, then moves by translation.

mbt check
test {
let scale : @moonmath.Vec3 = @moonmath.Vec3::splat(2.0)
let offset = @moonmath.Vec3::new(1.0, 0.0, 0.0)
let m = @moonmath.Mat4::from_trs(
@moonmath.Trs::new(offset, @moonmath.Quat::identity(), scale),
)
// One, scaled by two, then moved one along x.
assert_true(
m
.transform_point(@moonmath.Vec3::one())
.approx(@moonmath.Vec3::new(3.0, 2.0, 2.0)),
)
}

frustum

pub fn Mat4::frustum(Float, Float, Float, Float, Float, Float) -> Self

A perspective projection from an explicit frustum with the depth range 0..1.

The rectangle on the near plane becomes the full clip volume, so the six numbers are all a camera needs: left and bottom are negative, right and top positive for a centred view, and offsetting them is what a lens shift does.

frustum_gl

pub fn Mat4::frustum_gl(Float, Float, Float, Float, Float, Float) -> Self

A perspective projection from an explicit frustum with the depth range -1..1.

get

pub fn Mat4::get(Self, Int32, Int32) -> Float

The element at row and column, both counted from zero.

identity

pub fn Mat4::identity() -> Self

The identity: the matrix that changes nothing.

inverse

pub fn Mat4::inverse(Self) -> Self?

The matrix that undoes this one, or None when there is none.

The usual use is the inverse of a camera's view-projection matrix, and the usual singular case is a projection built with far equal to near.

is_finite

pub fn Mat4::is_finite(Self) -> Bool

Whether every element is finite.

look_at

pub fn Mat4::look_at(Vec3, Vec3, Vec3) -> Self

The view matrix of a camera at eye looking at target, with up telling it which way is up.

Right-handed: the camera looks down its own -z, so the third column of the result is eye - target, normalized. up need not be perpendicular to the view direction, only not parallel to it; when it is parallel there is no answer and the identity comes back rather than a matrix full of NaNs.

mul_vec4

pub fn Mat4::mul_vec4(Self, Vec4) -> Vec4

The vector the matrix takes v to, without any division by w.

This is what a shader's matrix * vector does: the projection divide happens after clipping, not here. One expression per component, for the reason given at Mat2::mul_vec2.

orthographic

pub fn Mat4::orthographic(Float, Float, Float, Float, Float, Float) -> Self

An orthographic projection with the depth range 0..1: the box the six planes bound becomes the unit cube in clip space.

Right-handed, so the camera looks down -z and near and far are distances in front of it, both positive. A box with left == right, bottom == top or near == far has no volume to map and gives the identity.

orthographic_gl

pub fn Mat4::orthographic_gl(Float, Float, Float, Float, Float, Float) -> Self

An orthographic projection with the depth range -1..1.

perspective

pub fn Mat4::perspective(Float, Float, Float, Float) -> Self

A perspective projection with the depth range 0..1: the near plane maps to zero and the far plane to one, which is what WebGPU clips against.

fov_y is the vertical field of view in radians and aspect the width divided by the height. Right-handed: the camera looks down -z, so near and far are distances in front of it, both positive.

mbt check
test {
let m = @moonmath.Mat4::perspective(@moonmath.half_pi, 1.0, 0.1, 100.0)
// The near plane lands on depth 0 and the far plane on depth 1.
let near = m.mul_vec4(@moonmath.Vec4::new(0.0, 0.0, -0.1, 1.0))
assert_true(@moonmath.approx(near.z / near.w, 0.0))
let far = m.mul_vec4(@moonmath.Vec4::new(0.0, 0.0, -100.0, 1.0))
assert_true(@moonmath.approx(far.z / far.w, 1.0))
}

perspective_gl

pub fn Mat4::perspective_gl(Float, Float, Float, Float) -> Self

A perspective projection with the depth range -1..1, for a pipeline that clips like OpenGL.

The same as perspective in every other respect; only the third row differs.

perspective_infinite

pub fn Mat4::perspective_infinite(Float, Float, Float) -> Self

A perspective projection with the depth range 0..1 and no far plane.

Precision is better spent near the eye: with no far plane to reach, the depth values crowd into the region where a depth buffer can still tell them apart, instead of being spread over a range whose far end nothing occupies.

perspective_infinite_gl

pub fn Mat4::perspective_infinite_gl(Float, Float, Float) -> Self

A perspective projection with the depth range -1..1 and no far plane.

row

pub fn Mat4::row(Self, Int32) -> Vec4

Row index, counted from zero.

to_array

pub fn Mat4::to_array(Self) -> FixedArray[Float]

The elements in column-major order, the sixteen a buffer holds.

to_trs

pub fn Mat4::to_trs(Self) -> Trs?

The translation, rotation and scale the matrix was built from, or None when it cannot be read that way.

A matrix with shear in it — the common case being a non-uniform scale applied after a rotation — is not a Trs and has no decomposition here; neither has one whose linear part is singular, whose rotation would be unrecoverable. When the determinant is negative the first component of scale carries the sign, because a mirrored basis is a rotation with one flipped axis.

transform_point

pub fn Mat4::transform_point(Self, Vec3) -> Vec3

The point the matrix takes p to, dividing by w when there is one.

A projection matrix leaves the result in homogeneous coordinates; the point only exists after that division, so it happens here. A w of zero — a point on the horizon of a perspective projection — leaves the numerator as it is.

transform_vector

pub fn Mat4::transform_vector(Self, Vec3) -> Vec3

The direction the matrix takes v to, ignoring the translation column.

Directions have no position, so the fourth row must not touch them: a translation leaves a direction alone, as it should.

transpose

pub fn Mat4::transpose(Self) -> Self

The matrix with rows and columns exchanged.

zero

pub fn Mat4::zero() -> Self

The zero matrix: the one that sends everything to the origin and loses w.

Shearstruct

pub(all) struct Shear

A shear: the three off-diagonal terms that slide one axis into another while leaving the origin and the axes themselves where they are.

A shear is a linear map, so it is applied through to_mat3 or to_mat4. xy slides y into x, xz slides z into x, and yz slides z into y, matching the (row, column) terms of the upper triangle. The three together are the general upper-triangular linear map, which is what a skew, a slanted view of a page, or a shear deformation of a mesh is.

Values are immutable.

Fields
xy : Float

How much x gains from y: the (0, 1) term.

xz : Float

How much x gains from z: the (0, 2) term.

yz : Float

How much y gains from z: the (1, 2) term.

CarriesDebug, Show

approx

pub fn Shear::approx(Self, Self, eps? : Float) -> Bool

Whether the three terms agree with other to within eps.

is_finite

pub fn Shear::is_finite(Self) -> Bool

Whether the three terms are finite.

new

pub fn Shear::new(Float, Float, Float) -> Self

The shear from its three terms.

to_mat3

pub fn Shear::to_mat3(Self) -> Mat3

The shear as a linear map, ready to compose with a rotation or a scale.

to_mat4

pub fn Shear::to_mat4(Self) -> Mat4

The shear as a 4×4 matrix whose translation is zero.

zero

pub fn Shear::zero() -> Self

No shear: the identity map.

Rotation

3

A rotation as four numbers, and the twelve ways of writing one as three angles.

Quatstruct

pub(all) struct Quat

A rotation, as a unit quaternion.

(x, y, z) is the axis of the rotation scaled by the sine of half its angle, and w the cosine of half the angle. Half angles, because a rotation acts on a vector from both sides: q v q⁻¹.

A quaternion is four numbers where a matrix is nine, composes in fewer operations, and interpolates smoothly — which is why animation and physics carry rotations this way and convert to a matrix only when handing one to a shader.

The rotations are the unit quaternions; the ones here do not enforce that on construction, because building one by summing or lerping intermediate values is legitimate and only the end result has to be normal. Anything that composes an arbitrary number of them — rotate, to_mat3, slerp — says when it assumes unit length.

Fields
x : Float

The x part of the axis, scaled by the sine of half the angle.

y : Float

The y part of the axis, scaled by the sine of half the angle.

z : Float

The z part of the axis, scaled by the sine of half the angle.

w : Float

The cosine of half the angle.

CarriesDebug, Div, Mul, Neg, Show

approx

pub fn Quat::approx(Self, Self, eps? : Float) -> Bool

Whether the two rotations are the same to within eps.

q and -q are the same rotation, so the sign between them is not a difference; the comparison uses the absolute dot product.

conjugate

pub fn Quat::conjugate(Self) -> Self

The conjugate: the quaternion with its axis part negated.

The inverse rotation for a unit quaternion, and cheaper than inverse because it divides by nothing.

dot

pub fn Quat::dot(Self, Self) -> Float

The dot product of the two, as four-component vectors.

Its sign says whether the two rotations take the short way round: negative means the interpolations in this module would travel the long way, and interpolating with the negated quaternion instead gives the short one.

from_axis_angle

pub fn Quat::from_axis_angle(Vec3, Float) -> Self

The rotation of radians about axis, by the right-hand rule.

axis is normalized first; a zero axis has no direction to turn about and gives the identity.

mbt check
test {
let quarter = @moonmath.Quat::from_axis_angle(
@moonmath.Vec3::unit_z(),
@moonmath.half_pi,
)
assert_true(
quarter.rotate(@moonmath.Vec3::unit_x()).approx(@moonmath.Vec3::unit_y()),
)
}

from_euler

pub fn Quat::from_euler(EulerOrder, Vec3) -> Self

The rotation the three angles describe, taken in order, in radians.

The components of angles are the turns about x, y and z, wherever in the order those axes turn up: for Zyx, which turns about z first, the third component is the first turn. That is the reading a caller expects from a vector named after axes, and it is exact for the six orders that name three different axes.

The other six turn about one axis twice — Xyx is the family — and two turns about one axis cannot both be given by its single component. Passing one of those orders to this function aborts; from_euler_turns takes the three turns in order and covers all twelve.

mbt check
test {
// Zyx turns about z first, so the third component is the first turn.
let turn = @moonmath.Quat::from_euler(
@moonmath.EulerOrder::Zyx,
@moonmath.Vec3::new(0.0, 0.0, @moonmath.half_pi),
)
assert_true(
turn.rotate(@moonmath.Vec3::unit_y()).approx(-@moonmath.Vec3::unit_x()),
)
}

from_euler_turns

pub fn Quat::from_euler_turns(EulerOrder, Turns) -> Self

The rotation the three turns describe, in the order the order names them.

The general form: it takes the first turn, the second and the third however many axes they use, so it covers all twelve orders. For the six that name three different axes it is the same rotation from_euler builds from a vector, with the turns already in order.

from_mat3

pub fn Quat::from_mat3(Mat3) -> Self

The rotation the matrix holds, for a matrix that is a rotation.

A matrix with a scale in it gives the rotation underneath only when the scale is uniform; one that is not a rotation at all gives the nearest unit quaternion to its columns, which is still a usable answer for a matrix that drifted.

from_mat4

pub fn Quat::from_mat4(Mat4) -> Self

The rotation the 4×4 matrix holds, read from its upper-left block.

from_rotation_arc

pub fn Quat::from_rotation_arc(Vec3, Vec3) -> Self

The shortest rotation that turns from towards to, for two directions.

The pair need not be normalized and need not be perpendicular to anything: the rotation takes the direction of from to the direction of to and leaves the plane they span alone. Opposed directions have no single shortest rotation — every half turn about a perpendicular axis works — and one is picked. A zero vector has no direction to turn and gives the identity.

mbt check
test {
let turn = @moonmath.Quat::from_rotation_arc(
@moonmath.Vec3::unit_x(),
@moonmath.Vec3::unit_y(),
)
assert_true(
turn.rotate(@moonmath.Vec3::unit_x()).approx(@moonmath.Vec3::unit_y()),
)
}

identity

pub fn Quat::identity() -> Self

The rotation that changes nothing.

inverse

pub fn Quat::inverse(Self) -> Self?

The rotation run backwards: the quaternion that undoes this one.

For a unit quaternion this is the conjugate; for any other it is the conjugate divided by the squared length, so that q * q.inverse() is the identity. None for the zero quaternion, which represents no rotation and has no inverse.

is_finite

pub fn Quat::is_finite(Self) -> Bool

Whether every component is finite.

length

pub fn Quat::length(Self) -> Float

The length of the quaternion as a four-component vector: one for a rotation.

length_squared

pub fn Quat::length_squared(Self) -> Float

The square of the length.

new

pub fn Quat::new(Float, Float, Float, Float) -> Self

The quaternion from its four components, in the order (x, y, z, w).

nlerp

pub fn Quat::nlerp(Self, Self, Float) -> Self

The rotation a fraction of the way from self to other along the straight line, normalized back onto the sphere.

Cheaper than slerp and close to it for small angles; the rate is not quite constant, which a long animation would show.

normalize

pub fn Quat::normalize(Self) -> Self

The quaternion scaled to length one, or the identity if it is zero.

A rotation is always a unit quaternion; one built by summing or lerping others has to be brought back before it can rotate anything, and the zero quaternion — which summing can produce — falls back to the identity rather than to a division by zero.

random

pub fn Quat::random(Float, Float, Float) -> Self

A uniformly distributed random rotation.

u1, u2 and u3 are independent uniform samples in [0, 1). The result is a unit quaternion spread evenly over the rotation group — the construction that makes it even is not obvious, and a quaternion built from three evenly sampled angles would not be.

rotate

pub fn Quat::rotate(Self, Vec3) -> Vec3

The vector turned by the rotation.

Assumes unit length. Two cross products rather than q v q⁻¹, which is the same result with fewer multiplications.

slerp

pub fn Quat::slerp(Self, Self, Float) -> Self

The rotation a fraction of the way from self to other, at constant angular speed.

Spherical interpolation: the intermediate rotations turn at a steady rate, which is what an animation between two orientations wants. The two are compared first, and the negated one is used when they point away from each other — q and -q are the same rotation, and the negation is the one that takes the short way.

to_array

pub fn Quat::to_array(Self) -> FixedArray[Float]

The four components in order, [x, y, z, w], for handing to a buffer.

to_axis_angle

pub fn Quat::to_axis_angle(Self) -> (Vec3, Float)

The angle and axis of the rotation, as (axis, radians) with the axis a unit vector and the angle in 0..pi.

A rotation of zero has no axis to name; it comes back as (x, 0) — the first axis, with a zero angle, which rotates nothing either way.

to_euler

pub fn Quat::to_euler(Self, EulerOrder) -> Vec3

The turn about each axis that produces this rotation in order, in radians.

The inverse of from_euler, and read the same way: the component of an axis is the turn about it, wherever in the order it comes. Aborts for the six orders that turn about one axis twice, whose two turns cannot both be written into one component; to_euler_turns returns them in order instead.

mbt check
test {
let turn = @moonmath.Quat::from_axis_angle(
@moonmath.Vec3::unit_x(),
@moonmath.quarter_pi,
)
let angles = turn.to_euler(@moonmath.EulerOrder::Yxz)
assert_true(@moonmath.approx(angles.x, @moonmath.quarter_pi))
}

to_euler_turns

pub fn Quat::to_euler_turns(Self, EulerOrder) -> Turns

The three turns that produce this rotation in order, in radians, in the order the order names them.

The inverse of from_euler_turns, for every one of the twelve orders. Feeding the result back gives the rotation again, except at the two angles where the first and third turns collapse into one — the gimbal lock every three-angle convention has. There the first turn comes back as zero and the whole of it is carried by the third.

to_mat3

pub fn Quat::to_mat3(Self) -> Mat3

The rotation as a 3×3 matrix.

Assumes unit length; a quaternion that drifted scales the matrix by the square of its norm.

to_mat4

pub fn Quat::to_mat4(Self) -> Mat4

The rotation as a 4×4 matrix whose translation is zero.

EulerOrderenum

pub(all) enum EulerOrder

The order the three Euler angles are applied in.

The name says which axis each angle turns about, read left to right: Xyz turns about x, then about the new y, then about the new z. That is the intrinsic reading, the one an aircraft's roll, pitch and yaw use, and it is the same as applying the three turns about the fixed axes in the opposite order.

Six orders turn about three different axes and six about two — the last group repeats the first axis and is what a turntable and a gyroscope do. Between them they cover every way to name a rotation by three angles; the choice is a convention of the file format or the editor that produced the angles, not of the arithmetic.

Variants
Xyz

Turns about x, then y, then z: the family that locks at a quarter turn of y.

Xzy

Turns about x, then z, then y.

Yxz

Turns about y, then x, then z.

Yzx

Turns about y, then z, then x.

Zxy

Turns about z, then x, then y.

Zyx

Turns about z, then y, then x: yaw, pitch and roll, in that order.

Xyx

Turns about x, then y, then x again: the first and third share an axis.

Xzx

Turns about x, then z, then x again.

Yxy

Turns about y, then x, then y again.

Yzy

Turns about y, then z, then y again.

Zxz

Turns about z, then x, then z again.

Zyz

Turns about z, then y, then z again.

Turnsstruct

pub(all) struct Turns

The three turns of a rotation, in the order the order names them.

first is the turn about the first axis of the order, second about the second and third about the third — which for six of the twelve orders is the first axis again. A record rather than a vector because a vector's components are named after axes, and for those six orders the third turn is not about the third axis; naming the slots after their place in the order says exactly what they are.

Fields
first : Float

The turn about the first axis the order names.

second : Float

The turn about the second axis the order names.

third : Float

The turn about the third axis the order names.

CarriesDebug, Show

approx

pub fn Turns::approx(Self, Self, eps? : Float) -> Bool

Whether the two triples agree to within eps.

new

pub fn Turns::new(Float, Float, Float) -> Self

The three turns, in the order the order names them.

Placement

4

The transforms a scene graph stores: a rotation, a scale and a translation, apart or as one motion.

Trsstruct

pub(all) struct Trs

A translation, a rotation and a scale, in that order of composition: a point is scaled, then turned, then moved.

This is what Mat4::to_trs recovers from a matrix that was built the same way, and what a scene graph stores per node — the three pieces are what an animation edits, and a decomposition keeps them editable.

Fields
translation : Vec3

Where the frame sits.

rotation : Quat

How it is turned.

scale : Vec3

How far it is stretched, per axis.

CarriesDebug, Show

new

pub fn Trs::new(Vec3, Quat, Vec3) -> Self

The three parts of a transformation.

Affine2struct

pub(all) struct Affine2

A 2D affine transform: a linear map and a translation, without the row of a matrix that does nothing but hold (0, 0, 1).

Composition, inversion and applying are all cheaper than the 3×3 matrix that would carry the same thing, and there is no way to build one of these that is not affine — which is what UI layout, sprite placement and 2D physics want.

Values are immutable.

Fields
linear : Mat2

The part that turns and scales: a 2×2 matrix.

translation : Vec2

The part that moves.

CarriesDebug, Div, Mul, Show

approx

pub fn Affine2::approx(Self, Self, eps? : Float) -> Bool

Whether the two transforms agree to within eps element by element.

from_angle

pub fn Affine2::from_angle(Float) -> Self

The transform that turns counter-clockwise by radians about the origin.

from_angle_translation

pub fn Affine2::from_angle_translation(Float, Vec2) -> Self

The transform that turns by radians and then moves by offset.

from_mat3

pub fn Affine2::from_mat3(Mat3) -> Self?

The affine transform a 3×3 matrix holds, or None when the matrix is not affine.

A matrix whose last row is not (0, 0, 1) — a projection, say — carries a perspective that this type cannot hold, and there is no transform to return.

from_scale

pub fn Affine2::from_scale(Vec2) -> Self

The transform that scales each axis by the matching component of scale.

from_translation

pub fn Affine2::from_translation(Vec2) -> Self

The transform that moves every point by offset.

identity

pub fn Affine2::identity() -> Self

The transform that changes nothing.

inverse

pub fn Affine2::inverse(Self) -> Self?

The transform that undoes this one, or None when the linear part is singular.

A singular linear part flattens the plane onto a line or a point, and no transform brings that back.

is_finite

pub fn Affine2::is_finite(Self) -> Bool

Whether every element is finite.

new

pub fn Affine2::new(Mat2, Vec2) -> Self

The transform that maps v to linear * v + translation.

to_mat3

pub fn Affine2::to_mat3(Self) -> Mat3

The same transform as a 3×3 matrix, with (0, 0, 1) as its last row.

transform_point

pub fn Affine2::transform_point(Self, Vec2) -> Vec2

The point the transform takes p to.

transform_vector

pub fn Affine2::transform_vector(Self, Vec2) -> Vec2

The direction the transform takes v to, without the translation.

A direction has no position, so moving the origin must leave it alone.

Affine3struct

pub(all) struct Affine3

A 3D affine transform: a linear map and a translation, without the fourth row of a matrix that does nothing but hold (0, 0, 0, 1).

This is the transform a scene node carries — position, rotation and scale applied to its geometry — and it is cheaper than the 4×4 matrix that would also happen to work, since the wasted row would be multiplied four times per vector.

Values are immutable.

Fields
linear : Mat3

The part that turns and scales: a 3×3 matrix.

translation : Vec3

The part that moves.

CarriesDebug, Div, Mul, Show

approx

pub fn Affine3::approx(Self, Self, eps? : Float) -> Bool

Whether the two transforms agree to within eps element by element.

from_axis_angle

pub fn Affine3::from_axis_angle(Vec3, Float) -> Self

The transform that turns by radians about axis, by the right-hand rule.

from_mat4

pub fn Affine3::from_mat4(Mat4) -> Self?

The affine transform a 4×4 matrix holds, or None when the matrix is not affine.

from_rotation

pub fn Affine3::from_rotation(Quat) -> Self

The transform that applies the rotation, about the origin.

from_scale

pub fn Affine3::from_scale(Vec3) -> Self

The transform that scales each axis by the matching component of scale.

from_translation

pub fn Affine3::from_translation(Vec3) -> Self

The transform that moves every point by offset.

from_trs

pub fn Affine3::from_trs(Trs) -> Self

The transform that scales, then rotates, then moves: the three parts of a Trs.

identity

pub fn Affine3::identity() -> Self

The transform that changes nothing.

inverse

pub fn Affine3::inverse(Self) -> Self?

The transform that undoes this one, or None when the linear part is singular.

is_finite

pub fn Affine3::is_finite(Self) -> Bool

Whether every element is finite.

new

pub fn Affine3::new(Mat3, Vec3) -> Self

The transform that maps v to linear * v + translation.

to_mat4

pub fn Affine3::to_mat4(Self) -> Mat4

The same transform as a 4×4 matrix, with (0, 0, 0, 1) as its last row.

to_trs

pub fn Affine3::to_trs(Self) -> Trs?

The three parts the transform was built from, or None when its linear part is singular or has shear in it. See Mat4::to_trs.

transform_point

pub fn Affine3::transform_point(Self, Vec3) -> Vec3

The point the transform takes p to.

transform_vector

pub fn Affine3::transform_vector(Self, Vec3) -> Vec3

The direction the transform takes v to, without the translation.

DualQuatstruct

pub(all) struct DualQuat

A rigid motion — a rotation, and the translation that follows it — written as a pair of quaternions.

real is the rotation, a unit quaternion; dual is half the translation, turned by that rotation, so the two halves carry eight numbers between them instead of the twelve a matrix needs. The point of the pair is what happens between two of them: a weighted sum keeps the motion a motion, because the rotation half is normalized afterwards, while the same sum of matrices pulls the rotation towards zero and with it the scale. That is what a skinning loop wants, and what a matrix cannot give it.

The convention is the library's: right-handed, column-major, the rotation applied first and the translation second.

Fields
real : Quat

The rotation.

dual : Quat

Half the translation, turned by the rotation: 0.5 * (t, 0) * real.

CarriesAdd, Debug, Mul, Neg, Show

approx

pub fn DualQuat::approx(Self, Self, eps? : Float) -> Bool

Whether the two motions agree to within eps.

The halves are compared component by component, after negating the other one when the two rotations lie on opposite sides of the four-dimensional sphere: the sign between them is not a difference, but the dual half has to follow the same negation for the two to describe the same motion.

dot

pub fn DualQuat::dot(Self, Self) -> Float

The dot product of the two rotations.

A negative one means the two rotations are more than a half turn apart in the four-dimensional sense, and that the second should be negated before the two are summed: q and -q are the same rotation, and summing without looking takes the long way round.

from_mat4

pub fn DualQuat::from_mat4(Mat4) -> Self?

The motion a matrix describes, or None when the matrix scales or shears.

A rigid motion is the only thing the pair can hold, so a matrix that stretches along an axis, or reflects, has no answer here; the check is the round trip, which is also what catches a matrix whose rotation cannot be read out.

from_rotation_translation

pub fn DualQuat::from_rotation_translation(Quat, Vec3) -> Self

The motion that turns by rotation and then moves by translation.

mbt check
test {
let moved : @moonmath.DualQuat = @moonmath.DualQuat::from_rotation_translation(
@moonmath.Quat::identity(),
@moonmath.Vec3::new(1.0, 2.0, 3.0),
)
assert_true(moved.translation().approx(@moonmath.Vec3::new(1.0, 2.0, 3.0)))
}

identity

pub fn DualQuat::identity() -> Self

The motion that changes nothing.

inverse

pub fn DualQuat::inverse(Self) -> Self?

The motion that undoes this one, or None when the rotation is zero.

is_finite

pub fn DualQuat::is_finite(Self) -> Bool

Whether every component of both halves is finite.

new

pub fn DualQuat::new(Quat, Quat) -> Self

The two halves as given, without normalizing either.

A motion is a unit pair, and a weighted sum of motions is not; normalize is what makes one again.

normalize

pub fn DualQuat::normalize(Self) -> Self

The same motion with both halves divided by the length of the rotation.

A weighted sum of motions is no longer a rotation and a translation; this is what makes it one again, and it is the step that keeps a skinning blend from shrinking the mesh. A sum whose rotation has cancelled out answers the identity.

rotation

pub fn DualQuat::rotation(Self) -> Quat

The rotation half, normalized.

scale

pub fn DualQuat::scale(Self, Float) -> Self

The same motion scaled about the identity, both halves by the same factor.

This is the multiplication a weighted sum of motions is made of; the sum itself is not a motion until it is normalized.

slerp

pub fn DualQuat::slerp(Self, Self, Float) -> Self

The motion a fraction t of the way from this one to other.

The rotation takes the shortest arc at constant angular speed, as Quat::slerp does; the translation moves at constant speed along the straight line between the two, as Vec3::lerp does. A screw motion — turning about the axis the two share — is a different curve, and not the one a keyframe between two poses describes.

to_array

pub fn DualQuat::to_array(Self) -> FixedArray[Float]

The eight components in order, [rx, ry, rz, rw, dx, dy, dz, dw], for handing to a buffer.

to_mat4

pub fn DualQuat::to_mat4(Self) -> Mat4

The matrix this motion is: the rotation, then the translation.

transform_point

pub fn DualQuat::transform_point(Self, Vec3) -> Vec3

The point moved by the motion: turned first, then moved.

transform_vector

pub fn DualQuat::transform_vector(Self, Vec3) -> Vec3

The direction turned by the rotation, with the translation left out.

translation

pub fn DualQuat::translation(Self) -> Vec3

The translation half, as the vector it stands for.

Geometry

11

Shapes, and whether two of them meet.

Rectstruct

pub(all) struct Rect

A rectangle given by its corner and its size: the shape a layout hands out.

A layout thinks in "here, this big", not in two opposite corners, which is why this is not Aabb2 — the two describe the same set of points and answer different questions. origin is the corner with the smaller coordinates and size the extent from it, so a size with a negative component describes the same points as the equivalent positive one, with the corners swapped.

Values are immutable.

Fields
origin : Vec2

The corner with the smallest coordinate on each axis.

size : Vec2

How far it extends along each axis; never negative.

CarriesDebug, Show

approx

pub fn Rect::approx(Self, Self, eps? : Float) -> Bool

Whether the two rectangles cover the same points to within eps.

area

pub fn Rect::area(Self) -> Float

The area the rectangle covers.

center

pub fn Rect::center(Self) -> Vec2

The point in the middle.

contains

pub fn Rect::contains(Self, Vec2) -> Bool

Whether the point is inside or on the edge.

corners

pub fn Rect::corners(Self) -> FixedArray[Vec2]

The four corners, starting at origin and going counter-clockwise.

from_edges

pub fn Rect::from_edges(Float, Float, Float, Float) -> Self

The rectangle spanning two opposite corners, in either order.

from_xywh

pub fn Rect::from_xywh(Float, Float, Float, Float) -> Self

The rectangle with its top-left corner at x, y and the given extent.

The usual spelling for a layout node; which way is "top" is the caller's convention, as everywhere else here.

height

pub fn Rect::height(Self) -> Float

The extent along y, always non-negative.

inset

pub fn Rect::inset(Self, Float) -> Self

The same rectangle with every edge moved in by amount.

A positive amount shrinks it, a negative one grows it; shrinking past the middle leaves an empty rectangle at the centre rather than a negative one.

intersection

pub fn Rect::intersection(Self, Self) -> Self?

The area the two share, or None when they share none.

intersects

pub fn Rect::intersects(Self, Self) -> Bool

Whether the two rectangles share any area.

Touching edges share no area and do not count; an empty rectangle intersects nothing.

is_empty

pub fn Rect::is_empty(Self) -> Bool

Whether the rectangle covers no area at all.

A zero width or height is empty: it is a line or a point, and nothing inside it can be drawn or hit.

max

pub fn Rect::max(Self) -> Vec2

The corner with the larger coordinates.

min

pub fn Rect::min(Self) -> Vec2

The corner with the smaller coordinates.

new

pub fn Rect::new(Vec2, Vec2) -> Self

The rectangle at origin extending size.

to_aabb

pub fn Rect::to_aabb(Self) -> Aabb2

The same points as an axis-aligned box.

translate

pub fn Rect::translate(Self, Vec2) -> Self

The same rectangle moved by offset.

union

pub fn Rect::union(Self, Self) -> Self

The smallest rectangle containing both.

width

pub fn Rect::width(Self) -> Float

The extent along x, always non-negative.

Aabb2struct

pub(all) struct Aabb2

An axis-aligned box in the plane, given by two opposite corners.

Broad-phase collision and culling ask "is this thing anywhere near that thing", and a box around each answers it without touching the contents. The corners are min and max rather than a corner and a size because that is the form the tests read, and because merging two boxes is then two component comparisons.

Values are immutable.

Fields
min : Vec2

The corner with the smallest coordinate on each axis.

max : Vec2

The corner with the largest coordinate on each axis.

CarriesDebug, Show

approx

pub fn Aabb2::approx(Self, Self, eps? : Float) -> Bool

Whether the two boxes agree to within eps.

area

pub fn Aabb2::area(Self) -> Float

The area the box covers, zero when it is empty.

center

pub fn Aabb2::center(Self) -> Vec2

The point in the middle.

contains

pub fn Aabb2::contains(Self, Self) -> Bool

Whether other lies entirely inside this box.

contains_point

pub fn Aabb2::contains_point(Self, Vec2) -> Bool

Whether the point is inside or on the boundary.

corners

pub fn Aabb2::corners(Self) -> FixedArray[Vec2]

The four corners, starting at min and going counter-clockwise.

empty

pub fn Aabb2::empty() -> Self

A box with nothing in it: the identity for union.

Its corners are the wrong way round on purpose, so that merging anything into it gives that thing back unchanged.

expand

pub fn Aabb2::expand(Self, Float) -> Self

The same box grown by amount in every direction.

extents

pub fn Aabb2::extents(Self) -> Vec2

The half extent along each axis: the distance from the middle to a face.

from_center_half_extents

pub fn Aabb2::from_center_half_extents(Vec2, Vec2) -> Self

The box with the given centre and half-extents.

from_points

pub fn Aabb2::from_points(FixedArray[Vec2]) -> Self?

The smallest box around the points, or None when there are none.

intersection

pub fn Aabb2::intersection(Self, Self) -> Self?

The overlapping box, or None when they do not overlap.

intersects

pub fn Aabb2::intersects(Self, Self) -> Bool

Whether the two boxes overlap in positive area.

is_empty

pub fn Aabb2::is_empty(Self) -> Bool

Whether the box holds nothing.

new

pub fn Aabb2::new(Vec2, Vec2) -> Self

The box with the two given corners.

size

pub fn Aabb2::size(Self) -> Vec2

The full extent along each axis.

to_rect

pub fn Aabb2::to_rect(Self) -> Rect

The same points as a rectangle.

union

pub fn Aabb2::union(Self, Self) -> Self

The smallest box containing both.

Aabb3struct

pub(all) struct Aabb3

An axis-aligned box in space, given by two opposite corners.

The same broad-phase role as Aabb2, with a third axis: a frustum is tested against one of these per object per frame, so the tests here are written to read the extremes of a plane's distance rather than to visit eight corners.

Values are immutable.

Fields
min : Vec3

The corner with the smallest coordinate on each axis.

max : Vec3

The corner with the largest coordinate on each axis.

CarriesDebug, Show

approx

pub fn Aabb3::approx(Self, Self, eps? : Float) -> Bool

Whether the two boxes agree to within eps.

center

pub fn Aabb3::center(Self) -> Vec3

The point in the middle.

contains

pub fn Aabb3::contains(Self, Self) -> Bool

Whether other lies entirely inside this box.

contains_point

pub fn Aabb3::contains_point(Self, Vec3) -> Bool

Whether the point is inside or on the boundary.

corners

pub fn Aabb3::corners(Self) -> FixedArray[Vec3]

The eight corners.

empty

pub fn Aabb3::empty() -> Self

A box with nothing in it: the identity for union.

expand

pub fn Aabb3::expand(Self, Float) -> Self

The same box grown by amount in every direction.

extents

pub fn Aabb3::extents(Self) -> Vec3

The half extent along each axis.

from_center_half_extents

pub fn Aabb3::from_center_half_extents(Vec3, Vec3) -> Self

The box with the given centre and half-extents.

from_points

pub fn Aabb3::from_points(FixedArray[Vec3]) -> Self?

The smallest box around the points, or None when there are none.

intersection

pub fn Aabb3::intersection(Self, Self) -> Self?

The overlapping box, or None when they do not overlap.

intersects

pub fn Aabb3::intersects(Self, Self) -> Bool

Whether the two boxes overlap in positive volume.

is_empty

pub fn Aabb3::is_empty(Self) -> Bool

Whether the box holds nothing.

new

pub fn Aabb3::new(Vec3, Vec3) -> Self

The box with the two given corners.

random_point

pub fn Aabb3::random_point(Self, Float, Float, Float) -> Vec3

A point uniformly distributed through the box.

u1, u2 and u3 are independent uniform samples in [0, 1), one per axis.

size

pub fn Aabb3::size(Self) -> Vec3

The full extent along each axis.

surface_area

pub fn Aabb3::surface_area(Self) -> Float

The total area of the six faces, zero when it is empty.

transform

pub fn Aabb3::transform(Self, Mat4) -> Self

The box around the transformed box.

A box turned by a rotation is no longer axis-aligned, so the result is the smallest axis-aligned box around the turned one: correct, and looser than it was before the turn.

union

pub fn Aabb3::union(Self, Self) -> Self

The smallest box containing both.

volume

pub fn Aabb3::volume(Self) -> Float

The volume the box encloses, zero when it is empty.

Ray2struct

pub(all) struct Ray2

A half-line in the plane: a start and a direction.

origin + direction * t for t >= 0. The direction is not normalized here — a ray whose direction carries the speed of something travelling along it is as useful as a unit one, and t then reads as time.

Values are immutable.

Fields
origin : Vec2

Where the ray starts.

direction : Vec2

Which way it goes. The intersections report t in units of this vector, so a unit direction makes t a distance.

CarriesDebug, Show

approx

pub fn Ray2::approx(Self, Self, eps? : Float) -> Bool

Whether the two rays start at the same point and head the same way.

at

pub fn Ray2::at(Self, Float) -> Vec2

The point t along the ray.

intersect_aabb

pub fn Ray2::intersect_aabb(Self, Aabb2) -> Float?

Where the ray first meets the box, as a t, or None when it misses.

A ray that starts inside the box meets its surface on the way out, and that crossing is the one reported — the nearest one at t >= 0, rather than "the one in front of the origin in the direction of travel".

intersect_aabb_interval

pub fn Ray2::intersect_aabb_interval(Self, Aabb2) -> (Float, Float)?

The stretch of the ray that lies inside the box, as a pair of t values.

A ray that starts inside the box is already inside at t = 0, and the entry is then negative — the point was inside before the ray started, and the interval says from where. None when the ray misses the box.

intersect_circle

pub fn Ray2::intersect_circle(Self, Vec2, Float) -> Float?

Where the ray first meets the circle, as a t, or None when it misses.

A ray that starts inside the circle meets it on the way out.

intersect_rect

pub fn Ray2::intersect_rect(Self, Rect) -> Float?

Where the ray first meets the rectangle, as a t, or None when it misses.

new

pub fn Ray2::new(Vec2, Vec2) -> Self

The ray starting at origin and heading along direction.

Ray3struct

pub(all) struct Ray3

A half-line in space: a start and a direction.

What a picking click, a mouse cursor in a 3D scene and a photon all are. The tests here return the parameter t of the first surface crossing rather than the point, because the caller usually needs the distance and the point is one multiplication away.

Values are immutable.

Fields
origin : Vec3

Where the ray starts.

direction : Vec3

Which way it goes. The intersections report t in units of this vector, so a unit direction makes t a distance.

CarriesDebug, Show

approx

pub fn Ray3::approx(Self, Self, eps? : Float) -> Bool

Whether the two rays start at the same point and head the same way.

at

pub fn Ray3::at(Self, Float) -> Vec3

The point t along the ray.

intersect_aabb

pub fn Ray3::intersect_aabb(Self, Aabb3) -> Float?

Where the ray first meets the box, as a t, or None when it misses.

A ray that starts inside the box reports its exit.

intersect_aabb_interval

pub fn Ray3::intersect_aabb_interval(Self, Aabb3) -> (Float, Float)?

The stretch of the ray that lies inside the box, as a pair of t values.

A ray that starts inside has an entry before its origin. This is the slab test: for each axis the ray is inside the box over an interval, and the intersection of the three intervals is the stretch wanted. A ray parallel to a face never leaves that axis' slab, or never enters it.

intersect_plane

pub fn Ray3::intersect_plane(Self, Plane) -> Float?

Where the ray meets the plane, as a t, or None when it runs parallel.

A ray lying inside the plane meets it everywhere and nowhere in particular; that comes back as None too.

intersect_sphere

pub fn Ray3::intersect_sphere(Self, Sphere) -> Float?

Where the ray first meets the sphere, as a t, or None when it misses.

A ray that starts inside the sphere reports its exit.

intersect_triangle

pub fn Ray3::intersect_triangle(Self, Triangle) -> Float?

Where the ray meets the triangle, as a t, or None when it misses.

Möller–Trumbore: the ray is solved against the triangle's barycentric coordinates directly, without building the plane first, and a hit behind the origin or outside the triangle gives None.

new

pub fn Ray3::new(Vec3, Vec3) -> Self

The ray starting at origin and heading along direction.

Planestruct

pub(all) struct Plane

An infinite plane in space: the set of points p with dot(normal, p) == distance, where the normal is a unit vector.

The offset form rather than point-and-normal, because the signed distance of a point is then a dot product and no subtraction, which is what a frustum does six times per box.

Values are immutable.

Fields
normal : Vec3

The unit normal: which side is out.

distance : Float

How far the plane is from the origin, measured along the normal.

CarriesDebug, Show

approx

pub fn Plane::approx(Self, Self, eps? : Float) -> Bool

Whether the two planes are the same to within eps.

flip

pub fn Plane::flip(Self) -> Self

The same plane with the other side facing out.

from_point_normal

pub fn Plane::from_point_normal(Vec3, Vec3) -> Self?

The plane through point with the given normal.

from_points

pub fn Plane::from_points(Vec3, Vec3, Vec3) -> Self?

The plane through the three points, or None when they are collinear.

The normal faces the way the points wind, by the right-hand rule, so the winding order decides which side is positive.

intersect_ray

pub fn Plane::intersect_ray(Self, Ray3) -> Float?

Where the ray meets the plane, as a t, or None when it runs parallel or the crossing is behind the origin.

is_finite

pub fn Plane::is_finite(Self) -> Bool

Whether the normal and the distance are finite.

new

pub fn Plane::new(Vec3, Float) -> Self

The plane whose normal is normal and whose signed distance from the origin is distance.

normal is normalized, and distance scaled with it, so that signed_distance counts the same units as the coordinates. A zero normal names no plane and aborts: there is no answer to give back.

project

pub fn Plane::project(Self, Vec3) -> Vec3

The point of the plane closest to point: the point projected onto it.

signed_distance

pub fn Plane::signed_distance(Self, Vec3) -> Float

The distance from the plane to the point, positive on the side the normal points to.

Spherestruct

pub(all) struct Sphere

A sphere: a centre and a radius.

Values are immutable.

Fields
center : Vec3

The centre.

radius : Float

The radius.

CarriesDebug, Show

approx

pub fn Sphere::approx(Self, Self, eps? : Float) -> Bool

Whether the two spheres agree to within eps.

contains_point

pub fn Sphere::contains_point(Self, Vec3) -> Bool

Whether the point is inside or on the surface.

intersects_aabb

pub fn Sphere::intersects_aabb(Self, Aabb3) -> Bool

Whether the sphere and the box overlap or touch.

The point of the box closest to the centre is the one that decides it: if that point is within the radius, the two meet. Testing the centre against the box alone would call a sphere near a corner a miss.

intersects_sphere

pub fn Sphere::intersects_sphere(Self, Self) -> Bool

Whether the two spheres overlap or touch.

new

pub fn Sphere::new(Vec3, Float) -> Self

The sphere with the given centre and radius.

random_inside

pub fn Sphere::random_inside(Self, Float, Float, Float) -> Vec3

A point uniformly distributed through the sphere.

u1, u2 and u3 are independent uniform samples in [0, 1), as for Vec3::random_in_ball.

random_on_surface

pub fn Sphere::random_on_surface(Self, Float, Float) -> Vec3

A point uniformly distributed over the surface of the sphere.

u1 and u2 are independent uniform samples in [0, 1), as for Vec3::random_on_sphere.

surface_area

pub fn Sphere::surface_area(Self) -> Float

The area of the surface.

volume

pub fn Sphere::volume(Self) -> Float

The volume it encloses.

Line3struct

pub(all) struct Line3

An infinite line in space: a point and a direction.

A ray has a start and runs one way; a line has neither end, which is what a construction axis, a normal or the intersection of two planes is. The direction need not be a unit vector — the results are the same whatever its length — but a zero direction names no line, and every operation treats it as the single point point.

Values are immutable.

Fields
point : Vec3

A point on the line.

direction : Vec3

The direction it runs in; its length does not matter.

CarriesDebug, Show

approx

pub fn Line3::approx(Self, Self, eps? : Float) -> Bool

Whether the two lines have the same point and direction to within eps.

at

pub fn Line3::at(Self, Float) -> Vec3

The point t of the direction from point; t may be any number.

closest_point_to

pub fn Line3::closest_point_to(Self, Vec3) -> Vec3

The point of the line closest to other.

The perpendicular foot: the vector from it to other is perpendicular to the direction. A zero direction leaves the line a point, and the answer is that point.

closest_point_to_line

pub fn Line3::closest_point_to_line(Self, Self) -> Vec3

The point of this line closest to the other line.

For two lines that meet or are skew, the closest points are the pair joined by the common perpendicular; this is the one on this line. Parallel lines have a whole family of closest pairs and the foot from the other line's point is returned. A degenerate line — a zero direction — gives its point.

distance_to_line

pub fn Line3::distance_to_line(Self, Self) -> Float

The distance between the two lines: zero when they meet.

distance_to_point

pub fn Line3::distance_to_point(Self, Vec3) -> Float

The distance from the line to the point.

intersect_plane

pub fn Line3::intersect_plane(Self, Plane) -> Vec3?

Where the line cuts the plane, or None when it runs parallel to it.

A line has no ends, so any crossing counts, on either side of point.

is_finite

pub fn Line3::is_finite(Self) -> Bool

Whether the point and the direction are finite.

new

pub fn Line3::new(Vec3, Vec3) -> Self

The line through point in direction.

Intervalstruct

pub(all) struct Interval

A one-dimensional range between two numbers, min at or below max.

It is the one-dimensional case of an axis-aligned box, and what a timeline, an exposure or a depth range is. An empty interval — no numbers at all — is the one with min above max, which is how the union of nothing starts and how empty builds it; every operation here treats it as the identity the set operations expect.

Values are immutable.

Fields
min : Float

The low end, inclusive.

max : Float

The high end, inclusive.

CarriesDebug, Show

approx

pub fn Interval::approx(Self, Self, eps? : Float) -> Bool

Whether the two intervals agree end for end to within eps.

center

pub fn Interval::center(Self) -> Float

The midpoint of the interval.

contains

pub fn Interval::contains(Self, Float) -> Bool

Whether value lies in the interval, ends included.

empty

pub fn Interval::empty() -> Self

The interval with no numbers in it, which every union starts from.

expand

pub fn Interval::expand(Self, Float) -> Self

The interval grown by amount at both ends; a negative amount shrinks it.

extend_by

pub fn Interval::extend_by(Self, Float) -> Self

The interval grown to include value; the empty interval becomes [value, value].

intersection

pub fn Interval::intersection(Self, Self) -> Self?

The overlap of the two, or None when they do not meet.

intersects

pub fn Interval::intersects(Self, Self) -> Bool

Whether the two intervals share at least one point.

is_empty

pub fn Interval::is_empty(Self) -> Bool

Whether the interval holds no numbers: min above max.

is_finite

pub fn Interval::is_finite(Self) -> Bool

Whether both ends are finite.

new

pub fn Interval::new(Float, Float) -> Self

The interval from min to max; the two are not reordered, so passing them the other way round gives the empty interval.

size

pub fn Interval::size(Self) -> Float

The distance from min to max, or zero for the empty interval.

union

pub fn Interval::union(Self, Self) -> Self

The smallest interval holding both; the empty interval is the identity.

Trianglestruct

pub(all) struct Triangle

A triangle in space: three corners in winding order.

The winding decides which side the normal faces, by the right-hand rule.

Values are immutable.

Fields
a : Vec3

The first corner.

b : Vec3

The second corner.

c : Vec3

The third corner.

CarriesDebug, Show

approx

pub fn Triangle::approx(Self, Self, eps? : Float) -> Bool

Whether the two triangles have the same corners to within eps.

area

pub fn Triangle::area(Self) -> Float

The area.

barycentric

pub fn Triangle::barycentric(Self, Vec3) -> Vec3?

The barycentric coordinates of a point with respect to the triangle.

The three weights sum to one, and a point inside has all three in 0..1. The point is projected onto the triangle's plane first, so a point off the plane still has coordinates — they are those of the closest point on the plane. None when the triangle has no area to weight against.

intersect_ray

pub fn Triangle::intersect_ray(Self, Ray3) -> Float?

Where the ray meets the triangle, as a t, or None when it misses.

The same test as Ray3::intersect_triangle, written from this side for code that already has the triangle.

new

pub fn Triangle::new(Vec3, Vec3, Vec3) -> Self

The triangle with the three given corners.

normal

pub fn Triangle::normal(Self) -> Vec3

The unit normal, facing the way the corners wind.

A triangle with no area — three collinear points — has no normal, and comes back as the zero vector rather than a NaN.

Frustumstruct

pub struct Frustum

The six planes bounding what a camera can see, each facing inwards.

A view-projection matrix describes the visible volume as a set of inequalities in clip space; each of the six becomes one plane in world space, and culling is then a signed distance per plane per object. That is the cheapest test that still rejects most of a scene, which is why it is the one every renderer starts with.

The planes are built for a matrix whose depth range is 0..1. For an OpenGL-style matrix, whose near plane sits at -1, use from_matrix_gl.

Fields
planes : FixedArray[Plane]

The six planes, in the order left, right, bottom, top, near, far.

CarriesDebug, Eq, Show

approx

pub fn Frustum::approx(Self, Self, eps? : Float) -> Bool

Whether two frusta have the same six planes to within eps.

contains_aabb

pub fn Frustum::contains_aabb(Self, Aabb3) -> Bool

Whether the box lies entirely inside the frustum.

The corner furthest from each plane — the one the normal points away from — decides: if even that corner is inside, all eight are.

contains_point

pub fn Frustum::contains_point(Self, Vec3) -> Bool

Whether the point is inside all six planes, boundary included.

contains_sphere

pub fn Frustum::contains_sphere(Self, Sphere) -> Bool

Whether the sphere lies entirely inside the frustum.

from_matrix

pub fn Frustum::from_matrix(Mat4) -> Self?

The frustum of a view-projection matrix whose depth range is 0..1, or None when the matrix does not describe one.

The six planes are the six clip-space inequalities pulled back into world space: the left plane is the row w + x of the matrix, and so on. A matrix that is singular or degenerate — a projection with no near plane, say — gives a plane with no normal, and there is no frustum to return.

mbt check
test {
let projection = @moonmath.Mat4::perspective(
@moonmath.half_pi, 1.0, 0.1, 100.0,
)
let frustum = @moonmath.Frustum::from_matrix(projection).unwrap()
// A point just in front of the camera is inside, one behind it is not.
assert_true(frustum.contains_point(@moonmath.Vec3::new(0.0, 0.0, -1.0)))
assert_false(frustum.contains_point(@moonmath.Vec3::new(0.0, 0.0, 1.0)))
}

from_matrix_gl

pub fn Frustum::from_matrix_gl(Mat4) -> Self?

The frustum of a view-projection matrix whose depth range is -1..1.

intersects_aabb

pub fn Frustum::intersects_aabb(Self, Aabb3) -> Bool

Whether the frustum overlaps any part of the box.

The opposite corner from contains_aabb, for the opposite question: a box is out only when it lies wholly behind one plane.

intersects_line

pub fn Frustum::intersects_line(Self, Line3) -> Bool

Whether the infinite line meets the frustum at all.

Each of the six planes is a linear inequality in the line's parameter, so the part of the line inside the frustum is the intersection of six half-lines: one interval. The line meets the frustum exactly when that interval is not empty, which is the honest test an infinite line needs — unlike a ray, it has no start that could already be outside one plane while inside another.

intersects_sphere

pub fn Frustum::intersects_sphere(Self, Sphere) -> Bool

Whether the frustum overlaps any part of the sphere.

plane

pub fn Frustum::plane(Self, Int32) -> Plane

The plane at index, counted from zero in the order left, right, bottom, top, near, far.

planes

pub fn Frustum::planes(Self) -> FixedArray[Plane]

The planes of the frustum, in the order left, right, bottom, top, near, far.

A copy: the array the frustum holds cannot be reached from outside, so a caller cannot break the six-plane invariant by writing into it.

Colour

2

Red, green, blue and alpha, and the hue-saturation-value form of the same.

Color3struct

pub(all) struct Color3

A colour with three components, red, green and blue, and no alpha.

The components are plain numbers: this library does the arithmetic — adding a light, blending two values, lerping a gradient — and leaves the encoding to the caller, who knows whether the numbers are linear or sRGB and whether they are in 0..1 or 0..255. The HSV conversion is rgb_to_hsv, with the hue in turns and the other two in 0..1.

Values are immutable, and the operators work component by component.

Fields
r : Float

The red component.

g : Float

The green component.

b : Float

The blue component.

CarriesAdd, Debug, Div, Mul, Neg, Show, Sub

approx

pub fn Color3::approx(Self, Self, eps? : Float) -> Bool

Whether the two colours agree to within eps component by component.

clamp

pub fn Color3::clamp(Self, Self, Self) -> Self

The colour with every component pinned between low and high.

is_finite

pub fn Color3::is_finite(Self) -> Bool

Whether every component is finite.

lerp

pub fn Color3::lerp(Self, Self, Float) -> Self

The colour a fraction of the way from self to other.

max

pub fn Color3::max(Self, Self) -> Self

The component-wise larger of the two.

min

pub fn Color3::min(Self, Self) -> Self

The component-wise smaller of the two.

new

pub fn Color3::new(Float, Float, Float) -> Self

The colour from its three components.

one

pub fn Color3::one() -> Self

White: the most of every component.

splat

pub fn Color3::splat(Float) -> Self

The colour with the same value in all three components: a grey.

to_array

pub fn Color3::to_array(Self) -> FixedArray[Float]

The three components in order, [r, g, b], for a buffer.

zero

pub fn Color3::zero() -> Self

Black: no light at all.

Color4struct

pub(all) struct Color4

A colour with alpha: the three components of Color3 and an opacity.

The arithmetic is the same as Color3, with the fourth component carried along, so an alpha-premultiplied or straight-alpha pipeline can blend with the operators and decide the policy itself.

Values are immutable.

Fields
r : Float

The red component.

g : Float

The green component.

b : Float

The blue component.

a : Float

The opacity: one is opaque, zero is invisible.

CarriesAdd, Debug, Div, Mul, Neg, Show, Sub

approx

pub fn Color4::approx(Self, Self, eps? : Float) -> Bool

Whether the two colours agree to within eps component by component.

from_color3

pub fn Color4::from_color3(Color3, Float) -> Self

The colour of rgb at the opacity a.

is_finite

pub fn Color4::is_finite(Self) -> Bool

Whether every component is finite.

lerp

pub fn Color4::lerp(Self, Self, Float) -> Self

The colour a fraction of the way from self to other.

max

pub fn Color4::max(Self, Self) -> Self

The component-wise larger of the two.

min

pub fn Color4::min(Self, Self) -> Self

The component-wise smaller of the two.

new

pub fn Color4::new(Float, Float, Float, Float) -> Self

The colour from its four components.

splat

pub fn Color4::splat(Float) -> Self

The colour with the same value in every component.

to_array

pub fn Color4::to_array(Self) -> FixedArray[Float]

The four components in order, [r, g, b, a], for a buffer.

to_color3

pub fn Color4::to_color3(Self) -> Color3

The three colour components, dropping the alpha.

moonmath/f64

the same, at Double

The same shapes as the parent package, in double precision. Every type, method and value above appears here under the same name and with the same meaning, with Float replaced by Double; the two packages are expanded from one template. The integer vectors are absent, because they count pixels. What follows is the index of names, not a second copy of the sentences.

Values

approxapprox_angleclamp01default_epsilonhalf_pihsv_to_rgbinverse_lerplerppiquarter_piremaprgb_to_hsvsmoothsteptauto_degreesto_radianswrapwrap_range

Vectors

Vec2struct

absangle_betweenapproxceilclampclamp_lengthcrossdistancedistance_squareddividedotfloorfractis_finitelengthlength_squaredlerpmaxmax_elementmidpointminmin_elementmove_towardsnewnormalizenormalize_oroneperpprojectreflectrefractrejectroundscalesplatto_arrayto_vec3to_vec4try_normalizeunit_xunit_ywith_xwith_yyxzero

Vec3struct

absangle_betweenany_orthonormal_pairany_orthonormal_vectorapproxceilclampclamp_lengthcrossdistancedistance_squareddividedotfloorfractis_finitelengthlength_squaredlerpmaxmax_elementmidpointminmin_elementmove_towardsnewnormalizenormalize_oroneprojectrandom_in_ballrandom_on_spherereflectrefractrejectrotate_axisrotate_xrotate_yrotate_zroundscaleslerpsplatto_arrayto_vec4try_normalizeunit_xunit_yunit_zwith_xwith_ywith_zxyxzxzyyxzyzyzxzerozxyzyx

Vec4struct

absapproxceilclampclamp_lengthdistancedistance_squareddividedotfloorfractis_finitelengthlength_squaredlerpmaxmax_elementminmin_elementmove_towardsnewnormalizenormalize_oroneroundscalesplatto_arraytry_normalizeunit_wunit_xunit_yunit_zwith_wwith_xwith_ywith_zwzyxxyxyzzero

Matrices

Mat2struct

approxcoldeterminantfrom_anglefrom_arrayfrom_colsfrom_rowsfrom_scalegetidentityinverseis_finitemul_vec2rowto_angleto_arraytransposezero

Mat3struct

approxcoldeterminantfrom_arrayfrom_axis_anglefrom_colsfrom_eulerfrom_euler_turnsfrom_mat4from_quatfrom_rowsfrom_scalegetidentityinverseis_finitemul_vec3rowto_arraytransposezero

Mat4struct

approxcoldeterminantfrom_arrayfrom_axis_anglefrom_colsfrom_eulerfrom_euler_turnsfrom_mat3from_quatfrom_rowsfrom_scalefrom_translationfrom_trsfrustumfrustum_glgetidentityinverseis_finitelook_atmul_vec4orthographicorthographic_glperspectiveperspective_glperspective_infiniteperspective_infinite_glrowto_arrayto_trstransform_pointtransform_vectortransposezero

Shearstruct

approxis_finitenewto_mat3to_mat4zero

Rotation

Quatstruct

approxconjugatedotfrom_axis_anglefrom_eulerfrom_euler_turnsfrom_mat3from_mat4from_rotation_arcidentityinverseis_finitelengthlength_squarednewnlerpnormalizerandomrotateslerpto_arrayto_axis_angleto_eulerto_euler_turnsto_mat3to_mat4

EulerOrderenum

Turnsstruct

approxnew

Placement

Trsstruct

new

Affine2struct

approxfrom_anglefrom_angle_translationfrom_mat3from_scalefrom_translationidentityinverseis_finitenewto_mat3transform_pointtransform_vector

Affine3struct

approxfrom_axis_anglefrom_mat4from_rotationfrom_scalefrom_translationfrom_trsidentityinverseis_finitenewto_mat4to_trstransform_pointtransform_vector

DualQuatstruct

approxdotfrom_mat4from_rotation_translationidentityinverseis_finitenewnormalizerotationscaleslerpto_arrayto_mat4transform_pointtransform_vectortranslation

Geometry

Rectstruct

approxareacentercontainscornersfrom_edgesfrom_xywhheightinsetintersectionintersectsis_emptymaxminnewto_aabbtranslateunionwidth

Aabb2struct

approxareacentercontainscontains_pointcornersemptyexpandextentsfrom_center_half_extentsfrom_pointsintersectionintersectsis_emptynewsizeto_rectunion

Aabb3struct

approxcentercontainscontains_pointcornersemptyexpandextentsfrom_center_half_extentsfrom_pointsintersectionintersectsis_emptynewrandom_pointsizesurface_areatransformunionvolume

Ray2struct

approxatintersect_aabbintersect_aabb_intervalintersect_circleintersect_rectnew

Ray3struct

approxatintersect_aabbintersect_aabb_intervalintersect_planeintersect_sphereintersect_trianglenew

Planestruct

approxflipfrom_point_normalfrom_pointsintersect_rayis_finitenewprojectsigned_distance

Spherestruct

approxcontains_pointintersects_aabbintersects_spherenewrandom_insiderandom_on_surfacesurface_areavolume

Line3struct

approxatclosest_point_toclosest_point_to_linedistance_to_linedistance_to_pointintersect_planeis_finitenew

Intervalstruct

approxcentercontainsemptyexpandextend_byintersectionintersectsis_emptyis_finitenewsizeunion

Trianglestruct

approxareabarycentricintersect_raynewnormal

Frustumstruct

approxcontains_aabbcontains_pointcontains_spherefrom_matrixfrom_matrix_glintersects_aabbintersects_lineintersects_sphereplaneplanes

Colour

Color3struct

approxclampis_finitelerpmaxminnewonesplatto_arrayzero

Color4struct

approxfrom_color3is_finitelerpmaxminnewsplatto_arrayto_color3

Special functions

33

Special functions at double precision: the gamma and error families, the Bessel functions, the elliptic integrals, the hypergeometric functions and the Riemann zeta.

bessel_ifunction

pub fn bessel_i(Double, Double) -> Double

The modified Bessel function of the first kind I_v(x), for x > 0.

It grows like e^x, so a large argument runs past the largest finite double.

bessel_jfunction

pub fn bessel_j(Double, Double) -> Double

The Bessel function of the first kind J_v(x), for x > 0 and real v.

bessel_kfunction

pub fn bessel_k(Double, Double) -> Double

The modified Bessel function of the second kind K_v(x), for x > 0.

It decays like e^-x: bessel_k(0, 40) is about 8.4e-19, and the tail keeps falling from there.

bessel_yfunction

pub fn bessel_y(Double, Double) -> Double

The Bessel function of the second kind Y_v(x), for x > 0 and real v.

betafunction

pub fn beta(Double, Double) -> Double

The Euler beta function B(a, b) = Γ(a) Γ(b) / Γ(a + b), for positive arguments.

It is the normalising constant of the beta distribution and the value of the integral ∫ t^(a-1) (1-t)^(b-1) dt over 0..1.

digammafunction

pub fn digamma(Double) -> Double

The digamma ψ(x) = d/dx ln Γ(x), the logarithmic derivative of the gamma function.

ellipefunction

pub fn ellipe(Double) -> Double

The complete elliptic integral of the second kind E(m).

ellipeincfunction

pub fn ellipeinc(Double, Double) -> Double

The incomplete elliptic integral of the second kind E(phi, m) = ∫_0^phi sqrt(1 - m sin²θ) dθ.

ellipkfunction

pub fn ellipk(Double) -> Double

The complete elliptic integral of the first kind K(m), with m the parameter.

ellipkincfunction

pub fn ellipkinc(Double, Double) -> Double

The incomplete elliptic integral of the first kind F(phi, m) = ∫_0^phi dθ / sqrt(1 - m sin²θ).

ellipkm1function

pub fn ellipkm1(Double) -> Double

The complete elliptic integral of the first kind from the complementary parameter, K(1 - m).

elliprcfunction

pub fn elliprc(Double, Double) -> Double

The Carlson symmetric integral of the third kind, degenerate form R_C(x, y) = R_F(x, y, y).

elliprdfunction

pub fn elliprd(Double, Double, Double) -> Double

The Carlson symmetric integral of the second kind R_D(x, y, z).

elliprffunction

pub fn elliprf(Double, Double, Double) -> Double

The Carlson symmetric integral of the first kind R_F(x, y, z).

elliprgfunction

pub fn elliprg(Double, Double, Double) -> Double

The Carlson symmetric integral of the second kind, completely symmetric form R_G(x, y, z).

elliprjfunction

pub fn elliprj(Double, Double, Double, Double) -> Double

The Carlson symmetric integral of the third kind R_J(x, y, z, p).

It is the form the incomplete elliptic integral of the third kind is written in: a caller with a potential 1/(t + p) under the same square root.

erffunction

pub fn erf(Double) -> Double

The error function erf(x) = (2/sqrt π) ∫_0^x e^(-t²) dt.

erfcfunction

pub fn erfc(Double) -> Double

The complementary error function erfc(x) = 1 - erf(x).

It is the one to call in the tail, where 1 - erf(x) would lose every digit the result has.

erfcinvfunction

pub fn erfcinv(Double) -> Double

The inverse of the complementary error function: the y with erfc(y) = x, for x in 0 .. 2.

erfcxfunction

pub fn erfcx(Double) -> Double

The scaled complementary error function erfcx(x) = e^(x²) erfc(x), which stays representable where erfc itself has long underflowed.

erfifunction

pub fn erfi(Double) -> Double

The imaginary error function erfi(x) = -i erf(i x).

erfinvfunction

pub fn erfinv(Double) -> Double

The inverse of the error function: the y with erf(y) = x, for x in -1 .. 1.

gammafunction

pub fn gamma(Double) -> Double

The gamma function Γ(x), the continuous extension of the factorial.

Γ(n) = (n - 1)! for a positive integer, and the function is the integral ∫ t^(x-1) e^(-t) dt for x > 0. The whole real line is covered by the Stirling expansion plus the reflection Γ(x) Γ(1 - x) = π / sin(π x). A pole at a non-positive integer comes back as an infinity, as it should.

gammaincfunction

pub fn gammainc(Double, Double) -> Double

The regularised lower incomplete gamma P(a, x) = γ(a, x) / Γ(a), the cumulative distribution of the gamma distribution with unit rate.

gammainccfunction

pub fn gammaincc(Double, Double) -> Double

The regularised upper incomplete gamma Q(a, x) = Γ(a, x) / Γ(a) = 1 - P(a, x).

hyper0f1function

pub fn hyper0f1(Double, Double) -> Double

The confluent limit 0F1(; b; x) = Σ x^k / ((b)_k k!).

Its terms are all positive for b > 0 and x > 0, so it does not cancel and is summed directly.

hyper1f1function

pub fn hyper1f1(Double, Double, Double) -> Double

Kummer's confluent hypergeometric 1F1(a; b; x) = Σ (a)_k / ((b)_k k!) x^k.

The series is summed directly, with Kummer's transformation e^x 1F1(b - a; b; -x) past x = -4. Past the point where the series's terms run beyond what any width this package will pay for holds — the large-parameter region, where a numerator of a few hundred thousand cancels a denominator of a million — the routing in special/generic picks a method for the point instead: Luke's rational continued fraction, the A&S 13.3.6 uniform expansion, the large-argument asymptotic, or the sum at the argument where the numerator is small enough for it to settle in a handful of terms. Where the terms still run a thousandfold past the result the sum is redone at a width that holds the digits the cancellation took.

hyper2f1function

pub fn hyper2f1(Double, Double, Double, Double) -> Double

The Gauss hypergeometric 2F1(a, b; c; x), for |x| < 1.

Past a half the argument is moved to 1 - x by the linear transformation, and a negative argument takes Pfaff's; the body in special/generic says which and why. When c - a - b is an integer that transformation has a logarithm in it instead of two powers, and the degenerate path answers the case by a limit of the connection formula rather than the two-power form. Both halves of the transformation are formed as logarithms of gamma factors, because with parameters of order a hundred a single factor is past 10^370 while the ratio of two of them is not.

The two halves also cancel, and by more than a double can spare: against Boost's own table, which lies wholly in this region, the worst row loses twenty-three digits. Those rows are re-run wider, which is what makes the table pass at 1e-12.

incbetafunction

pub fn incbeta(Double, Double, Double) -> Double

The regularised incomplete beta I_x(a, b), the cumulative distribution of the beta distribution.

lbetafunction

pub fn lbeta(Double, Double) -> Double

The natural logarithm of the beta function.

The log form stays finite where beta itself would overflow or underflow.

lgammafunction

pub fn lgamma(Double) -> Double

The natural logarithm of the absolute value of the gamma function.

The log form is what a caller wants when Γ(x) itself would overflow a double: lgamma(1000) is about 5905, while gamma(1000) is past the largest finite double.

polygammafunction

pub fn polygamma(Int32, Double) -> Double

The polygamma ψ^(n)(x), the n-th derivative of the digamma.

n = 0 is the digamma itself; n = 1 the trigamma and n = 2 the tetragamma, the names a caller meets when a sum over 1/(k + x)^(n+1) has to be closed.

zetafunction

pub fn zeta(Double) -> Double

The Riemann zeta function ζ(s).

ζ(s) = Σ n^(-s) for s > 1, by Euler-Maclaurin. Below one the analytic continuation fills in through the functional equation, so a negative argument answers as well; the trivial zeros at the negative even integers come back as exactly zero. The simple pole at s = 1 is a positive infinity.

Special functions, over an algebra

40

The special-function algorithms once, over an explicit Ops[T] algebra, so the same body serves Double and moonnum's arbitrary-precision BigFloat. The record is the seam: adding a number type means writing one Ops value, and every algorithm written against it follows.

bessel_ifunction

pub fn[T] bessel_i(T, T, Ops[T]) -> T

The modified Bessel function of the first kind I_v(x), for x > 0.

The series is the same one as J_v without the alternating sign, so it never cancels and is used everywhere; the exponential in it is what eventually runs past what the width holds.

bessel_jfunction

pub fn[T] bessel_j(T, T, Ops[T]) -> T

The Bessel function of the first kind J_v(x), for x > 0 and v >= 0.

J_v(x) = Σ (-1)^k (x/2)^(2k+v) / (k! Γ(k + v + 1)). The series is used while x is near the order, where it converges before its alternating terms have grown far past the result; past that the asymptotic expansion takes over, and its terms are summed until they begin to grow.

bessel_kfunction

pub fn[T] bessel_k(T, T, Ops[T]) -> T

The modified Bessel function of the second kind K_v(x), for x > 0.

For an integer order it is the limit of (π/2)(I_-v - I_v)/sin vπ, written out as K_n(x) = (1/2)(x/2)^(-n) Σ_(k<n) (n-k-1)!/k! (-x²/4)^k + (-1)^(n+1) ln(x/2) I_n(x) + (-1)^n (1/2)(x/2)^n Σ_k (ψ(k+1) + ψ(n+k+1)) / (k! (n+k)!) (x²/4)^k.

bessel_yfunction

pub fn[T] bessel_y(T, T, Ops[T]) -> T

The Bessel function of the second kind Y_v(x), for x > 0 and v >= 0.

For an integer order this is the limit of (J_v cos vπ - J_-v) / sin vπ, written out as the logarithm series `Y_n(x) = -(1/π) Σ_(k<n) (n-k-1)!/k! (x/2)^(2k-n) + (2/π) ln(x/2) J_n(x)

  • (1/π)(x/2)^n Σ_k (ψ(k+1) + ψ(n+k+1)) / (k! (n+k)!) (-x²/4)^k`,

which is finite where the limit form is 0/0.

betafunction

pub fn[T] beta(T, T, Ops[T]) -> T

B(a, b) = Γ(a) Γ(b) / Γ(a + b).

bigfloat_opsfunction

pub fn bigfloat_ops(Int32) -> Ops[@moonnum.BigFloat]

The algebra of a BigFloat at digits decimal digits.

The binary operations are the context-taking forms rather than the operators: an operator takes the wider of its two operands and rounds to that, so a value formed at the working width and a constant that carries one extra bit would settle at the wider of the two instead of the width the run asks for. Naming the context on every operation pins the answer to it.

digammafunction

pub fn[T] digamma(T, Ops[T]) -> T

The digamma ψ(x) = d/dx ln Γ(x).

The reflection ψ(1 - x) - ψ(x) = π cot(π x) reaches the half-line below one half; above it the recurrence ψ(x) = ψ(x + 1) - 1/x raises the argument to the asymptotic expansion ln z - 1/(2z) - Σ B_2k / (2k z^(2k)).

digits_to_precisionfunction

pub fn digits_to_precision(Int32) -> Int32

The significand width, in bits, a working precision of digits decimal digits needs.

A decimal digit is log2 10 of a binary bit, and the little slack on top keeps the decimal-digit reading and the binary width from parting company in the last place: a width of exactly digits log2 10 bits rounds the hundredth decimal digit the wrong way now and then, and one that carries a fraction of a digit more does not.

double_algebravalue

pub let double_algebra : Ops[Double]

The Double algebra, built once so that every double-precision entry point shares one record instead of rebuilding it per call.

double_opsfunction

pub fn double_ops() -> Ops[Double]

The algebra of Double.

ellipefunction

pub fn[T] ellipe(T, Ops[T]) -> T

The complete elliptic integral of the second kind, E(m).

E(m) = R_F(0, 1 - m, 1) - (m/3) R_D(0, 1 - m, 1).

ellipeincfunction

pub fn[T] ellipeinc(T, T, Ops[T]) -> T

The incomplete elliptic integral of the second kind, E(phi, m) = ∫_0^phi sqrt(1 - m sin²θ) dθ.

E = sin(phi) R_F(cos²phi, 1 - m sin²phi, 1) - (m/3) sin³(phi) R_D(...).

ellipkfunction

pub fn[T] ellipk(T, Ops[T]) -> T

The complete elliptic integral of the first kind, K(m), with m the parameter (m = k²).

K(m) = R_F(0, 1 - m, 1).

ellipkincfunction

pub fn[T] ellipkinc(T, T, Ops[T]) -> T

The incomplete elliptic integral of the first kind, F(phi, m) = ∫_0^phi dθ / sqrt(1 - m sin²θ).

F = sin(phi) R_F(cos²phi, 1 - m sin²phi, 1).

ellipkm1function

pub fn[T] ellipkm1(T, Ops[T]) -> T

The complete elliptic integral of the first kind from the complementary parameter, K(1 - m1). The form a caller reaches for when m is a hair below one, where K(m) itself would be given to the subtraction as garbage.

elliprcfunction

pub fn[T] elliprc(T, T, Ops[T]) -> T

The Carlson symmetric integral of the third kind, degenerate form, R_C(x, y) = 1/2 ∫_0^∞ dt / ((t+y) sqrt(t+x)).

It is R_F(x, y, y) — the third kind with two equal arguments — so it needs no algorithm of its own.

elliprdfunction

pub fn[T] elliprd(T, T, T, Ops[T]) -> T

The Carlson symmetric integral of the second kind, R_D(x, y, z) = 3/2 ∫_0^∞ dt / ((t+z) sqrt((t+x)(t+y)(t+z))).

elliprffunction

pub fn[T] elliprf(T, T, T, Ops[T]) -> T

The Carlson symmetric integral of the first kind, R_F(x, y, z) = 1/2 ∫_0^∞ dt / sqrt((t+x)(t+y)(t+z)).

The duplication step replaces the three arguments by combinations that are closer together, and the differences shrink by four each round, so the series that finishes the job only has to be right to sixth order.

elliprgfunction

pub fn[T] elliprg(T, T, T, Ops[T]) -> T

The Carlson symmetric integral of the second kind, completely symmetric form, R_G(x, y, z) = 1/4 ∫_0^∞ dt / sqrt((t+x)(t+y)(t+z)) · (x/(t+x) + y/(t+y) + z/(t+z)).

It follows from R_F and R_D by 2 R_G = z R_F - (x - z)(y - z) R_D / 3 + sqrt(x y / z), which is one call to each of the two forms above.

elliprjfunction

pub fn[T] elliprj(T, T, T, T, Ops[T]) -> T

The Carlson symmetric integral of the third kind, R_J(x, y, z, p) = 3/2 ∫_0^∞ dt / ((t+p) sqrt((t+x)(t+y)(t+z))).

The same duplication as R_D, with one more argument carried along: the term the step contributes is a degenerate third-kind integral R_C, of the pair (p(sx+sy+sz) + sx sy sz) squared and p (p + lambda) squared. It is the form the incomplete elliptic integral of the third kind is written in, and the one no Legendre integral in this package needs — it is here because a caller with a potential of their own does.

erffunction

pub fn[T] erf(T, Ops[T]) -> T

The error function erf(x) = (2/sqrt π) ∫_0^x e^(-t²) dt.

Below one the power series converges without cancellation. Past it the tail is the better-behaved quantity, so erf(x) = 1 - erfc(x) is used and the digits come from the continued fraction rather than from subtracting two numbers that are both nearly one.

erfcfunction

pub fn[T] erfc(T, Ops[T]) -> T

The complementary error function erfc(x) = 1 - erf(x).

erfcinvfunction

pub fn[T] erfcinv(T, Ops[T]) -> T

The inverse of erfc: the y with erfc(y) = x, for x in 0 .. 2.

erfcxfunction

pub fn[T] erfcx(T, Ops[T]) -> T

The scaled complementary error function erfcx(x) = e^(x²) erfc(x).

The exponential is what makes the tail representable: erfc(30) is around 1e-392, past what a double holds, while erfcx(30) is a perfectly ordinary 0.0188.

erfifunction

pub fn[T] erfi(T, Ops[T]) -> T

The imaginary error function erfi(x) = -i erf(i x) = (2/sqrt π) ∫_0^x e^(t²) dt.

Every term of its series is positive, so it needs no range split; it is the exponential that eventually runs past what the width holds.

erfinvfunction

pub fn[T] erfinv(T, Ops[T]) -> T

The inverse of erf: the y with erf(y) = x, for x in -1 .. 1.

There is no closed form, so the value is bracketed and then polished by Newton's method. The bracket doubles until it contains the answer, which costs nothing and keeps the method honest near the ends of the range, where the inverse runs off to infinity.

gammafunction

pub fn[T] gamma(T, Ops[T]) -> T

Γ(x), the continuous extension of the factorial.

Above one half it is exp(ln Γ(x)); below, the reflection is used instead, which keeps the sign of the result and avoids the cancellation that exponentiating a large negative logarithm would bring for x just below a pole.

gammaincfunction

pub fn[T] gammainc(T, T, Ops[T]) -> T

The regularised lower incomplete gamma P(a, x) = γ(a, x) / Γ(a).

The power series x^a e^-x Σ x^n / (a(a+1)…(a+n)) converges quickly while x is below a + 1; past that the continued fraction for the upper tail is the better one, and P = 1 - Q completes the range.

gammainccfunction

pub fn[T] gammaincc(T, T, Ops[T]) -> T

The regularised upper incomplete gamma Q(a, x), by the continued fraction of Legendre, evaluated with the modified Lentz algorithm.

hyper0f1function

pub fn[T] hyper0f1(T, T, Ops[T]) -> T

The confluent limit 0F1(; b; x) = Σ x^k / ((b)_k k!).

hyper1f1function

pub fn[T] hyper1f1(T, T, T, Ops[T]) -> T

Kummer's confluent hypergeometric 1F1(a; b; x) = Σ (a)_k / ((b)_k k!) x^k.

A large negative argument makes the series alternate with terms much larger than the result; Kummer's transformation 1F1(a; b; x) = e^x 1F1(b - a; b; -x) turns it into a positive argument, where every term adds.

hyper1f1_scaledfunction

pub fn[T] hyper1f1_scaled(T, T, T, Ops[T]) -> (T, T)

1F1 together with the largest term the sum formed.

The pair is what a caller needs to judge the answer: a sum whose terms ran past the result by 10^d kept width - d digits of it, and a caller with a wider type available can spend them. The double-precision face does exactly that — see special/hypergeom.mbt.

hyper1f1_uniformfunction

pub fn[T] hyper1f1_uniform(T, T, T, Ops[T]) -> (T, T)

The uniform dispatcher for the large-parameter region: the routing that chooses a method for a point, mirroring how the methods split the plane. It is reached only for parameters well past the ones the plain series answers (the caller gates it), and it falls back to the series — run at whatever width the caller gave it — for the points it has no method for yet, so a missing method degrades to the width's best effort rather than to a wrong answer.

hyper2f1function

pub fn[T] hyper2f1(T, T, T, T, Ops[T]) -> T

The Gauss hypergeometric 2F1(a, b; c; x) = Σ (a)_k (b)_k / ((c)_k k!) x^k, for |x| < 1.

Three representations cover the unit interval, and the argument decides which:

  • a negative one takes Pfaff's transformation

2F1(a,b;c;x) = (1-x)^(-a) 2F1(a,c-b;c;x/(x-1)), which halves it and leaves a positive one;

  • up to a half the series is summed where it stands, at a ratio no larger

than a half;

  • past a half the linear transformation around one is used,

2F1(a,b;c;x) = Γ(c)Γ(c-a-b)/(Γ(c-a)Γ(c-b)) 2F1(a,b;a+b-c+1;1-x) + (1-x)^(c-a-b) Γ(c)Γ(a+b-c)/(Γ(a)Γ(b)) 2F1(c-a,c-b;c-a-b+1;1-x), whose two series run on 1 - x.

Every scale is folded into the first term of the series it multiplies rather than applied afterwards. That is not a detail: with parameters of order a hundred a scale is 10^-60 while the terms of the series it multiplies reach 10^55, and a type that has to hold both at once needs a hundred and thirty digits before it can add them. Multiplying as the series runs keeps every partial sum at the size of the answer, and leaves only the cancellation the answer itself is made of.

hyper2f1_scaledfunction

pub fn[T] hyper2f1_scaled(T, T, T, T, Ops[T]) -> (T, T)

2F1 together with the largest magnitude any term of the run reached.

incbetafunction

pub fn[T] incbeta(T, T, T, Ops[T]) -> T

The regularised incomplete beta I_x(a, b).

The continued fraction is evaluated for whichever of x and 1 - x is the smaller, and the symmetry I_x(a, b) = 1 - I_(1-x)(b, a) supplies the rest, so the fraction always runs where it converges.

lbetafunction

pub fn[T] lbeta(T, T, Ops[T]) -> T

ln B(a, b), the logarithm of the Euler beta function.

lgammafunction

pub fn[T] lgamma(T, Ops[T]) -> T

ln Γ(x) for any real x, over Ops.

The Stirling expansion is asymptotic — its terms shrink, reach a minimum and then grow — so the argument is first raised to stirling_shift by the recurrence Γ(x) = Γ(x + 1) / x, and the logarithms the shift added are subtracted at the end. The reflection Γ(x) Γ(1 - x) = π / sin(π x) covers the half-line below one half. A pole at a non-positive integer is a division by zero and comes back as an infinity, as it should.

polygammafunction

pub fn[T] polygamma(Int32, T, Ops[T]) -> T

The polygamma ψ^(n)(x), the n-th derivative of the digamma.

n = 0 is the digamma itself. For n >= 1 the recurrence ψ^(n)(x) = ψ^(n)(x + 1) - (-1)^n n! / x^(n+1) raises the argument, and the expansion is the term-by-term derivative of the one digamma uses.

zetafunction

pub fn[T] zeta(T, Ops[T]) -> T

The Riemann zeta function ζ(s).

ζ(s) = Σ n^(-s) for s > 1, by Euler-Maclaurin: the sum to N, the integral N^(1-s)/(s-1), the half term, and the Bernoulli corrections. N and the number of corrections both grow with the working precision, because the correction series is asymptotic and has to be truncated where its terms stop shrinking.

Below one the same value is reached through ζ(s) = 2^s π^(s-1) sin(πs/2) Γ(1 - s) ζ(1 - s), which is the analytic continuation; the negative even integers are its trivial zeros.