box2d_rs/private/collision/
b2_collide_edge.rs1use crate::b2_collision::*;
2use crate::b2_math::*;
3use crate::b2_common::*;
4use crate::b2_settings::*;
5use crate::shapes::b2_circle_shape::*;
6use crate::shapes::b2_edge_shape::*;
7use crate::shapes::b2_polygon_shape::*;
8
9pub fn b2_collide_edge_and_circle(
12 manifold: &mut B2manifold,
13 edge_a: &B2edgeShape,
14 xf_a: &B2Transform,
15 circle_b: &B2circleShape,
16 xf_b: &B2Transform,
17) {
18 manifold.point_count = 0;
19 let q: B2vec2 =
21 b2_mul_t_transform_by_vec2(*xf_a, b2_mul_transform_by_vec2(*xf_b, circle_b.m_p));
22
23 let (a, b) = (edge_a.m_vertex1, edge_a.m_vertex2);
24 let e: B2vec2 = b - a;
25
26 let mut n = B2vec2::new(e.y, -e.x);
28 let offset: f32 = b2_dot(n, q - a);
29
30 let one_sided: bool = edge_a.m_one_sided;
31 if one_sided && offset < 0.0 {
32 return;
33 }
34
35 let u: f32 = b2_dot(e, b - q);
37 let v: f32 = b2_dot(e, q - a);
38
39 let radius: f32 = edge_a.base.m_radius + circle_b.base.m_radius;
40 let mut cf = B2contactFeature::default();
41 cf.index_b = 0;
42 cf.type_b = B2contactFeatureType::EVertex as u8;
43 if v <= 0.0 {
45 let p: B2vec2 = a;
46 let d: B2vec2 = q - p;
47 let dd: f32 = b2_dot(d, d);
48 if dd > radius * radius {
49 return;
50 }
51 if edge_a.m_one_sided {
53 let a1: B2vec2 = edge_a.m_vertex0;
54 let b1: B2vec2 = a;
55 let e1: B2vec2 = b1 - a1;
56 let u1: f32 = b2_dot(e1, b1 - q);
57 if u1 > 0.0 {
59 return;
60 }
61 }
62 cf.index_a = 0;
63 cf.type_a = B2contactFeatureType::EVertex as u8;
64 manifold.point_count = 1;
65 manifold.manifold_type = B2manifoldType::ECircles;
66 manifold.local_normal.set_zero();
67 manifold.local_point = p;
68 manifold.points[0].id.cf = cf;
69 manifold.points[0].local_point = circle_b.m_p;
70 return;
71 }
72 if u <= 0.0 {
74 let p: B2vec2 = b;
75 let d: B2vec2 = q - p;
76 let dd: f32 = b2_dot(d, d);
77 if dd > radius * radius {
78 return;
79 }
80 if edge_a.m_one_sided {
82 let b2: B2vec2 = edge_a.m_vertex3;
83 let a2: B2vec2 = b;
84 let e2: B2vec2 = b2 - a2;
85 let v2: f32 = b2_dot(e2, q - a2);
86 if v2 > 0.0 {
88 return;
89 }
90 }
91 cf.index_a = 1;
92 cf.type_a = B2contactFeatureType::EVertex as u8;
93 manifold.point_count = 1;
94 manifold.manifold_type = B2manifoldType::ECircles;
95 manifold.local_normal.set_zero();
96 manifold.local_point = p;
97 manifold.points[0].id.cf = cf;
98 manifold.points[0].local_point = circle_b.m_p;
99 return;
100 }
101 let den: f32 = b2_dot(e, e);
103 b2_assert(den > 0.0);
104 let p: B2vec2 = (1.0 / den) * (u * a + v * b);
105 let d: B2vec2 = q - p;
106 let dd: f32 = b2_dot(d, d);
107 if dd > radius * radius {
108 return;
109 }
110
111 if offset < 0.0 {
112 n.set(-n.x, -n.y);
113 }
114 n.normalize();
115 cf.index_a = 0;
116 cf.type_a = B2contactFeatureType::EFace as u8;
117 manifold.point_count = 1;
118 manifold.manifold_type = B2manifoldType::EFaceA;
119 manifold.local_normal = n;
120 manifold.local_point = a;
121 manifold.points[0].id.cf = cf;
122 manifold.points[0].local_point = circle_b.m_p;
123}
124
125#[derive(Clone, Copy, Debug, PartialEq, Eq)]
126enum B2ePAxisType {
127 EUnknown,
128 EEdgeA,
129 EEdgeB,
130}
131
132impl Default for B2ePAxisType {
133 fn default() -> Self {
134 return B2ePAxisType::EUnknown;
135 }
136}
137
138#[derive(Clone, Default, Copy, Debug)]
140struct B2epaxis {
141 normal: B2vec2,
142 axis_type: B2ePAxisType,
143 index: i32,
144 separation: f32,
145}
146
147#[derive(Clone, Default, Copy, Debug)]
149struct B2tempPolygon {
150 vertices: [B2vec2; B2_MAX_POLYGON_VERTICES],
151 normals: [B2vec2; B2_MAX_POLYGON_VERTICES],
152 count: usize,
153}
154
155#[derive(Clone, Default, Copy, Debug)]
157struct B2referenceFace {
158 i1: usize,
159 i2: usize,
160
161 v1: B2vec2,
162 v2: B2vec2,
163
164 normal: B2vec2,
165 side_normal1: B2vec2,
166 side_offset1: f32,
167
168 side_normal2: B2vec2,
169 side_offset2: f32,
170}
171
172fn b2_compute_edge_separation(polygon_b: B2tempPolygon, v1: B2vec2, normal1: B2vec2) -> B2epaxis {
173 let mut axis = B2epaxis {
174 axis_type: B2ePAxisType::EEdgeA,
175 index: -1,
176 separation: -B2_MAX_FLOAT,
177 normal: B2vec2::zero(),
178 };
179
180 let axes: [B2vec2; 2] = [normal1, -normal1];
181
182 for j in 0..2 {
184 let mut sj: f32 = B2_MAX_FLOAT;
185
186 for i in 0..polygon_b.count {
188 let si: f32 = b2_dot(axes[j], polygon_b.vertices[i] - v1);
189 if si < sj {
190 sj = si;
191 }
192 }
193
194 if sj > axis.separation {
195 axis.index = j as i32;
196 axis.separation = sj;
197 axis.normal = axes[j];
198 }
199 }
200
201 return axis;
202}
203
204fn b2_compute_polygon_separation(polygon_b: B2tempPolygon, v1: B2vec2, v2: B2vec2) -> B2epaxis {
205 let mut axis = B2epaxis {
206 axis_type: B2ePAxisType::EUnknown,
207 index: -1,
208 separation: -B2_MAX_FLOAT,
209 normal: B2vec2::zero(),
210 };
211
212 for i in 0..polygon_b.count {
213 let n: B2vec2 = -polygon_b.normals[i];
214
215 let s1: f32 = b2_dot(n, polygon_b.vertices[i] - v1);
216 let s2: f32 = b2_dot(n, polygon_b.vertices[i] - v2);
217 let s: f32 = b2_min(s1, s2);
218
219 if s > axis.separation {
220 axis.axis_type = B2ePAxisType::EEdgeB;
221 axis.index = i as i32;
222 axis.separation = s;
223 axis.normal = n;
224 }
225 }
226
227 return axis;
228}
229
230pub fn b2_collide_edge_and_polygon(
231 manifold: &mut B2manifold,
232 edge_a: &B2edgeShape,
233 xf_a: &B2Transform,
234 polygon_b: &B2polygonShape,
235 xf_b: &B2Transform,
236) {
237 manifold.point_count = 0;
238
239 let xf: B2Transform = b2_mul_t_transform(*xf_a, *xf_b);
240
241 let centroid_b: B2vec2 = b2_mul_transform_by_vec2(xf, polygon_b.m_centroid);
242
243 let v1: B2vec2 = edge_a.m_vertex1;
244 let v2: B2vec2 = edge_a.m_vertex2;
245
246 let mut edge1: B2vec2 = v2 - v1;
247 edge1.normalize();
248
249 let normal1 = B2vec2::new(edge1.y, -edge1.x);
251 let offset1: f32 = b2_dot(normal1, centroid_b - v1);
252
253 let one_sided: bool = edge_a.m_one_sided;
254 if one_sided && offset1 < 0.0 {
255 return;
256 }
257
258 let mut temp_polygon_b = B2tempPolygon::default();
260 temp_polygon_b.count = polygon_b.m_count;
261 for i in 0..polygon_b.m_count {
262 temp_polygon_b.vertices[i] = b2_mul_transform_by_vec2(xf, polygon_b.m_vertices[i]);
263 temp_polygon_b.normals[i] = b2_mul_rot_by_vec2(xf.q, polygon_b.m_normals[i]);
264 }
265
266 let radius: f32 = polygon_b.base.m_radius + edge_a.base.m_radius;
267
268 let edge_axis: B2epaxis = b2_compute_edge_separation(temp_polygon_b, v1, normal1);
269 if edge_axis.separation > radius {
270 return;
271 }
272
273 let polygon_axis: B2epaxis = b2_compute_polygon_separation(temp_polygon_b, v1, v2);
274 if polygon_axis.separation > radius {
275 return;
276 }
277
278 const K_RELATIVE_TOL: f32 = 0.98;
280 const K_ABSOLUTE_TOL: f32 = 0.001;
281
282 let mut primary_axis: B2epaxis;
283 if polygon_axis.separation - radius
284 > K_RELATIVE_TOL * (edge_axis.separation - radius) + K_ABSOLUTE_TOL
285 {
286 primary_axis = polygon_axis;
287 } else {
288 primary_axis = edge_axis;
289 }
290
291 if one_sided {
292 let mut edge0: B2vec2 = v1 - edge_a.m_vertex0;
296 edge0.normalize();
297 let normal0 = B2vec2::new(edge0.y, -edge0.x);
298 let convex1: bool = b2_cross(edge0, edge1) >= 0.0;
299
300 let mut edge2: B2vec2 = edge_a.m_vertex3 - v2;
301 edge2.normalize();
302 let normal2 = B2vec2::new(edge2.y, -edge2.x);
303 let convex2: bool = b2_cross(edge1, edge2) >= 0.0;
304
305 const SIN_TOL: f32 = 0.1;
306 let side1: bool = b2_dot(primary_axis.normal, edge1) <= 0.0;
307
308 if side1 {
310 if convex1 {
311 if b2_cross(primary_axis.normal, normal0) > SIN_TOL {
312 return;
314 }
315
316 } else {
318 primary_axis = edge_axis;
320 }
321 } else {
322 if convex2 {
323 if b2_cross(normal2, primary_axis.normal) > SIN_TOL {
324 return;
326 }
327
328 } else {
330 primary_axis = edge_axis;
332 }
333 }
334 }
335
336 let mut clip_points = <[B2clipVertex; 2]>::default();
337 let mut rf = B2referenceFace::default();
338 if primary_axis.axis_type == B2ePAxisType::EEdgeA {
339 manifold.manifold_type = B2manifoldType::EFaceA;
340
341 let mut best_index: i32 = 0;
343 let mut best_value: f32 = b2_dot(primary_axis.normal, temp_polygon_b.normals[0]);
344 for i in 1..temp_polygon_b.count {
345 let value: f32 = b2_dot(primary_axis.normal, temp_polygon_b.normals[i]);
346 if value < best_value {
347 best_value = value;
348 best_index = i as i32;
349 }
350 }
351
352 let i1: i32 = best_index;
353 let i2: i32 = if i1 + 1 < temp_polygon_b.count as i32 {
354 i1 + 1
355 } else {
356 0
357 };
358
359 clip_points[0].v = temp_polygon_b.vertices[i1 as usize];
360 clip_points[0].id.cf.index_a = 0;
361 clip_points[0].id.cf.index_b = i1 as u8;
362 clip_points[0].id.cf.type_a = B2contactFeatureType::EFace as u8;
363 clip_points[0].id.cf.type_b = B2contactFeatureType::EVertex as u8;
364
365 clip_points[1].v = temp_polygon_b.vertices[i2 as usize];
366 clip_points[1].id.cf.index_a = 0;
367 clip_points[1].id.cf.index_b = i2 as u8;
368 clip_points[1].id.cf.type_a = B2contactFeatureType::EFace as u8;
369 clip_points[1].id.cf.type_b = B2contactFeatureType::EVertex as u8;
370
371 rf.i1 = 0;
372 rf.i2 = 1;
373 rf.v1 = v1;
374 rf.v2 = v2;
375 rf.normal = primary_axis.normal;
376 rf.side_normal1 = -edge1;
377 rf.side_normal2 = edge1;
378 } else {
379 manifold.manifold_type = B2manifoldType::EFaceB;
380
381 clip_points[0].v = v2;
382 clip_points[0].id.cf.index_a = 1;
383 clip_points[0].id.cf.index_b = primary_axis.index as u8;
384 clip_points[0].id.cf.type_a = B2contactFeatureType::EVertex as u8;
385 clip_points[0].id.cf.type_b = B2contactFeatureType::EFace as u8;
386
387 clip_points[1].v = v1;
388 clip_points[1].id.cf.index_a = 0;
389 clip_points[1].id.cf.index_b = primary_axis.index as u8;
390 clip_points[1].id.cf.type_a = B2contactFeatureType::EVertex as u8;
391 clip_points[1].id.cf.type_b = B2contactFeatureType::EFace as u8;
392
393 rf.i1 = primary_axis.index as usize;
394 rf.i2 = if rf.i1 + 1 < temp_polygon_b.count {
395 rf.i1 + 1
396 } else {
397 0
398 };
399 rf.v1 = temp_polygon_b.vertices[rf.i1];
400 rf.v2 = temp_polygon_b.vertices[rf.i2];
401 rf.normal = temp_polygon_b.normals[rf.i1];
402
403 rf.side_normal1.set(rf.normal.y, -rf.normal.x);
405 rf.side_normal2 = -rf.side_normal1;
406 }
407
408 rf.side_offset1 = b2_dot(rf.side_normal1, rf.v1);
409 rf.side_offset2 = b2_dot(rf.side_normal2, rf.v2);
410
411 let mut clip_points1 = <[B2clipVertex; 2]>::default();
413 let mut clip_points2 = <[B2clipVertex; 2]>::default();
414
415 let np: usize = b2_clip_segment_to_line(
417 &mut clip_points1,
418 clip_points,
419 rf.side_normal1,
420 rf.side_offset1,
421 rf.i1,
422 );
423
424 if np < B2_MAX_MANIFOLD_POINTS {
425 return;
426 }
427
428 let np: usize = b2_clip_segment_to_line(
430 &mut clip_points2,
431 clip_points1,
432 rf.side_normal2,
433 rf.side_offset2,
434 rf.i2,
435 );
436
437 if np < B2_MAX_MANIFOLD_POINTS {
438 return;
439 }
440
441 if primary_axis.axis_type == B2ePAxisType::EEdgeA {
443 manifold.local_normal = rf.normal;
444 manifold.local_point = rf.v1;
445 } else {
446 manifold.local_normal = polygon_b.m_normals[rf.i1];
447 manifold.local_point = polygon_b.m_vertices[rf.i1];
448 }
449
450 let mut point_count: usize = 0;
451 for i in 0..B2_MAX_MANIFOLD_POINTS {
452 let separation: f32;
453
454 separation = b2_dot(rf.normal, clip_points2[i].v - rf.v1);
455
456 if separation <= radius {
457 let cp: &mut B2manifoldPoint = &mut manifold.points[point_count];
458
459 if primary_axis.axis_type == B2ePAxisType::EEdgeA {
460 cp.local_point = b2_mul_t_transform_by_vec2(xf, clip_points2[i].v);
461 cp.id = clip_points2[i].id;
462 } else {
463 cp.local_point = clip_points2[i].v;
464 cp.id.cf.type_a = clip_points2[i].id.cf.type_b;
465 cp.id.cf.type_b = clip_points2[i].id.cf.type_a;
466 cp.id.cf.index_a = clip_points2[i].id.cf.index_b;
467 cp.id.cf.index_b = clip_points2[i].id.cf.index_a;
468 }
469
470 point_count += 1;
471 }
472 }
473
474 manifold.point_count = point_count;
475}