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