1extern crate geo;
40extern crate num_traits;
41
42use geo::{Line, Point};
43use num_traits::Float;
44
45#[derive(Debug, PartialEq)]
56pub struct LineInterval<T: Float> {
57 pub line: Line<T>,
58 pub interval_of_intersection: (T, T),
59}
60
61#[derive(Debug, PartialEq)]
63pub enum LineRelation<T: Float> {
64 DivergentIntersecting(Point<T>),
67 DivergentDisjoint,
70 Collinear,
73 Parallel,
75}
76
77impl<T: Float> LineRelation<T> {
78 pub fn unique_intersection(self) -> Option<Point<T>> {
79 match self {
80 LineRelation::DivergentIntersecting(p) => Some(p),
81 _ => None,
82 }
83 }
84}
85
86impl<T: Float> LineInterval<T> {
87 pub fn line_segment(line: Line<T>) -> LineInterval<T> {
88 LineInterval {
89 line: line,
90 interval_of_intersection: (T::zero(), T::one()),
91 }
92 }
93
94 pub fn ray(line: Line<T>) -> LineInterval<T> {
95 LineInterval {
96 line: line,
97 interval_of_intersection: (T::zero(), T::infinity()),
98 }
99 }
100
101 pub fn line(line: Line<T>) -> LineInterval<T> {
102 LineInterval {
103 line: line,
104 interval_of_intersection: (T::neg_infinity(), T::infinity()),
105 }
106 }
107
108 pub fn relate(&self, other: &LineInterval<T>) -> LineRelation<T> {
110 let p = self.line.start;
112 let q = other.line.start;
113 let r = self.line.end - self.line.start;
114 let s = other.line.end - other.line.start;
115
116 let r_cross_s = Self::cross(&r, &s);
117 let q_minus_p = q - p;
118 let q_minus_p_cross_r = Self::cross(&q_minus_p, &r);
119
120 if r_cross_s == T::zero() {
122 if q_minus_p_cross_r == T::zero() {
124 LineRelation::Collinear
126 } else {
127 LineRelation::Parallel
129 }
130 } else {
131 let t = Self::cross(&q_minus_p, &Self::div(&s, r_cross_s));
133 let u = Self::cross(&q_minus_p, &Self::div(&r, r_cross_s));
134
135 let t_in_range = self.interval_of_intersection.0 <= t &&
137 t <= self.interval_of_intersection.1;
138 let u_in_range = other.interval_of_intersection.0 <= u &&
139 u <= other.interval_of_intersection.1;
140
141 if t_in_range && u_in_range {
142 LineRelation::DivergentIntersecting(Self::t_coord_to_point(&p, &r, t))
144 } else {
145 LineRelation::DivergentDisjoint
147 }
148 }
149 }
150
151 fn cross(a: &Point<T>, b: &Point<T>) -> T {
152 a.x() * b.y() - a.y() * b.x()
153 }
154
155 fn div(a: &Point<T>, b: T) -> Point<T> {
156 (a.x() / b, a.y() / b).into()
157 }
158
159 fn t_coord_to_point(p: &Point<T>, r: &Point<T>, t: T) -> Point<T> {
160 (p.x() + t * r.x(), p.y() + t * r.y()).into()
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn divergent_intersecting_segments() {
170 let a = Line {
171 start: (1.0, 0.0).into(),
172 end: (1.0, 1.0).into(),
173 };
174 let b = Line {
175 start: (0.0, 0.0).into(),
176 end: (2.0, 0.5).into(),
177 };
178 let s1 = LineInterval::line_segment(a);
179 let s2 = LineInterval::line_segment(b);
180 let relation = LineRelation::DivergentIntersecting((1.0, 0.25).into());
181
182 assert_eq!(relation, s1.relate(&s2));
183 assert_eq!(relation, s2.relate(&s1));
184 }
185
186 #[test]
187 fn divergent_intersecting_segment_and_ray() {
188 let a = Line {
189 start: (0.0, 0.0).into(),
190 end: (1.0, 1.0).into(),
191 };
192 let b = Line {
193 start: (2.0, 0.0).into(),
194 end: (2.0, 3.0).into(),
195 };
196 let s1 = LineInterval::ray(a);
197 let s2 = LineInterval::line_segment(b);
198 let relation = LineRelation::DivergentIntersecting((2.0, 2.0).into());
199
200 assert_eq!(relation, s1.relate(&s2));
201 assert_eq!(relation, s2.relate(&s1));
202 }
203
204 #[test]
205 fn divergent_disjoint_segments() {
206 let a = Line {
207 start: (0.0, 0.0).into(),
208 end: (1.0, 1.0).into(),
209 };
210 let b = Line {
211 start: (3.0, 0.0).into(),
212 end: (0.0, 3.0).into(),
213 };
214 let s1 = LineInterval::line_segment(a);
215 let s2 = LineInterval::line_segment(b);
216 let relation = LineRelation::DivergentDisjoint;
217
218 assert_eq!(relation, s1.relate(&s2));
219 assert_eq!(relation, s2.relate(&s1));
220 }
221
222 #[test]
223 fn divergent_disjoint_ray_and_line() {
224 let a = Line {
225 start: (1.0, 1.0).into(),
226 end: (0.0, 0.0).into(),
227 };
228 let b = Line {
229 start: (3.0, 0.0).into(),
230 end: (0.0, 3.0).into(),
231 };
232 let s1 = LineInterval::ray(a);
233 let s2 = LineInterval::line(b);
234 let relation = LineRelation::DivergentDisjoint;
235
236 assert_eq!(relation, s1.relate(&s2));
237 assert_eq!(relation, s2.relate(&s1));
238 }
239
240 #[test]
241 fn parallel_disjoint_segments() {
242 let a = Line {
243 start: (0.0, 0.0).into(),
244 end: (1.0, 1.0).into(),
245 };
246 let b = Line {
247 start: (0.0, 1.0).into(),
248 end: (1.0, 2.0).into(),
249 };
250 let s1 = LineInterval::line(a);
251 let s2 = LineInterval::line(b);
252 let relation = LineRelation::Parallel;
253
254 assert_eq!(relation, s1.relate(&s2));
255 assert_eq!(relation, s2.relate(&s1));
256 }
257
258 #[test]
259 fn collinear_overlapping_segment_and_line() {
260 let a = Line {
261 start: (0.0, 0.0).into(),
262 end: (0.0, 1.5).into(),
263 };
264 let b = Line {
265 start: (0.0, 4.0).into(),
266 end: (0.0, 5.0).into(),
267 };
268 let s1 = LineInterval::line(a);
269 let s2 = LineInterval::ray(b);
270 let relation = LineRelation::Collinear;
271
272 assert_eq!(relation, s1.relate(&s2));
273 assert_eq!(relation, s2.relate(&s1));
274 }
275}