geometry/
edge.rs

1//! The edges of rectangular geometry.
2
3use serde::{Deserialize, Serialize};
4
5use crate::dir::Dir;
6use crate::side::Side;
7use crate::span::Span;
8
9/// An edge of a rectangle.
10#[derive(Debug, Clone, Copy, Serialize, Deserialize, Hash, PartialEq, Eq)]
11pub struct Edge {
12    /// The side of the rectangle this edge corresponds to.
13    side: Side,
14    /// The coordinate of the edge.
15    coord: i64,
16    /// The perpendicular span of the edge.
17    span: Span,
18}
19
20impl Edge {
21    /// Create a new edge.
22    ///
23    /// # Example
24    ///
25    /// ```
26    /// # use geometry::prelude::*;
27    /// let edge = Edge::new(Side::Left, 20, Span::new(40, 100));
28    /// ```
29    pub fn new(side: Side, coord: i64, span: Span) -> Self {
30        Self { side, coord, span }
31    }
32
33    /// The side (of a rectangle) to which this edge corresponds.
34    ///
35    /// # Example
36    ///
37    /// ```
38    /// # use geometry::prelude::*;
39    /// let edge = Edge::new(Side::Left, 20, Span::new(40, 100));
40    /// assert_eq!(edge.side(), Side::Left);
41    /// ```
42    pub fn side(&self) -> Side {
43        self.side
44    }
45
46    /// The coordinate of the edge.
47    ///
48    /// For left/right edges, this will be the x coordinate of the edge.
49    /// For top/bottom edges, this will be the y coordinate of the edge.
50    ///
51    /// # Example
52    ///
53    /// ```
54    /// # use geometry::prelude::*;
55    /// let edge = Edge::new(Side::Left, 20, Span::new(40, 100));
56    /// assert_eq!(edge.coord(), 20);
57    /// ```
58    pub fn coord(&self) -> i64 {
59        self.coord
60    }
61
62    /// The span of the edge.
63    ///
64    /// For left/right edges, this will be the range of y-coordinates encompassed by the edge.
65    /// For top/bottom edges, this will be the range of x-coordinates encompassed by the edge.
66    ///
67    /// # Example
68    ///
69    /// ```
70    /// # use geometry::prelude::*;
71    /// let edge = Edge::new(Side::Left, 20, Span::new(40, 100));
72    /// assert_eq!(edge.span(), Span::new(40, 100));
73    /// ```
74    pub fn span(&self) -> Span {
75        self.span
76    }
77
78    /// Returns an `Edge` with the same properties as the provided `Edge` but with a new span.
79    ///
80    /// # Example
81    ///
82    /// ```
83    /// # use geometry::prelude::*;
84    /// let edge = Edge::new(Side::Left, 20, Span::new(40, 100));
85    /// assert_eq!(edge.span(), Span::new(40, 100));
86    /// let edge_new = edge.with_span(Span::new(20, 100));
87    /// assert_eq!(edge_new.span(), Span::new(20, 100));
88    /// ```
89    pub fn with_span(&self, span: Span) -> Edge {
90        Edge { span, ..*self }
91    }
92
93    /// The direction perpendicular to the edge.
94    ///
95    /// For left/right edges, this will be [`Dir::Horiz`].
96    /// For top/bottom edges, this will be [`Dir::Vert`].
97    ///
98    /// # Example
99    ///
100    /// ```
101    /// # use geometry::prelude::*;
102    /// let edge = Edge::new(Side::Left, 20, Span::new(40, 100));
103    /// assert_eq!(edge.norm_dir(), Dir::Horiz);
104    /// let edge = Edge::new(Side::Right, 20, Span::new(40, 100));
105    /// assert_eq!(edge.norm_dir(), Dir::Horiz);
106    /// let edge = Edge::new(Side::Top, 20, Span::new(40, 100));
107    /// assert_eq!(edge.norm_dir(), Dir::Vert);
108    /// let edge = Edge::new(Side::Bot, 20, Span::new(40, 100));
109    /// assert_eq!(edge.norm_dir(), Dir::Vert);
110    /// ```
111    pub fn norm_dir(&self) -> Dir {
112        self.side.coord_dir()
113    }
114
115    /// The direction parallel to the edge.
116    ///
117    /// For left/right edges, this will be [`Dir::Vert`].
118    /// For top/bottom edges, this will be [`Dir::Horiz`].
119    ///
120    /// # Example
121    ///
122    /// ```
123    /// # use geometry::prelude::*;
124    /// let edge = Edge::new(Side::Left, 20, Span::new(40, 100));
125    /// assert_eq!(edge.edge_dir(), Dir::Vert);
126    /// let edge = Edge::new(Side::Right, 20, Span::new(40, 100));
127    /// assert_eq!(edge.edge_dir(), Dir::Vert);
128    /// let edge = Edge::new(Side::Top, 20, Span::new(40, 100));
129    /// assert_eq!(edge.edge_dir(), Dir::Horiz);
130    /// let edge = Edge::new(Side::Bot, 20, Span::new(40, 100));
131    /// assert_eq!(edge.edge_dir(), Dir::Horiz);
132    /// ```
133    pub fn edge_dir(&self) -> Dir {
134        self.side.edge_dir()
135    }
136
137    /// Returns a new [`Edge`] offset some amount **away** from this edge.
138    ///
139    /// Left edges will be offset to the left; right edges will be offset to the right.
140    /// Top edges will be offset upwards; bottom edges will be offset downwards.
141    ///
142    /// # Example
143    ///
144    /// ```
145    /// # use geometry::prelude::*;
146    /// let edge = Edge::new(Side::Left, 20, Span::new(40, 100));
147    /// assert_eq!(edge.offset(10), Edge::new(Side::Left, 10, Span::new(40, 100)));
148    ///
149    /// let edge = Edge::new(Side::Top, 20, Span::new(40, 100));
150    /// assert_eq!(edge.offset(10), Edge::new(Side::Top, 30, Span::new(40, 100)));
151    /// ```
152    pub fn offset(&self, offset: i64) -> Edge {
153        Edge {
154            coord: self.coord + self.side.sign().as_int() * offset,
155            ..*self
156        }
157    }
158}