parry3d/query/contact_manifolds/
contact_manifolds_voxels_composite_shape.rs1use crate::bounding_volume::Aabb;
2use crate::math::{Isometry, Real, Translation, 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::IsometryOpt;
13use alloc::{boxed::Box, vec::Vec};
14use na::Vector3;
15
16impl WorkspaceData for VoxelsShapeContactManifoldsWorkspace<3> {
17 fn as_typed_workspace_data(&self) -> TypedWorkspaceData<'_> {
18 TypedWorkspaceData::VoxelsCompositeShapeContactManifoldsWorkspace(self)
19 }
20
21 fn clone_dyn(&self) -> Box<dyn WorkspaceData> {
22 Box::new(self.clone())
23 }
24}
25
26pub fn contact_manifolds_voxels_composite_shape_shapes<ManifoldData, ContactData>(
28 dispatcher: &dyn PersistentQueryDispatcher<ManifoldData, ContactData>,
29 pos12: &Isometry<Real>,
30 shape1: &dyn Shape,
31 shape2: &dyn Shape,
32 prediction: Real,
33 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
34 workspace: &mut Option<ContactManifoldsWorkspace>,
35) where
36 ManifoldData: Default + Clone,
37 ContactData: Default + Copy,
38{
39 if let (Some(voxels1), Some(shape2)) = (shape1.as_voxels(), shape2.as_composite_shape()) {
40 contact_manifolds_voxels_composite_shape(
41 dispatcher, pos12, voxels1, shape2, prediction, manifolds, workspace, false,
42 );
43 } else if let (Some(shape1), Some(voxels2)) = (shape1.as_composite_shape(), shape2.as_voxels())
44 {
45 contact_manifolds_voxels_composite_shape(
46 dispatcher,
47 &pos12.inverse(),
48 voxels2,
49 shape1,
50 prediction,
51 manifolds,
52 workspace,
53 true,
54 );
55 }
56}
57
58pub fn contact_manifolds_voxels_composite_shape<ManifoldData, ContactData>(
60 dispatcher: &dyn PersistentQueryDispatcher<ManifoldData, ContactData>,
61 pos12: &Isometry<Real>,
62 voxels1: &Voxels,
63 shape2: &dyn CompositeShape,
64 prediction: Real,
65 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
66 workspace: &mut Option<ContactManifoldsWorkspace>,
67 flipped: bool,
68) where
69 ManifoldData: Default + Clone,
70 ContactData: Default + Copy,
71{
72 VoxelsShapeContactManifoldsWorkspace::<3>::ensure_exists(workspace);
73 let workspace: &mut VoxelsShapeContactManifoldsWorkspace<3> =
74 workspace.as_mut().unwrap().0.downcast_mut().unwrap();
75 let new_timestamp = !workspace.timestamp;
76 workspace.timestamp = new_timestamp;
77
78 let mut old_manifolds = core::mem::take(manifolds);
80 let bvh2 = shape2.bvh();
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 = Translation::from(-canonical_center1) * pos12;
107
108 let mut detect_hit = |leaf2: u32| {
109 let key = Vector3::new(canon1.workspace_key.x, canon1.workspace_key.y, leaf2);
110
111 let (sub_detector, manifold_updated) = match workspace.sub_detectors.entry(key) {
114 Entry::Occupied(entry) => {
115 let sub_detector = entry.into_mut();
116
117 if sub_detector.timestamp != new_timestamp {
118 let manifold = old_manifolds[sub_detector.manifold_id].take();
119 *sub_detector = VoxelsShapeSubDetector {
120 manifold_id: manifolds.len(),
121 timestamp: new_timestamp,
122 selected_contacts: 0,
123 };
124
125 manifolds.push(manifold);
126 (sub_detector, false)
127 } else {
128 (sub_detector, true)
129 }
130 }
131 Entry::Vacant(entry) => {
132 let sub_detector = VoxelsShapeSubDetector {
133 manifold_id: manifolds.len(),
134 selected_contacts: 0,
135 timestamp: new_timestamp,
136 };
137
138 let vox_id = vox1.linear_id;
139 let (id1, id2) = if flipped {
140 (leaf2, vox_id)
141 } else {
142 (vox_id, leaf2)
143 };
144 manifolds.push(ContactManifold::with_data(
145 id1,
146 id2,
147 ManifoldData::default(),
148 ));
149
150 (entry.insert(sub_detector), false)
151 }
152 };
153
154 let manifold = &mut manifolds[sub_detector.manifold_id];
158
159 shape2.map_part_at(leaf2, &mut |part_pos2, part_shape2, _| {
160 let relative_pos12 = part_pos2.prepend_to(&canonical_pose12);
161
162 if !manifold_updated {
163 let prev_center = if flipped {
170 manifold
171 .subshape_pos2
172 .as_ref()
173 .map(|p| p.translation.vector)
174 .unwrap_or_default()
175 } else {
176 manifold
177 .subshape_pos1
178 .as_ref()
179 .map(|p| p.translation.vector)
180 .unwrap_or_default()
181 };
182 let delta_center = canonical_center1.coords - prev_center;
183
184 if flipped {
185 for pt in &mut manifold.points {
186 pt.local_p2 -= delta_center;
187 }
188 } else {
189 for pt in &mut manifold.points {
190 pt.local_p1 -= delta_center;
191 }
192 }
193
194 if flipped {
196 manifold.subshape_pos1 = part_pos2.copied();
197 manifold.subshape_pos2 = Some(Isometry::from(canonical_center1));
198 let _ = dispatcher.contact_manifold_convex_convex(
199 &relative_pos12.inverse(),
200 part_shape2,
201 &canonical_shape1,
202 None,
203 None,
204 prediction,
205 manifold,
206 );
207 } else {
208 manifold.subshape_pos1 = Some(Isometry::from(canonical_center1));
209 manifold.subshape_pos2 = part_pos2.copied();
210 let _ = dispatcher.contact_manifold_convex_convex(
211 &relative_pos12,
212 &canonical_shape1,
213 part_shape2,
214 None,
215 None,
216 prediction,
217 manifold,
218 );
219 }
220 }
221
222 let test_voxel = Cuboid::new(radius1 + Vector::repeat(1.0e-2));
226 let penetration_dir1 = if flipped {
227 manifold.local_n2
228 } else {
229 manifold.local_n1
230 };
231
232 for (i, pt) in manifold.points.iter().enumerate() {
233 if pt.dist < 0.0 {
234 let cuboid1 = Cuboid::new(radius1);
238 let sp1 = cuboid1.local_support_point(&-penetration_dir1)
239 + vox1.center.coords;
240 let sm2 = part_shape2
241 .as_support_map()
242 .expect("Unsupported collision pair.");
243 let sp2 = sm2.support_point(&relative_pos12, &penetration_dir1)
244 + canonical_center1.coords;
245 let test_dist = (sp2 - sp1).dot(&-penetration_dir1);
246 let keep = test_dist < pt.dist;
247
248 if !keep {
249 continue;
252 }
253 }
254
255 let pt_in_voxel_space = if flipped {
256 manifold.subshape_pos2.transform_point(&pt.local_p2)
257 - vox1.center.coords
258 } else {
259 manifold.subshape_pos1.transform_point(&pt.local_p1)
260 - vox1.center.coords
261 };
262 sub_detector.selected_contacts |=
263 (test_voxel.contains_local_point(&pt_in_voxel_space) as u32) << i;
264 }
265 });
266 };
267
268 let canon_aabb1_2 = canonical_shape1.compute_aabb(&canonical_pose12.inverse());
269
270 for leaf_id in bvh2.intersect_aabb(&canon_aabb1_2) {
271 detect_hit(leaf_id);
272 }
273 }
274 }
275
276 for sub_detector in workspace.sub_detectors.values() {
278 if sub_detector.timestamp == new_timestamp {
279 let manifold = &mut manifolds[sub_detector.manifold_id];
280 let mut k = 0;
281 manifold.points.retain(|_| {
282 let keep = (sub_detector.selected_contacts & (1 << k)) != 0;
283 k += 1;
284 keep
285 });
286 }
287 }
288
289 workspace
291 .sub_detectors
292 .retain(|_, detector| detector.timestamp == new_timestamp);
293}