parry2d/query/contact_manifolds/
contact_manifolds_voxels_composite_shape.rs1use crate::bounding_volume::Aabb;
2use crate::math::{Pose, Real, Vector};
3use crate::query::details::{
4 CanonicalVoxelShape, VoxelsShapeContactManifoldsWorkspace, VoxelsShapeSubDetector,
5};
6use crate::query::{
7 ContactManifold, ContactManifoldsWorkspace, PersistentQueryDispatcher, PointQuery,
8 TypedWorkspaceData, WorkspaceData,
9};
10use crate::shape::{CompositeShape, Cuboid, Shape, SupportMap, VoxelType, Voxels};
11use crate::utils::hashmap::Entry;
12use crate::utils::PoseOpt;
13use alloc::{boxed::Box, vec::Vec};
14
15impl WorkspaceData for VoxelsShapeContactManifoldsWorkspace<3> {
16 fn as_typed_workspace_data(&self) -> TypedWorkspaceData<'_> {
17 TypedWorkspaceData::VoxelsCompositeShapeContactManifoldsWorkspace(self)
18 }
19
20 fn clone_dyn(&self) -> Box<dyn WorkspaceData> {
21 Box::new(self.clone())
22 }
23}
24
25pub fn contact_manifolds_voxels_composite_shape_shapes<ManifoldData, ContactData>(
27 dispatcher: &dyn PersistentQueryDispatcher<ManifoldData, ContactData>,
28 pos12: &Pose,
29 shape1: &dyn Shape,
30 shape2: &dyn Shape,
31 prediction: Real,
32 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
33 workspace: &mut Option<ContactManifoldsWorkspace>,
34) where
35 ManifoldData: Default + Clone,
36 ContactData: Default + Copy,
37{
38 if let (Some(voxels1), Some(shape2)) = (shape1.as_voxels(), shape2.as_composite_shape()) {
39 contact_manifolds_voxels_composite_shape(
40 dispatcher, pos12, voxels1, shape2, prediction, manifolds, workspace, false,
41 );
42 } else if let (Some(shape1), Some(voxels2)) = (shape1.as_composite_shape(), shape2.as_voxels())
43 {
44 contact_manifolds_voxels_composite_shape(
45 dispatcher,
46 &pos12.inverse(),
47 voxels2,
48 shape1,
49 prediction,
50 manifolds,
51 workspace,
52 true,
53 );
54 }
55}
56
57pub fn contact_manifolds_voxels_composite_shape<ManifoldData, ContactData>(
59 dispatcher: &dyn PersistentQueryDispatcher<ManifoldData, ContactData>,
60 pos12: &Pose,
61 voxels1: &Voxels,
62 shape2: &dyn CompositeShape,
63 prediction: Real,
64 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
65 workspace: &mut Option<ContactManifoldsWorkspace>,
66 flipped: bool,
67) where
68 ManifoldData: Default + Clone,
69 ContactData: Default + Copy,
70{
71 VoxelsShapeContactManifoldsWorkspace::<3>::ensure_exists(workspace);
72 let workspace: &mut VoxelsShapeContactManifoldsWorkspace<3> =
73 workspace.as_mut().unwrap().0.downcast_mut().unwrap();
74 let new_timestamp = !workspace.timestamp;
75 workspace.timestamp = new_timestamp;
76
77 let mut old_manifolds = core::mem::take(manifolds);
79 let bvh2 = shape2.bvh();
80 let deformable = shape2.is_deformable();
81
82 let radius1 = voxels1.voxel_size() / 2.0;
83
84 let aabb1 = voxels1.local_aabb();
85 let aabb2_1 = shape2.bvh().root_aabb().transform_by(pos12);
86 let domain2_1 = Aabb {
87 mins: aabb2_1.mins - radius1 * 10.0,
88 maxs: aabb2_1.maxs + radius1 * 10.0,
89 };
90
91 if let Some(intersection_aabb1) = aabb1.intersection(&aabb2_1) {
92 for vox1 in voxels1.voxels_intersecting_local_aabb(&intersection_aabb1) {
93 let vox_type1 = vox1.state.voxel_type();
94
95 if vox_type1 == VoxelType::Empty || vox_type1 == VoxelType::Interior {
97 continue;
98 }
99
100 let canon1 = CanonicalVoxelShape::from_voxel(voxels1, &vox1);
105 let (canonical_center1, canonical_shape1) = canon1.cuboid(voxels1, &vox1, domain2_1);
106 let canonical_pose12 = Pose::from_translation(-canonical_center1) * pos12;
107
108 let mut detect_hit = |leaf2: u32| {
109 let key = [canon1.workspace_key[0], canon1.workspace_key[1], leaf2];
110
111 let (sub_detector, manifold_updated) =
114 match workspace.sub_detectors.entry(key.into()) {
115 Entry::Occupied(entry) => {
116 let sub_detector = entry.into_mut();
117
118 if sub_detector.timestamp != new_timestamp {
119 let manifold = old_manifolds[sub_detector.manifold_id].take();
120 *sub_detector = VoxelsShapeSubDetector {
121 manifold_id: manifolds.len(),
122 timestamp: new_timestamp,
123 selected_contacts: 0,
124 };
125
126 manifolds.push(manifold);
127 (sub_detector, false)
128 } else {
129 (sub_detector, true)
130 }
131 }
132 Entry::Vacant(entry) => {
133 let sub_detector = VoxelsShapeSubDetector {
134 manifold_id: manifolds.len(),
135 selected_contacts: 0,
136 timestamp: new_timestamp,
137 };
138
139 let vox_id = vox1.linear_id.flat_id() as u32;
140 let (id1, id2) = if flipped {
141 (leaf2, vox_id)
142 } else {
143 (vox_id, leaf2)
144 };
145 manifolds.push(ContactManifold::with_data(
146 id1,
147 id2,
148 ManifoldData::default(),
149 ));
150
151 (entry.insert(sub_detector), false)
152 }
153 };
154
155 let manifold = &mut manifolds[sub_detector.manifold_id];
159
160 shape2.map_part_at(leaf2, &mut |part_pos2, part_shape2, _| {
161 let relative_pos12 = part_pos2.prepend_to(&canonical_pose12);
162
163 if !manifold_updated {
164 if deformable {
165 manifold.mark_shapes_deformed();
166 }
167
168 let prev_center = if flipped {
175 manifold
176 .subshape_pos2()
177 .as_ref()
178 .map(|p| p.translation)
179 .unwrap_or_default()
180 } else {
181 manifold
182 .subshape_pos1()
183 .as_ref()
184 .map(|p| p.translation)
185 .unwrap_or_default()
186 };
187 let delta_center = canonical_center1 - prev_center;
188
189 if flipped {
190 for pt in &mut manifold.points {
191 pt.local_p2 -= delta_center;
192 }
193 } else {
194 for pt in &mut manifold.points {
195 pt.local_p1 -= delta_center;
196 }
197 }
198
199 if flipped {
201 manifold.set_subshape_pos1(part_pos2.copied());
202 manifold
203 .set_subshape_pos2(Some(Pose::from_translation(canonical_center1)));
204 let _ = dispatcher.contact_manifold_convex_convex(
205 &relative_pos12.inverse(),
206 part_shape2,
207 &canonical_shape1,
208 None,
209 None,
210 prediction,
211 manifold,
212 );
213 } else {
214 manifold
215 .set_subshape_pos1(Some(Pose::from_translation(canonical_center1)));
216 manifold.set_subshape_pos2(part_pos2.copied());
217 let _ = dispatcher.contact_manifold_convex_convex(
218 &relative_pos12,
219 &canonical_shape1,
220 part_shape2,
221 None,
222 None,
223 prediction,
224 manifold,
225 );
226 }
227 }
228
229 let test_voxel = Cuboid::new(radius1 + Vector::splat(1.0e-2));
233 let penetration_dir1 = if flipped {
234 manifold.local_n2
235 } else {
236 manifold.local_n1
237 };
238
239 for (i, pt) in manifold.points.iter().enumerate() {
240 if pt.dist < 0.0 {
241 let cuboid1 = Cuboid::new(radius1);
245 let sp1 = cuboid1.local_support_point(-penetration_dir1) + vox1.center;
246 let sm2 = part_shape2
247 .as_support_map()
248 .expect("Unsupported collision pair.");
249 let sp2 = sm2.support_point(&relative_pos12, penetration_dir1)
250 + canonical_center1;
251 let test_dist = (sp2 - sp1).dot(-penetration_dir1);
252 let keep = test_dist < pt.dist;
253
254 if !keep {
255 continue;
258 }
259 }
260
261 let pt_in_voxel_space = if flipped {
262 manifold.subshape_pos2().transform_point(pt.local_p2) - vox1.center
263 } else {
264 manifold.subshape_pos1().transform_point(pt.local_p1) - vox1.center
265 };
266 sub_detector.selected_contacts |=
267 (test_voxel.contains_local_point(pt_in_voxel_space) as u32) << i;
268 }
269 });
270 };
271
272 let canon_aabb1_2 = canonical_shape1.compute_aabb(&canonical_pose12.inverse());
273
274 for leaf_id in bvh2.intersect_aabb(&canon_aabb1_2) {
275 detect_hit(leaf_id);
276 }
277 }
278 }
279
280 for sub_detector in workspace.sub_detectors.values() {
282 if sub_detector.timestamp == new_timestamp {
283 let manifold = &mut manifolds[sub_detector.manifold_id];
284 let mut k = 0;
285 manifold.points.retain(|_| {
286 let keep = (sub_detector.selected_contacts & (1 << k)) != 0;
287 k += 1;
288 keep
289 });
290 }
291 }
292
293 workspace
295 .sub_detectors
296 .retain(|_, detector| detector.timestamp == new_timestamp);
297}