Skip to main content

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;