parry3d/query/contact_manifolds/
contact_manifolds_voxels_voxels.rs1use crate::bounding_volume::BoundingVolume;
2use crate::math::{Pose, Real, Vector};
3use crate::query::contact_manifolds::{CanonicalVoxelShape, VoxelsShapeContactManifoldsWorkspace};
4use crate::query::details::VoxelsShapeSubDetector;
5use crate::query::{
6 ContactManifold, ContactManifoldsWorkspace, PersistentQueryDispatcher, PointQuery,
7 TypedWorkspaceData, WorkspaceData,
8};
9use crate::shape::{Cuboid, Shape, SupportMap, VoxelData, VoxelType, Voxels};
10use crate::utils::hashmap::Entry;
11use crate::utils::PoseOpt;
12use alloc::{boxed::Box, vec::Vec};
13
14impl WorkspaceData for VoxelsShapeContactManifoldsWorkspace<4> {
15 fn as_typed_workspace_data(&self) -> TypedWorkspaceData<'_> {
16 TypedWorkspaceData::VoxelsVoxelsContactManifoldsWorkspace(self)
17 }
18
19 fn clone_dyn(&self) -> Box<dyn WorkspaceData> {
20 Box::new(self.clone())
21 }
22}
23
24pub fn contact_manifolds_voxels_voxels_shapes<ManifoldData, ContactData>(
26 dispatcher: &dyn PersistentQueryDispatcher<ManifoldData, ContactData>,
27 pos12: &Pose,
28 shape1: &dyn Shape,
29 shape2: &dyn Shape,
30 prediction: Real,
31 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
32 workspace: &mut Option<ContactManifoldsWorkspace>,
33) where
34 ManifoldData: Default + Clone,
35 ContactData: Default + Copy,
36{
37 if let (Some(voxels1), Some(voxels2)) = (shape1.as_voxels(), shape2.as_voxels()) {
38 contact_manifolds_voxels_voxels(
39 dispatcher, pos12, voxels1, voxels2, prediction, manifolds, workspace,
40 );
41 }
42}
43
44pub fn contact_manifolds_voxels_voxels<'a, ManifoldData, ContactData>(
46 dispatcher: &dyn PersistentQueryDispatcher<ManifoldData, ContactData>,
47 pos12: &Pose,
48 voxels1: &'a Voxels,
49 voxels2: &'a Voxels,
50 prediction: Real,
51 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
52 workspace: &mut Option<ContactManifoldsWorkspace>,
53) where
54 ManifoldData: Default + Clone,
55 ContactData: Default + Copy,
56{
57 VoxelsShapeContactManifoldsWorkspace::<4>::ensure_exists(workspace);
58 let workspace: &mut VoxelsShapeContactManifoldsWorkspace<4> =
59 workspace.as_mut().unwrap().0.downcast_mut().unwrap();
60 let new_timestamp = !workspace.timestamp;
61 workspace.timestamp = new_timestamp;
62
63 let mut old_manifolds = core::mem::take(manifolds);
65
66 let radius1 = voxels1.voxel_size() / 2.0;
67 let radius2 = voxels2.voxel_size() / 2.0;
68
69 let aabb1 = voxels1.local_aabb().loosened(prediction / 2.0);
70 let aabb2 = voxels2.local_aabb().loosened(prediction / 2.0);
71
72 let pos21 = pos12.inverse();
73
74 let mut checked_hits = 0;
75
76 if let Some((intersection_aabb1, intersection_aabb2)) =
77 aabb1.aligned_intersections(pos12, &aabb2)
78 {
79 let domain_margin = (radius1 + radius2) * 10.0;
80 let full_domain2_1 = voxels2.compute_aabb(pos12).add_half_extents(domain_margin);
81 let domain2_1 = full_domain2_1
82 .intersection(&aabb1.add_half_extents(domain_margin))
83 .unwrap_or(full_domain2_1);
84 let full_domain1_2 = voxels1.compute_aabb(&pos21).add_half_extents(domain_margin);
85 let domain1_2 = full_domain1_2
86 .intersection(&aabb2.add_half_extents(domain_margin))
87 .unwrap_or(full_domain1_2);
88
89 let mut detect_hit = |canon1: CanonicalVoxelShape,
90 canon2: CanonicalVoxelShape,
91 vox1: &VoxelData,
92 vox2: &VoxelData| {
93 let workspace_key = [
95 canon1.workspace_key[0],
96 canon1.workspace_key[1],
97 canon2.workspace_key[0],
98 canon2.workspace_key[1],
99 ];
100
101 checked_hits += 1;
102
103 let (sub_detector, manifold_updated) =
106 match workspace.sub_detectors.entry(workspace_key.into()) {
107 Entry::Occupied(entry) => {
108 let sub_detector = entry.into_mut();
109
110 if sub_detector.timestamp != new_timestamp {
111 let manifold = old_manifolds[sub_detector.manifold_id].take();
112 *sub_detector = VoxelsShapeSubDetector {
113 manifold_id: manifolds.len(),
114 timestamp: new_timestamp,
115 selected_contacts: 0,
116 };
117
118 manifolds.push(manifold);
119 (sub_detector, false)
120 } else {
121 (sub_detector, true)
122 }
123 }
124 Entry::Vacant(entry) => {
125 let sub_detector = VoxelsShapeSubDetector {
126 manifold_id: manifolds.len(),
127 selected_contacts: 0,
128 timestamp: new_timestamp,
129 };
130
131 manifolds.push(ContactManifold::with_data(
132 vox1.linear_id.flat_id() as u32,
133 vox2.linear_id.flat_id() as u32,
134 ManifoldData::default(),
135 ));
136
137 (entry.insert(sub_detector), false)
138 }
139 };
140
141 let manifold = &mut manifolds[sub_detector.manifold_id];
145 let (canonical_center1, canonical_pseudo_cube1) =
146 canon1.cuboid(voxels1, vox1, domain2_1);
147 let (canonical_center2, canonical_pseudo_cube2) =
148 canon2.cuboid(voxels2, vox2, domain1_2);
149
150 if !manifold_updated {
151 let canonical_pos12 = Pose::from_translation(-canonical_center1)
152 * pos12
153 * Pose::from_translation(canonical_center2);
154
155 let prev_center1 = manifold
162 .subshape_pos1
163 .as_ref()
164 .map(|p| p.translation)
165 .unwrap_or_default();
166 let delta_center1 = canonical_center1 - prev_center1;
167 let prev_center2 = manifold
168 .subshape_pos2
169 .as_ref()
170 .map(|p| p.translation)
171 .unwrap_or_default();
172 let delta_center2 = canonical_center2 - prev_center2;
173
174 for pt in &mut manifold.points {
175 pt.local_p1 -= delta_center1;
176 pt.local_p2 -= delta_center2;
177 }
178
179 manifold.subshape_pos1 = Some(Pose::from_translation(canonical_center1));
181 manifold.subshape_pos2 = Some(Pose::from_translation(canonical_center2));
182 let _ = dispatcher.contact_manifold_convex_convex(
183 &canonical_pos12,
184 &canonical_pseudo_cube1,
185 &canonical_pseudo_cube2,
186 None,
187 None,
188 prediction,
189 manifold,
190 );
191 }
192
193 let test_voxel1 = Cuboid::new(radius1 + Vector::splat(1.0e-2));
197 let test_voxel2 = Cuboid::new(radius2 + Vector::splat(1.0e-2));
198 let penetration_dir1 = manifold.local_n1;
199
200 for (i, pt) in manifold.points.iter().enumerate() {
201 if pt.dist < 0.0 {
202 let cuboid1 = Cuboid::new(radius1);
206 let cuboid2 = Cuboid::new(radius2);
207 let sp1 = cuboid1.local_support_point(-penetration_dir1) + vox1.center;
208 let sp2 = cuboid2.support_point(
209 &(pos12 * Pose::from_translation(vox2.center)),
210 penetration_dir1,
211 );
212 let test_dist = (sp2 - sp1).dot(-penetration_dir1);
213 let keep = test_dist < pt.dist;
214
215 if !keep {
216 continue;
219 }
220 }
221
222 let pt_in_voxel_space1 =
223 manifold.subshape_pos1.transform_point(pt.local_p1) - vox1.center;
224 let pt_in_voxel_space2 =
225 manifold.subshape_pos2.transform_point(pt.local_p2) - vox2.center;
226 sub_detector.selected_contacts |=
227 ((test_voxel1.contains_local_point(pt_in_voxel_space1) as u32) << i)
228 & ((test_voxel2.contains_local_point(pt_in_voxel_space2) as u32) << i);
229 }
230 };
231
232 for vox1 in voxels1.voxels_intersecting_local_aabb(&intersection_aabb1) {
233 let type1 = vox1.state.voxel_type();
234 match type1 {
235 #[cfg(feature = "dim2")]
236 VoxelType::Vertex => { }
237 #[cfg(feature = "dim3")]
238 VoxelType::Vertex | VoxelType::Edge => { }
239 _ => continue,
240 }
241
242 let canon1 = CanonicalVoxelShape::from_voxel(voxels1, &vox1);
243 let centered_aabb1_2 = Cuboid::new(radius1 + Vector::splat(prediction))
244 .compute_aabb(&(pos21 * Pose::from_translation(vox1.center)));
245
246 for vox2 in voxels2.voxels_intersecting_local_aabb(¢ered_aabb1_2) {
247 let type2 = vox2.state.voxel_type();
248
249 #[cfg(feature = "dim2")]
250 match (type1, type2) {
251 (VoxelType::Vertex, VoxelType::Vertex)
252 | (VoxelType::Vertex, VoxelType::Face)
253 | (VoxelType::Face, VoxelType::Vertex) => { }
254 _ => continue, }
256
257 #[cfg(feature = "dim3")]
258 match (type1, type2) {
259 (VoxelType::Vertex, VoxelType::Vertex)
260 | (VoxelType::Vertex, VoxelType::Edge)
261 | (VoxelType::Vertex, VoxelType::Face)
262 | (VoxelType::Edge, VoxelType::Vertex)
263 | (VoxelType::Edge, VoxelType::Edge)
264 | (VoxelType::Face, VoxelType::Vertex) => { }
265 _ => continue, }
267
268 let canon2 = CanonicalVoxelShape::from_voxel(voxels2, &vox2);
269 detect_hit(canon1, canon2, &vox1, &vox2);
270 }
271 }
272
273 for vox2 in voxels2.voxels_intersecting_local_aabb(&intersection_aabb2) {
274 let type2 = vox2.state.voxel_type();
275 match type2 {
276 #[cfg(feature = "dim2")]
277 VoxelType::Vertex => { }
278 #[cfg(feature = "dim3")]
279 VoxelType::Vertex | VoxelType::Edge => { }
280 _ => continue,
281 }
282
283 let canon2 = CanonicalVoxelShape::from_voxel(voxels2, &vox2);
284 let centered_aabb2_1 = Cuboid::new(radius2 + Vector::splat(prediction))
285 .compute_aabb(&(pos12 * Pose::from_translation(vox2.center)));
286
287 for vox1 in voxels1.voxels_intersecting_local_aabb(¢ered_aabb2_1) {
288 let type1 = vox1.state.voxel_type();
289
290 #[cfg(feature = "dim2")]
291 match (type1, type2) {
292 (VoxelType::Vertex, VoxelType::Vertex)
293 | (VoxelType::Vertex, VoxelType::Face)
294 | (VoxelType::Face, VoxelType::Vertex) => { }
295 _ => continue, }
297
298 #[cfg(feature = "dim3")]
299 match (type1, type2) {
300 (VoxelType::Vertex, VoxelType::Vertex)
301 | (VoxelType::Vertex, VoxelType::Edge)
302 | (VoxelType::Vertex, VoxelType::Face)
303 | (VoxelType::Edge, VoxelType::Vertex)
304 | (VoxelType::Edge, VoxelType::Edge)
305 | (VoxelType::Face, VoxelType::Vertex) => { }
306 _ => continue, }
308
309 let canon1 = CanonicalVoxelShape::from_voxel(voxels1, &vox1);
310 detect_hit(canon1, canon2, &vox1, &vox2);
311 }
312 }
313
314 for sub_detector in workspace.sub_detectors.values() {
316 if sub_detector.timestamp == new_timestamp {
317 let manifold = &mut manifolds[sub_detector.manifold_id];
318 let mut k = 0;
319 manifold.points.retain(|_| {
320 let keep = (sub_detector.selected_contacts & (1 << k)) != 0;
321 k += 1;
322 keep
323 });
324 }
325 }
326 }
327
328 workspace
330 .sub_detectors
331 .retain(|_, detector| detector.timestamp == new_timestamp);
332}