parry3d/query/sat/sat_cuboid_segment.rs
1use crate::math::{Isometry, Real, Vector};
2use crate::query::sat;
3use crate::shape::{Cuboid, Segment};
4
5/// Finds the best separating axis by testing edge-edge combinations between a cuboid and a segment (3D only).
6///
7/// In 3D, when a box collides with a line segment, the contact might occur along an axis
8/// perpendicular to both a cuboid edge and the segment itself. This function tests all such
9/// axes (cross products) to find the one with maximum separation.
10///
11/// # Parameters
12///
13/// - `cube1`: The cuboid
14/// - `segment2`: The line segment
15/// - `pos12`: The position of the segment relative to the cuboid
16///
17/// # Returns
18///
19/// A tuple containing:
20/// - `Real`: The maximum separation found across all edge-edge axes
21/// - **Positive**: Shapes are separated
22/// - **Negative**: Shapes are overlapping
23/// - `Vector<Real>`: The axis direction that gives this separation
24///
25/// # The 3 Axes Tested
26///
27/// A segment is a single edge, so we test cross products between:
28/// - The segment's direction (B - A)
29/// - Each of the 3 cuboid edge directions (X, Y, Z)
30///
31/// This gives 3 potential separating axes. The function delegates to
32/// [`cuboid_support_map_find_local_separating_edge_twoway`](super::cuboid_support_map_find_local_separating_edge_twoway)
33/// to perform the actual separation tests.
34///
35/// # Example
36///
37/// ```rust
38/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
39/// use parry3d::shape::{Cuboid, Segment};
40/// use parry3d::query::sat::cuboid_segment_find_local_separating_edge_twoway;
41/// use nalgebra::{Point3, Vector3, Isometry3};
42///
43/// let cube = Cuboid::new(Vector3::new(1.0, 1.0, 1.0));
44/// let segment = Segment::new(
45/// Point3::origin(),
46/// Point3::new(0.0, 2.0, 0.0)
47/// );
48///
49/// // Position segment to the right of the cube
50/// let pos12 = Isometry3::translation(2.5, 0.0, 0.0);
51///
52/// let (separation, axis) = cuboid_segment_find_local_separating_edge_twoway(
53/// &cube,
54/// &segment,
55/// &pos12
56/// );
57///
58/// println!("Edge-edge separation: {}", separation);
59/// # }
60/// ```
61///
62/// # Usage in Complete SAT
63///
64/// For a complete cuboid-segment collision test, you must also test:
65/// 1. Cuboid face normals (X, Y, Z axes)
66/// 2. Segment normal (in 2D) or face normal (for degenerate 3D cases)
67/// 3. Edge-edge axes (this function, 3D only)
68#[cfg(feature = "dim3")]
69pub fn cuboid_segment_find_local_separating_edge_twoway(
70 cube1: &Cuboid,
71 segment2: &Segment,
72 pos12: &Isometry<Real>,
73) -> (Real, Vector<Real>) {
74 let x2 = pos12 * (segment2.b - segment2.a);
75
76 let axes = [
77 // Vector::{x, y ,z}().cross(y2)
78 Vector::new(0.0, -x2.z, x2.y),
79 Vector::new(x2.z, 0.0, -x2.x),
80 Vector::new(-x2.y, x2.x, 0.0),
81 ];
82
83 sat::cuboid_support_map_find_local_separating_edge_twoway(cube1, segment2, &axes, pos12)
84}
85
86/// Finds the best separating axis by testing a segment's normal against a cuboid (2D only).
87///
88/// In 2D, a segment (line segment) has an associated normal vector perpendicular to the segment.
89/// This function tests both directions of this normal to find the maximum separation from the cuboid.
90///
91/// # How It Works
92///
93/// The function treats the segment as a point-with-normal using one of its endpoints (point A)
94/// and delegates to [`point_cuboid_find_local_separating_normal_oneway`](super::point_cuboid_find_local_separating_normal_oneway).
95///
96/// # Parameters
97///
98/// - `segment1`: The line segment whose normal will be tested
99/// - `shape2`: The cuboid
100/// - `pos12`: The position of the cuboid relative to the segment
101///
102/// # Returns
103///
104/// A tuple containing:
105/// - `Real`: The separation distance along the segment's normal
106/// - **Positive**: Shapes are separated
107/// - **Negative**: Shapes are overlapping
108/// - `Vector<Real>`: The normal direction that gives this separation
109///
110/// # Example
111///
112/// ```rust
113/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
114/// use parry2d::shape::{Segment, Cuboid};
115/// use parry2d::query::sat::segment_cuboid_find_local_separating_normal_oneway;
116/// use nalgebra::{Point2, Vector2, Isometry2};
117///
118/// // Horizontal segment
119/// let segment = Segment::new(
120/// Point2::origin(),
121/// Point2::new(2.0, 0.0)
122/// );
123/// let cuboid = Cuboid::new(Vector2::new(1.0, 1.0));
124///
125/// // Position cuboid above the segment
126/// let pos12 = Isometry2::translation(1.0, 2.5);
127///
128/// let (separation, normal) = segment_cuboid_find_local_separating_normal_oneway(
129/// &segment,
130/// &cuboid,
131/// &pos12
132/// );
133///
134/// println!("Separation along segment normal: {}", separation);
135/// # }
136/// ```
137///
138/// # 2D Only
139///
140/// This function is only available in 2D. In 3D, segments don't have a unique normal direction
141/// (there are infinitely many perpendicular directions), so edge-edge cross products are used
142/// instead (see `cuboid_segment_find_local_separating_edge_twoway`).
143#[cfg(feature = "dim2")]
144pub fn segment_cuboid_find_local_separating_normal_oneway(
145 segment1: &Segment,
146 shape2: &Cuboid,
147 pos12: &Isometry<Real>,
148) -> (Real, Vector<Real>) {
149 sat::point_cuboid_find_local_separating_normal_oneway(
150 segment1.a,
151 segment1.normal(),
152 shape2,
153 pos12,
154 )
155}