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}