maths_rs/
lib.rs

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