parry2d/query/contact_manifolds/
contact_manifolds_composite_shape_shape.rs1use alloc::{boxed::Box, vec::Vec};
2
3use crate::bounding_volume::BoundingVolume;
4use crate::math::{Pose, Real};
5use crate::query::contact_manifolds::contact_manifolds_workspace::{
6 TypedWorkspaceData, WorkspaceData,
7};
8use crate::query::contact_manifolds::ContactManifoldsWorkspace;
9use crate::query::query_dispatcher::PersistentQueryDispatcher;
10use crate::query::ContactManifold;
11use crate::shape::{CompositeShape, Shape};
12use crate::utils::hashmap::{Entry, HashMap};
13use crate::utils::PoseOpt;
14
15#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
16#[cfg_attr(
17 feature = "rkyv",
18 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
19)]
20#[derive(Clone)]
21struct SubDetector {
22 manifold_id: usize,
23 timestamp: bool,
24}
25
26#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
27#[derive(Clone, Default)]
28pub struct CompositeShapeShapeContactManifoldsWorkspace {
29 timestamp: bool,
30 sub_detectors: HashMap<u32, SubDetector>,
31}
32
33impl CompositeShapeShapeContactManifoldsWorkspace {
34 pub fn new() -> Self {
35 Self::default()
36 }
37}
38
39fn ensure_workspace_exists(workspace: &mut Option<ContactManifoldsWorkspace>) {
40 if workspace
41 .as_ref()
42 .and_then(|w| {
43 w.0.downcast_ref::<CompositeShapeShapeContactManifoldsWorkspace>()
44 })
45 .is_some()
46 {
47 return;
48 }
49
50 *workspace = Some(ContactManifoldsWorkspace(Box::new(
51 CompositeShapeShapeContactManifoldsWorkspace::new(),
52 )));
53}
54
55#[cfg(feature = "parallel")]
58const PARALLEL_LEAVES: usize = 256;
59
60pub fn contact_manifolds_composite_shape_shape<ManifoldData, ContactData>(
66 dispatcher: &dyn PersistentQueryDispatcher<ManifoldData, ContactData>,
67 pos12: &Pose,
68 composite1: &(dyn CompositeShape + Sync),
69 shape2: &dyn Shape,
70 prediction: Real,
71 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
72 workspace: &mut Option<ContactManifoldsWorkspace>,
73 flipped: bool,
74) where
75 ManifoldData: Default + Clone + Send + Sync,
76 ContactData: Default + Copy + Send + Sync,
77{
78 ensure_workspace_exists(workspace);
79 let workspace: &mut CompositeShapeShapeContactManifoldsWorkspace =
80 workspace.as_mut().unwrap().0.downcast_mut().unwrap();
81 let new_timestamp = !workspace.timestamp;
82 workspace.timestamp = new_timestamp;
83
84 let pos12 = *pos12;
89 let pos21 = pos12.inverse();
90 let deformable = composite1.is_deformable();
91
92 let ls_aabb2_1 = shape2.compute_aabb(&pos12).loosened(prediction);
94 let mut old_manifolds = core::mem::take(manifolds);
95
96 let mut bookkeep =
99 |leaf1: u32, manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>| {
100 match workspace.sub_detectors.entry(leaf1) {
101 Entry::Occupied(entry) => {
102 let sub_detector = entry.into_mut();
103 let mut manifold = old_manifolds[sub_detector.manifold_id].take();
104 sub_detector.manifold_id = manifolds.len();
105 sub_detector.timestamp = new_timestamp;
106 if deformable {
107 manifold.mark_shapes_deformed();
108 }
109 manifolds.push(manifold);
110 false
111 }
112 Entry::Vacant(entry) => {
113 let _ = entry.insert(SubDetector {
114 manifold_id: manifolds.len(),
115 timestamp: new_timestamp,
116 });
117 let mut manifold = ContactManifold::new();
118 if flipped {
119 manifold.subshape1 = 0;
120 manifold.subshape2 = leaf1;
121 } else {
122 manifold.subshape1 = leaf1;
123 manifold.subshape2 = 0;
124 }
125 if deformable {
126 manifold.mark_shapes_deformed();
127 }
128 manifolds.push(manifold);
129 true
130 }
131 }
132 };
133 let compute =
135 |leaf1: u32, fresh: bool, manifold: &mut ContactManifold<ManifoldData, ContactData>| {
136 composite1.map_part_at(leaf1, &mut |part_pos1, part_shape1, normal_constraints1| {
137 if fresh {
138 if flipped {
139 manifold.set_subshape_pos2(part_pos1.copied());
140 } else {
141 manifold.set_subshape_pos1(part_pos1.copied());
142 }
143 }
144 if flipped {
145 let _ = dispatcher.contact_manifold_convex_convex(
146 &part_pos1.prepend_to(&pos21),
147 shape2,
148 part_shape1,
149 None,
150 normal_constraints1,
151 prediction,
152 manifold,
153 );
154 } else {
155 let _ = dispatcher.contact_manifold_convex_convex(
156 &part_pos1.inv_mul(&pos12),
157 part_shape1,
158 shape2,
159 normal_constraints1,
160 None,
161 prediction,
162 manifold,
163 );
164 }
165 });
166 };
167
168 #[cfg(feature = "parallel")]
169 {
170 let leaves: Vec<u32> = composite1.bvh().intersect_aabb(&ls_aabb2_1).collect();
171 if leaves.len() >= PARALLEL_LEAVES {
172 use rayon::prelude::*;
173 let fresh: Vec<bool> = leaves
174 .iter()
175 .map(|&leaf1| bookkeep(leaf1, manifolds))
176 .collect();
177 manifolds
178 .par_iter_mut()
179 .zip(leaves.par_iter())
180 .zip(fresh.par_iter())
181 .for_each(|((manifold, &leaf1), &fresh)| compute(leaf1, fresh, manifold));
182 } else {
183 for leaf1 in leaves {
184 let fresh = bookkeep(leaf1, manifolds);
185 compute(leaf1, fresh, manifolds.last_mut().unwrap());
186 }
187 }
188 }
189 #[cfg(not(feature = "parallel"))]
190 for leaf1 in composite1.bvh().intersect_aabb(&ls_aabb2_1) {
191 let fresh = bookkeep(leaf1, manifolds);
192 compute(leaf1, fresh, manifolds.last_mut().unwrap());
193 }
194
195 workspace
196 .sub_detectors
197 .retain(|_, detector| detector.timestamp == new_timestamp)
198}
199
200impl WorkspaceData for CompositeShapeShapeContactManifoldsWorkspace {
201 fn as_typed_workspace_data(&self) -> TypedWorkspaceData<'_> {
202 TypedWorkspaceData::CompositeShapeShapeContactManifoldsWorkspace(self)
203 }
204
205 fn clone_dyn(&self) -> Box<dyn WorkspaceData> {
206 Box::new(self.clone())
207 }
208}