parry3d/query/split/
split_segment.rs

1use crate::math::{Point, Real, UnitVector, Vector};
2use crate::query::SplitResult;
3use crate::shape::Segment;
4
5impl Segment {
6    /// Splits this segment along the given canonical axis.
7    ///
8    /// This will split the segment by a plane with a normal with it’s `axis`-th component set to 1.
9    /// The splitting plane is shifted wrt. the origin by the `bias` (i.e. it passes through the point
10    /// equal to `normal * bias`).
11    ///
12    /// # Result
13    /// Returns the result of the split. The first shape returned is the piece lying on the negative
14    /// half-space delimited by the splitting plane. The second shape returned is the piece lying on the
15    /// positive half-space delimited by the splitting plane.
16    pub fn canonical_split(&self, axis: usize, bias: Real, epsilon: Real) -> SplitResult<Self> {
17        // TODO: optimize this.
18        self.local_split(&Vector::ith_axis(axis), bias, epsilon)
19    }
20
21    /// Splits this segment by a plane identified by its normal `local_axis` and
22    /// the `bias` (i.e. the plane passes through the point equal to `normal * bias`).
23    pub fn local_split(
24        &self,
25        local_axis: &UnitVector<Real>,
26        bias: Real,
27        epsilon: Real,
28    ) -> SplitResult<Self> {
29        self.local_split_and_get_intersection(local_axis, bias, epsilon)
30            .0
31    }
32
33    /// Split a segment with a plane.
34    ///
35    /// This returns the result of the splitting operation, as well as
36    /// the intersection point (and barycentric coordinate of this point)
37    /// with the plane. The intersection point is `None` if the plane is
38    /// parallel or near-parallel to the segment.
39    pub fn local_split_and_get_intersection(
40        &self,
41        local_axis: &UnitVector<Real>,
42        bias: Real,
43        epsilon: Real,
44    ) -> (SplitResult<Self>, Option<(Point<Real>, Real)>) {
45        let dir = self.b - self.a;
46        let a = bias - local_axis.dot(&self.a.coords);
47        let b = local_axis.dot(&dir);
48        let bcoord = a / b;
49        let dir_norm = dir.norm();
50
51        if relative_eq!(b, 0.0)
52            || bcoord * dir_norm <= epsilon
53            || bcoord * dir_norm >= dir_norm - epsilon
54        {
55            if a >= 0.0 {
56                (SplitResult::Negative, None)
57            } else {
58                (SplitResult::Positive, None)
59            }
60        } else {
61            let intersection = self.a + dir * bcoord;
62            let s1 = Segment::new(self.a, intersection);
63            let s2 = Segment::new(intersection, self.b);
64            if a >= 0.0 {
65                (SplitResult::Pair(s1, s2), Some((intersection, bcoord)))
66            } else {
67                (SplitResult::Pair(s2, s1), Some((intersection, bcoord)))
68            }
69        }
70    }
71}