1use crate::{Coord, CoordNum, Point};
2
3#[derive(Eq, PartialEq, Clone, Copy, Hash)]
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12pub struct Line<T: CoordNum = f64> {
13 pub start: Coord<T>,
14 pub end: Coord<T>,
15}
16
17impl<T: CoordNum> Line<T> {
18 pub fn new<C>(start: C, end: C) -> Self
31 where
32 C: Into<Coord<T>>,
33 {
34 Self {
35 start: start.into(),
36 end: end.into(),
37 }
38 }
39
40 pub fn delta(&self) -> Coord<T> {
42 self.end - self.start
43 }
44
45 pub fn dx(&self) -> T {
61 self.delta().x
62 }
63
64 pub fn dy(&self) -> T {
80 self.delta().y
81 }
82
83 pub fn slope(&self) -> T {
110 self.dy() / self.dx()
111 }
112
113 pub fn determinant(&self) -> T {
140 self.start.x * self.end.y - self.start.y * self.end.x
141 }
142
143 pub fn start_point(&self) -> Point<T> {
144 Point::from(self.start)
145 }
146
147 pub fn end_point(&self) -> Point<T> {
148 Point::from(self.end)
149 }
150
151 pub fn points(&self) -> (Point<T>, Point<T>) {
152 (self.start_point(), self.end_point())
153 }
154}
155
156impl<T: CoordNum> From<[(T, T); 2]> for Line<T> {
157 fn from(coord: [(T, T); 2]) -> Self {
158 Line::new(coord[0], coord[1])
159 }
160}
161
162#[cfg(any(feature = "approx", test))]
163mod approx_integration {
164 use super::*;
165 use approx::{AbsDiffEq, RelativeEq, UlpsEq};
166
167 impl<T> RelativeEq for Line<T>
168 where
169 T: CoordNum + RelativeEq<Epsilon = T>,
170 {
171 #[inline]
172 fn default_max_relative() -> Self::Epsilon {
173 T::default_max_relative()
174 }
175
176 #[inline]
189 fn relative_eq(
190 &self,
191 other: &Self,
192 epsilon: Self::Epsilon,
193 max_relative: Self::Epsilon,
194 ) -> bool {
195 self.start.relative_eq(&other.start, epsilon, max_relative)
196 && self.end.relative_eq(&other.end, epsilon, max_relative)
197 }
198 }
199
200 impl<T> AbsDiffEq for Line<T>
201 where
202 T: CoordNum + AbsDiffEq<Epsilon = T>,
203 {
204 type Epsilon = T;
205
206 #[inline]
207 fn default_epsilon() -> Self::Epsilon {
208 T::default_epsilon()
209 }
210
211 #[inline]
224 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
225 self.start.abs_diff_eq(&other.start, epsilon)
226 && self.end.abs_diff_eq(&other.end, epsilon)
227 }
228 }
229
230 impl<T> UlpsEq for Line<T>
231 where
232 T: CoordNum + UlpsEq<Epsilon = T>,
233 {
234 fn default_max_ulps() -> u32 {
235 T::default_max_ulps()
236 }
237
238 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
239 self.start.ulps_eq(&other.start, epsilon, max_ulps)
240 && self.end.ulps_eq(&other.end, epsilon, max_ulps)
241 }
242 }
243}
244
245#[cfg(any(
246 feature = "rstar_0_8",
247 feature = "rstar_0_9",
248 feature = "rstar_0_10",
249 feature = "rstar_0_11",
250 feature = "rstar_0_12"
251))]
252macro_rules! impl_rstar_line {
253 ($rstar:ident) => {
254 impl<T> ::$rstar::RTreeObject for Line<T>
255 where
256 T: ::num_traits::Float + ::$rstar::RTreeNum,
257 {
258 type Envelope = ::$rstar::AABB<Point<T>>;
259
260 fn envelope(&self) -> Self::Envelope {
261 ::$rstar::AABB::from_corners(self.start_point(), self.end_point())
262 }
263 }
264
265 impl<T> ::$rstar::PointDistance for Line<T>
266 where
267 T: ::num_traits::Float + ::$rstar::RTreeNum,
268 {
269 fn distance_2(&self, point: &Point<T>) -> T {
270 let d = crate::private_utils::point_line_euclidean_distance(*point, *self);
271 d.powi(2)
272 }
273 }
274 };
275}
276
277#[cfg(feature = "rstar_0_8")]
278impl_rstar_line!(rstar_0_8);
279
280#[cfg(feature = "rstar_0_9")]
281impl_rstar_line!(rstar_0_9);
282
283#[cfg(feature = "rstar_0_10")]
284impl_rstar_line!(rstar_0_10);
285
286#[cfg(feature = "rstar_0_11")]
287impl_rstar_line!(rstar_0_11);
288
289#[cfg(feature = "rstar_0_12")]
290impl_rstar_line!(rstar_0_12);
291
292#[cfg(test)]
293mod test {
294 use super::*;
295 use crate::{coord, point};
296 use approx::{AbsDiffEq, RelativeEq};
297
298 #[test]
299 fn test_abs_diff_eq() {
300 let delta = 1e-6;
301 let line = Line::new(coord! { x: 0., y: 0. }, coord! { x: 1., y: 1. });
302 let line_start_x = Line::new(
303 point! {
304 x: 0. + delta,
305 y: 0.,
306 },
307 point! { x: 1., y: 1. },
308 );
309 assert!(line.abs_diff_eq(&line_start_x, 1e-2));
310 assert!(line.abs_diff_ne(&line_start_x, 1e-12));
311
312 let line_start_y = Line::new(
313 coord! {
314 x: 0.,
315 y: 0. + delta,
316 },
317 coord! { x: 1., y: 1. },
318 );
319 assert!(line.abs_diff_eq(&line_start_y, 1e-2));
320 assert!(line.abs_diff_ne(&line_start_y, 1e-12));
321
322 let line_end_x = Line::new(
323 coord! { x: 0., y: 0. },
324 coord! {
325 x: 1. + delta,
326 y: 1.,
327 },
328 );
329
330 assert!(line.abs_diff_eq(&line_end_x, 1e-2));
331 assert!(line.abs_diff_ne(&line_end_x, 1e-12));
332
333 let line_end_y = Line::new(
334 coord! { x: 0., y: 0. },
335 coord! {
336 x: 1.,
337 y: 1. + delta,
338 },
339 );
340
341 assert!(line.abs_diff_eq(&line_end_y, 1e-2));
342 assert!(line.abs_diff_ne(&line_end_y, 1e-12));
343 }
344
345 #[test]
346 fn test_relative_eq() {
347 let delta = 1e-6;
348
349 let line = Line::new(coord! { x: 0., y: 0. }, coord! { x: 1., y: 1. });
350 let line_start_x = Line::new(
351 point! {
352 x: 0. + delta,
353 y: 0.,
354 },
355 point! { x: 1., y: 1. },
356 );
357 let line_start_y = Line::new(
358 coord! {
359 x: 0.,
360 y: 0. + delta,
361 },
362 coord! { x: 1., y: 1. },
363 );
364
365 assert!(line.relative_eq(&line_start_x, 1e-2, 1e-2));
366 assert!(line.relative_ne(&line_start_x, 1e-12, 1e-12));
367
368 assert!(line.relative_eq(&line_start_y, 1e-2, 1e-2));
369 assert!(line.relative_ne(&line_start_y, 1e-12, 1e-12));
370 }
371}