Skip to main content

geometry_model/
infinite_line.rs

1//! Infinite 2D line in general form, `a*x + b*y + c = 0`.
2//!
3//! Mirrors `boost::geometry::model::infinite_line` from
4//! `geometries/infinite_line.hpp:29-52` and the operations in
5//! `arithmetic/infinite_line_functions.hpp:24-107`.
6
7use geometry_coords::CoordinateScalar;
8use geometry_cs::Cartesian;
9use geometry_trait::Point;
10
11use crate::Point2D;
12
13/// An infinite line in the general form `a*x + b*y + c = 0`.
14///
15/// Mirrors `model::infinite_line<Type>` from
16/// `geometries/infinite_line.hpp:35-52`. It is intentionally not a
17/// [`geometry_trait::Geometry`] because the C++ source likewise notes that the
18/// type is not conceptized.
19#[derive(Debug, Clone, Copy, PartialEq)]
20pub struct InfiniteLine<T: CoordinateScalar = f64> {
21    /// Coefficient of x. A horizontal line has `a == 0`.
22    pub a: T,
23    /// Coefficient of y. A vertical line has `b == 0`.
24    pub b: T,
25    /// Constant term. A line through the origin has `c == 0`.
26    pub c: T,
27    /// Whether the coefficients have been normalized by a caller.
28    pub normalized: bool,
29}
30
31impl<T: CoordinateScalar> InfiniteLine<T> {
32    /// Construct a line from its general-form coefficients.
33    #[inline]
34    #[must_use]
35    pub const fn new(a: T, b: T, c: T) -> Self {
36        Self {
37            a,
38            b,
39            c,
40            normalized: false,
41        }
42    }
43
44    /// Construct the infinite line through `(x1, y1)` and `(x2, y2)`.
45    ///
46    /// Mirrors `detail::make::make_infinite_line` from
47    /// `algorithms/detail/make/make.hpp:21-32`:
48    /// `a = y1-y2`, `b = x2-x1`, `c = -a*x1-b*y1`.
49    #[inline]
50    #[must_use]
51    pub fn from_coordinates(x1: T, y1: T, x2: T, y2: T) -> Self {
52        let a = y1 - y2;
53        let b = x2 - x1;
54        let c = -(a * x1) - b * y1;
55        Self::new(a, b, c)
56    }
57
58    /// Construct the infinite line through two points.
59    ///
60    /// Mirrors `make_infinite_line(PointA, PointB)` from
61    /// `algorithms/detail/make/make.hpp:34-40`.
62    #[inline]
63    #[must_use]
64    pub fn from_points<P>(start: &P, end: &P) -> Self
65    where
66        P: Point<Scalar = T>,
67    {
68        Self::from_coordinates(
69            start.get::<0>(),
70            start.get::<1>(),
71            end.get::<0>(),
72            end.get::<1>(),
73        )
74    }
75
76    /// Return the unnormalized signed side measure at `(x, y)`.
77    ///
78    /// Positive is left, negative is right, and zero is on the line.
79    /// Mirrors `arithmetic::side_value` from
80    /// `arithmetic/infinite_line_functions.hpp:70-93`.
81    #[inline]
82    #[must_use]
83    pub fn side_value(&self, x: T, y: T) -> T {
84        self.a * x + self.b * y + self.c
85    }
86
87    /// Return whether both directional coefficients are zero.
88    ///
89    /// Mirrors `arithmetic::is_degenerate` from
90    /// `arithmetic/infinite_line_functions.hpp:99-104`.
91    #[inline]
92    #[must_use]
93    pub fn is_degenerate(&self) -> bool {
94        self.a == T::ZERO && self.b == T::ZERO
95    }
96
97    /// Calculate the intersection of two non-parallel infinite lines.
98    ///
99    /// Mirrors `arithmetic::intersection_point` and
100    /// `assign_intersection_point` from
101    /// `arithmetic/infinite_line_functions.hpp:32-67`. `None` represents
102    /// parallel or collinear lines.
103    #[inline]
104    #[must_use]
105    pub fn intersection(&self, other: &Self) -> Option<Point2D<T, Cartesian>> {
106        let denominator = self.a * other.b - self.b * other.a;
107        if denominator == T::ZERO {
108            return None;
109        }
110        let x = (self.b * other.c - self.c * other.b) / denominator;
111        let y = (self.c * other.a - self.a * other.c) / denominator;
112        Some(Point2D::new(x, y))
113    }
114}
115
116impl<T: CoordinateScalar> Default for InfiniteLine<T> {
117    #[inline]
118    fn default() -> Self {
119        Self::new(T::ZERO, T::ZERO, T::ZERO)
120    }
121}