Skip to main content

maths_rs/
lib.rs

1//! A linear algebra library for gamedev and graphics.
2//!
3//! # Conventions
4//!
5//! ## Angles
6//! All angles are in **radians** unless the function name explicitly states otherwise.
7//! The exceptions are [`focal_length_to_fov`] and [`fov_to_focal_length`], which
8//! work in degrees to match common camera/lens tooling conventions.
9//!
10//! ## Matrix Layout
11//! Matrices are stored in **row-major** order in memory. The element `m[row * cols + col]`
12//! accesses the element at a given row and column.
13//!
14//! ## Handedness
15//! The library does not enforce a single coordinate system handedness. Functions that
16//! depend on handedness — such as perspective projection — are provided in both variants
17//! and indicate their convention explicitly in the function name (e.g. `_lh_yup` for
18//! left-handed y-up, `_rh_yup` for right-handed y-up).
19
20/// base traits and operations for scalar numbers, signed numbers, integers and floats
21pub mod num;
22
23/// multi dimensional column vector with generic vec2, vec3 and vec4 implementations
24pub mod vec;
25
26/// multi dimensional row-major matrix with generic mat2, mat3, mat34 and mat4 implementations
27/// there is a mat43 type for mat34 transposes but it does not support the full functionality
28pub mod mat;
29
30/// generic quaternion for varying floating point precision
31pub mod quat;
32
33/// module containing vector swizzling traits
34pub mod swizz;
35
36use num::*;
37use vec::*;
38use mat::*;
39use quat::*;
40
41/// opinionated type abbreviations
42#[cfg(feature = "short_types")]
43pub type Vec2f = Vec2<f32>;
44
45#[cfg(feature = "short_types")]
46pub type Vec3f = Vec3<f32>;
47
48#[cfg(feature = "short_types")]
49pub type Vec4f = Vec4<f32>;
50
51#[cfg(feature = "short_types")]
52pub type Vec2d = Vec2<f64>;
53
54#[cfg(feature = "short_types")]
55pub type Vec3d = Vec3<f64>;
56
57#[cfg(feature = "short_types")]
58pub type Vec4d = Vec4<f64>;
59
60#[cfg(feature = "short_types")]
61pub type Vec2i = Vec2<i32>;
62
63#[cfg(feature = "short_types")]
64pub type Vec3i = Vec3<i32>;
65
66#[cfg(feature = "short_types")]
67pub type Vec4i = Vec4<i32>;
68
69#[cfg(feature = "short_types")]
70pub type Vec2u = Vec2<u32>;
71
72#[cfg(feature = "short_types")]
73pub type Vec3u = Vec3<u32>;
74
75#[cfg(feature = "short_types")]
76pub type Vec4u = Vec4<u32>;
77
78#[cfg(feature = "short_types")]
79pub type Mat2f = Mat2<f32>;
80
81#[cfg(feature = "short_types")]
82pub type Mat3f = Mat3<f32>;
83
84#[cfg(feature = "short_types")]
85pub type Mat34f = Mat34<f32>;
86
87#[cfg(feature = "short_types")]
88pub type Mat43f = Mat43<f32>;
89
90#[cfg(feature = "short_types")]
91pub type Mat4f = Mat4<f32>;
92
93#[cfg(feature = "short_types")]
94pub type Mat2d = Mat2<f64>;
95
96#[cfg(feature = "short_types")]
97pub type Mat3d = Mat3<f64>;
98
99#[cfg(feature = "short_types")]
100pub type Mat34d = Mat34<f64>;
101
102#[cfg(feature = "short_types")]
103pub type Mat43d = Mat43<f64>;
104
105#[cfg(feature = "short_types")]
106pub type Mat4d = Mat4<f64>;
107
108#[cfg(feature = "short_types")]
109pub type Quatf = Quat<f32>;
110
111#[cfg(feature = "short_types")]
112pub type Quatd = Quat<f64>;
113
114/// classification for tests vs planes (behind, infront or intersects)
115#[derive(PartialEq, Debug)]
116pub enum Classification {
117    /// behind the plane in the opposite direction of the planes normal
118    Behind,
119    /// infront of the plane in the direction of the planes normal
120    Infront,
121    /// intersecting the plane
122    Intersects,
123}
124
125/// returns the minimum of `a` and `b`
126pub fn min<T: Number, V: NumberOps<T>>(a: V, b: V) -> V {
127    V::min(a, b)
128}
129
130/// returns the maximum of `a` and `b`
131pub fn max<T: Number, V: NumberOps<T>>(a: V, b: V) -> V {
132    V::max(a, b)
133}
134
135/// returns the tuple (min, max) of the value `a` and `min_max` tuple (min, max)
136pub fn min_max<T: Number, V: NumberOps<T> + Copy>(a: V, min_max: (V, V)) -> (V, V) {
137    (V::min(a, min_max.0), V::max(a, min_max.1))
138}
139
140/// returns the value `x` clamped to the range of `min` and `max`
141pub fn clamp<T: Number, V: NumberOps<T>>(x: V, min: V, max: V) -> V {
142    V::clamp(x, min, max)
143}
144
145/// returns 1 if `a > b` or 0 otherwise
146pub fn step<T: Number, V: NumberOps<T>>(a: V, b: V) -> V {
147    V::step(a, b)
148}
149
150/// returns -1 if value `a` is negative, 1 if positive and 0 if zero (integers)
151pub fn signum<T: SignedNumber, V: SignedNumberOps<T>>(a: V) -> V {
152    V::signum(a)
153}
154
155/// returns the value `a` with the same sign as second parameter `sign`
156pub fn copysign<T: Float, V: FloatOps<T>>(a: V, sign: T) -> V {
157    V::copysign(a, sign)
158}
159
160/// returns the absolute (positive) value of `a`
161pub fn abs<T: SignedNumber, V: SignedNumberOps<T>>(a: V) -> V {
162    V::abs(a)
163}
164
165/// returns the radian value converted from value `a` which is specified in degrees
166pub fn deg_to_rad<T: Float, V: FloatOps<T>>(a: V) -> V {
167    V::deg_to_rad(a)
168}
169
170/// returns the degree value converted from value `a` which is specified in radians
171pub fn rad_to_deg<T: Float, V: FloatOps<T>>(a: V) -> V {
172    V::rad_to_deg(a)
173}
174
175/// returns the floored value of `a` (round down to nearest integer)
176pub fn floor<T: Float, V: FloatOps<T>>(a: V) -> V {
177    V::floor(a)
178}
179
180/// returns the ceil'd value of `a` (round up to nearest integer)
181pub fn ceil<T: Float, V: FloatOps<T>>(a: V) -> V {
182    V::ceil(a)
183}
184
185/// returns the value `a` rounded to closest integer floor if `a < 0.5` or ceil if `a >= 0.5`
186pub fn round<T: Float, V: FloatOps<T>>(a: V) -> V {
187    V::round(a)
188}
189
190/// returns true if value `a` is approximately equal to value `b` within the specified epsilon `eps`
191pub fn approx<T: Float, V: FloatOps<T>>(a: V, b: V, eps: T) -> bool {
192    V::approx(a, b, eps)
193}
194
195/// returns the square root of value `a`
196pub fn sqrt<T: Float, V: FloatOps<T>>(a: V) -> V {
197    V::sqrt(a)
198}
199
200/// returns value `a` raised to the integer power of value `b`
201pub fn powi<T: Float, V: FloatOps<T>>(a: V, b: i32) -> V {
202    V::powi(a, b)
203}
204
205/// returns value `a` squared (raised to the power 2)
206pub fn sqr<T: Float, V: FloatOps<T> + Base<T>>(a: V) -> V {
207    a * a
208}
209
210/// returns value `a` cubed (raised to the power 3)
211pub fn cube<T: Float, V: FloatOps<T> + Base<T>>(a: V) -> V {
212    a * a * a
213}
214
215/// returns value `a` raised to the floating point power of value `b`
216pub fn powf<T: Float, V: FloatOps<T>>(a: V, b: T) -> V {
217    V::powf(a, b)
218}
219
220/// returns fused multiply add `m * a + b`
221pub fn mad<T: Float, V: FloatOps<T>>(m: V, a: V, b: V) -> V {
222    V::mad(m, a, b)
223}
224
225/// returns the floating point remainder of `a / b`
226pub fn fmod<T: Float, V: FloatOps<T>>(a: V, b: V) -> V {
227    V::fmod(a, b)
228}
229
230/// returns the fractional part of value `a`
231pub fn frac<T: Float, V: FloatOps<T>>(a: V) -> V {
232    V::frac(a)
233}
234
235/// truncates value `a` - removing the fractional part, truncating to an integer
236pub fn trunc<T: Float, V: FloatOps<T>>(a: V) -> V {
237    V::trunc(a)
238}
239
240/// returns the reciprocal square root of value `a`
241pub fn rsqrt<T: Float, V: FloatOps<T>>(a: V) -> V {
242    V::rsqrt(a)
243}
244
245/// returns the reciprocal of value `a`
246pub fn recip<T: Float, V: FloatOps<T>>(a: V) -> V {
247    V::recip(a)
248}
249
250/// returns the value `v` broken down into a tuple (fractional, integer) parts
251pub fn modf<T: Float, V: FloatOps<T>>(v: V) -> (V, V) {
252    V::modf(v)
253}
254
255/// returns a value interpolated between edges `e0` and `e1` by percentage `t`
256pub fn lerp<T: Float, V: Lerp<T>>(e0: V, e1: V, t: T) -> V {
257    V::lerp(e0, e1, t)
258}
259
260/// returns a value interpolated between edges `e0` and `e1` by percentage `t` with the result being normalised
261pub fn nlerp<T: Float, V: Nlerp<T>>(e0: V, e1: V, t: T) -> V {
262    V::nlerp(e0, e1, t)
263}
264
265/// returns a value spherically interpolated between edges `e0` and `e1` by percentage `t`
266pub fn slerp<T: Float + NumberOps<T> + FloatOps<T>, V: Slerp<T>>(e0: V, e1: V, t: T) -> V {
267    V::slerp(e0, e1, t)
268}
269
270/// returns the hermite interpolated value between edge `e0` and `e1` by percentage `t`
271pub fn smoothstep<T: Float, V: FloatOps<T>>(e0: V, e1: V, t: T) -> V {
272    V::smoothstep(e0, e1, t)
273}
274
275/// returns the saturated value of `x` into to the 0-1 range, this is the same as `clamp(x, 0.0, 1.0)`
276pub fn saturate<T: Float, V: FloatOps<T>>(x: V) -> V {
277    V::saturate(x)
278}
279
280/// returns the vector cross product of `a x b`, makes sense only for 3 or 7 dimensional vectors
281pub fn cross<T: Number, V: Cross<T>>(a: V, b: V) -> V {
282    V::cross(a, b)
283}
284
285/// returns the scalar triple product of `a x b x c`, makes sense only for 3 dimensional vectors
286pub fn scalar_triple<T: Number + SignedNumber, V: Triple<T>>(a: V, b: V, c: V) -> T {
287    V::scalar_triple(a, b, c)
288}
289
290/// returns the vector triple product of `a x b x c`, mainly used for 3D vectors, but with a 2D specialisation leveraging z-up
291pub fn vector_triple<T: Number + SignedNumber, V: Triple<T>>(a: V, b: V, c: V) -> V {
292    V::vector_triple(a, b, c)
293}
294
295/// returns the perpendicular vector of `a` performing anti-clockwise rotation by 90 degrees
296pub fn perp<T: SignedNumber>(a: Vec2<T>) -> Vec2<T> {
297    Vec2 {
298        x: -a.y,
299        y: a.x
300    }
301}
302
303/// returns the vector dot product between `a . b`
304pub fn dot<T: Number, V: Dot<T>>(a: V, b: V) -> T {
305    V::dot(a, b)
306}
307
308/// returns the scalar magnitude or length of vector `a`
309pub fn length<T: Float, V: Magnitude<T>>(a: V) -> T {
310    V::length(a)
311}
312
313/// returns the scalar magnitude or length of vector `a`
314pub fn mag<T: Float, V: Magnitude<T>>(a: V) -> T {
315    V::mag(a)
316}
317
318/// returns the scalar magnitude or length of vector `a` squared to avoid using sqrt
319pub fn mag2<T: Float, V: Magnitude<T>>(a: V) -> T {
320    V::mag2(a)
321}
322
323/// returns a normalized unit vector of `a`
324pub fn normalize<T: Float, V: Magnitude<T>>(a: V) -> V {
325    V::normalize(a)
326}
327
328/// returns a Chebyshev normalized unit vector of `a` (where the normalization projects onto the unit cube)
329pub fn chebyshev_normalize<T: Float, V: VecFloatOps<T> + VecN<T> + SignedNumberOps<T>>(a: V) -> V {
330    a / V::max_scalar(V::abs(a))
331}
332
333/// returns scalar distance between 2 points `a` and `b` (magnitude of the vector between the 2 points)
334pub fn distance<T: Float, V: VecFloatOps<T>>(a: V, b: V) -> T {
335    V::distance(a, b)
336}
337
338/// returns scalar distance between 2 points `a` and `b` (magnitude of the vector between the 2 points)
339pub fn dist<T: Float, V: VecFloatOps<T>>(a: V, b: V) -> T {
340    V::dist(a, b)
341}
342
343/// returns scalar squared distance between 2 points `a` and `b` to avoid using sqrt
344pub fn dist2<T: Float, V: VecFloatOps<T>>(a: V, b: V) -> T {
345    V::dist2(a, b)
346}
347
348/// returns the barycentric coordinate `(u, v, w)` of point `p` inside triangle `t1-t2-t3`
349pub fn barycentric<T: Float + NumberOps<T>, V: VecN<T> + VecFloatOps<T> + NumberOps<T>>(p: V, t1: V, t2: V, t3: V) -> (T, T, T) {
350    let x13 = t1 - t3;
351    let x23 = t2 - t3;
352    let x03 = p - t3;
353    let m13 = mag2(x13);
354    let m23 = mag2(x23);
355    let d = dot(x13, x23);
356    let invdet = T::one() / T::max(m13 * m23 - d * d, T::small_epsilon());
357    let a = dot(x13, x03);
358    let b = dot(x23, x03);
359    let u = invdet * (m23 * a - d * b);
360    let v = invdet * (m13 * b - d * a);
361    let w = T::one() - u - v;
362    (u, v, w)
363}
364
365/// returns an `xyz` directional unit vector converted from `azimuth` and `altitude` angles in radians
366pub fn azimuth_altitude_to_xyz<T: Float + FloatOps<T>>(azimuth: T, altitude: T) -> Vec3<T> {
367    let z = T::sin(altitude);
368    let hyp = T::cos(altitude);
369    let y = hyp * T::cos(azimuth);
370    let x = hyp * T::sin(azimuth);
371    Vec3::<T>::new(x, z, y)
372}
373
374/// returns field of view in degrees converted from focal length with the specified aperture_width
375pub fn focal_length_to_fov<T: Float + FloatOps<T> + Cast<T>>(focal_length: T, aperture_width: T) -> T {
376    T::two() * rad_to_deg(atan((aperture_width * T::from_f64(25.4)) / (T::two() * focal_length)))
377}
378
379/// returns focal length converted from field of view `fov` in degrees with the specified aperture_width
380pub fn fov_to_focal_length<T: Float + FloatOps<T> + Cast<T>>(fov: T, aperture_width: T) -> T {
381    (aperture_width * T::from_f64(25.4)) / (T::two() * tan(deg_to_rad(fov / T::two())))
382}
383
384/// returns `(azimuth, altitude)` in radians converted from directional unit vector `xyz`
385pub fn xyz_to_azimuth_altitude<T: Float + FloatOps<T>>(xyz: Vec3<T>) -> (T, T) {
386    (T::atan2(xyz.y, xyz.x), T::atan2(xyz.z, sqrt(xyz.x * xyz.x + xyz.y * xyz.y)))
387}
388
389/// returns the cosine of `v` where the value `v` is in radians
390pub fn cos<T: Float, V: FloatOps<T>>(v: V) -> V {
391    V::cos(v)
392}
393
394/// returns the sine of `v` where the value `v` is in radians
395pub fn sin<T: Float, V: FloatOps<T>>(v: V) -> V {
396    V::sin(v)
397}
398
399/// returns the tangent of `v` where the value `v` is in radians
400pub fn tan<T: Float, V: FloatOps<T>>(v: V) -> V {
401    V::tan(v)
402}
403
404/// returns the arc-cosine of `v` where the value `v` is in radians
405pub fn acos<T: Float, V: FloatOps<T>>(v: V) -> V {
406    V::acos(v)
407}
408
409/// returns the arc-sine of `v` where the value `v` is in radians
410pub fn asin<T: Float, V: FloatOps<T>>(v: V) -> V {
411    V::asin(v)
412}
413
414/// returns the arc-tangent of `v` where the value `v` is in radians
415pub fn atan<T: Float, V: FloatOps<T>>(v: V) -> V {
416    V::atan(v)
417}
418
419/// returns the arc-tangent of `v` where the value `v` is in radians
420pub fn atan2<T: Float, V: FloatOps<T>>(y: V, x: V) -> V {
421    V::atan2(y, x)
422}
423
424/// returns the hyperbolic cosine of `v` where the value `v` is in radians
425pub fn cosh<T: Float, V: FloatOps<T>>(v: V) -> V {
426    V::cosh(v)
427}
428
429/// returns the hyperbolic sine of v where the value v is in radians
430pub fn sinh<T: Float, V: FloatOps<T>>(v: V) -> V {
431    V::sinh(v)
432}
433
434/// returns the hyperbolic tangent of `v` where the value `v` is in radians
435pub fn tanh<T: Float, V: FloatOps<T>>(v: V) -> V {
436    V::tanh(v)
437}
438
439/// returns a tuple of (sin(v), cos(v)) of `v` where the value `v` is in radian
440pub fn sin_cos<T: Float, V: FloatOps<T>>(v: V) -> (V, V) {
441    V::sin_cos(v)
442}
443
444/// returns the base-e exponential function of `v`, which is e raised to the power `v`
445pub fn exp<T: Float, V: FloatOps<T>>(v: V) -> V {
446    V::exp(v)
447}
448
449/// returns 2 raised to the given power `v`
450pub fn exp2<T: Float, V: FloatOps<T>>(v: V) -> V {
451    V::exp2(v)
452}
453
454/// returns the binary (base-2) logarithm of `v`
455pub fn log2<T: Float, V: FloatOps<T>>(v: V) -> V {
456    V::log2(v)
457}
458
459/// returns the common (base-10) logarithm of `v`
460pub fn log10<T: Float, V: FloatOps<T>>(v: V) -> V {
461    V::log10(v)
462}
463
464/// returns the logarithm of `v` in `base`
465pub fn log<T: Float, V: FloatOps<T>>(v: V, base: T) -> V {
466    V::log(v, base)
467}
468
469/// returns the vec2 rotated anti-clockwise rotation by radian `angle`
470pub fn rotate_2d<T: Float + FloatOps<T>>(v: Vec2<T>, angle: T) -> Vec2<T> {
471    let c = cos(angle);
472    let s = sin(angle);
473    Vec2::new(c * v.x - s * v.y, s * v.x + c * v.y)
474}
475
476/// returns a convex hull wound clockwise from point cloud `points`
477pub fn convex_hull_from_points<T: Float + SignedNumberOps<T> + NumberOps<T> + FloatOps<T>>(points: &[Vec2<T>]) -> Vec<Vec2<T>> {
478    //find right most point
479    let mut cur = points[0];
480    let mut curi = 0;
481    for (i, item) in points.iter().enumerate().skip(1) {
482        if item.x > cur.x || (item.x == cur.x && item.y > cur.y) {
483            // pritorites by xmost then y most if == x
484            cur = *item;
485            curi = i;
486        }
487    }
488
489    // wind the hull clockwise by using cross product to test which side of an edge a point lies on
490    // discarding points that do not form the perimeter
491    let mut hull = vec![cur];
492    loop {
493        let mut rm = (curi+1)%points.len();
494        let mut x1 = points[rm];
495
496        for (i, item) in points.iter().enumerate() {
497            if i == curi {
498                continue;
499            }
500            let x2 = *item;
501            let v1 = x1 - cur;
502            let v2 = x2 - cur;
503            let z = v2.x * v1.y - v2.y * v1.x;
504            if z > T::zero() {
505                x1 = *item;
506                rm = i;
507            }
508        }
509
510        if approx(x1, hull[0], T::small_epsilon()) {
511            break;
512        }
513
514        cur = x1;
515        curi = rm;
516        hull.push(x1);
517    }
518    hull
519}
520
521/// returns a plane packed into Vec4 in the form `.xyz = plane normal, .w = plane distance (constant)` from `x` (point on plane) and `n` (planes normal)
522pub fn plane_from_normal_and_point<T: SignedNumber>(x: Vec3<T>, n: Vec3<T>) -> Vec4<T> {
523    Vec4 {
524        x: n.x,
525        y: n.y,
526        z: n.z,
527        w: plane_distance(x, n)
528    }
529}
530
531/// returns the normalized unit vector normal of triangle `t1-t2-t3`
532pub fn get_triangle_normal<T: Float, V: VecFloatOps<T> + VecN<T> + Cross<T>>(t1: V, t2: V, t3: V) -> V {
533    normalize(cross(t2 - t1, t3 - t1))
534}
535
536/// returns the 3D normalized device coordinate of point `p` projected by `view_projection` matrix, performing homogenous divide
537pub fn project_to_ndc<T: Float>(p: Vec3<T>, view_projection: Mat4<T>) -> Vec3<T> {
538    let ndc = view_projection * Vec4::from((p, T::one()));
539    Vec3::from(ndc) / ndc.w
540}
541
542/// returns the 2D screen coordinate of 3D point `p` projected with `view_projection`, performing homogenous divide and `viewport` correction
543/// assumes screen coordinates are vup in the y-axis y.0 = bottom y.height = top
544pub fn project_to_sc<T: Float + FloatOps<T>>(p: Vec3<T>, view_projection: Mat4<T>, viewport: Vec2<T>) -> Vec3<T> {
545    let ndc = project_to_ndc(p, view_projection);
546    let sc  = ndc * T::point_five() + T::point_five();
547    Vec3::from((Vec2::<T>::from(sc) * viewport, sc.z))
548}
549
550/// returns the 2D screen coordinate of 3D point `p` projected with `view_projection`, performing homogenous divide and `viewport` correction
551/// coordinates are vdown in the y-axis vdown = y.0 = top y.height = bottom
552pub fn project_to_sc_vdown<T: Float + FloatOps<T>>(p: Vec3<T>, view_projection: Mat4<T>, viewport: Vec2<T>) -> Vec2<T> {
553    let ndc = project_to_ndc(p, view_projection);
554    let sc  = ndc * Vec3::new(T::point_five(), -T::point_five(), T::point_five()) + T::point_five();
555    Vec2::<T>::from(sc) * viewport
556}
557
558/// returns the unprojected 3D world position of point `p` which is specified in normalized device coordinates
559pub fn unproject_ndc<T: Float>(p: Vec3<T>, view_projection: Mat4<T>) -> Vec3<T> {
560    let inv = view_projection.inverse();
561    inv * p
562}
563
564/// returns the unprojected 3D world position of screen coordinate `p`
565/// assumes screen coordinates are vup in the y-axis y.0 = bottom y.height = top
566pub fn unproject_sc<T: Float>(p: Vec3<T>, view_projection: Mat4<T>, viewport: Vec2<T>) -> Vec3<T> {
567    let ndc_xy = (Vec2::from(p) / viewport) * Vec2::from(T::two()) - Vec2::from(T::one());
568    let ndc = Vec3::from((ndc_xy, p.z));
569    unproject_ndc(ndc, view_projection)
570}
571
572/// returns the unprojected 3D world position of screen coordinate `p`
573/// coordinates are vdown in the y-axis vdown = y.0 = top y.height = bottom
574pub fn unproject_sc_vdown<T: Float>(p: Vec3<T>, view_projection: Mat4<T>, viewport: Vec2<T>) -> Vec3<T> {
575    let ndc_xy = (Vec2::from(p) / viewport) * Vec2::new(T::two(), -T::two()) - Vec2::from(T::one());
576    let ndc = Vec3::from((ndc_xy, p.z));
577    unproject_ndc(ndc, view_projection)
578}
579
580/// returns the distance to the plane define by a point on the plane `x` and normal of the plane `n`
581pub fn plane_distance<T: SignedNumber, V: VecN<T>>(x: V, n: V) -> T {
582    -V::dot(x, n)
583}
584
585/// returns the distance parameter t of point `p` projected along the line `l1-l2`, the value is not clamped to the line segment extents
586pub fn distance_on_line<T: Float, V: VecFloatOps<T> + VecN<T>>(p: V, l1: V, l2: V) -> T {
587    let v1 = p - l1;
588    let v2 = V::normalize(l2 - l1);
589    dot(v2, v1)
590}
591
592/// returns the distance parameter t of point `p` projected along the ray `r0` with direction `rv`, the value is not clamped to 0 or the start of the ray
593pub fn distance_on_ray<T: Float, V: VecFloatOps<T> + VecN<T>>(p: V, r0: V, rv: V) -> T {
594    dot(p - r0, rv)
595}
596
597/// returns the distance to the plane from point `p` where the plane is defined by point on plane `x` and normal `n`
598pub fn point_plane_distance<T: SignedNumber, V: VecN<T>>( p: V, x: V, n: V) -> T {
599    V::dot(p, n) - V::dot(x, n)
600}
601
602/// returns the distance that point `p` is from the line segment defined by `l1-l2`
603pub fn point_line_segment_distance<T: Float + FloatOps<T>, V: VecFloatOps<T> + VecN<T>>(p: V, l1: V, l2: V) -> T {
604    let dx = l2 - l1;
605    let m2 = mag2(dx);
606    // find parameter value of closest point on segment
607    let s12 = saturate(dot(l2 - p, dx) / m2);
608    // and find the distance
609    dist(p, l1 * s12 + l2 * (T::one() - s12))
610}
611
612/// returns the distance that point `p` is from an aabb defined by `aabb_min` to `aabb_max`
613pub fn point_aabb_distance<T: Float, V: VecN<T> + NumberOps<T> + VecFloatOps<T>>(p: V, aabb_min: V, aabb_max: V) -> T {
614    dist(closest_point_on_aabb(p, aabb_min, aabb_max), p)
615}
616
617/// returns the unsigned distance from point `p0` to the sphere (or 2d circle) centred at `s0` with radius `r`
618pub fn point_sphere_distance<T: Float, V: VecN<T> + NumberOps<T> + VecFloatOps<T>>(p0: V, s0: V, r: T) -> T {
619    dist(p0, closest_point_on_sphere(p0, s0, r))
620}
621
622/// returns the distance point `p` is from a triangle defined by `t1-t2-t3`
623pub fn point_triangle_distance<T: Float + FloatOps<T> + NumberOps<T>, V: VecN<T> + NumberOps<T> + VecFloatOps<T>>(p: V, t1: V, t2: V, t3: V) -> T {
624    let (w23, w31, w12) = barycentric(p, t1, t2, t3);
625    if w23 >= T::zero() && w31 >= T::zero() && w12 >= T::zero() {
626        // if we're inside the triangle
627        dist(p, t1 * w23 + t2 * w31 + t3 * w12)
628    }
629    else {
630        // clamp to one of the edges
631        if w23 > T::zero() {
632            // this rules out edge 2-3 for us
633            T::min(point_line_segment_distance(p, t1, t2), point_line_segment_distance(p, t1, t3))
634        }
635        else if w31 > T::zero() {
636            // this rules out edge 1-3
637            T::min(point_line_segment_distance(p, t1, t2), point_line_segment_distance(p, t2, t3))
638        }
639        else {
640            // w12 must be >0, ruling out edge 1-2
641            T::min(point_line_segment_distance(p, t1, t3), point_line_segment_distance(p, t2, t3))
642        }
643    }
644}
645
646/// returns the distance from point `p` to the cone defined by position `cp`, with height `h` and radius at the base of `r`
647pub fn point_cone_distance<T: Float, V: VecN<T> + SignedVecN<T> + VecFloatOps<T>>(p: V, cp: V, cv: V, h: T, r: T) -> T {
648    dist(p, closest_point_on_cone(p, cp, cv, h, r))
649}
650
651/// returns the distance from point `p` to the edge of the convex hull defined by point list 'hull' with clockwise winding
652pub fn point_convex_hull_distance<T: Float + FloatOps<T>>(p: Vec2<T>, hull: &[Vec2<T>]) -> T {
653    dist(p, closest_point_on_polygon(p, hull))
654}
655
656/// returns the distance from point `p` to the edge of the polygon defined by point list 'poly'
657pub fn point_polygon_distance<T: Float + FloatOps<T>>(p: Vec2<T>, hull: &[Vec2<T>]) -> T {
658    dist(p, closest_point_on_polygon(p, hull))
659}
660
661/// returns the unsigned distance from point `p` to the obb defined by matrix `obb`, where the matrix transforms a unit cube
662/// from -1 to 1 into an obb
663pub fn point_obb_distance<T: Float, V: VecFloatOps<T> + NumberOps<T> + SignedNumberOps<T> + VecN<T> + SignedVecN<T>, M: MatTranslate<V> + MatInverse<T> + MatN<T, V>>(p: V, mat: M) -> T {
664    dist(p, closest_point_on_obb(p, mat))
665}
666
667/// returns the closest point on the line `l1-l2` to point `p`
668pub fn closest_point_on_line_segment<T: Float, V: VecFloatOps<T> + VecN<T>>(p: V, l1: V, l2: V) -> V {
669    let v1 = p - l1;
670    let v2 = V::normalize(l2 - l1);
671    let t = V::dot(v2, v1);
672    if t < T::zero() {
673        l1
674    }
675    else if t > V::dist(l1, l2) {
676        l2
677    }
678    else {
679        l1 + (v2 * t)
680    }
681}
682
683/// returns the closest point on the plane to point `p` where the plane is defined by point on plane `x` and normal `n`
684pub fn closest_point_on_plane<T: SignedNumber, V: VecN<T> + SignedVecN<T>>(p: V, x: V, n: V) -> V {
685    p + n * -(V::dot(p, n) - V::dot(x, n))
686}
687
688/// returns the closest point on the aabb defined by `aabb_min` and `aabb_max` to point `p`, if the point is inside the aabb it will return `p`
689pub fn closest_point_on_aabb<T: Float, V: NumberOps<T> + VecN<T>>(p: V, aabb_min: V, aabb_max: V) -> V {
690    V::min(V::max(p, aabb_min), aabb_max)
691}
692
693/// returns the closest point from `p` on sphere or circle centred at `s` with radius `r`
694pub fn closest_point_on_sphere<T: Float, V: VecFloatOps<T> + VecN<T>>(p: V, s: V, r: T) -> V {
695    s + V::normalize(p - s) * r
696}
697
698/// returns the closest point to `p` on the the ray starting at `r0` with direction `rv`
699pub fn closest_point_on_ray<T: Float, V: VecFloatOps<T> + VecN<T>>(p: V, r0: V, rv: V) -> V {
700    let v1 = p - r0;
701    let t = dot(v1, rv);
702    if t < T::zero() {
703        r0
704    }
705    else {
706        r0 + rv * t
707    }
708}
709
710/// returns the closest point to point `p` on the obb defined by `mat` which will transform an aabb with extents -1 to 1 into an obb
711pub fn closest_point_on_obb<T: Float, V: VecFloatOps<T> + NumberOps<T> + SignedNumberOps<T> + VecN<T> + SignedVecN<T>, M: MatTranslate<V> + MatInverse<T> + MatN<T, V>>(p: V, mat: M) -> V {
712    let invm = mat.inverse();
713    let tp = invm * p;
714    let cp = closest_point_on_aabb(tp, V::minus_one(), V::one());
715    mat * cp
716}
717
718/// returns the closest point to `p` on the triangle defined by `t1-t2-t3`
719pub fn closest_point_on_triangle<T: Float + FloatOps<T> + NumberOps<T>, V: VecN<T> + NumberOps<T> + VecFloatOps<T>>(p: V, t1: V, t2: V, t3: V) -> V {
720    let (w23, w31, w12) = barycentric(p, t1, t2, t3);
721    if w23 >= T::zero() && w31 >= T::zero() && w12 >= T::zero() {
722        p
723    }
724    else {
725        // clamp to one of the edges
726        if w23 > T::zero() {
727            // this rules out edge 2-3 for us
728            let p1 = closest_point_on_line_segment(p, t1, t2);
729            let p2 = closest_point_on_line_segment(p, t1, t3);
730            if dist2(p, p1) < dist2(p, p2) {
731                p1
732            }
733            else {
734                p2
735            }
736        }
737        else if w31 > T::zero() {
738            // this rules out edge 1-3
739            let p1 = closest_point_on_line_segment(p, t1, t2);
740            let p2 = closest_point_on_line_segment(p, t2, t3);
741            if dist2(p, p1) < dist2(p, p2) {
742                p1
743            }
744            else {
745                p2
746            }
747        }
748        else {
749            // w12 must be >0, ruling out edge 1-2
750            let p1 = closest_point_on_line_segment(p, t1, t3);
751            let p2 = closest_point_on_line_segment(p, t2, t3);
752            if dist2(p, p1) < dist2(p, p2) {
753                p1
754            }
755            else {
756                p2
757            }
758        }
759    }
760}
761
762/// returns the closest point to `p` on the cone defined by `cp` position, with direction `cv` height `h` and radius `r`
763pub fn closest_point_on_cone<T: Float, V: VecN<T> + VecFloatOps<T>>(p: V, cp: V, cv: V, h: T, r: T) -> V {
764    // centre point of the cones base (where radius is largest)
765    let l2 = cp + cv * h;
766
767    // find point onbase plane and clamp to the extent
768    let cplane = closest_point_on_plane(p, l2, cv);
769    let extent = l2 + normalize(cplane - l2) * r;
770
771    // test closest point on line with the axis along the side and bottom of the cone
772    let e1 = closest_point_on_line_segment(p, cp, extent);
773    let e2 = closest_point_on_line_segment(p, l2, extent);
774
775    if dist2(p, e1) < dist2(p, e2) {
776        e1
777    }
778    else {
779        e2
780    }
781}
782
783/// returns the clostest point to `p` on the edge of the convex hull defined by point list 'hull' with clockwise winding
784pub fn closest_point_on_convex_hull<T: Float + FloatOps<T>>(p: Vec2<T>, hull: &[Vec2<T>]) -> Vec2<T> {
785    closest_point_on_polygon(p, hull)
786}
787
788/// returns the clostest point to `p` on the edge of the polygon defined by point list `poly`.
789pub fn closest_point_on_polygon<T: Float + FloatOps<T>>(p: Vec2<T>, poly: &[Vec2<T>]) -> Vec2<T> {
790    let ncp = poly.len();
791    let mut cp = Vec2::max_value();
792    let mut cd2 = T::max_value();
793    for i in 0..ncp {
794        let i2 = (i+1)%ncp;
795        let cpp = closest_point_on_line_segment(p, poly[i], poly[i2]);
796        let cppd2 = dist2(p, cpp);
797        if dist2(p, cpp) < cd2 {
798            cp = cpp;
799            cd2 = cppd2;
800        }
801    }
802    cp
803}
804
805/// returns true if point `p` is inside the aabb defined by `aabb_min` and `aabb_max`
806pub fn point_inside_aabb<T: Float, V: VecN<T> + VecFloatOps<T>>(p: V, aabb_min: V, aabb_max: V) -> bool {
807    for i in 0..V::len() {
808        if p[i] < aabb_min[i] || p[i] > aabb_max[i] {
809            return false;
810        }
811    }
812    true
813}
814
815/// returns true if sphere (or circle) with centre `s` and radius `r` contains point `p`
816pub fn point_inside_sphere<T: Float, V: VecFloatOps<T> + VecN<T>>(p: V, s: V, r: T) -> bool {
817    dist2(p, s) < r * r
818}
819
820/// returns true if the point `p` is inside the obb defined by `mat` which will transform an aabb with extents -1 to 1 into an obb
821pub fn point_inside_obb<T: Float, V: VecFloatOps<T> + NumberOps<T> + SignedNumberOps<T> + VecN<T> + SignedVecN<T>, M: MatTranslate<V> + MatInverse<T> + MatN<T, V>>(p: V, mat: M) -> bool {
822    let invm = mat.inverse();
823    let tp = invm * p;
824    point_inside_aabb(tp, V::minus_one(), V::one())
825}
826
827/// returns true if the point `p` is inside the triangle defined by `t1-t2-t3`
828pub fn point_inside_triangle<T: Float + FloatOps<T> + NumberOps<T>, V: VecN<T> + NumberOps<T> + VecFloatOps<T>>(p: V, t1: V, t2: V, t3: V) -> bool {
829    let (w23, w31, w12) = barycentric(p, t1, t2, t3);
830    w23 >= T::zero() && w31 >= T::zero() && w12 >= T::zero()
831}
832
833/// returns true if point `p` is inside cone defined by position `cp` facing direction `cv` with height `h` and radius `r`
834pub fn point_inside_cone<T: Float + FloatOps<T> + NumberOps<T>, V: VecN<T> + VecFloatOps<T>>(p: V, cp: V, cv: V, h: T, r: T) -> bool {
835    let l2 = cp + cv * h;
836    let dh = distance_on_line(p, cp, l2) / h;
837    let x0 = closest_point_on_line_segment(p, cp, l2);
838    let d = dist(x0, p);
839    d < dh * r && dh < T::one()
840}
841
842/// returns true if the point `p` is inside the 2D convex hull defined by point list `hull` with clockwise winding
843pub fn point_inside_convex_hull<T: Float>(p: Vec2<T>, hull: &[Vec2<T>]) -> bool {
844    let ncp = hull.len();
845    for i in 0..ncp {
846        let i2 = (i+1)%ncp;
847        let p1 = hull[i];
848        let p2 = hull[i2];
849        let v1 = p2 - p1;
850        let v2 = p - p1;
851        let z = v1.x * v2.y - v2.x * v1.y;
852        if z > T::zero() {
853            return false;
854        }
855    }
856    true
857}
858
859/// returns true if point `p` is inside the polygon defined by point list `poly`
860pub fn point_inside_polygon<T: Float>(p: Vec2<T>, poly: &[Vec2<T>]) -> bool {
861    // copyright (c) 1970-2003, Wm. Randolph Franklin
862    // https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
863    let npol = poly.len();
864    let mut c = false;
865    let mut j = npol-1;
866    for i in 0..npol {
867        if (((poly[i].y <= p.y) && (p.y < poly[j].y)) || ((poly[j].y <= p.y) && (p.y < poly[i].y))) &&
868            (p.x < (poly[j].x - poly[i].x) * (p.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x) {
869            c = !c;
870        }
871        j = i
872    }
873    c
874}
875
876/// returns true if the point `p` is inside the frustum defined by 6 planes packed as vec4's `.xyz = normal, .w = plane distance`
877pub fn point_inside_frustum<T: Number>(p: Vec3<T>, planes: &[Vec4<T>; 6]) -> bool {
878    for plane in planes.iter().take(6) {
879        let d = dot(p, Vec3::from(*plane)) + plane.w;
880        if d > T::zero() {
881            return false;
882        }
883    }
884    true
885}
886
887/// returns the classification of point `p` vs the plane defined by point on plane `x` and normal `n`
888pub fn point_vs_plane<T: SignedNumber + SignedNumberOps<T>>(p: Vec3<T>,  x: Vec3<T>, n: Vec3<T>) -> Classification {
889    let pd = plane_distance(x, n);
890    let d = dot(n, p) + pd;
891    if d < T::zero() {
892        Classification::Behind
893    }
894    else if d > T::zero() {
895        Classification::Infront
896    }
897    else {
898        Classification::Intersects
899    }
900}
901
902/// returns the classification of the 3D aabb defined as `aabb_min` to `aabb_max` vs the plane defined by point on plane `x` and normal `n`
903pub fn aabb_vs_plane<T: SignedNumber + SignedNumberOps<T>>(aabb_min: Vec3<T>, aabb_max: Vec3<T>, x: Vec3<T>, n: Vec3<T>) -> Classification {
904    let e = (aabb_max - aabb_min) / T::two();
905    let centre = aabb_min + e;
906    let radius = abs(n.x * e.x) + abs(n.y * e.y) + abs(n.z * e.z);
907    let pd = plane_distance(x, n);
908    let d = dot(n, centre) + pd;
909    if d > radius {
910        Classification::Infront
911    }
912    else if d < -radius {
913        Classification::Behind
914    }
915    else {
916        Classification::Intersects
917    }
918}
919
920/// returns the classification of sphere defined by centre `s` and radius `r` vs the plane defined by point on plane `x` and normal `n`
921pub fn sphere_vs_plane<T: SignedNumber + SignedNumberOps<T>>(s: Vec3<T>, r: T,  x: Vec3<T>, n: Vec3<T>) -> Classification {
922    let pd = plane_distance(x, n);
923    let d = dot(n, s) + pd;
924    if d > r {
925        Classification::Infront
926    }
927    else if d < -r {
928        Classification::Behind
929    }
930    else {
931        Classification::Intersects
932    }
933}
934
935/// returns the classification of a capsule defined by line `c1-c2` with radius `r` vs a plane defined by point on plane `x` and normal `n`
936pub fn capsule_vs_plane<T: Float + FloatOps<T> + SignedNumber + SignedNumberOps<T>>(c1: Vec3<T>, c2: Vec3<T>, r: T, x: Vec3<T>, n: Vec3<T>) -> Classification {
937    let pd = plane_distance(x, n);
938    // classify both spheres at the ends of the capsule
939    // sphere 1
940    let d1 = dot(n, c1) + pd;
941    let r1 = if d1 > r {
942        Classification::Infront
943    }
944    else if d1 < -r {
945        Classification::Behind
946    }
947    else {
948        Classification::Intersects
949    };
950    // sphere 2
951    let d2 = dot(n, c2) + pd;
952    let r2 = if d2 > r {
953        Classification::Infront
954    }
955    else if d2 < -r {
956        Classification::Behind
957    }
958    else {
959        Classification::Intersects
960    };
961    if r1 == r2 {
962        // if both speheres are the same, we return their classification this could give us infront, behind or intersects
963        r1
964    }
965    else {
966        // the else case means r1 != r2 and this means we are on opposite side of the plane or one of them intersects
967        Classification::Intersects
968    }
969}
970
971/// return the classification of cone defined by position `cp`, direction `cv` with height `h` and radius at the base of `r`
972/// vs the plane defined by point `x` and normal `n`
973pub fn cone_vs_plane<T: Float + SignedNumberOps<T>, V: VecN<T> + Cross<T> + Dot<T> + SignedVecN<T> + VecFloatOps<T>>(cp: V, cv: V, h: T, r: T, x: V, n: V) -> Classification {
974    let l2 = cp + cv * h;
975    let pd = plane_distance(x, n);
976    // check if the tip and cones extent are on different sides of the plane
977    let d1 = dot(n, cp) + pd;
978    // extent from the tip is at the base centre point perp of cv at the radius edge... we need to choose the side toward the plane
979    let perp = normalize(cross(cross(n, cv), cv));
980    let extent = l2 + perp * r;
981    let extent2 = l2 + perp * -r;
982    let d2 = dot(n, extent) + pd;
983    let d3 = dot(n, extent2) + pd;
984    if d1 < T::zero() && d2 < T::zero() && d3 < T::zero() {
985        Classification::Behind
986    }
987    else if d1 > T::zero() && d2 > T::zero() && d3 > T::zero() {
988        Classification::Infront
989    }
990    else {
991        Classification::Intersects
992    }
993}
994
995/// returns the intersection point of the ray defined as origin of ray `r0` and direction `rv` with the plane defined by point on plane `x` and normal `n`
996pub fn ray_vs_plane<T: Float + SignedNumberOps<T>>(r0: Vec3<T>, rv: Vec3<T>, x: Vec3<T>, n: Vec3<T>) -> Option<Vec3<T>> {
997    let t = -(dot(r0, n) - dot(x, n))  / dot(rv, n);
998    if t < T::zero() {
999        None
1000    }
1001    else {
1002        Some(r0 + rv * t)
1003    }
1004}
1005
1006/// returns the intersection point of the infinite line defined as point on line `l0` and direction `lv` with the plane defined by point on plane `x` and normal `n`
1007pub fn line_vs_plane<T: Float + SignedNumberOps<T>>(l0: Vec3<T>, lv: Vec3<T>, x: Vec3<T>, n: Vec3<T>) -> Option<Vec3<T>> {
1008    let r = dot(lv, n);
1009    if r == T::zero() {
1010        None
1011    }
1012    else {
1013        let t = -(dot(l0, n) - dot(x, n))  / dot(lv, n);
1014        Some(l0 + lv * t)
1015    }
1016}
1017
1018/// returns the intersection point of the line segment `l1-l2` and plane defined by point on plane `x` and normal `n`, returns `None` if no intersection exists
1019pub fn line_segment_vs_plane<T: Float + FloatOps<T> + SignedNumber + SignedNumberOps<T>>(l1: Vec3<T>, l2: Vec3<T>, x: Vec3<T>, n: Vec3<T>) -> Option<Vec3<T>> {
1020    let ll = l2-l1;
1021    let m = mag(ll);
1022    let lv = ll / m;
1023    let t = -(dot(l1, n) - dot(x, n))  / dot(lv, n);
1024    if t < T::zero() || t > m {
1025        None
1026    }
1027    else {
1028        Some(l1 + lv * t)
1029    }
1030}
1031
1032/// returns true if the sphere or circle at centre `s1` with radius `r1` intersects `s2-r2`
1033pub fn sphere_vs_sphere<T: Float, V: VecN<T> + VecFloatOps<T>>(s1: V, r1: T, s2: V, r2: T) -> bool {
1034    let d2 = dist2(s1, s2);
1035    let r22 = r1 + r2;
1036    d2 < r22 * r22
1037}
1038
1039/// returns true if the sphere or circle at centre `s1` with radius `r1` intersects capsule `c0-c1` with radius `cr`
1040pub fn sphere_vs_capsule<T: Float + FloatOps<T>, V: VecN<T> + VecFloatOps<T> + FloatOps<T>>(s1: V, r1: T, c0: V, c1: V, cr: T) -> bool {
1041    let cp = closest_point_on_line_segment(s1, c0, c1);
1042    let r2 = sqr(r1 + cr);
1043    dist2(s1, cp) < r2
1044}
1045
1046/// returns true if the aabb defined by `aabb_min` to `aabb_max` intersects the sphere (or circle) centred at `s` with radius `r`
1047pub fn aabb_vs_sphere<T: Float, V: VecN<T> + VecFloatOps<T> + NumberOps<T>>(aabb_min: V, aabb_max: V, s: V, r: T) -> bool {
1048    let cp = closest_point_on_aabb(s, aabb_min, aabb_max);
1049    dist2(cp, s) < r * r
1050}
1051
1052/// returns true if the aabb defined by `aabb_min1` to `aabb_max1` intersects `aabb_min2-aabb_max2`
1053pub fn aabb_vs_aabb<T: Number, V: VecN<T> + NumberOps<T>>(aabb_min1: V, aabb_max1: V, aabb_min2: V, aabb_max2: V) -> bool {
1054    for i in 0..V::len() {
1055        if aabb_max1[i] < aabb_min2[i] || aabb_min1[i] > aabb_max2[i] {
1056            return false;
1057        }
1058    }
1059    true
1060}
1061
1062/// returns true if the aabb defined by `aabb_min` to `aabb_max` overlaps obb defined by matrix `obb`, where the matrix transforms an aabb with -1 to 1 extents into an obb
1063pub fn aabb_vs_obb<T: Number + Float + SignedNumber + SignedNumberOps<T> + NumberOps<T> + FloatOps<T>, V: VecN<T> + NumberOps<T> + FloatOps<T> + Triple<T> + Cross<T>, M: MatTranslate<V> + MatInverse<T> + MatRotate3D<T, V> + MatN<T, V> + std::ops::Mul<Vec3<T>, Output=Vec3<T>>>(aabb_min: Vec3<T>, aabb_max: Vec3<T>, obb: M) -> bool {
1064    // this function is for convenience, you can extract vertices and pass to gjk_3d yourself
1065    let corners = [
1066        Vec3::<T>::new(-T::one(), -T::one(), -T::one()),
1067        Vec3::<T>::new( T::one(), -T::one(), -T::one()),
1068        Vec3::<T>::new( T::one(),  T::one(), -T::one()),
1069        Vec3::<T>::new(-T::one(),  T::one(), -T::one()),
1070        Vec3::<T>::new(-T::one(), -T::one(),  T::one()),
1071        Vec3::<T>::new( T::one(), -T::one(),  T::one()),
1072        Vec3::<T>::new( T::one(),  T::one(),  T::one()),
1073        Vec3::<T>::new(-T::one(),  T::one(),  T::one()),
1074    ];
1075
1076    // aabb
1077    let verts0 = vec![
1078        aabb_min,
1079        Vec3::<T>::new(aabb_min.x, aabb_min.y, aabb_max.z),
1080        Vec3::<T>::new(aabb_max.x, aabb_min.y, aabb_min.z),
1081        Vec3::<T>::new(aabb_max.x, aabb_min.y, aabb_max.z),
1082        Vec3::<T>::new(aabb_min.x, aabb_max.y, aabb_min.z),
1083        Vec3::<T>::new(aabb_min.x, aabb_max.y, aabb_max.z),
1084        Vec3::<T>::new(aabb_max.x, aabb_max.y, aabb_min.z),
1085        aabb_max
1086    ];
1087
1088    // obb from corners
1089    let mut verts1 = Vec::new();
1090    for corner in corners {
1091        verts1.push(obb * corner);
1092    }
1093
1094    gjk_3d(verts0, verts1)
1095}
1096
1097/// returns true if the sphere with centre `s0` and radius `r0` overlaps obb defined by matrix `obb`, where the matrix
1098/// transforms a unit cube with extents -1 to 1 into an obb
1099pub fn sphere_vs_obb<T: Float, V: VecN<T> + VecFloatOps<T> + NumberOps<T> + SignedNumberOps<T>, M: MatTranslate<V> + MatInverse<T> + MatRotate3D<T, V> + MatN<T, V>>(s: V, r: T, obb: M) -> bool {
1100    // test the distance to the closest point on the obb
1101    let cp = closest_point_on_obb(s, obb);
1102    dist2(s, cp) < r * r
1103}
1104
1105/// returns true if the aabb defined by `obb0` overlaps `obb1` where the obb's are defined by a matrix and the matrix transforms an aabb with -1 to 1 extents into an obb
1106pub fn obb_vs_obb<T: Number + Float + SignedNumber + SignedNumberOps<T> + NumberOps<T> + FloatOps<T>, V: VecN<T> + NumberOps<T> + FloatOps<T> + Triple<T> + Cross<T>, M: MatTranslate<V> + MatInverse<T> + MatRotate3D<T, V> + MatN<T, V> + std::ops::Mul<Vec3<T>, Output=Vec3<T>>>(obb0: M, obb1: M) -> bool {
1107    // this function is for convenience, you can extract vertices and pass to gjk_3d yourself
1108    let corners = [
1109        Vec3::<T>::new(-T::one(), -T::one(), -T::one()),
1110        Vec3::<T>::new( T::one(), -T::one(), -T::one()),
1111        Vec3::<T>::new( T::one(),  T::one(), -T::one()),
1112        Vec3::<T>::new(-T::one(),  T::one(), -T::one()),
1113        Vec3::<T>::new(-T::one(), -T::one(),  T::one()),
1114        Vec3::<T>::new( T::one(), -T::one(),  T::one()),
1115        Vec3::<T>::new( T::one(),  T::one(),  T::one()),
1116        Vec3::<T>::new(-T::one(),  T::one(),  T::one()),
1117    ];
1118
1119    // obb from corners
1120    let mut verts0 = Vec::new();
1121    for corner in corners {
1122        verts0.push(obb0 * corner);
1123    }
1124
1125    let mut verts1 = Vec::new();
1126    for corner in corners {
1127        verts1.push(obb1 * corner);
1128    }
1129
1130    gjk_3d(verts0, verts1)
1131}
1132
1133/// returns true if the capsule `cp0-cp1` with radius `cr0` overlaps the capsule `cp2-cp3` with radius `cr1`
1134pub fn capsule_vs_capsule<T: Float + FloatOps<T> + SignedNumberOps<T>, V: VecN<T> + VecFloatOps<T> + FloatOps<T> + SignedNumberOps<T>>(cp0: V, cp1: V, cr0: T, cp2: V, cp3: V, cr1: T) -> bool {
1135    // min sqr distance between capsule to save on sqrts
1136    let r2 = (cr0 + cr1) * (cr0 + cr1);
1137
1138    // check shortest distance between the 2 capsule line segments, if less than the sq radius we overlap
1139    if let Some((start, end)) = shortest_line_segment_between_line_segments(cp0, cp1, cp2, cp3) {
1140        let d = dist2(start, end);
1141        d < r2
1142    }
1143    else {
1144        // we must be orthogonal, which means there is no one single closest point between the 2 lines
1145        // find the distance between the 2 axes
1146        let l0 = normalize(cp1 - cp0);
1147        let t0 = dot(cp2 - cp0, l0);
1148        let ip0 = cp0 + l0 * t0;
1149        let d = dist2(cp2, ip0);
1150
1151        // check axes are within distance
1152        if d < r2 {
1153            let l1 = normalize(cp3 - cp2);
1154            let t1 = dot(cp0 - cp2, l1);
1155
1156            // now check if the capsule axes overlap
1157            if t0 >= T::zero() && t0*t0 < dist2(cp1, cp0) {
1158                true
1159            }
1160            else {
1161                t1 > T::zero() && t1*t1 < dist2(cp2, cp3)
1162            }
1163        }
1164        else {
1165            false
1166        }
1167    }
1168}
1169
1170/// returns the intersection point of ray with origin `r0` and direction `rv` against the sphere (or circle) centred at `s0` with radius `r`
1171pub fn ray_vs_sphere<T: Float + FloatOps<T> + NumberOps<T>, V: VecN<T> + VecFloatOps<T>>(r0: V, rv: V, s0: V, r: T) -> Option<V> {
1172    let oc = r0 - s0;
1173    let a = dot(rv, rv);
1174    let b = T::two() * dot(oc, rv);
1175    let c = dot(oc,oc) - r*r;
1176    let discriminant = b*b - T::four()*a*c;
1177    let hit = discriminant > T::zero();
1178    if !hit {
1179        None
1180    }
1181    else {
1182        let t1 = (-b - sqrt(discriminant)) / (T::two()*a);
1183        let t2 = (-b + sqrt(discriminant)) / (T::two()*a);
1184        let t = if t1 > T::zero() && t2 > T::zero() {
1185            min(t1, t2)
1186        }
1187        else if t1 > T::zero() {
1188            t1
1189        }
1190        else {
1191            t2
1192        };
1193        Some(r0 + rv * t)
1194    }
1195}
1196
1197/// returns the intersection point of the ray with origin `r0` and direction `rv` with the aabb defined by `aabb_min` and `aabb_max`
1198pub fn ray_vs_aabb<T: Number + NumberOps<T>, V: VecN<T>>(r0: V, rv: V, aabb_min: V, aabb_max: V) -> Option<V> {
1199    // http://gamedev.stackexchange.com/a/18459
1200    // min / max's from aabb axes
1201    let dirfrac = V::one() / rv;
1202    let tx = (aabb_min[0] - r0[0]) * dirfrac[0];
1203    let tm = (aabb_max[0] - r0[0]) * dirfrac[0];
1204    let mut tmin = min(tx, tm);
1205    let mut tmax = max(tx, tm);
1206    for i in 0..V::len() {
1207        let t1 = (aabb_min[i] - r0[i]) * dirfrac[i];
1208        let t2 = (aabb_max[i] - r0[i]) * dirfrac[i];
1209        tmin = max(min(t1, t2), tmin);
1210        tmax = min(max(t1, t2), tmax);
1211    }
1212
1213    if tmax < T::zero() || tmin > tmax {
1214        // if tmin > tmax, ray doesn't intersect AABB
1215        // if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us
1216        None
1217    }
1218    else {
1219        // otherwise tmin is length along the ray we intersect at
1220        Some(r0 + rv * tmin)
1221    }
1222}
1223
1224/// returns the intersection of the 3D ray with origin `r0` and direction `rv` with the obb defined by `mat`
1225pub fn ray_vs_obb<T: Float + NumberOps<T>,
1226    V: VecFloatOps<T> + NumberOps<T> + SignedNumberOps<T> + VecN<T> + SignedVecN<T>,
1227    M: MatTranslate<V> + MatInverse<T> + MatRotate3D<T, V> + MatN<T, V>
1228    + Into<Mat3<T>> + Copy>
1229    (r0: V, rv: V, mat: M) -> Option<V> where Mat3<T> : MatN<T, V> {
1230    let invm = mat.inverse();
1231    let tr1 = invm * r0;
1232    let rotm : Mat3<T> = invm.into();
1233    let trv = rotm * rv;
1234    let ip = ray_vs_aabb(tr1, normalize(trv), -V::one(), V::one());
1235    ip.map(|ip| mat * ip)
1236}
1237
1238/// returns the intersection point of ray `r0` and normalized direction `rv` with triangle `t0-t1-t2`
1239pub fn ray_vs_triangle<T: Float>(r0: Vec3<T>, rv: Vec3<T>, t0: Vec3<T>, t1: Vec3<T>, t2: Vec3<T>) -> Option<Vec3<T>> {
1240    // möller–trumbore intersection algorithm
1241    // ported verbatim https://en.wikipedia.org/wiki/Möller–Trumbore_intersection_algorithm
1242    let edge1 = t1 - t0;
1243    let edge2 = t2 - t0;
1244    let h = cross(rv, edge2);
1245    let a = dot(edge1, h);
1246    if a > -T::small_epsilon() && a < T::small_epsilon() {
1247        // ray is parallel to the triangle
1248        None
1249    }
1250    else {
1251        let f = T::one() / a;
1252        let s = r0 - t0;
1253        let u = f * dot(s, h);
1254        if u < T::zero() || u > T::one() {
1255            None
1256        }
1257        else {
1258            let q = cross(s, edge1);
1259            let v = f * dot(rv, q);
1260            if v < T::zero() || u + v > T::one() {
1261                None
1262            }
1263            else {
1264                // now we can compute t to find out where the intersection point is on the line
1265                let t = f * dot(edge2, q);
1266                if t > T::zero() {
1267                    Some(r0 + rv * t)
1268                }
1269                else {
1270                    // line intersects but ray does not
1271                    None
1272                }
1273            }
1274        }
1275    }
1276}
1277
1278/// returns the intersection point of ray wih origin `r0` and direction `rv` against the capsule with line `c0-c1` and radius `cr`
1279pub fn ray_vs_capsule<T: Float + FloatOps<T> + NumberOps<T> + SignedNumberOps<T>, V: VecN<T> + Cross<T> + VecFloatOps<T> + SignedNumberOps<T> + FloatOps<T>>(r0: V, rv: V, c0: V, c1: V, cr: T) -> Option<V> {
1280    // shortest line seg within radius will indicate we intersect an infinite cylinder about an axis
1281    let seg = shortest_line_segment_between_line_and_line_segment(r0, r0 + rv, c0, c1);
1282    let mut ipc = V::max_value();
1283    let mut bc = false;
1284    if let Some((l0, l1)) = seg {
1285        // check we intesect the cylinder
1286        if dist2(l0, l1) < sqr(cr) {
1287            // intesection of ray and infinite cylinder about axis
1288            // https://stackoverflow.com/questions/4078401/trying-to-optimize-line-vs-cylinder-intersection
1289            let a = c0;
1290            let b = c1;
1291            let v = rv;
1292            let r = cr;
1293
1294            let ab = b - a;
1295            let ao = r0 - a;
1296            let aoxab = cross(ao, ab);
1297            let vxab = cross(v, ab);
1298            let ab2 = dot(ab, ab);
1299
1300            let aa = dot(vxab, vxab);
1301            let bb = T::two() * dot(vxab, aoxab);
1302            let cc = dot(aoxab, aoxab) - (r*r * ab2);
1303            let dd = bb * bb - T::four() * aa * cc;
1304
1305            if dd >= T::zero() {
1306                let t = (-bb - sqrt(dd)) / (T::two() * aa);
1307                if t >= T::zero() {
1308                    // intersection point
1309                    ipc = r0 + rv * t;
1310                    // clamps to finite cylinder extents
1311                    let ipd = distance_on_line(ipc, a, b);
1312                    if ipd >= T::zero() && ipd <= dist(a, b) {
1313                        bc = true;
1314                    }
1315                }
1316            }
1317        }
1318    }
1319
1320    // if our line doesnt intersect the cylinder, we might still intersect the top / bottom sphere
1321    // test intersections with the end spheres
1322    let bs1 = ray_vs_sphere(r0, rv, c0, cr);
1323    let bs2 = ray_vs_sphere(r0, rv, c1, cr);
1324
1325    // get optional intersection points
1326    let ips1 = if let Some(ip) = bs1 {
1327        ip
1328    }
1329    else {
1330        V::max_value()
1331    };
1332
1333    let ips2 = if let Some(ip) = bs2 {
1334        ip
1335    }
1336    else {
1337        V::max_value()
1338    };
1339
1340    // we need to choose the closes intersection if we have multiple
1341    let ips : [V; 3] = [ips1, ips2, ipc];
1342    let bips : [bool; 3] = [bs1.is_some(), bs2.is_some(), bc];
1343
1344    let mut iclosest = -1;
1345    let mut dclosest = T::max_value();
1346    for i in 0..3 {
1347        if bips[i] {
1348            let dd = distance_on_line(ips[i], r0, r0 + rv);
1349            if dd < dclosest {
1350                iclosest = i as i32;
1351                dclosest = dd;
1352            }
1353        }
1354    }
1355
1356    // if we have a valid closest point
1357    if iclosest != -1 {
1358        Some(ips[iclosest as usize])
1359    }
1360    else {
1361        None
1362    }
1363}
1364
1365/// returns true if there is an intersection between ray wih origin `r0` and direction `rv` against the cylinder with line `c0-c1` and radius `cr`
1366/// the intersection point is return as an `Option` if it exists.
1367pub fn ray_vs_cylinder<T: Float + FloatOps<T> + NumberOps<T> + SignedNumberOps<T>>(r0: Vec3<T>, rv: Vec3<T>, c0: Vec3<T>, c1: Vec3<T>, cr: T) -> Option<Vec3<T>> {
1368    // intesection of ray and infinite cylinder about axis
1369    // https://stackoverflow.com/questions/4078401/trying-to-optimize-line-vs-cylinder-intersection
1370    let a = c0;
1371    let b = c1;
1372    let v = rv;
1373    let r = cr;
1374
1375    let ab = b - a;
1376    let ao = r0 - a;
1377    let aoxab = cross(ao, ab);
1378    let vxab = cross(v, ab);
1379    let ab2 = dot(ab, ab);
1380
1381    let aa = dot(vxab, vxab);
1382    let bb = T::two() * dot(vxab, aoxab);
1383    let cc = dot(aoxab, aoxab) - (r*r * ab2);
1384    let dd = bb * bb - T::four() * aa * cc;
1385
1386    if dd >= T::zero() {
1387        let t = (-bb - sqrt(dd)) / (T::two() * aa);
1388        if t >= T::zero() {
1389            // intersection point
1390            let ipc = r0 + rv * t;
1391            // clamps to finite cylinder extents
1392            let ipd = distance_on_line(ipc, a, b);
1393            if ipd >= T::zero() && ipd <= dist(a, b) {
1394                return Some(ipc);
1395            }
1396        }
1397    }
1398
1399    // intersect with the top and bottom circles
1400    let ip_top = ray_vs_plane(r0, rv, c0, normalize(c0 - c1));
1401    let ip_bottom = ray_vs_plane(r0, rv, c1, normalize(c1 - c0));
1402    let r2 = r*r;
1403
1404    let mut btop = false;
1405    if let Some(ip_top) = ip_top {
1406        if dist2(ip_top, c0) < r2 {
1407            btop = true;
1408        }
1409    }
1410
1411    if let Some(ip_bottom) = ip_bottom {
1412        if dist2(ip_bottom, c1) < r2 {
1413            if btop {
1414                if let Some(ip_top) = ip_top {
1415                    let d1 = distance_on_line(ip_top, r0, r0 + rv);
1416                    let d2 = distance_on_line(ip_bottom, r0, r0 + rv);
1417                    if d2 < d1 {
1418                        return Some(ip_bottom);
1419                    }
1420                }
1421            }
1422            else {
1423                return Some(ip_bottom);
1424            }
1425        }
1426    }
1427
1428    if btop {
1429        if let Some(ip_top) = ip_top {
1430            return Some(ip_top);
1431        }
1432    }
1433
1434
1435    None
1436}
1437
1438/// returns true if the sphere with centre `s` and radius `r` is inside the frustum defined by 6 planes packed as vec4's `.xyz = normal, .w = plane distance`
1439pub fn sphere_vs_frustum<T: Number>(s: Vec3<T>, r: T, planes: &[Vec4<T>; 6]) -> bool {
1440    for p in planes.iter().take(6) {
1441        let d = dot(s, Vec3::from(*p)) + p.w;
1442        if d > r {
1443            return false;
1444        }
1445    }
1446    true
1447}
1448
1449/// returns true if the aabb defined by `aabb_pos` (centre) and `aabb_extent` is inside the frustum defined by 6 planes packed as vec4's `.xyz = normal, .w = plane distance`
1450pub fn aabb_vs_frustum<T: SignedNumber + SignedNumberOps<T>>(aabb_pos: Vec3<T>, aabb_extent: Vec3<T>, planes: &[Vec4<T>; 6]) -> bool {
1451    let mut inside = true;
1452    for p in planes.iter().take(6) {
1453        let pn = Vec3::from(*p);
1454        let sign_flip = Vec3::signum(pn) * T::minus_one();
1455        let pd = p.w;
1456        let d2 = dot(aabb_pos + aabb_extent * sign_flip, pn);
1457        if d2 > -pd {
1458            inside = false;
1459        }
1460    }
1461    inside
1462}
1463
1464/// returns the intersection point if the line segment `l1-l2` intersects with `s1-s2`
1465pub fn line_segment_vs_line_segment<T: Float + SignedNumberOps<T> + FloatOps<T>>(l1: Vec3<T>, l2: Vec3<T>,  s1: Vec3<T>, s2: Vec3<T>) -> Option<Vec3<T>> {
1466    let da = l2 - l1;
1467    let db = s2 - s1;
1468    let dc = s1 - l1;
1469    if dot(dc, cross(da, db)) != T::zero() {
1470        // lines are not coplanar
1471        None
1472    }
1473    else {
1474        let s = dot(cross(dc, db), cross(da, db)) / mag2(cross(da, db));
1475        if s >= T::zero() && s <= T::one() {
1476            let ip = l1 + da * s;
1477            let t = distance_on_line(ip, s1, s2) / dist(s1, s2);
1478            if t >= T::zero() && t <= T::one() {
1479                Some(ip)
1480            }
1481            else {
1482                None
1483            }
1484        }
1485        else {
1486            None
1487        }
1488    }
1489}
1490
1491/// returns the intersection point if the infinite line `l1-l2` intersects with `s1-s2`
1492pub fn line_vs_line<T: Float + SignedNumberOps<T> + FloatOps<T>>(l1: Vec3<T>, l2: Vec3<T>, s1: Vec3<T>, s2: Vec3<T>) -> Option<Vec3<T>> {
1493    let da = l2 - l1;
1494    let db = s2 - s1;
1495    let dc = s1 - l1;
1496    if dot(dc, cross(da, db)) != T::zero() {
1497        // lines are not coplanar
1498        None
1499    }
1500    else {
1501        let s = dot(cross(dc, db), cross(da, db)) / mag2(cross(da, db));
1502        let ip = l1 + da * s;
1503        let t = distance_on_line(ip, s1, s2) / dist(s1, s2);
1504        if t >= T::zero() && t <= T::one() {
1505            Some(ip)
1506        }
1507        else {
1508            None
1509        }
1510    }
1511}
1512
1513/// returns the intersection point if the ray with origin `r0` and direction `rv` intersects the line segment `l1-l2`
1514pub fn ray_vs_line_segment<T: Float + SignedNumberOps<T> + FloatOps<T>>(r0: Vec3<T>, rv: Vec3<T>, l1: Vec3<T>, l2: Vec3<T>) -> Option<Vec3<T>> {
1515    let da = l2 - l1;
1516    let db = rv;
1517    let dc = r0 - l1;
1518    if dot(dc, cross(da, db)) != T::zero() {
1519        // lines are not coplanar
1520        None
1521    }
1522    else {
1523        let s = dot(cross(dc, db), cross(da, db)) / mag2(cross(da, db));
1524        let ip = l1 + da * s;
1525        let t = distance_on_ray(ip, r0, rv);
1526        if s >= T::zero() && s <= T::one() && t >= T::zero() {
1527            Some(ip)
1528        }
1529        else {
1530            None
1531        }
1532    }
1533}
1534
1535/// returns the shortest line segment between 2 line segments `p1-p2` and `p3-p4` as an option tuple where `.0` is the point on line segment 1 and `.1` is the point on line segment 2
1536pub fn shortest_line_segment_between_line_segments<T: Float + SignedNumberOps<T> + FloatOps<T>, V: VecN<T> + SignedNumberOps<T> + FloatOps<T> + Dot<T>>(p1: V, p2: V, p3: V, p4: V) -> Option<(V, V)> {
1537    // https://web.archive.org/web/20120404121511/http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline3d/lineline.c
1538
1539    let p13 = p1 - p3;
1540    let p43 = p4 - p3;
1541
1542    if approx(abs(p43), V::zero(), T::small_epsilon()) {
1543        return None;
1544    }
1545
1546    let p21 = p2 - p1;
1547    if approx(abs(p21), V::zero(), T::small_epsilon()) {
1548        return None;
1549    }
1550
1551    let d1343 = dot(p13, p43);
1552    let d4321 = dot(p43, p21);
1553    let d1321 = dot(p13, p21);
1554    let d4343 = dot(p43, p43);
1555    let d2121 = dot(p21, p21);
1556
1557    let denom = d2121 * d4343 - d4321 * d4321;
1558    if abs(denom) < T::small_epsilon() {
1559        return None;
1560    }
1561
1562    let numer = d1343 * d4321 - d1321 * d4343;
1563    let mua = saturate(numer / denom);
1564    let mub = saturate((d1343 + d4321 * mua) / d4343);
1565
1566    Some((
1567        p1 + (p21 * mua),
1568        p3 + (p43 * mub)
1569    ))
1570}
1571
1572/// returns the shortest line segment between 2 lines `p1-p2` and `p3-p4` as an option tuple where `.0` is the point on line segment 1 and `.1` is the point on line segment 2
1573pub fn shortest_line_segment_between_lines<T: Float + SignedNumberOps<T> + FloatOps<T>, V: VecN<T> + SignedNumberOps<T> + FloatOps<T> + Dot<T>>(p1: V, p2: V, p3: V, p4: V) -> Option<(V, V)> {
1574    // https://web.archive.org/web/20120404121511/http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline3d/lineline.c
1575
1576    let p13 = p1 - p3;
1577    let p43 = p4 - p3;
1578
1579    if approx(abs(p43), V::zero(), T::small_epsilon()) {
1580        return None;
1581    }
1582
1583    let p21 = p2 - p1;
1584    if approx(abs(p21), V::zero(), T::small_epsilon()) {
1585        return None;
1586    }
1587
1588    let d1343 = dot(p13, p43);
1589    let d4321 = dot(p43, p21);
1590    let d1321 = dot(p13, p21);
1591    let d4343 = dot(p43, p43);
1592    let d2121 = dot(p21, p21);
1593
1594    let denom = d2121 * d4343 - d4321 * d4321;
1595    if abs(denom) < T::small_epsilon() {
1596        return None;
1597    }
1598
1599    let numer = d1343 * d4321 - d1321 * d4343;
1600    let mua = numer / denom;
1601    let mub = (d1343 + d4321 * mua) / d4343;
1602
1603    Some((
1604        p1 + (p21 * mua),
1605        p3 + (p43 * mub)
1606    ))
1607}
1608
1609/// returns the shortest line segment between 2 line segments `p1-p2` and `p3-p4` as an option tuple where `.0` is the point on line segment 1 and `.1` is the point on line segment 2
1610pub fn shortest_line_segment_between_line_and_line_segment<T: Float + SignedNumberOps<T> + FloatOps<T>, V: VecN<T> + SignedNumberOps<T> + FloatOps<T> + Dot<T>>(p1: V, p2: V, p3: V, p4: V) -> Option<(V, V)> {
1611    // https://web.archive.org/web/20120404121511/http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline3d/lineline.c
1612
1613    let p13 = p1 - p3;
1614    let p43 = p4 - p3;
1615
1616    if approx(abs(p43), V::zero(), T::small_epsilon()) {
1617        return None;
1618    }
1619
1620    let p21 = p2 - p1;
1621    if approx(abs(p21), V::zero(), T::small_epsilon()) {
1622        return None;
1623    }
1624
1625    let d1343 = dot(p13, p43);
1626    let d4321 = dot(p43, p21);
1627    let d1321 = dot(p13, p21);
1628    let d4343 = dot(p43, p43);
1629    let d2121 = dot(p21, p21);
1630
1631    let denom = d2121 * d4343 - d4321 * d4321;
1632    if abs(denom) < T::small_epsilon() {
1633        return None;
1634    }
1635
1636    let numer = d1343 * d4321 - d1321 * d4343;
1637    let mua = numer / denom;
1638    let mub = saturate((d1343 + d4321 * mua) / d4343);
1639
1640    Some((
1641        p1 + (p21 * mua),
1642        p3 + (p43 * mub)
1643    ))
1644}
1645
1646/// returns soft clipping (in a cubic fashion) of `x`; let m be the threshold (anything above m stays unchanged), and n the value things will take when the signal is zero
1647pub fn almost_identity<T: Number + Float>(x: T, m: T, n: T) -> T {
1648    // <https://iquilezles.org/articles/functions/>
1649    let a = T::two()*n - m;
1650    let b = T::two()*m - T::three()*n;
1651    let t = x/m;
1652    if x > m {
1653        x
1654    }
1655    else {
1656        (a*t + b)*t*t + n
1657    }
1658}
1659
1660/// returns the integral smoothstep of `x` it's derivative is never larger than 1
1661pub fn integral_smoothstep<T: Number + Float + FloatOps<T>>(x: T, t: T) -> T {
1662    // inigo quilez: https://iquilezles.org/articles/functions/
1663    if x > t {
1664        x - t/T::two()
1665    }
1666    else {
1667        x*x*x*(T::one()-x*T::point_five()/t)/t/t
1668    }
1669}
1670
1671/// returns an exponential impulse (y position on a graph for `x`); `k` controls the stretching of the function
1672pub fn exp_impulse<T: Number + Float, X: Base<T> + FloatOps<T>>(k: X, x: X) -> X {
1673    // inigo quilez: https://iquilezles.org/articles/functions/
1674    let h = k * x;
1675    h * X::exp(X::one() - h)
1676}
1677
1678/// returns an quadratic impulse (y position on a graph for `x`); `k` controls the stretching of the function
1679pub fn quad_impulse<T: Number + Float + Base<T> + FloatOps<T>>(k: T, x: T) -> T {
1680    // inigo quilez: https://iquilezles.org/articles/functions/
1681    T::two() * T::sqrt(k) * x / (T::one()+k*x*x)
1682}
1683
1684/// returns a quadratic impulse (y position on a graph for `x`); `n` is the degree of the polynomial and `k` controls the stretching of the function
1685pub fn poly_impulse<T: Number + Float + Base<T> + FloatOps<T>>(k: T, x: T, n: T) -> T {
1686    // inigo quilez: https://iquilezles.org/articles/functions/
1687    let one = T::one();
1688    (n/(n-one))* T::powf((n-one)*k,one/n)*x/(one+k*T::powf(x,n))
1689}
1690
1691/// returns an exponential sustained impulse (y position on a graph for `x`); control on the width of attack with `k` and release with `f`
1692pub fn exp_sustained_impulse<T: SignedNumber + Float, X: Base<T> + FloatOps<T> + SignedNumberOps<T> + NumberOps<T>>(x: X, f: X, k: X) -> X {
1693    // inigo quilez: https://iquilezles.org/articles/functions/
1694    let s = X::max(x-f, X::zero());
1695    X::min(x*x/(f*f), X::one() + (X::two()/f)*s*X::exp(-k*s))
1696}
1697
1698/// returns a cubic pulse (y position on a graph for `x`); equivalent to: `smoothstep(c-w,c,x)-smoothstep(c,c+w,x)`
1699pub fn cubic_pulse<X: Float + SignedNumberOps<X>>(c: X, w: X, x: X) -> X {
1700    // inigo quilez: https://iquilezles.org/articles/functions/
1701    let mut x = abs(x - c);
1702    if x > w {
1703        X::zero()
1704    }
1705    else {
1706        x /= w;
1707        X::one() - x * x*(X::three() - X::two()*x)
1708    }
1709}
1710
1711/// returns an exponential step (y position on a graph for `x`); `k` is control parameter, `n` is power which gives sharper curves.
1712pub fn exp_step<T: SignedNumber + Float, X: Base<T> + FloatOps<T> + SignedNumberOps<T>>(x: X, k: X, n: T) -> X {
1713    // inigo quilez: https://iquilezles.org/articles/functions/
1714    X::exp(-k * X::powf(x, n))
1715}
1716
1717/// returns gain (y position on a graph for `x`); remapping the unit interval into the unit interval by expanding the sides and compressing the center
1718pub fn gain<T: SignedNumber + Float + FloatOps<T>>(x: T, k: T) -> T {
1719    // inigo quilez: https://iquilezles.org/articles/functions/
1720    let y = if x < T::point_five() {
1721        x
1722    }
1723    else {
1724        T::one()-x
1725    };
1726    let a = T::point_five()*T::powf(T::two()*(y), k);
1727    if x < T::point_five() {
1728        a
1729    }
1730    else {
1731        T::one() - a
1732    }
1733}
1734
1735/// returns a parabola (y position on a graph for `x`); use `k` to control its shape
1736pub fn parabola<T: SignedNumber + Float, X: Base<T> + FloatOps<T> + SignedNumberOps<T>>(x: X, k: T) -> X {
1737    // inigo quilez: https://iquilezles.org/articles/functions/
1738    powf(X::four() * x * (X::one() - x), k)
1739}
1740
1741/// returns a power curve (y position on a graph for `x`); this is a generalziation of the parabola
1742pub fn pcurve<T: SignedNumber + Float + Base<T> + FloatOps<T>>(x: T, a: T, b: T) -> T {
1743    // inigo quilez: https://iquilezles.org/articles/functions/
1744    let k = powf(a + b, a + b) / (powf(a, a) * powf(b, b));
1745    k * powf(x, a) * powf(T::one() - x, b)
1746}
1747
1748/// returns a sin curve (y position on a graph for `x`); can be used for some bouncing behaviors. give `k` different integer values to tweak the amount of bounces
1749pub fn sinc<T: SignedNumber + Float, X: Base<T> + FloatOps<T> + SignedNumberOps<T>>(x: X, k: X) -> X {
1750    // inigo quilez: https://iquilezles.org/articles/functions/
1751    let a = X::pi() * (k*x-X::one());
1752    X::sin(a)/a
1753}
1754
1755/// returns a hsv value in 0-1 range converted from `rgb` in 0-1 range
1756pub fn rgb_to_hsv<T: Float + SignedNumberOps<T> + Cast<T>>(rgb: Vec3<T>) -> Vec3<T> {
1757    // from Foley & van Dam p592
1758    // optimized: http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
1759    let mut r = rgb.x;
1760    let mut g = rgb.y;
1761    let mut b = rgb.z;
1762
1763    let mut k = T::zero();
1764    if g < b {
1765        std::mem::swap(&mut g, &mut b);
1766        k = T::minus_one();
1767    }
1768
1769    if r < g {
1770        std::mem::swap(&mut r, &mut g);
1771        k = -T::two() / T::from_f64(6.0) - k;
1772    }
1773
1774    let chroma = r - if g < b { g } else { b };
1775
1776    Vec3 {
1777        x: abs(k + (g - b) / (T::from_f64(6.0)  * chroma + T::small_epsilon())),
1778        y: chroma / (r + T::small_epsilon()),
1779        z: r
1780    }
1781}
1782
1783/// returns an rgb value in 0-1 range converted from `hsv` in 0-1 range
1784pub fn hsv_to_rgb<T: Float + FloatOps<T> + Cast<T>>(hsv: Vec3<T>) -> Vec3<T> {
1785    // from Foley & van Dam p593: http://en.wikipedia.org/wiki/HSL_and_HSV
1786    let h = hsv.x;
1787    let s = hsv.y;
1788    let v = hsv.z;
1789
1790    if s == T::zero() {
1791        // gray
1792        return Vec3 {
1793            x: v,
1794            y: v,
1795            z: v
1796        };
1797    }
1798
1799    let h = T::fmod(h, T::one()) / T::from_f64(0.16666666666);
1800    let i = h.as_i32();
1801    let f = h - floor(h);
1802    let p = v * (T::one() - s);
1803    let q = v * (T::one() - s * f);
1804    let t = v * (T::one() - s * (T::one() - f));
1805
1806    match i {
1807        0 => {
1808            Vec3::new(v, t, p)
1809        }
1810        1 => {
1811            Vec3::new(q, v, p)
1812        }
1813        2 => {
1814            Vec3::new(p, v, t)
1815        }
1816        3 => {
1817            Vec3::new(p, q, v)
1818        }
1819        4 => {
1820            Vec3::new(t, p, v)
1821        }
1822        _ => {
1823            Vec3::new(v, p, q)
1824        }
1825    }
1826}
1827
1828/// returns a vec4 of rgba in 0-1 range from a packed `rgba` which is inside u32 (4 bytes, 0xRRGGBBAA)
1829pub fn rgba8_to_vec4<T: Float + FloatOps<T> + Cast<T>>(rgba: u32) -> Vec4<T> {
1830    let one_over_255 = T::from_f32(1.0 / 255.0);
1831    Vec4 {
1832        x: T::from_u32((rgba >> 24) & 0xff) * one_over_255,
1833        y: T::from_u32((rgba >> 16) & 0xff) * one_over_255,
1834        z: T::from_u32((rgba >> 8) & 0xff) * one_over_255,
1835        w: T::from_u32(rgba & 0xff) * one_over_255
1836    }
1837}
1838
1839/// returns a packed u32 containing rgba8 (4 bytes, R8G8B8A8) converted from a Vec4 `v` of rgba in 0-1 range
1840pub fn vec4_to_rgba8<T: Float + Cast<T>>(v: Vec4<T>) -> u32 {
1841    let mut rgba : u32 = 0;
1842    let x = T::from_f32(255.0);
1843    rgba |= (v[0] * x).as_u32() << 24;
1844    rgba |= (v[1] * x).as_u32() << 16;
1845    rgba |= (v[2] * x).as_u32() << 8;
1846    rgba |= (v[3] * x).as_u32();
1847    rgba
1848}
1849
1850/// returns value `t` between the range `c` and `d` with offset `b` creating smooth easing at the start (t^2)
1851pub fn smooth_start2<T: Float, X: Base<T>>(t: X, b: X, c: X, d: X) -> X {
1852    let t = t/d;
1853    c * t*t + b
1854}
1855
1856/// returns value `t` between the range `c` and `d` with offset `b` creating smooth easing at the start (t^3)
1857pub fn smooth_start3<T: Float, X: Base<T>>(t: X, b: X, c: X, d: X) -> X {
1858    let t = t/d;
1859    c * t*t*t + b
1860}
1861
1862/// returns value `t` between the range `c` and `d` with offset `b` creating smooth easing at the start (t^4)
1863pub fn smooth_start4<T: Float, X: Base<T>>(t: X, b: X, c: X, d: X) -> X {
1864    let t = t/d;
1865    c * t*t*t*t + b
1866}
1867
1868/// returns value `t` between the range `c` and `d` with offset `b` creating smooth easing at the start (t^5)
1869pub fn smooth_start5<T: Float, X: Base<T>>(t: X, b: X, c: X, d: X) -> X {
1870    let t = t/d;
1871    c * t*t*t*t*t + b
1872}
1873
1874/// returns value `t` between the range `c` and `d` with offset `b` creating smooth easing at the end of t (t^2)
1875pub fn smooth_stop2<T: Float, X: Base<T> + SignedNumberOps<T>>(t: X, b: X, c: X, d: X) -> X {
1876    let t = t/d;
1877    -c * t * (t - X::two()) + b
1878}
1879
1880/// returns value `t` between the range `c` and `d` with offset `b` creating smooth easing at the end of t (t^3)
1881pub fn smooth_stop3<T: Float, X: Base<T> + SignedNumberOps<T>>(t: X, b: X, c: X, d: X) -> X {
1882    let t = t/d;
1883    c * (t*t*t + X::one()) + b
1884}
1885
1886/// returns value `t` between the range `c` and `d` with offset `b` creating smooth easing at the end of t (t^4)
1887pub fn smooth_stop4<T: Float, X: Base<T> + SignedNumberOps<T>>(t: X, b: X, c: X, d: X) -> X {
1888    let t = t/d;
1889    c * (t*t*t*t + X::one()) + b
1890}
1891
1892/// returns value `t` between the range `c` and `d` with offset `b` creating smooth easing at the end of t (t^5)
1893pub fn smooth_stop5<T: Float, X: Base<T> + SignedNumberOps<T>>(t: X, b: X, c: X, d: X) -> X {
1894    let t = t/d;
1895    c * (t*t*t*t*t + X::one()) + b
1896}
1897
1898/// returns the cubic interpolation of bezier control points `p1-p2-p3-p4` with percentage t
1899pub fn cubic_interpolate<T: Float, V: VecN<T> + NumberOps<T> + VecFloatOps<T>>(p1: V, p2: V, p3: V, p4: V, t: T) -> V {
1900    p1 * (T::one() - t) * (T::one() - t) * (T::one() - t) +
1901    p2 * T::three() * t * (T::one() - t) * (T::one() - t) +
1902    p3 * T::three() * t * t * (T::one() - t) +
1903    p4 * t * t * t
1904}
1905
1906/// returns the tangent of bezier control points `p1-p2-p3-p4` with percentage t
1907pub fn cubic_tangent<T: Float, V: VecN<T> + NumberOps<T> + VecFloatOps<T>>(p1: V, p2: V, p3: V, p4: V, t: T) -> V {
1908    p1 * (-T::one() + T::two() * t - t * t) +
1909    p2 * (T::one() - T::four() * t + T::three() * t * t) +
1910    p3 * (T::two() * t - T::three() * t * t) +
1911    p4 * (t * t)
1912}
1913
1914/// returns the morten order index from `x,y` position
1915pub fn morton_xy(x: u64, y: u64) -> u64 {
1916    let mut x = x;
1917    x = (x | (x << 16)) & 0x0000FFFF0000FFFF;
1918    x = (x | (x << 8)) & 0x00FF00FF00FF00FF;
1919    x = (x | (x << 4)) & 0x0F0F0F0F0F0F0F0F;
1920    x = (x | (x << 2)) & 0x3333333333333333;
1921    x = (x | (x << 1)) & 0x5555555555555555;
1922
1923    let mut y = y;
1924    y = (y | (y << 16)) & 0x0000FFFF0000FFFF;
1925    y = (y | (y << 8)) & 0x00FF00FF00FF00FF;
1926    y = (y | (y << 4)) & 0x0F0F0F0F0F0F0F0F;
1927    y = (y | (y << 2)) & 0x3333333333333333;
1928    y = (y | (y << 1)) & 0x5555555555555555;
1929
1930    x | (y << 1)
1931}
1932
1933/// returns the morten order index from `x,y,z` position
1934pub fn morton_xyz(x: u64, y: u64, z: u64) -> u64 {
1935    let mut x = x;
1936    x = (x | (x << 16)) & 0xFFFF00000000FFFF;
1937    x = (x | (x <<  8)) & 0xF00F00F00F00F;
1938    x = (x | (x <<  4)) & 0x30C30C30C30C30C3;
1939    x = (x | (x <<  2)) & 0x9249249249249249;
1940
1941    let mut y = y;
1942    y = (y | (y << 16)) & 0xFFFF00000000FFFF;
1943    y = (y | (y <<  8)) & 0xF00F00F00F00F;
1944    y = (y | (y <<  4)) & 0x30C30C30C30C30C3;
1945    y = (y | (y <<  2)) & 0x9249249249249249;
1946
1947    let mut z = z;
1948    z = (z | (z << 16)) & 0xFFFF00000000FFFF;
1949    z = (z | (z <<  8)) & 0xF00F00F00F00F;
1950    z = (z | (z <<  4)) & 0x30C30C30C30C30C3;
1951    z = (z | (z <<  2)) & 0x9249249249249249;
1952
1953    x | (y << 1) | (z << 2)
1954}
1955
1956/// returns the number even bits extracted from `x` as set bits in the return; value `0b010101` returns `0b111`
1957pub fn morton_1(x: u64) -> u64 {
1958    let mut x = x & 0x5555555555555555;
1959    x = (x | (x >> 1)) & 0x3333333333333333;
1960    x = (x | (x >> 2)) & 0x0F0F0F0F0F0F0F0F;
1961    x = (x | (x >> 4)) & 0x00FF00FF00FF00FF;
1962    x = (x | (x >> 8)) & 0x0000FFFF0000FFFF;
1963    x = (x | (x >> 16)) & 0x00000000FFFFFFFF;
1964    x
1965}
1966
1967/// returns the number of bits divisible by 3 in `x`. value `0b001001001` returns `0b111`
1968pub fn morton_2(x: u64) -> u64 {
1969    let mut x = x & 0x9249249249249249;
1970    x = (x | (x >> 2)) & 0x30C30C30C30C30C3;
1971    x = (x | (x >> 4)) & 0xF00F00F00F00F;
1972    x = (x | (x >> 8)) & 0xFF0000FF0000FF;
1973    x = (x | (x >> 16)) &  0xFFFF00000000FFFF;
1974    x = (x | (x >> 32)) & 0x00000000FFFFFFFF;
1975    x
1976}
1977
1978/// returns the `x,y` grid position for morten order index `d`
1979pub fn morton_to_xy(d: u64) -> (u64, u64) {
1980    (morton_1(d), morton_1(d >> 1))
1981}
1982
1983/// returns the `x,y,z` grid position for morten order index `d`
1984pub fn morton_to_xyz(d: u64) -> (u64, u64, u64) {
1985    (morton_2(d), morton_2(d >> 1), morton_2(d >> 2))
1986}
1987
1988/// remap `v` within `in_start` -> `in_end` range to the new range `out_start` -> `out_end`
1989pub fn map_to_range<T: Float, X: Base<T>>(v: X, in_start: X, in_end: X, out_start: X, out_end: X) -> X {
1990    let slope = X::one() * (out_end - out_start) / (in_end - in_start);
1991    out_start + slope * (v - in_start)
1992}
1993
1994/// finds support vertices for gjk based on convex meshses where `convex0` and `convex1` are an array of vertices that form a convex hull
1995pub fn gjk_mesh_support_function<T: Float + FloatOps<T> + NumberOps<T> + SignedNumberOps<T>, V: VecN<T> + VecFloatOps<T> + SignedNumberOps<T> + FloatOps<T>> (convex0: &[V], convex1: &[V], dir: V) -> V {
1996    let furthest_point = |dir: V, vertices: &[V]| -> V {
1997        let mut fd = -T::max_value();
1998        let mut fv = vertices[0];
1999        for v in vertices {
2000            let d = dot(dir, *v);
2001            if d > fd {
2002                fv = *v;
2003                fd = d;
2004            }
2005        }
2006        fv
2007    };
2008
2009    // selects the furthest points on the 2 meshes in opposite directions
2010    let fp0 = furthest_point(dir, convex0);
2011    let fp1 = furthest_point(-dir, convex1);
2012    fp0 - fp1
2013}
2014
2015/// simplex evolution for 2d mesh overlaps using gjk
2016fn handle_simplex_2d<T: Float + FloatOps<T> + NumberOps<T> + SignedNumber + SignedNumberOps<T>, V: VecN<T> + VecFloatOps<T> + Triple<T>> (simplex: &mut Vec<V>, dir: &mut V) -> bool {
2017    match simplex.len() {
2018        2 => {
2019            let a = simplex[1];
2020            let b = simplex[0];
2021            let ab = b - a;
2022            let ao = -a;
2023
2024            *dir = vector_triple(ab, ao, ab);
2025
2026            false
2027        },
2028        3 => {
2029            let a = simplex[2];
2030            let b = simplex[1];
2031            let c = simplex[0];
2032
2033            let ab = b - a;
2034            let ac = c - a;
2035            let ao = -a;
2036
2037            let abperp = vector_triple(ac, ab, ab);
2038            let acperp = vector_triple(ab, ac, ac);
2039
2040            if dot(abperp, ao) > T::zero() {
2041                simplex.remove(0);
2042                *dir = abperp;
2043                false
2044            }
2045            else if dot(acperp, ao) > T::zero() {
2046                simplex.remove(1);
2047                *dir = acperp;
2048                false
2049            }
2050            else {
2051                true
2052            }
2053        }
2054        _ => {
2055            panic!("we should always have 2 or 3 points in the simplex!");
2056        }
2057    }
2058}
2059
2060/// returns true if the 2d convex hull `convex0` overlaps with `convex1` using the gjk algorithm
2061pub fn gjk_2d<T: Float + FloatOps<T> + NumberOps<T> + SignedNumber + SignedNumberOps<T>, V: VecN<T> + FloatOps<T> + SignedNumberOps<T> + VecFloatOps<T> + Triple<T>>(convex0: Vec<V>, convex1: Vec<V>) -> bool {
2062    // implemented following details in this insightful video: https://www.youtube.com/watch?v=ajv46BSqcK4
2063
2064    // start with arbitrary direction
2065    let mut dir = V::unit_x();
2066    let support = gjk_mesh_support_function(&convex0, &convex1, dir);
2067    dir = normalize(-support);
2068
2069    // iterative build and test simplex
2070    let mut simplex = vec![support];
2071
2072    let max_iters = 32;
2073    for _i in 0..max_iters {
2074        let a = gjk_mesh_support_function(&convex0, &convex1, dir);
2075
2076        if dot(a, dir) < T::zero() {
2077            return false;
2078        }
2079        simplex.push(a);
2080
2081        if handle_simplex_2d(&mut simplex, &mut dir) {
2082            return true;
2083        }
2084    }
2085
2086    // if we reach here we likely have got stuck in a simplex building loop, we assume the shapes are touching but not intersecting
2087    false
2088}
2089
2090/// returns true if the convex hull `convex0` overlaps `convex1` where convex hull is an array of vertices forming a 2D convex polygon
2091pub fn convex_hull_vs_convex_hull<T: Float + FloatOps<T> + NumberOps<T> + SignedNumber + SignedNumberOps<T>, V: VecN<T> + FloatOps<T> + SignedNumberOps<T> + VecFloatOps<T> + Triple<T>>(convex0: Vec<V>, convex1: Vec<V>) -> bool {
2092    gjk_2d(convex0, convex1)
2093}
2094
2095/// simplex evolution for 3d mesh overlaps
2096fn handle_simplex_3d<T: Float + FloatOps<T> + NumberOps<T> + SignedNumber + SignedNumberOps<T>, V: VecN<T> + VecFloatOps<T> + Triple<T> + Cross<T>> (simplex: &mut Vec<V>, dir: &mut V) -> bool {
2097    match simplex.len() {
2098        2 => {
2099            let a = simplex[1];
2100            let b = simplex[0];
2101
2102            let ab = b - a;
2103            let ao = -a;
2104
2105            *dir = vector_triple(ab, ao, ab);
2106
2107            false
2108        },
2109        3 => {
2110            let a = simplex[2];
2111            let b = simplex[1];
2112            let c = simplex[0];
2113
2114            let ab = b - a;
2115            let ac = c - a;
2116            let ao = -a;
2117
2118            *dir = cross(ac, ab);
2119
2120            // flip normal so it points toward the origin
2121            if dot(*dir, ao) < T::zero() {
2122                *dir = -*dir;
2123            }
2124
2125            false
2126        },
2127        4 => {
2128            let a = simplex[3];
2129            let b = simplex[2];
2130            let c = simplex[1];
2131            let d = simplex[0];
2132
2133            let centre = (a+b+c+d) / T::four();
2134
2135            let ab = b - a;
2136            let ac = c - a;
2137            let ad = d - a;
2138            let ao = -a;
2139
2140            let mut abac = cross(ab, ac);
2141            let mut acad = cross(ac, ad);
2142            let mut adab = cross(ad, ab);
2143
2144            // flip the normals so they always face outward
2145            let centre_abc = (a + b + c) / T::three();
2146            let centre_acd = (a + c + d) / T::three();
2147            let centre_adb = (a + d + b) / T::three();
2148
2149            if dot(centre - centre_abc, abac) > T::zero() {
2150                abac = -abac;
2151            }
2152
2153            if dot(centre - centre_acd, acad) > T::zero() {
2154                acad = -acad;
2155            }
2156
2157            if dot(centre - centre_adb, adab) > T::zero() {
2158                adab = -adab;
2159            }
2160
2161            if dot(abac, ao) > T::zero() {
2162                // erase c
2163                simplex.remove(0);
2164                *dir = abac;
2165                false
2166            }
2167            else if dot(acad, ao) > T::zero() {
2168                // erase a
2169                simplex.remove(1);
2170                *dir = acad;
2171                false
2172            }
2173            else if dot(adab, ao) > T::zero() {
2174                // erase b
2175                simplex.remove(2);
2176                *dir = adab;
2177                false
2178            }
2179            else {
2180                true
2181            }
2182        },
2183        _ => {
2184            panic!("we should always have 2, 3 or 4 points in the simplex!");
2185        }
2186    }
2187}
2188
2189/// returns true if the 3D convex hull `convex0` overlaps with `convex1` using the gjk algorithm
2190pub fn gjk_3d<T: Float + FloatOps<T> + NumberOps<T> + SignedNumber + SignedNumberOps<T>, V: VecN<T> + FloatOps<T> + SignedNumberOps<T> + VecFloatOps<T> + Triple<T> + Cross<T>>(convex0: Vec<V>, convex1: Vec<V>) -> bool {
2191    // implemented following details in this insightful video: https://www.youtube.com/watch?v=ajv46BSqcK4
2192
2193    // start with arbitrary direction
2194    let mut dir = V::unit_x();
2195    let support = gjk_mesh_support_function(&convex0, &convex1, dir);
2196    dir = normalize(-support);
2197
2198    // iterative build and test simplex
2199    let mut simplex = vec![support];
2200
2201    let max_iters = 32;
2202    for _i in 0..max_iters {
2203        let a = gjk_mesh_support_function(&convex0, &convex1, dir);
2204
2205        if dot(a, dir) < T::zero() {
2206            return false;
2207        }
2208        simplex.push(a);
2209
2210        if handle_simplex_3d(&mut simplex, &mut dir) {
2211            return true;
2212        }
2213    }
2214
2215    // if we reach here we likely have got stuck in a simplex building loop, we assume the shapes are touching but not intersecting
2216    false
2217}
2218
2219/// export float types and all functions for qick and easy integration
2220pub mod prelude {
2221    #[doc(hidden)]
2222    pub use crate::{
2223        // modules
2224        vec::*,
2225        mat::*,
2226        num::*,
2227        quat::*,
2228        swizz::*,
2229
2230        // types
2231        Vec2f, Vec3f, Vec4f,
2232        Mat2f, Mat3f, Mat34f, Mat4f,
2233        Quatf,
2234
2235        // functions in lib.rs
2236        *,
2237    };
2238}
2239
2240// tests;;
2241// quilez functions
2242// quat tests