parry3d/query/contact_manifolds/
contact_manifolds_composite_shape_shape.rs1use alloc::{boxed::Box, vec::Vec};
2
3use crate::bounding_volume::BoundingVolume;
4use crate::math::{Pose, Real};
5use crate::query::contact_manifolds::contact_manifolds_workspace::{
6 TypedWorkspaceData, WorkspaceData,
7};
8use crate::query::contact_manifolds::ContactManifoldsWorkspace;
9use crate::query::query_dispatcher::PersistentQueryDispatcher;
10use crate::query::ContactManifold;
11use crate::shape::{CompositeShape, Shape};
12use crate::utils::hashmap::{Entry, HashMap};
13use crate::utils::PoseOpt;
14
15#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
16#[cfg_attr(
17 feature = "rkyv",
18 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
19)]
20#[derive(Clone)]
21struct SubDetector {
22 manifold_id: usize,
23 timestamp: bool,
24}
25
26#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
27#[derive(Clone, Default)]
28pub struct CompositeShapeShapeContactManifoldsWorkspace {
29 timestamp: bool,
30 sub_detectors: HashMap<u32, SubDetector>,
31}
32
33impl CompositeShapeShapeContactManifoldsWorkspace {
34 pub fn new() -> Self {
35 Self::default()
36 }
37}
38
39fn ensure_workspace_exists(workspace: &mut Option<ContactManifoldsWorkspace>) {
40 if workspace
41 .as_ref()
42 .and_then(|w| {
43 w.0.downcast_ref::<CompositeShapeShapeContactManifoldsWorkspace>()
44 })
45 .is_some()
46 {
47 return;
48 }
49
50 *workspace = Some(ContactManifoldsWorkspace(Box::new(
51 CompositeShapeShapeContactManifoldsWorkspace::new(),
52 )));
53}
54
55pub fn contact_manifolds_composite_shape_shape<ManifoldData, ContactData>(
57 dispatcher: &dyn PersistentQueryDispatcher<ManifoldData, ContactData>,
58 pos12: &Pose,
59 composite1: &dyn CompositeShape,
60 shape2: &dyn Shape,
61 prediction: Real,
62 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
63 workspace: &mut Option<ContactManifoldsWorkspace>,
64 flipped: bool,
65) where
66 ManifoldData: Default + Clone,
67 ContactData: Default + Copy,
68{
69 ensure_workspace_exists(workspace);
70 let workspace: &mut CompositeShapeShapeContactManifoldsWorkspace =
71 workspace.as_mut().unwrap().0.downcast_mut().unwrap();
72 let new_timestamp = !workspace.timestamp;
73 workspace.timestamp = new_timestamp;
74
75 let pos12 = *pos12;
80 let pos21 = pos12.inverse();
81
82 let ls_aabb2_1 = shape2.compute_aabb(&pos12).loosened(prediction);
84 let mut old_manifolds = core::mem::take(manifolds);
85
86 let mut leaf1_fn = |leaf1: u32| {
87 composite1.map_part_at(leaf1, &mut |part_pos1, part_shape1, normal_constraints1| {
88 let sub_detector = match workspace.sub_detectors.entry(leaf1) {
89 Entry::Occupied(entry) => {
90 let sub_detector = entry.into_mut();
91 let manifold = old_manifolds[sub_detector.manifold_id].take();
92 sub_detector.manifold_id = manifolds.len();
93 sub_detector.timestamp = new_timestamp;
94 manifolds.push(manifold);
95 sub_detector
96 }
97 Entry::Vacant(entry) => {
98 let sub_detector = SubDetector {
99 manifold_id: manifolds.len(),
100 timestamp: new_timestamp,
101 };
102
103 let mut manifold = ContactManifold::new();
104
105 if flipped {
106 manifold.subshape1 = 0;
107 manifold.subshape2 = leaf1;
108 manifold.subshape_pos2 = part_pos1.copied();
109 } else {
110 manifold.subshape1 = leaf1;
111 manifold.subshape2 = 0;
112 manifold.subshape_pos1 = part_pos1.copied();
113 };
114
115 manifolds.push(manifold);
116 entry.insert(sub_detector)
117 }
118 };
119
120 let manifold = &mut manifolds[sub_detector.manifold_id];
121
122 if flipped {
123 let _ = dispatcher.contact_manifold_convex_convex(
124 &part_pos1.prepend_to(&pos21),
125 shape2,
126 part_shape1,
127 None,
128 normal_constraints1,
129 prediction,
130 manifold,
131 );
132 } else {
133 let _ = dispatcher.contact_manifold_convex_convex(
134 &part_pos1.inv_mul(&pos12),
135 part_shape1,
136 shape2,
137 normal_constraints1,
138 None,
139 prediction,
140 manifold,
141 );
142 }
143 });
144 };
145
146 for leaf_id in composite1.bvh().intersect_aabb(&ls_aabb2_1) {
147 leaf1_fn(leaf_id);
148 }
149
150 workspace
151 .sub_detectors
152 .retain(|_, detector| detector.timestamp == new_timestamp)
153}
154
155impl WorkspaceData for CompositeShapeShapeContactManifoldsWorkspace {
156 fn as_typed_workspace_data(&self) -> TypedWorkspaceData<'_> {
157 TypedWorkspaceData::CompositeShapeShapeContactManifoldsWorkspace(self)
158 }
159
160 fn clone_dyn(&self) -> Box<dyn WorkspaceData> {
161 Box::new(self.clone())
162 }
163}