parry3d/query/contact_manifolds/
contact_manifolds_heightfield_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;
9use crate::query::query_dispatcher::PersistentQueryDispatcher;
10use crate::query::ContactManifold;
11#[cfg(feature = "dim2")]
12use crate::shape::Capsule;
13use crate::shape::{HeightField, Shape};
14use crate::utils::hashmap::{Entry, HashMap};
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 HeightFieldShapeContactManifoldsWorkspace {
31 timestamp: bool,
32 sub_detectors: HashMap<u32, SubDetector>,
33}
34
35impl HeightFieldShapeContactManifoldsWorkspace {
36 pub fn new() -> Self {
37 Self::default()
38 }
39}
40
41pub fn contact_manifolds_heightfield_shape_shapes<ManifoldData, ContactData>(
43 dispatcher: &dyn PersistentQueryDispatcher<ManifoldData, ContactData>,
44 pos12: &Isometry<Real>,
45 shape1: &dyn Shape,
46 shape2: &dyn Shape,
47 prediction: Real,
48 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
49 workspace: &mut Option<ContactManifoldsWorkspace>,
50) where
51 ManifoldData: Default + Clone,
52 ContactData: Default + Copy,
53{
54 if let Some(heightfield1) = shape1.as_heightfield() {
55 contact_manifolds_heightfield_shape(
56 dispatcher,
57 pos12,
58 heightfield1,
59 shape2,
60 prediction,
61 manifolds,
62 workspace,
63 false,
64 )
65 } else if let Some(heightfield2) = shape2.as_heightfield() {
66 contact_manifolds_heightfield_shape(
67 dispatcher,
68 &pos12.inverse(),
69 heightfield2,
70 shape1,
71 prediction,
72 manifolds,
73 workspace,
74 true,
75 )
76 }
77}
78
79fn ensure_workspace_exists(workspace: &mut Option<ContactManifoldsWorkspace>) {
80 if workspace
81 .as_ref()
82 .and_then(|w| {
83 w.0.downcast_ref::<HeightFieldShapeContactManifoldsWorkspace>()
84 })
85 .is_some()
86 {
87 return;
88 }
89
90 *workspace = Some(ContactManifoldsWorkspace(Box::new(
91 HeightFieldShapeContactManifoldsWorkspace::new(),
92 )));
93}
94
95pub fn contact_manifolds_heightfield_shape<ManifoldData, ContactData>(
97 dispatcher: &dyn PersistentQueryDispatcher<ManifoldData, ContactData>,
98 pos12: &Isometry<Real>,
99 heightfield1: &HeightField,
100 shape2: &dyn Shape,
101 prediction: Real,
102 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
103 workspace: &mut Option<ContactManifoldsWorkspace>,
104 flipped: bool,
105) where
106 ManifoldData: Default + Clone,
107 ContactData: Default + Copy,
108{
109 ensure_workspace_exists(workspace);
110 let workspace: &mut HeightFieldShapeContactManifoldsWorkspace =
111 workspace.as_mut().unwrap().0.downcast_mut().unwrap();
112 let new_timestamp = !workspace.timestamp;
113 workspace.timestamp = new_timestamp;
114
115 let ls_aabb2 = shape2.compute_aabb(pos12).loosened(prediction);
120 let mut old_manifolds = core::mem::take(manifolds);
121
122 heightfield1.map_elements_in_local_aabb(&ls_aabb2, &mut |i, part1| {
123 #[cfg(feature = "dim2")]
124 let sub_shape1 = Capsule::new(part1.a, part1.b, 0.0); #[cfg(feature = "dim3")]
126 let sub_shape1 = *part1;
127
128 let sub_detector = match workspace.sub_detectors.entry(i) {
129 Entry::Occupied(entry) => {
130 let sub_detector = entry.into_mut();
131 let manifold = old_manifolds[sub_detector.manifold_id].take();
132 sub_detector.manifold_id = manifolds.len();
133 sub_detector.timestamp = new_timestamp;
134 manifolds.push(manifold);
135 sub_detector
136 }
137 Entry::Vacant(entry) => {
138 let sub_detector = SubDetector {
139 manifold_id: manifolds.len(),
140 timestamp: new_timestamp,
141 };
142
143 let (id1, id2) = if flipped { (0, i) } else { (i, 0) };
144 manifolds.push(ContactManifold::with_data(
145 id1,
146 id2,
147 ManifoldData::default(),
148 ));
149
150 entry.insert(sub_detector)
151 }
152 };
153
154 let manifold = &mut manifolds[sub_detector.manifold_id];
155
156 #[cfg(feature = "dim2")]
157 let pseudo_normals = None::<()>;
158 #[cfg(feature = "dim3")]
159 let pseudo_normals = heightfield1.triangle_normal_constraints(i);
160
161 let normal_constraints1 = pseudo_normals.as_ref().map(|pn| pn as &_);
162
163 if flipped {
164 let _ = dispatcher.contact_manifold_convex_convex(
165 &pos12.inverse(),
166 shape2,
167 &sub_shape1,
168 None,
169 normal_constraints1,
170 prediction,
171 manifold,
172 );
173 } else {
174 let _ = dispatcher.contact_manifold_convex_convex(
175 pos12,
176 &sub_shape1,
177 shape2,
178 normal_constraints1,
179 None,
180 prediction,
181 manifold,
182 );
183 }
184 });
185
186 workspace
187 .sub_detectors
188 .retain(|_, detector| detector.timestamp == new_timestamp);
189}
190
191impl WorkspaceData for HeightFieldShapeContactManifoldsWorkspace {
192 fn as_typed_workspace_data(&self) -> TypedWorkspaceData<'_> {
193 TypedWorkspaceData::HeightfieldShapeContactManifoldsWorkspace(self)
194 }
195
196 fn clone_dyn(&self) -> Box<dyn WorkspaceData> {
197 Box::new(self.clone())
198 }
199}