parry2d/query/closest_points/
closest_points_segment_segment.rs1use crate::math::{Pose, Real, Vector2};
2use crate::query::ClosestPoints;
3use crate::shape::{Segment, SegmentPointLocation};
4
5use crate::math::Vector;
6
7#[inline]
9pub fn closest_points_segment_segment(
10 pos12: &Pose,
11 seg1: &Segment,
12 seg2: &Segment,
13 margin: Real,
14) -> ClosestPoints {
15 let (loc1, loc2) = closest_points_segment_segment_with_locations(pos12, seg1, seg2);
16 let p1 = seg1.point_at(&loc1);
17 let p2 = seg2.point_at(&loc2);
18
19 if (p1 - (pos12 * p2)).length_squared() <= margin * margin {
20 ClosestPoints::WithinMargin(p1, p2)
21 } else {
22 ClosestPoints::Disjoint
23 }
24}
25
26#[inline]
29pub fn closest_points_segment_segment_with_locations(
30 pos12: &Pose,
31 seg1: &Segment,
32 seg2: &Segment,
33) -> (SegmentPointLocation, SegmentPointLocation) {
34 let seg2_1 = seg2.transformed(pos12);
35 closest_points_segment_segment_with_locations_nD((&seg1.a, &seg1.b), (&seg2_1.a, &seg2_1.b))
36}
37
38macro_rules! impl_closest_points(
39 ($Vect: ty, $fname: ident) => {
40 #[allow(non_snake_case)]
42 #[inline]
43 pub fn $fname(
44 seg1: (&$Vect, &$Vect),
45 seg2: (&$Vect, &$Vect),
46 ) -> (SegmentPointLocation, SegmentPointLocation) {
47 let d1 = seg1.1 - seg1.0;
49 let d2 = seg2.1 - seg2.0;
50 let r = seg1.0 - seg2.0;
51
52 let a = d1.length_squared();
53 let e = d2.length_squared();
54 let f = d2.dot(r);
55
56 let mut s;
57 let mut t;
58
59 let _eps = crate::math::DEFAULT_EPSILON;
60 if a <= _eps && e <= _eps {
61 s = 0.0;
62 t = 0.0;
63 } else if a <= _eps {
64 s = 0.0;
65 t = (f / e).clamp(0.0, 1.0);
66 } else {
67 let c = d1.dot(r);
68 if e <= _eps {
69 t = 0.0;
70 s = (-c / a).clamp(0.0, 1.0);
71 } else {
72 let b = d1.dot(d2);
73 let ae = a * e;
74 let bb = b * b;
75 let denom = ae - bb;
76
77 if denom > _eps && !ulps_eq!(ae, bb) {
79 s = ((b * f - c * e) / denom).clamp(0.0, 1.0);
80 } else {
81 s = 0.0;
82 }
83
84 t = (b * s + f) / e;
85
86 if t < 0.0 {
87 t = 0.0;
88 s = (-c / a).clamp(0.0, 1.0);
89 } else if t > 1.0 {
90 t = 1.0;
91 s = ((b - c) / a).clamp(0.0, 1.0);
92 }
93 }
94 }
95
96 let loc1 = if s == 0.0 {
97 SegmentPointLocation::OnVertex(0)
98 } else if s == 1.0 {
99 SegmentPointLocation::OnVertex(1)
100 } else {
101 SegmentPointLocation::OnEdge([1.0 - s, s])
102 };
103
104 let loc2 = if t == 0.0 {
105 SegmentPointLocation::OnVertex(0)
106 } else if t == 1.0 {
107 SegmentPointLocation::OnVertex(1)
108 } else {
109 SegmentPointLocation::OnEdge([1.0 - t, t])
110 };
111
112 (loc1, loc2)
113 }
114 }
115);
116
117impl_closest_points!(Vector2, closest_points_segment_segment_2d);
118impl_closest_points!(Vector, closest_points_segment_segment_with_locations_nD);