parry3d/query/contact_manifolds/
contact_manifolds_trimesh_shape.rs1use alloc::{boxed::Box, vec::Vec};
2
3use crate::bounding_volume::{Aabb, 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::details::NormalConstraints;
10use crate::query::query_dispatcher::PersistentQueryDispatcher;
11use crate::query::ContactManifold;
12use crate::shape::{Shape, TriMesh};
13
14#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
15#[cfg_attr(
16 feature = "rkyv",
17 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
18 archive(check_bytes)
19)]
20#[derive(Clone)]
21pub struct TriMeshShapeContactManifoldsWorkspace {
22 interferences: Vec<u32>,
23 local_aabb2: Aabb,
24 old_interferences: Vec<u32>,
25}
26
27impl Default for TriMeshShapeContactManifoldsWorkspace {
28 fn default() -> Self {
29 Self::new()
30 }
31}
32
33impl TriMeshShapeContactManifoldsWorkspace {
34 pub fn new() -> Self {
35 Self {
36 interferences: Vec::new(),
37 local_aabb2: Aabb::new_invalid(),
38 old_interferences: Vec::new(),
39 }
40 }
41}
42
43pub fn contact_manifolds_trimesh_shape_shapes<ManifoldData, ContactData>(
45 dispatcher: &dyn PersistentQueryDispatcher<ManifoldData, ContactData>,
46 pos12: &Isometry<Real>,
47 shape1: &dyn Shape,
48 shape2: &dyn Shape,
49 prediction: Real,
50 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
51 workspace: &mut Option<ContactManifoldsWorkspace>,
52) where
53 ManifoldData: Default,
54 ContactData: Default + Copy,
55{
56 if let Some(trimesh1) = shape1.as_trimesh() {
57 contact_manifolds_trimesh_shape(
58 dispatcher, pos12, trimesh1, shape2, prediction, manifolds, workspace, false,
59 )
60 } else if let Some(trimesh2) = shape2.as_trimesh() {
61 contact_manifolds_trimesh_shape(
62 dispatcher,
63 &pos12.inverse(),
64 trimesh2,
65 shape1,
66 prediction,
67 manifolds,
68 workspace,
69 true,
70 )
71 }
72}
73
74fn ensure_workspace_exists(workspace: &mut Option<ContactManifoldsWorkspace>) {
75 if workspace
76 .as_mut()
77 .and_then(|w| w.0.downcast_mut::<TriMeshShapeContactManifoldsWorkspace>())
78 .is_some()
79 {
80 return;
81 }
82
83 *workspace = Some(ContactManifoldsWorkspace(Box::new(
84 TriMeshShapeContactManifoldsWorkspace::new(),
85 )));
86}
87
88pub fn contact_manifolds_trimesh_shape<ManifoldData, ContactData>(
90 dispatcher: &dyn PersistentQueryDispatcher<ManifoldData, ContactData>,
91 pos12: &Isometry<Real>,
92 trimesh1: &TriMesh,
93 shape2: &dyn Shape,
94 prediction: Real,
95 manifolds: &mut Vec<ContactManifold<ManifoldData, ContactData>>,
96 workspace: &mut Option<ContactManifoldsWorkspace>,
97 flipped: bool,
98) where
99 ManifoldData: Default,
100 ContactData: Default + Copy,
101{
102 ensure_workspace_exists(workspace);
103 let workspace: &mut TriMeshShapeContactManifoldsWorkspace =
104 workspace.as_mut().unwrap().0.downcast_mut().unwrap();
105
106 let mut new_local_aabb2 = shape2.compute_aabb(pos12).loosened(prediction);
111 let same_local_aabb2 = workspace.local_aabb2.contains(&new_local_aabb2);
112 let mut old_manifolds = Vec::new();
113
114 if !same_local_aabb2 {
115 let extra_margin =
116 (new_local_aabb2.maxs - new_local_aabb2.mins).map(|e| (e / 10.0).min(0.1));
117 new_local_aabb2.mins -= extra_margin;
118 new_local_aabb2.maxs += extra_margin;
119
120 let local_aabb2 = new_local_aabb2; core::mem::swap(
122 &mut workspace.old_interferences,
123 &mut workspace.interferences,
124 );
125
126 core::mem::swap(manifolds, &mut old_manifolds);
127
128 workspace.interferences.clear();
140 workspace
141 .interferences
142 .extend(trimesh1.bvh().intersect_aabb(&local_aabb2));
143 workspace.local_aabb2 = local_aabb2;
144 }
145
146 let new_interferences = &workspace.interferences;
150 let mut old_inter_it = workspace.old_interferences.drain(..).peekable();
151 let mut old_manifolds_it = old_manifolds.drain(..);
152
153 for (i, triangle_id) in new_interferences.iter().enumerate() {
156 if *triangle_id >= trimesh1.num_triangles() as u32 {
157 continue;
160 }
161
162 if !same_local_aabb2 {
163 loop {
164 match old_inter_it.peek() {
165 Some(old_triangle_id) if *old_triangle_id < *triangle_id => {
166 let _ = old_inter_it.next();
167 let _ = old_manifolds_it.next();
168 }
169 _ => break,
170 }
171 }
172
173 let manifold = if old_inter_it.peek() != Some(triangle_id) {
174 let (id1, id2) = if flipped {
175 (0, *triangle_id)
176 } else {
177 (*triangle_id, 0)
178 };
179 ContactManifold::with_data(id1, id2, ManifoldData::default())
180 } else {
181 let _ = old_inter_it.next();
183 old_manifolds_it.next().unwrap()
184 };
185
186 manifolds.push(manifold);
187 }
188
189 let manifold = &mut manifolds[i];
190 let triangle1 = trimesh1.triangle(*triangle_id);
191 let triangle_normals1 = trimesh1.triangle_normal_constraints(*triangle_id);
192 let normal_constraints1 = triangle_normals1
193 .as_ref()
194 .map(|proj| proj as &dyn NormalConstraints);
195
196 if flipped {
197 let _ = dispatcher.contact_manifold_convex_convex(
198 &pos12.inverse(),
199 shape2,
200 &triangle1,
201 None,
202 normal_constraints1,
203 prediction,
204 manifold,
205 );
206 } else {
207 let _ = dispatcher.contact_manifold_convex_convex(
208 pos12,
209 &triangle1,
210 shape2,
211 normal_constraints1,
212 None,
213 prediction,
214 manifold,
215 );
216 }
217 }
218}
219
220impl WorkspaceData for TriMeshShapeContactManifoldsWorkspace {
221 fn as_typed_workspace_data(&self) -> TypedWorkspaceData<'_> {
222 TypedWorkspaceData::TriMeshShapeContactManifoldsWorkspace(self)
223 }
224
225 fn clone_dyn(&self) -> Box<dyn WorkspaceData> {
226 Box::new(self.clone())
227 }
228}