ncollide3d/pipeline/narrow_phase/contact_generator/
heightfield_shape_manifold_generator.rs1use crate::bounding_volume::{self, BoundingVolume};
2use crate::math::Isometry;
3use crate::pipeline::{ContactAlgorithm, ContactDispatcher, ContactManifoldGenerator};
4use crate::query::{ContactManifold, ContactPrediction, ContactPreprocessor};
5use crate::shape::{HeightField, Shape};
6use crate::utils::DeterministicState;
7use na::{self, RealField};
8use std::collections::{hash_map::Entry, HashMap};
9
10pub struct HeightFieldShapeManifoldGenerator<N: RealField + Copy> {
12 sub_detectors: HashMap<usize, (ContactAlgorithm<N>, usize), DeterministicState>,
13 flip: bool,
14 timestamp: usize,
15}
16
17impl<N: RealField + Copy> HeightFieldShapeManifoldGenerator<N> {
18 pub fn new(flip: bool) -> HeightFieldShapeManifoldGenerator<N> {
20 HeightFieldShapeManifoldGenerator {
21 sub_detectors: HashMap::with_hasher(DeterministicState),
22 flip,
23 timestamp: 0,
24 }
25 }
26
27 fn do_update(
28 &mut self,
29 dispatcher: &dyn ContactDispatcher<N>,
30 m1: &Isometry<N>,
31 g1: &HeightField<N>,
32 proc1: Option<&dyn ContactPreprocessor<N>>,
33 m2: &Isometry<N>,
34 g2: &dyn Shape<N>,
35 proc2: Option<&dyn ContactPreprocessor<N>>,
36 prediction: &ContactPrediction<N>,
37 manifold: &mut ContactManifold<N>,
38 flip: bool,
39 ) {
40 self.timestamp += 1;
41
42 let ls_m2 = m1.inverse() * m2.clone();
44 let ls_aabb2 = bounding_volume::aabb(g2, &ls_m2).loosened(prediction.linear());
45
46 g1.map_elements_in_local_aabb(&ls_aabb2, &mut |i, elt1, part_proc1| match self
47 .sub_detectors
48 .entry(i)
49 {
50 Entry::Occupied(mut entry) => {
51 let ok = if flip {
52 entry.get_mut().0.generate_contacts(
53 dispatcher,
54 m2,
55 g2,
56 proc2,
57 m1,
58 elt1,
59 Some(&(proc1, part_proc1)),
60 prediction,
61 manifold,
62 )
63 } else {
64 entry.get_mut().0.generate_contacts(
65 dispatcher,
66 m1,
67 elt1,
68 Some(&(proc1, part_proc1)),
69 m2,
70 g2,
71 proc2,
72 prediction,
73 manifold,
74 )
75 };
76
77 if ok {
78 entry.get_mut().1 = self.timestamp;
79 }
80 }
81 Entry::Vacant(entry) => {
82 let new_detector = if flip {
83 dispatcher.get_contact_algorithm(g2, elt1)
84 } else {
85 dispatcher.get_contact_algorithm(elt1, g2)
86 };
87
88 if let Some(mut new_detector) = new_detector {
89 if flip {
90 let _ = new_detector.generate_contacts(
91 dispatcher,
92 m2,
93 g2,
94 proc2,
95 m1,
96 elt1,
97 Some(&(proc1, part_proc1)),
98 prediction,
99 manifold,
100 );
101 } else {
102 let _ = new_detector.generate_contacts(
103 dispatcher,
104 m1,
105 elt1,
106 Some(&(proc1, part_proc1)),
107 m2,
108 g2,
109 proc2,
110 prediction,
111 manifold,
112 );
113 }
114 let _ = entry.insert((new_detector, self.timestamp));
115 }
116 }
117 });
118
119 let timestamp = self.timestamp;
121 self.sub_detectors
122 .retain(|_, detector| detector.1 == timestamp);
123 }
124}
125
126impl<N: RealField + Copy> ContactManifoldGenerator<N> for HeightFieldShapeManifoldGenerator<N> {
127 fn generate_contacts(
128 &mut self,
129 d: &dyn ContactDispatcher<N>,
130 ma: &Isometry<N>,
131 a: &dyn Shape<N>,
132 proc1: Option<&dyn ContactPreprocessor<N>>,
133 mb: &Isometry<N>,
134 b: &dyn Shape<N>,
135 proc2: Option<&dyn ContactPreprocessor<N>>,
136 prediction: &ContactPrediction<N>,
137 manifold: &mut ContactManifold<N>,
138 ) -> bool {
139 if !self.flip {
140 if let Some(hf) = a.as_shape::<HeightField<N>>() {
141 self.do_update(d, ma, hf, proc1, mb, b, proc2, prediction, manifold, false);
142 return true;
143 }
144 } else {
145 if let Some(hf) = b.as_shape::<HeightField<N>>() {
146 self.do_update(d, mb, hf, proc2, ma, a, proc1, prediction, manifold, true);
147 return true;
148 }
149 }
150
151 return false;
152 }
153
154 }