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