Skip to main content

devela/geom/space/topol/
point_segment.rs

1// devela/src/geom/space/topol/point_segment.rs
2
3use crate::{_impl_init, Turn};
4
5#[doc = crate::_tags!(geom topol)]
6/// The relation of a point to a directed planar segment.
7#[doc = crate::_doc_meta!{
8    location("geom/space",  enum PointSegmentRelation),
9    test_size_of(PointSegmentRelation = 1|8; niche Option)
10}]
11/// The reference segment is directed from its **origin** to its
12/// **destination**.
13///
14/// ```text
15///                         Left
16///                           •
17///
18/// Behind    Origin       Between       Destination    Beyond
19///   •─────────•─────────────•──────────────•────────────•
20///
21///                           •
22///                         Right
23/// ```
24///
25/// The collinear relations distinguish whether the point lies:
26///
27/// - before the segment origin;
28/// - at either endpoint;
29/// - strictly between the endpoints;
30/// - or beyond the destination.
31///
32/// A degenerate segment whose endpoints coincide has no such relation.
33#[must_use]
34#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
35pub enum PointSegmentRelation {
36    /// The point lies to the left of the directed segment.
37    Left,
38
39    /// The point lies to the right of the directed segment.
40    Right,
41
42    /// The point is collinear and lies before the origin.
43    Behind,
44
45    /// The point coincides with the segment origin.
46    Origin,
47
48    /// The point is collinear and lies strictly between the endpoints.
49    Between,
50
51    /// The point coincides with the segment destination.
52    Destination,
53
54    /// The point is collinear and lies beyond the destination.
55    Beyond,
56}
57_impl_init! { Self::Origin => PointSegmentRelation }
58
59impl PointSegmentRelation {
60    /// Returns the relation for the oppositely directed segment.
61    ///
62    /// Reversing the segment exchanges its sides, endpoints, and outward
63    /// directions while preserving its interior.
64    pub const fn reversed(self) -> Self {
65        match self {
66            Self::Left => Self::Right,
67            Self::Right => Self::Left,
68            Self::Behind => Self::Beyond,
69            Self::Origin => Self::Destination,
70            Self::Between => Self::Between,
71            Self::Destination => Self::Origin,
72            Self::Beyond => Self::Behind,
73        }
74    }
75    /// Returns the corresponding planar turn.
76    pub const fn as_turn(self) -> Turn {
77        match self {
78            Self::Left => Turn::Left,
79            Self::Right => Turn::Right,
80            Self::Behind | Self::Origin | Self::Between | Self::Destination | Self::Beyond => {
81                Turn::Collinear
82            }
83        }
84    }
85    /// Whether the point lies to the left of the directed segment.
86    pub const fn is_left(self) -> bool {
87        matches!(self, Self::Left)
88    }
89    /// Whether the point lies to the right of the directed segment.
90    pub const fn is_right(self) -> bool {
91        matches!(self, Self::Right)
92    }
93    /// Whether the point is collinear with the segment.
94    pub const fn is_collinear(self) -> bool {
95        !matches!(self, Self::Left | Self::Right)
96    }
97    /// Whether the point belongs to the closed segment.
98    pub const fn is_on_segment(self) -> bool {
99        matches!(self, Self::Origin | Self::Between | Self::Destination)
100    }
101    /// Whether the point coincides with either endpoint.
102    pub const fn is_endpoint(self) -> bool {
103        matches!(self, Self::Origin | Self::Destination)
104    }
105}