1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
use crate;
use crate;
/// Computes the separation distance between two cuboids along a given axis.
///
/// This function is part of the Separating Axis Theorem (SAT) implementation for cuboid-cuboid
/// collision detection. It projects both cuboids onto the specified axis and computes how far
/// apart they are (positive = separated, negative = overlapping).
///
/// # How It Works
///
/// 1. Orients the axis to point from cuboid1 toward cuboid2 (using the translation vector)
/// 2. Finds the support points (furthest points) on each cuboid in that direction
/// 3. Computes the signed distance between these support points along the axis
///
/// # Parameters
///
/// - `cuboid1`: The first cuboid (in its local coordinate frame)
/// - `cuboid2`: The second cuboid
/// - `pos12`: The position of cuboid2 relative to cuboid1 (transforms from cuboid2's space to cuboid1's space)
/// - `axis1`: The axis direction in cuboid1's local space to test for separation
///
/// # Returns
///
/// A tuple containing:
/// - `Real`: The separation distance along the axis
/// - **Positive**: Shapes are separated by this distance
/// - **Negative**: Shapes are overlapping (penetration depth is the absolute value)
/// - **Zero**: Shapes are exactly touching
/// - `Vector`: The oriented axis direction (pointing from cuboid1 toward cuboid2)
///
/// # Example
///
/// ```rust
/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
/// use parry3d::shape::Cuboid;
/// use parry3d::query::sat::cuboid_cuboid_compute_separation_wrt_local_line;
/// use parry3d::math::{Pose, Vector};
///
/// let cube1 = Cuboid::new(Vector::splat(1.0));
/// let cube2 = Cuboid::new(Vector::splat(1.0));
///
/// // Position cube2 at (3, 0, 0) relative to cube1
/// let pos12 = Pose::translation(3.0, 0.0, 0.0);
///
/// // Test separation along the X axis
/// let (separation, _axis) = cuboid_cuboid_compute_separation_wrt_local_line(
/// &cube1,
/// &cube2,
/// &pos12,
/// Vector::X
/// );
///
/// // Should be separated by 1.0 (distance 3.0 - half_extents 1.0 - 1.0)
/// assert!(separation > 0.0);
/// # }
/// ```
/// Finds the best separating axis by testing all edge-edge combinations between two cuboids.
///
/// In 3D, edge-edge contact is common when two boxes collide. This function tests all possible
/// axes formed by the cross product of edges from each cuboid to find the axis with maximum
/// separation (or minimum penetration).
///
/// # Why Test Edge Cross Products?
///
/// When two 3D convex polyhedra collide, the separating axis (if one exists) must be either:
/// 1. A face normal from one shape
/// 2. A face normal from the other shape
/// 3. **Perpendicular to an edge from each shape** (the cross product of the edges)
///
/// This function handles case 3. For two cuboids, there are 3 edges per cuboid (aligned with X, Y, Z),
/// giving 3 × 3 = 9 possible edge pair combinations to test.
///
/// # Parameters
///
/// - `cuboid1`: The first cuboid (in its local coordinate frame)
/// - `cuboid2`: The second cuboid
/// - `pos12`: The position of cuboid2 relative to cuboid1
///
/// # Returns
///
/// A tuple containing:
/// - `Real`: The best (maximum) separation found across all edge-edge axes
/// - **Positive**: Shapes are separated
/// - **Negative**: Shapes are overlapping
/// - `Vector`: The axis direction that gives this separation
///
/// # Example
///
/// ```rust
/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
/// use parry3d::shape::Cuboid;
/// use parry3d::query::sat::cuboid_cuboid_find_local_separating_edge_twoway;
/// use parry3d::math::{Pose, Vector};
///
/// let cube1 = Cuboid::new(Vector::new(1.0, 1.0, 1.0));
/// let cube2 = Cuboid::new(Vector::new(1.0, 1.0, 1.0));
///
/// // Rotate and position cube2 so edge-edge contact is likely
/// let pos12 = Pose::translation(2.0, 2.0, 0.0);
///
/// let (separation, _axis) = cuboid_cuboid_find_local_separating_edge_twoway(
/// &cube1,
/// &cube2,
/// &pos12
/// );
///
/// if separation > 0.0 {
/// println!("Separated by {} along an edge-edge axis", separation);
/// }
/// # }
/// ```
///
/// # Note
///
/// This function only tests edge-edge axes. For a complete SAT test, you must also test
/// face normals using [`cuboid_cuboid_find_local_separating_normal_oneway`].
/// Finds the best separating axis by testing the face normals of the first cuboid.
///
/// This function tests the face normals (X, Y, Z axes in 2D/3D) of `cuboid1` to find which
/// direction gives the maximum separation between the two cuboids. This is the "one-way" test
/// that only considers faces from one cuboid.
///
/// # Why "One-Way"?
///
/// For a complete SAT test between two cuboids, you need to test:
/// 1. Face normals from cuboid1 (this function)
/// 2. Face normals from cuboid2 (call this function again with swapped arguments)
/// 3. Edge-edge cross products in 3D (`cuboid_cuboid_find_local_separating_edge_twoway`)
///
/// By testing only one shape's normals at a time, the implementation can be more efficient
/// and reusable.
///
/// # Parameters
///
/// - `cuboid1`: The cuboid whose face normals will be tested
/// - `cuboid2`: The other cuboid
/// - `pos12`: The position of cuboid2 relative to cuboid1
///
/// # Returns
///
/// A tuple containing:
/// - `Real`: The maximum separation found among cuboid1's face normals
/// - **Positive**: Shapes are separated by at least this distance
/// - **Negative**: Shapes are overlapping (penetration)
/// - `Vector`: The face normal direction that gives this separation
///
/// # Example
///
/// ```rust
/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
/// use parry2d::shape::Cuboid;
/// use parry2d::query::sat::cuboid_cuboid_find_local_separating_normal_oneway;
/// use parry2d::math::{Pose, Vector};
///
/// let rect1 = Cuboid::new(Vector::new(1.0, 1.0));
/// let rect2 = Cuboid::new(Vector::new(0.5, 0.5));
///
/// // Position rect2 to the right of rect1
/// let pos12 = Pose::translation(2.5, 0.0);
///
/// // Test rect1's face normals (X and Y axes)
/// let (sep1, normal1) = cuboid_cuboid_find_local_separating_normal_oneway(
/// &rect1, &rect2, &pos12
/// );
///
/// // Test rect2's face normals by swapping arguments and inverting the transform
/// let (sep2, normal2) = cuboid_cuboid_find_local_separating_normal_oneway(
/// &rect2, &rect1, &pos12.inverse()
/// );
///
/// // The maximum separation indicates if shapes collide
/// let max_separation = sep1.max(sep2);
/// if max_separation > 0.0 {
/// println!("Shapes are separated!");
/// }
/// # }
/// ```
///
/// # Algorithm Details
///
/// For each axis (X, Y, and Z in 3D):
/// 1. Computes the support point on cuboid2 in the negative axis direction
/// 2. Transforms it to cuboid1's space
/// 3. Measures the signed distance from cuboid1's boundary
/// 4. Tracks the axis with maximum separation