rapier3d/dynamics/soft_body/tearing/
tearing.rs1use crate::alloc_prelude::*;
5use crate::math::{DIM, Real, Vector};
6#[cfg(not(feature = "std"))]
7#[allow(unused_imports)]
8use simba::scalar::{ComplexField as _, RealField as _};
9
10use super::super::SoftBody;
11use super::tearing_cut::blade_hit;
12use super::tearing_event::{CATASTROPHIC_STRESS, SoftBodyTearEvent};
13use super::tearing_particle_split::SplitLog;
14
15pub(super) fn pair(a: u32, b: u32) -> [u32; 2] {
17 [a.min(b), a.max(b)]
18}
19
20pub(super) fn shared_others(a: &[u32], b: &[u32], v: u32) -> usize {
22 a.iter().filter(|&&x| x != v && b.contains(&x)).count()
23}
24
25impl SoftBody {
26 pub fn tear_edge(&mut self, i: usize) {
30 if let Some(e) = self.edges.get_mut(i) {
31 e.torn = true;
32 e.stress = e.stress.max(CATASTROPHIC_STRESS);
34 self.tearing_pending = true;
35 }
36 }
37
38 pub fn tear_cell(&mut self, i: usize) {
42 if let Some(c) = self.cells.get_mut(i) {
43 c.torn = true;
44 self.tearing_pending = true;
45 }
46 }
47
48 pub fn has_pending_tears(&self) -> bool {
50 self.tearing_pending
51 }
52
53 pub fn crossing_elements(&self, blade: &[Vector; DIM]) -> (Vec<u32>, Vec<u32>) {
57 let position = |i: u32| self.particles[i as usize].position;
58 let crosses = |a: u32, b: u32| blade_hit(blade, position(a), position(b)).is_some();
59 let edges = self
60 .edges
61 .iter()
62 .enumerate()
63 .filter(|(_, e)| crosses(e.vertices[0], e.vertices[1]))
64 .map(|(i, _)| i as u32)
65 .collect();
66 let cells = self
67 .cells
68 .iter()
69 .enumerate()
70 .filter(|(_, c)| {
71 (0..DIM + 1)
72 .any(|a| (a + 1..DIM + 1).any(|b| crosses(c.vertices[a], c.vertices[b])))
73 })
74 .map(|(i, _)| i as u32)
75 .collect();
76 (edges, cells)
77 }
78
79 pub(crate) fn take_torn(&mut self) -> (Vec<u32>, Vec<u32>) {
83 self.tearing_pending = false;
84 let mut edges: Vec<(Real, u32)> = Vec::new();
85 for (i, e) in self.edges.iter_mut().enumerate() {
86 if core::mem::take(&mut e.torn) {
87 edges.push((e.stress, i as u32));
88 }
89 }
90 let limit = self.material.max_tears_per_step as usize;
91 if edges.len() > limit {
92 edges.sort_by(|x, y| y.0.total_cmp(&x.0).then(x.1.cmp(&y.1)));
96 let keep = edges
97 .iter()
98 .filter(|(stress, _)| *stress > CATASTROPHIC_STRESS)
99 .count()
100 .max(limit);
101 edges.truncate(keep);
102 }
103 let mut edges: Vec<u32> = edges.into_iter().map(|(_, i)| i).collect();
104 edges.sort_unstable();
105 let mut cells = Vec::new();
106 for (i, c) in self.cells.iter_mut().enumerate() {
107 if core::mem::take(&mut c.torn) {
108 cells.push(i as u32);
109 }
110 }
111 (edges, cells)
112 }
113
114 pub(crate) fn tear_topology(
117 &mut self,
118 torn_edges: &[u32],
119 torn_cells: &[u32],
120 event: &mut SoftBodyTearEvent,
121 ) -> bool {
122 self.crack_body(torn_edges, torn_cells, event)
123 }
124
125 pub(super) fn finish_topology_change(&mut self, log: &SplitLog) {
129 let mut sources = log.split_particles.clone();
130 sources.extend(
131 log.inserted
132 .iter()
133 .flat_map(|&[a, b, p, q]| [(p, a), (q, b)]),
134 );
135 self.inherit_cluster_membership(&sources);
137 let remap_tables = super::collision_mesh::SoftTopologyRemap {
138 cells: &[],
139 particles: &[],
140 split: &log.split_particles,
141 inserted: &log.inserted,
142 };
143 self.for_each_mesh_mut(|body, mesh| {
144 mesh.remap_topology(body, &remap_tables);
145 mesh.clear_contacts();
146 });
147 self.rebuild_boundary_tables();
148 self.recolor();
149 self.modified = true;
150 self.topology_version = self.topology_version.wrapping_add(1);
151 }
152}