rapier3d/dynamics/soft_body/tearing/tearing_event.rs
1//! The tear event and the stress level past which a tear is never paced.
2
3use crate::alloc_prelude::*;
4use crate::dynamics::{ImpulseJointHandle, RigidBodyHandle};
5use crate::math::{DIM, Real};
6
7use super::super::SoftBodyHandle;
8
9/// A cluster piece a tear left: where a cluster the crack ran through ended up (see
10/// [`SoftBodyTearEvent::clusters`]).
11#[derive(Copy, Clone, Debug, PartialEq, Eq)]
12pub struct SoftClusterSplit {
13 /// The index of the cluster that was split, in the torn body, before the tear.
14 pub source_cluster: u32,
15 /// The soft body holding the piece.
16 pub soft_body: SoftBodyHandle,
17 /// The piece's cluster index in that body.
18 pub cluster: u32,
19 /// The piece's proxy rigid body.
20 pub proxy: RigidBodyHandle,
21 /// Whether the piece kept the source cluster's proxy (the joints and colliders that were not
22 /// moved stay on it); the other pieces got a fresh one.
23 pub keeps_proxy: bool,
24}
25
26/// A soft body a tear left: the torn body itself, or a body split off it (see
27/// [`SoftBodyTearEvent::pieces`]).
28#[derive(Clone, Debug, PartialEq, Eq)]
29pub struct SoftBodyPiece {
30 /// The soft body holding the piece.
31 pub soft_body: SoftBodyHandle,
32 /// The particles of the piece: `particles[i]` is the index, in the torn body after the tear
33 /// (the indices the other fields of the event use), of the piece's `i`-th particle.
34 pub particles: Vec<u32>,
35 /// The clusters of the piece, as `[index in the torn body before the split, index in the
36 /// piece]` (a cluster split by the tear is listed under the index its piece got, see
37 /// [`SoftBodyTearEvent::clusters`]).
38 pub clusters: Vec<[u32; 2]>,
39}
40
41/// An impulse joint a tear re-attached: its proxy was split, and the piece closest to the joint's
42/// anchor in the rest shape is not the one that kept the proxy (see
43/// [`SoftBodyTearEvent::moved_joints`]).
44#[derive(Copy, Clone, Debug, PartialEq, Eq)]
45pub struct SoftJointMove {
46 /// The joint.
47 pub joint: ImpulseJointHandle,
48 /// The proxy it was attached to.
49 pub from: RigidBodyHandle,
50 /// The proxy it is attached to now.
51 pub to: RigidBodyHandle,
52}
53
54/// What a tear or a cut did to a soft body (see `EventHandler::handle_soft_body_tear_event`,
55/// [`crate::dynamics::SoftBodySet::tear`] and [`crate::dynamics::SoftBodySet::cut`]); the
56/// indices of `torn_edges`/`torn_cells` predate the tear, the others follow it, before the split.
57#[derive(Clone, Debug, Default)]
58pub struct SoftBodyTearEvent {
59 /// The soft body that tore.
60 pub soft_body: SoftBodyHandle,
61 /// The particle pairs of the torn edges a crack opened across. In a cut, the edges the blade
62 /// meets (see [`crate::dynamics::SoftBody::crossing_elements`]).
63 pub torn_edges: Vec<[u32; 2]>,
64 /// The vertices of the torn cells a crack opened through (a tear removes no cell). In a cut,
65 /// the cells the blade meets.
66 pub torn_cells: Vec<[u32; DIM + 1]>,
67 /// The particle pairs of the edges removed for straddling an opened crack: bending edges over
68 /// a split particle, quad diagonals across an opened triangle side, edges joining two pieces.
69 pub removed_edges: Vec<[u32; 2]>,
70 /// The particles the tear passed through, duplicated one copy per piece: `(copy, source)`.
71 pub split_particles: Vec<(u32, u32)>,
72 /// The particles a cut inserted where it crosses a rope, polyline or wire segment: two per
73 /// crossed segment, both at the crossing, the first joined to the segment's first particle.
74 pub inserted_particles: Vec<u32>,
75 /// The soft bodies the torn body came apart into, the piece with the largest rest measure
76 /// (which keeps the handle) first, the others new soft bodies remembering their origin. Empty
77 /// when nothing split off; else the first entry maps the retained body's compacted particles.
78 pub pieces: Vec<SoftBodyPiece>,
79 /// The pieces of every cluster the crack split (see
80 /// [`crate::dynamics::SoftBody::seeded_components`]): one piece keeps the proxy, the others
81 /// get a fresh one. Empty when no cluster was split.
82 pub clusters: Vec<SoftClusterSplit>,
83 /// The impulse joints moved to another proxy by a cluster split: a joint follows the piece
84 /// closest to its anchor in the rest shape.
85 pub moved_joints: Vec<SoftJointMove>,
86}
87
88impl SoftBodyTearEvent {
89 /// The soft bodies the torn body is in after the tear, the one keeping the handle first: the
90 /// torn body alone when nothing was split off, the [`Self::pieces`] otherwise.
91 pub fn bodies(&self) -> impl Iterator<Item = SoftBodyHandle> + '_ {
92 let whole = self.pieces.is_empty().then_some(self.soft_body);
93 whole
94 .into_iter()
95 .chain(self.pieces.iter().map(|piece| piece.soft_body))
96 }
97
98 /// Where the particle `particle` of the torn body (a post-tear index, as the other fields
99 /// use) is now: the soft body holding it and its index there. `None` for an index the torn
100 /// body never had.
101 pub fn particle_destination(&self, particle: u32) -> Option<(SoftBodyHandle, u32)> {
102 if self.pieces.is_empty() {
103 return Some((self.soft_body, particle));
104 }
105 self.pieces.iter().find_map(|piece| {
106 piece
107 .particles
108 .binary_search(&particle)
109 .ok()
110 .map(|i| (piece.soft_body, i as u32))
111 })
112 }
113
114 /// The particle pairs this tear or cut separated: every split copy with its source, and the
115 /// two particles a cut inserted on each side of a crossed segment. The seeds of
116 /// [`crate::dynamics::SoftBody::seeded_components`] (post-tear indices).
117 pub fn seeds(&self) -> Vec<[u32; 2]> {
118 let mut seeds: Vec<[u32; 2]> = self
119 .split_particles
120 .iter()
121 .map(|&(copy, source)| [copy, source])
122 .collect();
123 seeds.extend(
124 self.inserted_particles
125 .chunks_exact(2)
126 .map(|pair| [pair[0], pair[1]]),
127 );
128 seeds
129 }
130}
131
132/// The smoothed load (a fraction of the tear threshold) past which a torn edge is never paced
133/// by `SoftBodyMaterial::max_tears_per_step`.
134pub(super) const CATASTROPHIC_STRESS: Real = 2.0;