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 feature = "rstar_0_13"
252))]
253macro_rules! impl_rstar_line {
254 ($rstar:ident) => {
255 impl<T> ::$rstar::RTreeObject for Line<T>
256 where
257 T: ::num_traits::Float + ::$rstar::RTreeNum,
258 {
259 type Envelope = ::$rstar::AABB<Point<T>>;
260
261 fn envelope(&self) -> Self::Envelope {
262 ::$rstar::AABB::from_corners(self.start_point(), self.end_point())
263 }
264 }
265
266 impl<T> ::$rstar::PointDistance for Line<T>
267 where
268 T: ::num_traits::Float + ::$rstar::RTreeNum,
269 {
270 fn distance_2(&self, point: &Point<T>) -> T {
271 let d = crate::private_utils::point_line_euclidean_distance(*point, *self);
272 d.powi(2)
273 }
274 }
275 };
276}
277
278#[cfg(feature = "rstar_0_8")]
279impl_rstar_line!(rstar_0_8);
280
281#[cfg(feature = "rstar_0_9")]
282impl_rstar_line!(rstar_0_9);
283
284#[cfg(feature = "rstar_0_10")]
285impl_rstar_line!(rstar_0_10);
286
287#[cfg(feature = "rstar_0_11")]
288impl_rstar_line!(rstar_0_11);
289
290#[cfg(feature = "rstar_0_12")]
291impl_rstar_line!(rstar_0_12);
292
293#[cfg(feature = "rstar_0_13")]
294impl_rstar_line!(rstar_0_13);
295
296#[cfg(test)]
297mod test {
298 use super::*;
299 use crate::{coord, point};
300 use approx::{AbsDiffEq, RelativeEq};
301
302 #[test]
303 fn test_abs_diff_eq() {
304 let delta = 1e-6;
305 let line = Line::new(coord! { x: 0., y: 0. }, coord! { x: 1., y: 1. });
306 let line_start_x = Line::new(
307 point! {
308 x: 0. + delta,
309 y: 0.,
310 },
311 point! { x: 1., y: 1. },
312 );
313 assert!(line.abs_diff_eq(&line_start_x, 1e-2));
314 assert!(line.abs_diff_ne(&line_start_x, 1e-12));
315
316 let line_start_y = Line::new(
317 coord! {
318 x: 0.,
319 y: 0. + delta,
320 },
321 coord! { x: 1., y: 1. },
322 );
323 assert!(line.abs_diff_eq(&line_start_y, 1e-2));
324 assert!(line.abs_diff_ne(&line_start_y, 1e-12));
325
326 let line_end_x = Line::new(
327 coord! { x: 0., y: 0. },
328 coord! {
329 x: 1. + delta,
330 y: 1.,
331 },
332 );
333
334 assert!(line.abs_diff_eq(&line_end_x, 1e-2));
335 assert!(line.abs_diff_ne(&line_end_x, 1e-12));
336
337 let line_end_y = Line::new(
338 coord! { x: 0., y: 0. },
339 coord! {
340 x: 1.,
341 y: 1. + delta,
342 },
343 );
344
345 assert!(line.abs_diff_eq(&line_end_y, 1e-2));
346 assert!(line.abs_diff_ne(&line_end_y, 1e-12));
347 }
348
349 #[test]
350 fn test_relative_eq() {
351 let delta = 1e-6;
352
353 let line = Line::new(coord! { x: 0., y: 0. }, coord! { x: 1., y: 1. });
354 let line_start_x = Line::new(
355 point! {
356 x: 0. + delta,
357 y: 0.,
358 },
359 point! { x: 1., y: 1. },
360 );
361 let line_start_y = Line::new(
362 coord! {
363 x: 0.,
364 y: 0. + delta,
365 },
366 coord! { x: 1., y: 1. },
367 );
368
369 assert!(line.relative_eq(&line_start_x, 1e-2, 1e-2));
370 assert!(line.relative_ne(&line_start_x, 1e-12, 1e-12));
371
372 assert!(line.relative_eq(&line_start_y, 1e-2, 1e-2));
373 assert!(line.relative_ne(&line_start_y, 1e-12, 1e-12));
374 }
375}