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
use crate;
use crate;
/// Computes the separation distance between a cuboid and a convex support map shape along a given axis.
///
/// This function tests both the positive and negative directions of the axis to find which
/// orientation gives the actual separation between the shapes. This is necessary because we don't
/// know in advance which direction will show the true separation.
///
/// # Parameters
///
/// - `cube1`: The cuboid
/// - `shape2`: Any convex shape implementing [`SupportMap`] (sphere, capsule, convex mesh, etc.)
/// - `pos12`: The position of `shape2` relative to `cube1`
/// - `axis1`: The unit direction vector (in `cube1`'s local space) to test
///
/// # Returns
///
/// A tuple containing:
/// - `Real`: The separation distance along the better of the two axis directions
/// - **Positive**: Shapes are separated
/// - **Negative**: Shapes are overlapping
/// - `Vector`: The axis direction (either `axis1` or `-axis1`) that gives this separation
///
/// # Why Test Both Directions?
///
/// When testing separation along an axis, we need to check both `axis1` and `-axis1` because:
/// - The shapes might be oriented such that one direction shows separation while the other shows overlap
/// - We want to find the direction that gives the maximum (least negative) separation
///
/// For symmetric shapes like sphere vs sphere, both directions give the same result, but for
/// asymmetric configurations, testing both is necessary for correctness.
///
/// # Example
///
/// ```rust
/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
/// use parry3d::shape::{Cuboid, Ball};
/// use parry3d::query::sat::cuboid_support_map_compute_separation_wrt_local_line;
/// use parry3d::math::{Pose, Vector};
///
/// let cube = Cuboid::new(Vector::splat(1.0));
/// let sphere = Ball::new(0.5);
///
/// // Position sphere near the cube
/// let pos12 = Pose::translation(2.0, 0.0, 0.0);
///
/// // Test separation along an arbitrary axis
/// let axis = Vector::new(1.0, 1.0, 0.0).normalize();
/// let (separation, chosen_axis) = cuboid_support_map_compute_separation_wrt_local_line(
/// &cube,
/// &sphere,
/// &pos12,
/// axis
/// );
///
/// println!("Separation: {} along axis: {:?}", separation, chosen_axis);
/// # }
/// ```
///
/// # Performance Note
///
/// This is a relatively expensive operation as it computes support points in both directions.
/// For specific shape pairs (like cuboid-cuboid), there are optimized versions that avoid this
/// double computation.
/// Finds the best separating axis by testing edge-edge combinations between a cuboid and a support map shape.
///
/// This function is used in 3D SAT implementations where edge-edge contact is possible. It tests
/// a precomputed set of axes (typically cross products of edges from both shapes) to find the
/// axis with maximum separation.
///
/// # Parameters
///
/// - `cube1`: The cuboid
/// - `shape2`: Any convex shape implementing [`SupportMap`]
/// - `axes`: A slice of axis directions to test (not necessarily unit length)
/// - `pos12`: The position of `shape2` relative to `cube1`
///
/// # Returns
///
/// A tuple containing:
/// - `Real`: The maximum separation found across all tested axes
/// - **Positive**: Shapes are separated
/// - **Negative**: Shapes are overlapping (minimum penetration)
/// - `Vector`: The axis direction that gives this separation (normalized)
///
/// # Why Precomputed Axes?
///
/// The caller typically computes the candidate axes as cross products of edges:
/// - Cuboid has 3 edge directions (X, Y, Z)
/// - The other shape's edges depend on its geometry
/// - Cross products of these edges give potential separating axes
///
/// This function handles the actual separation testing for those precomputed axes.
///
/// # Example
///
/// ```rust
/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
/// use parry3d::shape::{Cuboid, Capsule};
/// use parry3d::query::sat::cuboid_support_map_find_local_separating_edge_twoway;
/// use parry3d::math::{Pose, Vector};
///
/// let cube = Cuboid::new(Vector::splat(1.0));
/// let capsule = Capsule::new(Vector::new(0.0, -1.0, 0.0), Vector::new(0.0, 1.0, 0.0), 0.5);
///
/// // Position capsule near the cube
/// let pos12 = Pose::translation(2.0, 0.0, 0.0);
///
/// // Compute edge cross products
/// let capsule_dir = Vector::Y; // capsule's axis direction
/// let axes = [
/// Vector::X.cross(capsule_dir), // cube X × capsule axis
/// Vector::Y.cross(capsule_dir), // cube Y × capsule axis
/// Vector::Z.cross(capsule_dir), // cube Z × capsule axis
/// ];
///
/// let (separation, axis) = cuboid_support_map_find_local_separating_edge_twoway(
/// &cube,
/// &capsule,
/// &axes,
/// &pos12
/// );
///
/// println!("Best edge-edge separation: {} along {:?}", separation, axis);
/// # }
/// ```
///
/// # Implementation Details
///
/// - Axes with near-zero length are skipped (they represent parallel or degenerate edges)
/// - Each axis is normalized before computing separation
/// - The function tests both positive and negative directions of each axis using
/// `cuboid_support_map_compute_separation_wrt_local_line`
/// Finds the best separating axis by testing the face normals of a cuboid against a support map shape.
///
/// This function tests all face normals (X, Y, and Z axes in both positive and negative directions)
/// of the cuboid to find which direction gives the maximum separation from the support map shape.
///
/// # Parameters
///
/// - `cube1`: The cuboid whose face normals will be tested
/// - `shape2`: Any convex shape implementing [`SupportMap`]
/// - `pos12`: The position of `shape2` relative to `cube1`
///
/// # Returns
///
/// A tuple containing:
/// - `Real`: The maximum separation found among the cuboid's face normals
/// - **Positive**: Shapes are separated
/// - **Negative**: Shapes are overlapping
/// - `Vector`: The face normal direction that gives this separation
///
/// # Usage in Complete SAT
///
/// This function tests only the face normals of the cuboid. For a complete SAT collision test
/// between a cuboid and another shape, you typically need to:
///
/// 1. Test cuboid's face normals (this function)
/// 2. Test the other shape's face normals (if applicable)
/// 3. Test edge-edge cross products in 3D (if both shapes have edges)
///
/// # Example
///
/// ```rust
/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
/// use parry2d::shape::{Cuboid, Ball};
/// use parry2d::query::sat::cuboid_support_map_find_local_separating_normal_oneway;
/// use parry2d::math::{Pose, Vector};
///
/// let cube = Cuboid::new(Vector::new(1.0, 1.0));
/// let sphere = Ball::new(0.5);
///
/// // Position sphere to the right of the cube
/// let pos12 = Pose::translation(2.0, 0.0);
///
/// let (separation, normal) = cuboid_support_map_find_local_separating_normal_oneway(
/// &cube,
/// &sphere,
/// &pos12
/// );
///
/// if separation > 0.0 {
/// println!("Shapes separated by {} along normal {}", separation, normal);
/// } else {
/// println!("Shapes overlapping by {} along normal {}", -separation, normal);
/// }
/// # }
/// ```
///
/// # Performance
///
/// This function is more efficient than `cuboid_support_map_compute_separation_wrt_local_line`
/// for face normals because it can directly compute the separation without testing both directions.
/// It tests 2×DIM axes (where DIM is 2 or 3).