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}