ncollide3d/pipeline/narrow_phase/
narrow_phase.rs1use na::RealField;
2use slotmap::{Key, SlotMap};
3
4use crate::pipeline::narrow_phase::{
5 ContactDispatcher, ContactEvent, ContactEvents, ContactManifoldGenerator, Interaction,
6 InteractionGraph, ProximityDetector, ProximityDispatcher, ProximityEvent, ProximityEvents,
7};
8use crate::pipeline::object::{
9 CollisionObjectHandle, CollisionObjectRef, CollisionObjectSet, GeometricQueryType,
10};
11use crate::query::{ContactId, ContactManifold, Proximity};
12
13pub struct NarrowPhase<N: RealField + Copy, Handle: CollisionObjectHandle> {
15 contact_dispatcher: Box<dyn ContactDispatcher<N>>,
16 proximity_dispatcher: Box<dyn ProximityDispatcher<N>>,
17 contact_events: ContactEvents<Handle>,
18 proximity_events: ProximityEvents<Handle>,
19 id_allocator: SlotMap<ContactId, bool>,
20}
21
22impl<N: RealField + Copy, Handle: CollisionObjectHandle> NarrowPhase<N, Handle> {
23 pub fn new(
25 contact_dispatcher: Box<dyn ContactDispatcher<N>>,
26 proximity_dispatcher: Box<dyn ProximityDispatcher<N>>,
27 ) -> NarrowPhase<N, Handle> {
28 NarrowPhase {
29 contact_dispatcher,
30 proximity_dispatcher,
31 contact_events: ContactEvents::new(),
32 proximity_events: ProximityEvents::new(),
33 id_allocator: SlotMap::with_key(),
34 }
35 }
36
37 fn garbage_collect_ids(&mut self, interactions: &mut InteractionGraph<N, Handle>) {
38 for interaction in interactions.0.edge_weights_mut() {
39 match interaction {
40 Interaction::Contact(_, manifold) => {
41 for contact in manifold.contacts() {
42 if !contact.id.is_null() {
43 self.id_allocator[contact.id] = true;
44 }
45 }
46 }
47 Interaction::Proximity(..) => {}
48 }
49 }
50
51 self.id_allocator
52 .retain(|_, is_valid| std::mem::replace(is_valid, false))
53 }
54
55 pub fn update_contact(
57 &mut self,
58 co1: &impl CollisionObjectRef<N>,
59 co2: &impl CollisionObjectRef<N>,
60 handle1: Handle,
61 handle2: Handle,
62 detector: &mut dyn ContactManifoldGenerator<N>,
63 manifold: &mut ContactManifold<N>,
64 ) {
65 let had_contacts = manifold.len() != 0;
66
67 if let Some(prediction) = co1
68 .query_type()
69 .contact_queries_to_prediction(co2.query_type())
70 {
71 manifold.save_cache_and_clear();
72 let _ = detector.generate_contacts(
73 &*self.contact_dispatcher,
74 &co1.position(),
75 co1.shape(),
76 None,
77 &co2.position(),
78 co2.shape(),
79 None,
80 &prediction,
81 manifold,
82 );
83
84 for contact in manifold.contacts_mut() {
85 if contact.id.is_null() {
86 contact.id = self.id_allocator.insert(false)
87 }
88 }
89 } else {
90 panic!("Unable to compute contact between collision objects with query types different from `GeometricQueryType::Contacts(..)`.")
91 }
92
93 if manifold.len() == 0 {
94 if had_contacts {
95 self.contact_events
96 .push(ContactEvent::Stopped(handle1, handle2));
97 }
98 } else {
99 if !had_contacts {
100 self.contact_events
101 .push(ContactEvent::Started(handle1, handle2));
102 }
103 }
104 }
105
106 #[doc(hidden)]
109 pub fn emit_proximity_event(
110 &mut self,
111 handle1: Handle,
112 handle2: Handle,
113 prev_prox: Proximity,
114 new_prox: Proximity,
115 ) {
116 if prev_prox != new_prox {
117 self.proximity_events
118 .push(ProximityEvent::new(handle1, handle2, prev_prox, new_prox));
119 }
120 }
121
122 pub fn update_proximity(
124 &mut self,
125 co1: &impl CollisionObjectRef<N>,
126 co2: &impl CollisionObjectRef<N>,
127 handle1: Handle,
128 handle2: Handle,
129 detector: &mut dyn ProximityDetector<N>,
130 curr_proximity: &mut Proximity,
131 ) {
132 if let Some(new_proximity) = detector.update(
133 &*self.proximity_dispatcher,
134 &co1.position(),
135 co1.shape(),
136 &co2.position(),
137 co2.shape(),
138 co1.query_type().query_limit() + co2.query_type().query_limit(),
139 ) {
140 self.emit_proximity_event(handle1, handle2, *curr_proximity, new_proximity);
141 *curr_proximity = new_proximity;
142 }
143 }
144
145 pub fn update_interaction(
147 &mut self,
148 co1: &impl CollisionObjectRef<N>,
149 co2: &impl CollisionObjectRef<N>,
150 handle1: Handle,
151 handle2: Handle,
152 interaction: &mut Interaction<N>,
153 ) {
154 match interaction {
155 Interaction::Contact(detector, manifold) => {
156 self.update_contact(co1, co2, handle1, handle2, &mut **detector, manifold)
157 }
158 Interaction::Proximity(detector, prox) => {
159 self.update_proximity(co1, co2, handle1, handle2, &mut **detector, prox)
160 }
161 }
162 }
163
164 pub fn update<Objects>(
169 &mut self,
170 interactions: &mut InteractionGraph<N, Objects::CollisionObjectHandle>,
171 objects: &Objects,
172 ) where
173 Objects: CollisionObjectSet<N, CollisionObjectHandle = Handle>,
174 {
175 for eid in interactions.0.edge_indices() {
176 let (id1, id2) = interactions.0.edge_endpoints(eid).unwrap();
177 let handle1 = interactions.0[id1];
178 let handle2 = interactions.0[id2];
179 let co1 = objects.collision_object(handle1).unwrap();
180 let co2 = objects.collision_object(handle2).unwrap();
181 let flags1 = co1.update_flags();
182 let flags2 = co2.update_flags();
183
184 if flags1.needs_narrow_phase_update() || flags2.needs_narrow_phase_update() {
185 self.update_interaction(
186 co1,
187 co2,
188 handle1,
189 handle2,
190 interactions.0.edge_weight_mut(eid).unwrap(),
191 )
192 }
193 }
194
195 self.garbage_collect_ids(interactions)
197 }
198
199 pub fn handle_interaction<Objects>(
201 &mut self,
202 interactions: &mut InteractionGraph<N, Objects::CollisionObjectHandle>,
203 objects: &Objects,
204 handle1: Objects::CollisionObjectHandle,
205 handle2: Objects::CollisionObjectHandle,
206 started: bool,
207 ) where
208 Objects: CollisionObjectSet<N, CollisionObjectHandle = Handle>,
209 {
210 let co1 = objects.collision_object(handle1).unwrap();
211 let co2 = objects.collision_object(handle2).unwrap();
212 let id1 = co1.graph_index().expect(crate::NOT_REGISTERED_ERROR);
213 let id2 = co2.graph_index().expect(crate::NOT_REGISTERED_ERROR);
214
215 if started {
216 if !interactions.0.contains_edge(id1, id2) {
217 match (co1.query_type(), co2.query_type()) {
218 (GeometricQueryType::Contacts(..), GeometricQueryType::Contacts(..)) => {
219 let dispatcher = &self.contact_dispatcher;
220
221 if let Some(detector) =
222 dispatcher.get_contact_algorithm(co1.shape(), co2.shape())
223 {
224 let manifold = detector.init_manifold();
225 let _ = interactions.0.add_edge(
226 id1,
227 id2,
228 Interaction::Contact(detector, manifold),
229 );
230 }
231 }
232 (_, GeometricQueryType::Proximity(_))
233 | (GeometricQueryType::Proximity(_), _) => {
234 let dispatcher = &self.proximity_dispatcher;
235
236 if let Some(detector) =
237 dispatcher.get_proximity_algorithm(co1.shape(), co2.shape())
238 {
239 let _ = interactions.0.add_edge(
240 id1,
241 id2,
242 Interaction::Proximity(detector, Proximity::Disjoint),
243 );
244 }
245 }
246 }
247 }
248 } else {
249 if let Some(eid) = interactions.0.find_edge(id1, id2) {
250 let endpoints = interactions.0.edge_endpoints(eid).unwrap();
251 let handle1 = *interactions.0.node_weight(endpoints.0).unwrap();
252 let handle2 = *interactions.0.node_weight(endpoints.1).unwrap();
253
254 if let Some(detector) = interactions.0.remove_edge(eid) {
255 match detector {
256 Interaction::Contact(_, mut manifold) => {
257 if manifold.len() != 0 {
259 self.contact_events
260 .push(ContactEvent::Stopped(handle1, handle2));
261 }
262
263 manifold.clear();
264 }
265 Interaction::Proximity(_, prev_prox) => {
266 self.emit_proximity_event(
268 handle1,
269 handle2,
270 prev_prox,
271 Proximity::Disjoint,
272 );
273 }
274 }
275 }
276 }
277 }
278 }
279
280 pub fn contact_events(&self) -> &ContactEvents<Handle> {
282 &self.contact_events
283 }
284
285 pub fn proximity_events(&self) -> &ProximityEvents<Handle> {
287 &self.proximity_events
288 }
289
290 pub fn clear_events(&mut self) {
292 self.contact_events.clear();
293 self.proximity_events.clear();
294 }
295}