parry3d/query/contact_manifolds/
contact_manifolds_composite_shape_composite_shape.rs1use alloc::boxed::Box;
2use alloc::vec::Vec;
3
4use crate::bounding_volume::BoundingVolume;
5use crate::math::{Isometry, Real};
6use crate::query::contact_manifolds::contact_manifolds_workspace::{
7 TypedWorkspaceData, WorkspaceData,
8};
9use crate::query::contact_manifolds::ContactManifoldsWorkspace;
10use crate::query::query_dispatcher::PersistentQueryDispatcher;
11use crate::query::ContactManifold;
12use crate::shape::CompositeShape;
13use crate::utils::hashmap::{Entry, HashMap};
14use crate::utils::IsometryOpt;
15
16#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
17#[cfg_attr(
18 feature = "rkyv",
19 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
20 archive(check_bytes)
21)]
22#[derive(Clone)]
23struct SubDetector {
24 manifold_id: usize,
25 timestamp: bool,
26}
27
28#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
29#[derive(Clone, Default)]
30pub struct CompositeShapeCompositeShapeContactManifoldsWorkspace {
31 timestamp: bool,
32 sub_detectors: HashMap<(u32, u32), SubDetector>,
33}
34
35impl CompositeShapeCompositeShapeContactManifoldsWorkspace {
36 pub fn new() -> Self {
37 Self::default()
38 }
39}
40
41fn ensure_workspace_exists(workspace: &mut Option<ContactManifoldsWorkspace>) {
42 if workspace
43 .as_ref()
44 .and_then(|w| {
45 w.0.downcast_ref::<CompositeShapeCompositeShapeContactManifoldsWorkspace>()
46 })
47 .is_some()
48 {
49 return;
50 }
51
52 *workspace = Some(ContactManifoldsWorkspace(Box::new(
53 CompositeShapeCompositeShapeContactManifoldsWorkspace::new(),
54 )));
55}
56
57pub fn contact_manifolds_composite_shape_composite_shape<'a, ManifoldData, ContactData>(
59 dispatcher: &dyn PersistentQueryDispatcher<ManifoldData, ContactData>,
60 pos12: &Isometry<Real>,
61 mut composite1: &'a dyn CompositeShape,
62 mut composite2: &'a dyn CompositeShape,
63 prediction: Real,
64 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
65 workspace: &mut Option<ContactManifoldsWorkspace>,
66) where
67 ManifoldData: Default + Clone,
68 ContactData: Default + Copy,
69{
70 ensure_workspace_exists(workspace);
71 let workspace: &mut CompositeShapeCompositeShapeContactManifoldsWorkspace =
72 workspace.as_mut().unwrap().0.downcast_mut().unwrap();
73 let new_timestamp = !workspace.timestamp;
74 workspace.timestamp = new_timestamp;
75
76 let mut bvh1 = composite1.bvh();
81 let mut bvh2 = composite2.bvh();
82
83 let mut pos12 = *pos12;
84 let mut pos21 = pos12.inverse();
85
86 let mut ls_aabb1 = bvh1.root_aabb();
87 let mut ls_aabb2 = bvh2.root_aabb();
88 let flipped = ls_aabb1.half_extents().norm_squared() < ls_aabb2.half_extents().norm_squared();
89
90 if flipped {
91 core::mem::swap(&mut composite1, &mut composite2);
92 core::mem::swap(&mut bvh1, &mut bvh2);
93 core::mem::swap(&mut pos12, &mut pos21);
94 core::mem::swap(&mut ls_aabb1, &mut ls_aabb2);
95 }
96
97 let ls_aabb2_1 = ls_aabb2.transform_by(&pos12).loosened(prediction);
99 let mut old_manifolds = core::mem::take(manifolds);
100
101 let mut leaf_fn1 = |leaf1: u32| {
102 composite1.map_part_at(leaf1, &mut |part_pos1, part_shape1, normal_constraints1| {
103 let pos211 = part_pos1.prepend_to(&pos21); let ls_part_aabb1_2 = part_shape1.compute_aabb(&pos211).loosened(prediction);
105 let mut leaf_fn2 = |leaf2: u32| {
106 composite2.map_part_at(
107 leaf2,
108 &mut |part_pos2, part_shape2, normal_constraints2| {
109 let pos2211 = part_pos2.inv_mul(&pos211);
110 let entry_key = if flipped {
111 (leaf2, leaf1)
112 } else {
113 (leaf1, leaf2)
114 };
115
116 let sub_detector = match workspace.sub_detectors.entry(entry_key) {
117 Entry::Occupied(entry) => {
118 let sub_detector = entry.into_mut();
119 let manifold = old_manifolds[sub_detector.manifold_id].take();
120 sub_detector.manifold_id = manifolds.len();
121 sub_detector.timestamp = new_timestamp;
122 manifolds.push(manifold);
123 sub_detector
124 }
125 Entry::Vacant(entry) => {
126 let sub_detector = SubDetector {
127 manifold_id: manifolds.len(),
128 timestamp: new_timestamp,
129 };
130
131 let mut manifold = ContactManifold::new();
132
133 if flipped {
134 manifold.subshape1 = leaf2;
135 manifold.subshape2 = leaf1;
136 manifold.subshape_pos1 = part_pos2.copied();
137 manifold.subshape_pos2 = part_pos1.copied();
138 } else {
139 manifold.subshape1 = leaf1;
140 manifold.subshape2 = leaf2;
141 manifold.subshape_pos1 = part_pos1.copied();
142 manifold.subshape_pos2 = part_pos2.copied();
143 };
144
145 manifolds.push(manifold);
146 entry.insert(sub_detector)
147 }
148 };
149
150 let manifold = &mut manifolds[sub_detector.manifold_id];
151
152 if flipped {
153 let _ = dispatcher.contact_manifold_convex_convex(
154 &pos2211,
155 part_shape2,
156 part_shape1,
157 normal_constraints2,
158 normal_constraints1,
159 prediction,
160 manifold,
161 );
162 } else {
163 let _ = dispatcher.contact_manifold_convex_convex(
164 &pos2211.inverse(),
165 part_shape1,
166 part_shape2,
167 normal_constraints1,
168 normal_constraints2,
169 prediction,
170 manifold,
171 );
172 }
173 },
174 );
175 };
176
177 for leaf_id in composite2.bvh().intersect_aabb(&ls_part_aabb1_2) {
178 leaf_fn2(leaf_id);
179 }
180 });
181 };
182
183 for leaf_id in composite1.bvh().intersect_aabb(&ls_aabb2_1) {
184 leaf_fn1(leaf_id);
185 }
186
187 workspace
188 .sub_detectors
189 .retain(|_, detector| detector.timestamp == new_timestamp)
190}
191
192impl WorkspaceData for CompositeShapeCompositeShapeContactManifoldsWorkspace {
193 fn as_typed_workspace_data(&self) -> TypedWorkspaceData<'_> {
194 TypedWorkspaceData::CompositeShapeCompositeShapeContactManifoldsWorkspace(self)
195 }
196
197 fn clone_dyn(&self) -> Box<dyn WorkspaceData> {
198 Box::new(self.clone())
199 }
200}