Skip to main content

mgf/
simplex.rs

1// Copyright 2017 Matthew Plant. This file is part of MGF.
2//
3// MGF is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// MGF is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU Lesser General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with MGF. If not, see <http://www.gnu.org/licenses/>.
15
16// TODO(map): This whole approach needs to be redone. Turns out this half-baked
17// idea of mine is way slower than just using an enum. Go figure.
18
19use std::f32;
20use std::fmt;
21use std::mem;
22use std::collections::HashMap;
23
24use cgmath::prelude::*;
25use cgmath::{EuclideanSpace, InnerSpace, Point3, Vector3};
26use crate::geom::*;
27use crate::collision::*;
28use crate::pool::*;
29
30pub struct Simplex<Point = Point3<f32>>
31where
32    Point: Into<Point3<f32>> + From<Point3<f32>> + Copy + Clone + 'static
33{
34    points: [Point; 4],
35    state: &'static SimplexState<Point>,
36}
37
38impl<Point> fmt::Debug for Simplex<Point>
39where
40    Point: Into<Point3<f32>> + From<Point3<f32>> + Copy + Clone + 'static + fmt::Debug
41{
42    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43        #[derive(Debug)]
44        enum StateName {
45            Vertex,
46            Edge,
47            Face,
48            Volume
49        };
50        let (state, points) = if self.state as *const _ == &VERTEX_DATAPTRLOC as *const _ {
51            (StateName::Vertex, &self.points[..1])
52        } else if self.state as *const _ == &EDGE_DATAPTRLOC as * const _  {
53            (StateName::Edge, &self.points[..2])
54        } else if self.state as * const _  == &FACE_DATAPTRLOC as * const _ {
55            (StateName::Face, &self.points[..3])
56        } else {
57            (StateName::Volume, &self.points[..4])
58        };
59        write!(f, "Simplex {{ state: {:?}, points: {:?} }}", state, points)
60    }
61}
62
63impl<Point> From<[Point; 1]> for Simplex<Point>
64where
65    Point: Into<Point3<f32>> + From<Point3<f32>> + Copy + Clone + 'static 
66{
67    fn from(p: [Point; 1]) -> Self {
68        Self::from(p[0])
69    }
70}
71          
72impl<Point> From<Point> for Simplex<Point>
73where
74    Point: Into<Point3<f32>> + From<Point3<f32>> + Copy + Clone + 'static
75{
76    fn from(p: Point) -> Self {
77        Simplex {
78            points: [
79                p,
80                Point::from(Point3::new(0.0, 0.0, 0.0)),
81                Point::from(Point3::new(0.0, 0.0, 0.0)),
82                Point::from(Point3::new(0.0, 0.0, 0.0)),
83            ],
84            state: &VERTEX_DATAPTRLOC,
85        }
86    }
87}
88
89impl<Point> From<[Point; 2]> for Simplex<Point>
90where
91    Point: Into<Point3<f32>> + From<Point3<f32>> + Copy + Clone + 'static
92{
93    fn from(p: [Point; 2]) -> Self {
94        Self::from((p[0], p[1]))
95    }
96}
97
98impl<Point> From<(Point, Point)> for Simplex<Point>
99where
100    Point: Into<Point3<f32>> + From<Point3<f32>> + Copy + Clone + 'static
101{
102    fn from(p: (Point, Point)) -> Self {
103        Simplex {
104            points: [
105                p.0,
106                p.1,
107                Point::from(Point3::new(0.0, 0.0, 0.0)),
108                Point::from(Point3::new(0.0, 0.0, 0.0)),
109            ],
110            state: &EDGE_DATAPTRLOC,
111        }
112    }
113}
114
115impl<Point> From<[Point; 3]> for Simplex<Point>
116where
117    Point: Into<Point3<f32>> + From<Point3<f32>> + Copy + Clone + 'static
118{
119    fn from(p: [Point; 3]) -> Self {
120        Self::from((p[0], p[1], p[2]))
121    }
122}
123          
124impl<Point> From<(Point, Point, Point)> for Simplex<Point>
125where
126    Point: Into<Point3<f32>> + From<Point3<f32>> + Copy + Clone + 'static
127{
128    fn from(p: (Point, Point, Point)) -> Self {
129        Simplex {
130            points: [
131                p.0,
132                p.1,
133                p.2,
134                Point::from(Point3::new(0.0, 0.0, 0.0)),
135            ],
136            state: &FACE_DATAPTRLOC,
137        }
138    }
139}
140
141impl<Point> From<[Point; 4]> for Simplex<Point>
142where
143    Point: Into<Point3<f32>> + From<Point3<f32>> + Copy + Clone + 'static
144{
145    fn from(p: [Point; 4]) -> Self {
146        Self::from((p[0], p[1], p[2], p[3]))
147    }
148}
149
150impl<Point> From<(Point, Point, Point, Point)> for Simplex<Point>
151where
152    Point: Into<Point3<f32>> + From<Point3<f32>> + Copy + Clone + 'static
153{
154    fn from(p: (Point, Point, Point, Point)) -> Self {
155        Simplex {
156            points: [
157                p.0,
158                p.1,
159                p.2,
160                p.3,
161            ],
162            state: &VOLUME_DATAPTRLOC,
163        }
164    }
165}
166
167impl<Point> Simplex<Point>
168where
169    Point: Into<Point3<f32>> + From<Point3<f32>> + Copy + Clone + 'static + fmt::Debug
170{
171    /// Finds the closest point on the shape to the origin
172    pub fn closest_point_to_origin<S>(&mut self, shape: &S) -> Point3<f32>
173    where
174        S: Convex<Point>
175    {
176        let mut prev_norm = Vector3::zero();
177        loop {
178            let (min_norm, next_state) = self.state.min_norm(&mut self.points);
179            if min_norm.magnitude2() < COLLISION_EPSILON  {
180                // If the simplex is not a tetrahedron, we want to sample more 
181                // axis until it is one.
182                for i in self.state.len()..4 {
183                    let min_norm = -Vector3::new(prev_norm.z, prev_norm.x, prev_norm.y);
184                    let support = shape.support(-min_norm.normalize());
185                    prev_norm = -min_norm.normalize();
186                    self.points[i] = support;
187                }
188                self.state = &VOLUME_DATAPTRLOC;
189                return Point3::new(0.0, 0.0, 0.0);
190            }
191            let support = shape.support(-min_norm.normalize());
192            let support_v = support.into().to_vec();
193            prev_norm = min_norm;
194            if min_norm.magnitude2() >= support_v.magnitude2() {
195                return Point3::from_vec(min_norm);
196            }
197            self.state = next_state;
198            self.state.add_point(&mut self.points, support);
199        }
200    }
201}
202
203trait SimplexState<Point>
204where
205    Point: Into<Point3<f32>> + Copy + Clone + 'static
206{
207    fn min_norm(&self, _: &mut [Point; 4]) -> (Vector3<f32>, &'static SimplexState<Point>);
208
209    fn add_point(&self, _: &mut [Point; 4], _: Point);
210
211    fn len(&self) -> usize;
212}
213
214struct VertexSimplex{}
215struct EdgeSimplex{}
216struct FaceSimplex{}
217struct VolumeSimplex{}
218
219static VERTEX_DATAPTRLOC: VertexSimplex = VertexSimplex{};
220static EDGE_DATAPTRLOC: EdgeSimplex = EdgeSimplex{};
221static FACE_DATAPTRLOC: FaceSimplex = FaceSimplex{};
222static VOLUME_DATAPTRLOC: VolumeSimplex = VolumeSimplex{};
223
224impl<Point> SimplexState<Point> for VertexSimplex
225where
226    Point: Into<Point3<f32>> + Copy + Clone + 'static
227{
228    fn min_norm(&self, simp: &mut [Point; 4]) -> (Vector3<f32>, &'static SimplexState<Point>) {
229        (simp[0].into().to_vec(), &EDGE_DATAPTRLOC)
230    }
231
232    fn add_point(&self, simp:  &mut [Point; 4], p: Point) {
233        simp[0] = p
234    }
235
236    fn len(&self) -> usize { 1 }
237}
238
239impl<Point> SimplexState<Point> for EdgeSimplex
240where
241    Point: Into<Point3<f32>> + Copy + Clone + 'static
242{
243    fn min_norm(&self, simp: &mut [Point; 4]) -> (Vector3<f32>, &'static SimplexState<Point>) {
244        let ab = simp[1].into() - simp[0].into();
245        let t = ab.dot(-simp[0].into().to_vec());
246        if t <= 0.0 {
247            (simp[0].into().to_vec(), &EDGE_DATAPTRLOC)
248        } else {
249            let denom = ab.dot(ab);
250            if t >= denom {
251                simp[0] = simp[1];
252                (simp[1].into().to_vec(), &EDGE_DATAPTRLOC)
253            } else {
254                (simp[0].into().to_vec() + ab * (t / denom), &FACE_DATAPTRLOC)
255            }
256        }
257    }
258
259    fn add_point(&self, simp: &mut [Point; 4], p: Point) {
260        simp[1] = p
261    }
262
263    fn len(&self) -> usize { 2 }
264}    
265
266
267impl<Point> SimplexState<Point> for FaceSimplex
268where
269    Point: Into<Point3<f32>> + Copy + Clone + 'static
270{
271    fn min_norm(&self, simp: &mut [Point; 4]) -> (Vector3<f32>, &'static SimplexState<Point>) {
272        let (a, b, c): (Point3<f32>, Point3<f32>, Point3<f32>) = (
273            simp[0].into(), simp[1].into(), simp[2].into()
274        );
275        let ab = b - a;
276        let ac = c - a;
277        let ap = -a.to_vec();
278        let d1 = ab.dot(ap);
279        let d2 = ac.dot(ap);
280
281        // Vertex region A
282        if d1 <= 0.0 && d2 <= 0.0 {
283            return (simp[0].into().to_vec(), &EDGE_DATAPTRLOC);
284        }
285
286        // Vertex region B
287        let bp = -b.to_vec();
288        let d3 = ab.dot(bp);
289        let d4 = ac.dot(bp);
290        if d3 >= 0.0 && d4 <= d3 {
291            simp[0] = simp[1];
292            return (simp[1].into().to_vec(), &EDGE_DATAPTRLOC);
293        }
294
295        // Edge region AB
296        let vc = d1 * d4 - d3 * d2;
297        if vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0 {
298            let v = d1 / (d1 - d3);
299            return ((simp[0].into().to_vec() + ab * v), &FACE_DATAPTRLOC);
300        }
301
302        // Vertex region C
303        let cp = -c.to_vec();
304        let d5 = ab.dot(cp);
305        let d6 = ac.dot(cp);
306        if d6 >= 0.0 && d5 <= d6 {
307            simp[0] = simp[2];
308            return (simp[2].into().to_vec(), &EDGE_DATAPTRLOC);
309        }
310
311        // Edge region AC
312        let vb = d5 * d2 - d1 * d6;
313        if vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0 {
314            let w = d2 / (d2 - d6);
315            simp[1] = simp[2];
316            return ((simp[0].into().to_vec() + ac * w), &FACE_DATAPTRLOC);
317        }
318
319        // Edge region BC
320        let va = d3 * d6 - d5 * d4;
321        if va <= 0.0 && (d4 - d3) >= 0.0 && (d5 - d6) >= 0.0 {
322            let w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
323            simp[0] = simp[2];
324            return ((simp[1].into().to_vec() + (simp[2].into() - simp[1].into()) * w), &FACE_DATAPTRLOC);
325        }
326
327        let denom = 1.0 / (va + vb + vc);
328        let v = vb * denom;
329        let w = vc * denom;
330        ((simp[0].into().to_vec() + ab * v + ac * w), &VOLUME_DATAPTRLOC)
331    }
332
333    fn add_point(&self, simp:  &mut [Point; 4], p: Point) {
334        simp[2] = p;
335    }
336
337    fn len(&self) -> usize { 3 }
338}
339
340fn origin_outside_plane(
341    a: Vector3<f32>, b: Vector3<f32>, c: Vector3<f32>, d: Vector3<f32>
342) -> bool {
343    let ab_x_ac = (b - a).cross(c - a);
344    let sign_p = (-a).dot(ab_x_ac);
345    let sign_d = (d - a).dot(ab_x_ac);
346    sign_p * sign_d < 0.0
347}
348
349impl<Point> SimplexState<Point> for VolumeSimplex
350where
351    Point: Into<Point3<f32>> + Copy + Clone + 'static
352{
353    fn min_norm(&self, simp: &mut [Point; 4]) -> (Vector3<f32>, &'static SimplexState<Point>) {
354        let mut closest_pt: Vector3<f32> = Vector3::zero();
355        let mut best_dist: f32 = f32::INFINITY;
356        let mut next_state: &'static SimplexState<Point> = &VERTEX_DATAPTRLOC;
357        let (a, b, c, d) = (simp[0], simp[1], simp[2], simp[3]);
358        let (av, bv, cv, dv) = (a.into().to_vec(), b.into().to_vec(), c.into().to_vec(), d.into().to_vec());
359        // Test face abc
360        if origin_outside_plane(av, bv, cv, dv) {
361            let mut new_simp = [ a, b, c, d ];
362            let (p, new_state) = FACE_DATAPTRLOC.min_norm(&mut new_simp);
363            let new_dist = p.magnitude2();
364            if new_dist < best_dist {
365                closest_pt = p;
366                best_dist = new_dist;
367                next_state = new_state;
368                *simp = new_simp;
369            }
370        }
371        // Test face acd
372        if origin_outside_plane(av, cv, dv, bv) {
373            let mut new_simp = [ a, c, d, b ];
374            let (p, new_state) = FACE_DATAPTRLOC.min_norm(&mut new_simp);
375            let new_dist = p.magnitude2();
376            if new_dist < best_dist {
377                closest_pt = p;
378                best_dist = new_dist;
379                next_state = new_state;
380                *simp = new_simp;
381            }
382        }
383        // Test face adb
384        if origin_outside_plane(av, dv, bv, cv) {
385            let mut new_simp = [ a, d, b, c ];
386            let (p, new_state) = FACE_DATAPTRLOC.min_norm(&mut new_simp);
387            let new_dist = p.magnitude2();
388            if new_dist < best_dist {
389                closest_pt = p;
390                best_dist = new_dist;
391                next_state = new_state;
392                *simp = new_simp;
393            }
394        }
395        // Test face bdc
396        if origin_outside_plane(bv, dv, cv, av) {
397            let mut new_simp = [ b, d, c, a ];
398            let (p, new_state) = FACE_DATAPTRLOC.min_norm(&mut new_simp);
399            let new_dist = p.magnitude2();
400            if new_dist < best_dist {
401                closest_pt = p;
402                next_state = new_state;
403                *simp = new_simp;
404            }
405        }
406
407        (closest_pt, next_state)
408    }
409
410    fn add_point(&self, simp: &mut [Point; 4], p: Point) {
411        simp[3] = p
412    }
413
414    fn len(&self) -> usize { 4 }
415}
416
417#[derive(Default)]
418struct EdgeMap {
419    map: HashMap<[ (u32, u32, u32); 2 ], [ (Point3<f32>, Point3<f32>); 2 ]>,
420}
421
422impl EdgeMap {
423    fn add_edge(&mut self, a: SupportPoint, b: SupportPoint) {
424        let la = (a.a, a.b);
425        let lb = (b.a, b.b);
426        let a = unsafe {
427            (
428                mem::transmute::<f32, u32>(a.p.x),
429                mem::transmute::<f32, u32>(a.p.y),
430                mem::transmute::<f32, u32>(a.p.z),
431            )
432        };
433        let b = unsafe {
434            (
435                mem::transmute::<f32, u32>(b.p.x),
436                mem::transmute::<f32, u32>(b.p.y),
437                mem::transmute::<f32, u32>(b.p.z),
438            )
439        };
440        let ba = [ b, a ];
441        if self.map.contains_key(&ba) {
442            self.map.remove(&ba);
443            return;
444        }
445        self.map.insert(
446            [ a, b ],
447            [ la, lb ]
448        );
449    }
450}
451        
452
453impl Simplex<SupportPoint> {
454    /// Generates a contact from a simplex. This uses the EPA algorithm. Based on
455    /// the description here: http://hacktank.net/blog/?p=119
456    pub fn compute_contact<S1, S2>(&self, s1: &S1, s2: &S2) -> Contact
457    where
458        S1: Convex,
459        S2: Convex
460    {
461        if self.state.len() != 4 {
462            panic!("simplex is too small");
463        }
464        let diff = MinkowskiDiff{ s1, s2 };
465        let [ a, b, c, d ] = self.points;
466        let mut tris = Pool::from(
467            vec![
468                (a, b, c),
469                (a, c, d),
470                (a, d, b),
471                (b, d, c)
472            ]
473        );
474        let mut edges = EdgeMap::default();
475        const MAX_ITERATIONS: usize = 100;
476        for iter in 0..=MAX_ITERATIONS {
477            let (closest_dist, closest_i, closest_n) = {
478                let mut closest_dist = f32::INFINITY;
479                let mut closest_i = 0usize;
480                let mut closest_n = Vector3::zero();
481                for (i, (a, b, c)) in tris.iter() {
482                    let tri = Triangle::from((a.p, b.p, c.p));
483                    let n = tri.normal();
484                    let dist = n.dot(a.p.to_vec()).abs();
485                    if closest_dist > dist {
486                        closest_dist = dist;
487                        closest_i = i;
488                        closest_n = n;
489                    }
490                }
491                (closest_dist, closest_i, closest_n)
492            };
493            let closest_tri = {
494                let (a, b, c) = tris[closest_i];
495                ( Triangle::from((a.p, b.p, c.p)), Triangle::from((a.a, b.a, c.a)) )
496            };
497            let support: SupportPoint = diff.support(closest_n);
498            let v = closest_n.dot(support.p.to_vec()) - closest_dist;
499            if v < COLLISION_EPSILON || iter == MAX_ITERATIONS {
500                let (u, v, w ) = closest_tri.0.barycentric(Point3::from_vec(closest_dist * closest_n));
501                let a = u * closest_tri.1.a + v * closest_tri.1.b + w * closest_tri.1.c;
502                return Contact {
503                    a: Point3::from_vec(a),
504                    b: Point3::from_vec(a - closest_dist*closest_n),
505                    n: closest_n,
506                    t: 0.0
507                };
508            }
509            // TODO: fix this being a thing.
510            let mut to_remove = Vec::new();
511            for (i, (a, b, c)) in tris.iter() {
512                let n = Triangle::from((a.p, b.p, c.p)).normal();
513                if n.dot(support.p - a.p) > 0.0 {
514                    edges.add_edge(*a, *b);
515                    edges.add_edge(*b, *c);
516                    edges.add_edge(*c, *a);
517                    to_remove.push(i);
518                }
519            }
520            for i in to_remove {
521                tris.remove(i);
522            }
523            for ([( apx, apy, apz ), ( bpx, bpy, bpz ) ], [ la, lb ]) in edges.map.iter() {
524                let a = unsafe {
525                    (
526                        mem::transmute::<u32, f32>(*apx),
527                        mem::transmute::<u32, f32>(*apy),
528                        mem::transmute::<u32, f32>(*apz)
529                    )
530                };
531                let b = unsafe {
532                    (
533                        mem::transmute::<u32, f32>(*bpx),
534                        mem::transmute::<u32, f32>(*bpy),
535                        mem::transmute::<u32, f32>(*bpz)
536                    )
537                };
538                let a = SupportPoint {
539                    p: Point3::new(a.0, a.1, a.2),
540                    a: la.0,
541                    b: la.1
542                };
543                let b = SupportPoint {
544                    p: Point3::new(b.0, b.1, b.2),
545                    a: lb.0,
546                    b: lb.1
547                };
548                tris.push((support, a, b));
549            }
550            edges.map.clear();
551        }
552        unreachable!()
553    }
554}
555