rapier3d/dynamics/soft_body/collision_mesh/
collision_mesh_accessors.rs1use crate::geometry::ColliderHandle;
5use crate::math::{DIM, Real, Vector};
6
7use super::{SoftBody, SoftCollisionMesh, SoftMeshCellBinding, SoftMeshId, SoftMeshMapping};
8
9impl SoftCollisionMesh {
10 pub fn id(&self) -> SoftMeshId {
12 self.id
13 }
14
15 pub(crate) fn set_id(&mut self, id: SoftMeshId) {
17 self.id = id;
18 }
19
20 pub fn collider(&self) -> ColliderHandle {
22 self.collider
23 }
24
25 pub fn collision_enabled(&self) -> bool {
27 self.collision_enabled
28 }
29
30 pub fn indices(&self) -> &[[u32; DIM]] {
33 &self.indices
34 }
35
36 #[inline]
38 pub fn element(&self, i: usize) -> &[u32] {
39 super::soft_body_builder::element_vertices(&self.indices[i])
40 }
41
42 #[inline]
45 pub fn arity(&self) -> usize {
46 self.indices
47 .first()
48 .map_or(DIM, |e| super::soft_body_builder::element_vertices(e).len())
49 }
50
51 #[inline]
53 pub fn is_wire(&self) -> bool {
54 self.arity() < DIM
55 }
56
57 pub(crate) fn element_edge_ids(&self, i: usize) -> impl Iterator<Item = u32> + '_ {
59 #[cfg(feature = "dim3")]
60 let ids: &[u32] = if self.is_wire() {
61 &[]
62 } else {
63 super::soft_body_builder::element_vertices(&self.element_edges[i])
64 };
65 #[cfg(feature = "dim2")]
66 let ids: &[u32] = &[];
67 let own = ids.is_empty().then_some(i as u32);
68 own.into_iter().chain(ids.iter().copied())
69 }
70
71 pub(crate) fn edge_vertices(&self, edge: u32) -> [u32; 2] {
73 #[cfg(feature = "dim3")]
74 if !self.is_wire() {
75 return self.edges[edge as usize];
76 }
77 let element = self.element(edge as usize);
78 [element[0], element[1]]
79 }
80
81 pub(crate) fn edge_owner(&self, edge: u32) -> u32 {
83 #[cfg(feature = "dim3")]
84 if !self.is_wire() {
85 return self.edge_owners[edge as usize];
86 }
87 edge
88 }
89
90 pub fn binding(&self) -> &SoftMeshMapping {
92 &self.binding
93 }
94
95 pub fn is_skinned(&self) -> bool {
97 matches!(self.binding, SoftMeshMapping::Skinned { .. })
98 }
99
100 pub fn is_closed(&self) -> bool {
103 self.closed
104 }
105
106 pub fn is_oriented(&self) -> bool {
108 self.oriented
109 }
110
111 pub fn is_solid(&self) -> bool {
114 self.closed && self.oriented
115 }
116
117 pub(crate) fn read_orientation(&mut self, colliders: &crate::geometry::ColliderSet) {
119 let Some(co) = colliders.get(self.collider) else {
120 return;
121 };
122 #[cfg(feature = "dim2")]
123 let oriented = co.shape().as_polyline().is_some_and(|polyline| {
124 polyline
125 .flags()
126 .contains(parry::shape::PolylineFlags::ORIENTED)
127 });
128 #[cfg(feature = "dim3")]
129 let oriented = co.shape().as_trimesh().is_some_and(|trimesh| {
130 trimesh
131 .flags()
132 .contains(parry::shape::TriMeshFlags::ORIENTED)
133 });
134 self.oriented = oriented;
135 }
136
137 pub fn self_contacts_enabled(&self) -> bool {
139 self.self_contacts
140 }
141
142 pub fn vertex_count(&self) -> usize {
144 match &self.binding {
145 SoftMeshMapping::Direct { particles } => particles.len(),
146 SoftMeshMapping::Skinned { .. } => self.vertices.len(),
147 }
148 }
149
150 pub fn vertices(&self) -> &[Vector] {
153 &self.vertices
154 }
155
156 pub fn vertex_positions<'a>(
158 &'a self,
159 body: &'a SoftBody,
160 ) -> impl ExactSizeIterator<Item = Vector> + 'a {
161 (0..self.vertex_count()).map(move |i| self.vertex(body, i))
162 }
163
164 pub fn vertex(&self, body: &SoftBody, i: usize) -> Vector {
166 match &self.binding {
167 SoftMeshMapping::Direct { particles } => body.particles[particles[i] as usize].position,
168 SoftMeshMapping::Skinned { .. } => self.vertices[i],
169 }
170 }
171
172 #[inline]
175 pub(crate) fn cached_vertex(&self, i: usize) -> Vector {
176 self.vertex_cache[i]
177 }
178
179 pub(crate) fn refresh_vertex_cache(&mut self, particles: &[super::super::SoftBodyParticle]) {
181 match &self.binding {
182 SoftMeshMapping::Direct { particles: map } => {
183 self.vertex_cache.clear();
184 self.vertex_cache
185 .extend(map.iter().map(|&p| particles[p as usize].position));
186 }
187 SoftMeshMapping::Skinned { .. } => {
188 self.vertex_cache.clear();
189 self.vertex_cache.extend_from_slice(&self.vertices);
190 }
191 }
192 }
193
194 pub fn vertex_velocity(&self, body: &SoftBody, i: usize) -> Vector {
196 match &self.binding {
197 SoftMeshMapping::Direct { particles } => body.particles[particles[i] as usize].velocity,
198 SoftMeshMapping::Skinned { bindings } => {
199 let binding = &bindings[i];
200 let Some(cell) = body.cells.get(binding.cell as usize) else {
201 return Vector::ZERO;
202 };
203 let mut velocity = Vector::ZERO;
204 for (vid, weight) in cell.vertices.iter().zip(&binding.weights) {
205 velocity += body.particles[*vid as usize].velocity * *weight;
206 }
207 velocity
208 }
209 }
210 }
211
212 pub(crate) fn vertex_on_surface(&self, i: usize) -> bool {
214 match (
215 self.vertex_elements_offsets.get(i),
216 self.vertex_elements_offsets.get(i + 1),
217 ) {
218 (Some(start), Some(end)) => end > start,
219 _ => false,
220 }
221 }
222
223 pub fn vertex_anchors(&self, body: &SoftBody, i: usize) -> ([u32; DIM + 1], [Real; DIM + 1]) {
227 match &self.binding {
228 SoftMeshMapping::Direct { particles } => {
229 let mut ids = [u32::MAX; DIM + 1];
230 let mut weights = [0.0; DIM + 1];
231 ids[0] = particles[i];
232 weights[0] = 1.0;
233 (ids, weights)
234 }
235 SoftMeshMapping::Skinned { bindings } => {
236 match body.cells.get(bindings[i].cell as usize) {
237 Some(cell) => (cell.vertices, bindings[i].weights),
238 None => ([u32::MAX; DIM + 1], [0.0; DIM + 1]),
239 }
240 }
241 }
242 }
243
244 pub(crate) fn contact_anchors(
248 &self,
249 body: &SoftBody,
250 vertices: &[u32],
251 weights: &[Real],
252 point: Vector,
253 ) -> ([u32; DIM + 1], [Real; DIM + 1], Vector) {
254 let pad = |vertices: &[u32]| {
255 let mut ids = [u32::MAX; DIM + 1];
256 let mut ws = [0.0; DIM + 1];
257 let len = vertices.len().min(DIM + 1);
258 ids[..len].copy_from_slice(&vertices[..len]);
259 ws[..len].copy_from_slice(&weights[..len]);
260 (ids, ws, point)
261 };
262
263 match &self.binding {
264 SoftMeshMapping::Direct { particles } => {
265 let mut ids = [u32::MAX; DIM + 1];
266 let mut ws = [0.0; DIM + 1];
267 for k in 0..vertices.len().min(DIM + 1) {
268 ids[k] = particles[vertices[k] as usize];
269 ws[k] = weights[k];
270 }
271 (ids, ws, point)
272 }
273 SoftMeshMapping::Skinned { bindings } => self
274 .skinned_contact_anchors(body, bindings, vertices, weights, point)
275 .unwrap_or_else(|| pad(vertices)),
276 }
277 }
278
279 fn skinned_contact_anchors(
280 &self,
281 body: &SoftBody,
282 bindings: &[SoftMeshCellBinding],
283 vertices: &[u32],
284 weights: &[Real],
285 point: Vector,
286 ) -> Option<([u32; DIM + 1], [Real; DIM + 1], Vector)> {
287 let first = bindings.get(*vertices.first()? as usize)?;
288 let shared = vertices
289 .iter()
290 .all(|v| bindings[*v as usize].cell == first.cell);
291
292 if shared {
293 let cell = body.cells.get(first.cell as usize)?;
294 let mut blended = [0.0; DIM + 1];
295 for (v, weight) in vertices.iter().zip(weights) {
296 for (w, bw) in blended.iter_mut().zip(&bindings[*v as usize].weights) {
297 *w += bw * weight;
298 }
299 }
300 return Some((cell.vertices, blended, point));
301 }
302
303 let heaviest = (0..vertices.len()).max_by(|a, b| weights[*a].total_cmp(&weights[*b]))?;
304 let vertex = vertices[heaviest] as usize;
305 let binding = &bindings[vertex];
306 let cell = body.cells.get(binding.cell as usize)?;
307 Some((cell.vertices, binding.weights, self.vertices[vertex]))
308 }
309
310 pub(crate) fn rest_vertex(&self, body: &SoftBody, i: usize) -> Vector {
313 match &self.binding {
314 SoftMeshMapping::Direct { particles } => {
315 body.particles[particles[i] as usize].rest_position
316 }
317 SoftMeshMapping::Skinned { bindings } => {
318 let binding = &bindings[i];
319 let Some(cell) = body.cells.get(binding.cell as usize) else {
320 return Vector::ZERO;
321 };
322 let mut position = Vector::ZERO;
323 for (vid, weight) in cell.vertices.iter().zip(&binding.weights) {
324 position += body.particles[*vid as usize].rest_position * *weight;
325 }
326 position
327 }
328 }
329 }
330
331 pub(crate) fn element_cell_ids<'a>(&'a self, body: &'a SoftBody) -> &'a [u32] {
334 if self.follows_boundary {
335 &body.boundary_element_cells
336 } else {
337 &self.element_cells
338 }
339 }
340
341 pub(crate) fn vertex_element_ids(&self, vertex: u32) -> &[u32] {
343 match (
344 self.vertex_elements_offsets.get(vertex as usize),
345 self.vertex_elements_offsets.get(vertex as usize + 1),
346 ) {
347 (Some(&start), Some(&end)) => &self.vertex_elements[start as usize..end as usize],
348 _ => &[],
349 }
350 }
351}