ncollide3d/query/contact/
contact_manifold.rs1use crate::math::Point;
2use crate::query::ContactPreprocessor;
3use crate::query::{Contact, ContactKinematic, TrackedContact};
4use crate::shape::FeatureId;
5use na::{self, RealField};
6use slab::Slab;
7use std::collections::{hash_map::Entry, HashMap};
8
9#[derive(Copy, Clone, Debug, PartialEq, Eq)]
11pub enum ContactTrackingMode<N: RealField + Copy> {
12 FeatureBased,
15 DistanceBased(N),
18}
19
20#[derive(Clone, Debug)]
21enum ContactCache<N: RealField + Copy> {
22 FeatureBased(HashMap<(FeatureId, FeatureId), usize>),
23 DistanceBased(Vec<(Point<N>, usize)>, N),
24}
25
26#[derive(Clone, Debug)]
33pub struct ContactManifold<N: RealField + Copy> {
34 ncontacts: usize,
35 persistence: usize,
36 deepest: usize,
37 contacts: Slab<(TrackedContact<N>, usize)>,
38 cache: ContactCache<N>,
39}
40
41impl<N: RealField + Copy> ContactManifold<N> {
42 pub fn new() -> Self {
46 ContactManifold {
47 ncontacts: 0,
48 deepest: 0,
49 persistence: 1,
50 contacts: Slab::new(),
51 cache: ContactCache::DistanceBased(Vec::new(), na::convert(0.02)),
52 }
53 }
54
55 pub fn len(&self) -> usize {
57 self.ncontacts
58 }
59
60 pub fn contacts(&self) -> impl Iterator<Item = &TrackedContact<N>> {
62 let persistence = self.persistence;
63 self.contacts
64 .iter()
65 .filter_map(move |(_, c)| if c.1 == persistence { Some(&c.0) } else { None })
66 }
67
68 pub fn contacts_mut(&mut self) -> impl Iterator<Item = &mut TrackedContact<N>> {
70 let persistence = self.persistence;
71 self.contacts.iter_mut().filter_map(move |(_, c)| {
72 if c.1 == persistence {
73 Some(&mut c.0)
74 } else {
75 None
76 }
77 })
78 }
79
80 pub fn deepest_contact(&self) -> Option<&TrackedContact<N>> {
82 if self.len() != 0 {
83 Some(&self.contacts[self.deepest].0)
84 } else {
85 None
86 }
87 }
88
89 pub fn clear(&mut self) {
91 match &mut self.cache {
92 ContactCache::FeatureBased(h) => h.clear(),
93 ContactCache::DistanceBased(v, _) => v.clear(),
94 }
95 self.contacts.clear();
96 self.ncontacts = 0;
97 }
98
99 pub fn tracking_mode(&self) -> ContactTrackingMode<N> {
101 match self.cache {
102 ContactCache::FeatureBased(_) => ContactTrackingMode::FeatureBased,
103 ContactCache::DistanceBased(_, threshold) => {
104 ContactTrackingMode::DistanceBased(threshold)
105 }
106 }
107 }
108
109 pub fn set_tracking_mode(&mut self, mode: ContactTrackingMode<N>) {
114 match mode {
115 ContactTrackingMode::FeatureBased => {
116 if let ContactCache::FeatureBased(_) = self.cache {
117 } else {
119 self.cache = ContactCache::FeatureBased(HashMap::new())
120 }
121 }
122 ContactTrackingMode::DistanceBased(new_threshold) => {
123 if let ContactCache::DistanceBased(_, threshold) = &mut self.cache {
124 *threshold = new_threshold;
125 return;
126 }
127
128 self.cache = ContactCache::DistanceBased(Vec::new(), new_threshold)
129 }
130 }
131 }
132
133 pub fn save_cache_and_clear(&mut self) {
135 match &mut self.cache {
136 ContactCache::DistanceBased(cache, _) => {
137 let ctcts = &self.contacts;
138 cache.retain(|c| ctcts[c.1].1 != 0);
139 }
140 ContactCache::FeatureBased(cache) => {
141 let ctcts = &self.contacts;
142 cache.retain(|_k, v| ctcts[*v].1 != 0);
143 }
144 }
145
146 self.deepest = 0;
147 self.ncontacts = 0;
148 self.contacts.retain(|_i, c| {
149 if c.1 == 0 {
150 false
151 } else {
152 c.1 -= 1;
153 true
154 }
155 });
156 }
157
158 pub fn push(
166 &mut self,
167 mut contact: Contact<N>,
168 mut kinematic: ContactKinematic<N>,
169 tracking_pt: Point<N>,
170 preprocessor1: Option<&dyn ContactPreprocessor<N>>,
171 preprocessor2: Option<&dyn ContactPreprocessor<N>>,
172 ) -> bool {
173 if let Some(pp) = preprocessor1 {
174 if !pp.process_contact(&mut contact, &mut kinematic, true) {
175 return false;
176 }
177 }
178
179 if let Some(pp) = preprocessor2 {
180 if !pp.process_contact(&mut contact, &mut kinematic, false) {
181 return false;
182 }
183 }
184
185 let is_deepest =
186 self.ncontacts == 0 || contact.depth > self.contacts[self.deepest].0.contact.depth;
187
188 match &mut self.cache {
189 ContactCache::DistanceBased(cache, threshold) => {
190 let mut closest = cache.len();
191 let mut closest_dist: N = *threshold * *threshold;
192
193 for (i, cached) in cache.iter().enumerate() {
194 let dist = na::distance_squared(&tracking_pt, &cached.0);
195 if dist < closest_dist {
196 closest_dist = dist;
197 closest = i;
198 }
199 }
200
201 if closest == cache.len() {
202 let tracked = TrackedContact::new(contact, kinematic);
203 let i = self.contacts.insert((tracked, self.persistence));
204 cache.push((tracking_pt, i));
205 self.ncontacts += 1;
206
207 if is_deepest {
208 self.deepest = i;
209 }
210
211 false
212 } else {
213 let contact_i = cache[closest].1;
214 if is_deepest {
215 self.deepest = contact_i;
216 }
217
218 let c = &mut self.contacts[contact_i];
219
220 if c.1 == self.persistence {
221 if contact.depth <= c.0.contact.depth {
222 return true;
224 }
225 } else {
226 self.ncontacts += 1;
227 c.1 = self.persistence;
228 }
229
230 c.0.contact = contact;
231 c.0.kinematic = kinematic;
232 cache[closest].0 = tracking_pt;
233
234 true
235 }
236 }
237 ContactCache::FeatureBased(cache) => {
238 match cache.entry((kinematic.feature1(), kinematic.feature2())) {
239 Entry::Vacant(e) => {
240 let tracked = TrackedContact::new(contact, kinematic);
241 let i = self.contacts.insert((tracked, self.persistence));
242 let _ = e.insert(i);
243 self.ncontacts += 1;
244
245 if is_deepest {
246 self.deepest = i;
247 }
248
249 false
250 }
251 Entry::Occupied(e) => {
252 if is_deepest {
253 self.deepest = *e.get();
254 }
255
256 let c = &mut self.contacts[*e.get()];
257
258 if c.1 == self.persistence {
259 if contact.depth <= c.0.contact.depth {
260 return true;
262 }
263 } else {
264 self.ncontacts += 1;
265 c.1 = self.persistence;
266 }
267
268 c.0.contact = contact;
269 c.0.kinematic = kinematic;
270
271 true
272 }
273 }
274 }
275 }
276 }
277}