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}