parry3d/query/contact_manifolds/
contact_manifolds_composite_shape_composite_shape.rs

1use 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
57/// Computes the contact manifolds between two composite shapes.
58pub 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    /*
77     * Compute interferences.
78     */
79
80    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    // Traverse bvh1 first.
98    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); // == pos21 * part_pos1
104            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}