Line data Source code
1 : //! Plain geometry: points, rectangles and the four sides.
2 :
3 : /// Coordinates closer than this are the same line (in the caller's
4 : /// units, typically pixels or points).
5 : pub(crate) const EPS: f32 = 1e-3;
6 :
7 : /// A point.
8 : #[derive(Clone, Copy, Debug, Default, PartialEq)]
9 : pub struct Point {
10 : /// The abscissa.
11 : pub x: f32,
12 : /// The ordinate.
13 : pub y: f32,
14 : }
15 :
16 : impl Point {
17 : /// A point at `x`, `y`.
18 17063 : pub const fn new(x: f32, y: f32) -> Point {
19 17063 : Point { x, y }
20 17063 : }
21 :
22 : /// Whether both coordinates are finite.
23 687 : pub fn is_finite(self) -> bool {
24 687 : self.x.is_finite() && self.y.is_finite()
25 687 : }
26 :
27 : /// The point moved `d` along a side's outward direction.
28 438 : pub(crate) fn toward(self, side: Side, d: f32) -> Point {
29 438 : let (dx, dy) = side.direction();
30 438 : Point::new(self.x + dx * d, self.y + dy * d)
31 438 : }
32 :
33 : /// Whether two points are the same within [`EPS`].
34 897 : pub(crate) fn near(self, other: Point) -> bool {
35 897 : (self.x - other.x).abs() <= EPS && (self.y - other.y).abs() <= EPS
36 897 : }
37 : }
38 :
39 : impl From<[f32; 2]> for Point {
40 248 : fn from([x, y]: [f32; 2]) -> Point {
41 248 : Point::new(x, y)
42 248 : }
43 : }
44 :
45 : impl From<(f32, f32)> for Point {
46 0 : fn from((x, y): (f32, f32)) -> Point {
47 0 : Point::new(x, y)
48 0 : }
49 : }
50 :
51 : impl From<Point> for [f32; 2] {
52 0 : fn from(p: Point) -> [f32; 2] {
53 0 : [p.x, p.y]
54 0 : }
55 : }
56 :
57 : /// An axis-aligned rectangle, from its smallest to its largest corner.
58 : #[derive(Clone, Copy, Debug, Default, PartialEq)]
59 : pub struct Rect {
60 : /// The corner with the smallest coordinates.
61 : pub min: Point,
62 : /// The corner with the largest coordinates.
63 : pub max: Point,
64 : }
65 :
66 : impl Rect {
67 : /// The rectangle between two corners, in any order.
68 92 : pub fn from_corners(a: impl Into<Point>, b: impl Into<Point>) -> Rect {
69 92 : let (a, b) = (a.into(), b.into());
70 92 : Rect {
71 92 : min: Point::new(a.x.min(b.x), a.y.min(b.y)),
72 92 : max: Point::new(a.x.max(b.x), a.y.max(b.y)),
73 92 : }
74 92 : }
75 :
76 : /// The rectangle at `min` of this width and height.
77 91 : pub fn from_min_size(min: impl Into<Point>, width: f32, height: f32) -> Rect {
78 91 : let min = min.into();
79 91 : Rect::from_corners(min, Point::new(min.x + width, min.y + height))
80 91 : }
81 :
82 : /// Its width.
83 0 : pub fn width(&self) -> f32 {
84 0 : self.max.x - self.min.x
85 0 : }
86 :
87 : /// Its height.
88 0 : pub fn height(&self) -> f32 {
89 0 : self.max.y - self.min.y
90 0 : }
91 :
92 : /// Whether its corners are finite and in order.
93 124 : pub fn is_valid(&self) -> bool {
94 124 : self.min.is_finite()
95 124 : && self.max.is_finite()
96 123 : && self.min.x <= self.max.x
97 123 : && self.min.y <= self.max.y
98 124 : }
99 :
100 : /// The rectangle grown by `d` on every side.
101 155 : pub fn expand(&self, d: f32) -> Rect {
102 155 : Rect {
103 155 : min: Point::new(self.min.x - d, self.min.y - d),
104 155 : max: Point::new(self.max.x + d, self.max.y + d),
105 155 : }
106 155 : }
107 : }
108 :
109 : /// The side of a node a port leaves from: a connector's first segment
110 : /// goes out that way, and its last segment comes in from that way.
111 : ///
112 : /// `Top` is toward smaller `y` and `Bottom` toward larger `y`, as on a
113 : /// screen where `y` grows downward; with `y` growing upward, swap them.
114 : #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
115 : pub enum Side {
116 : /// Toward smaller `x`.
117 : Left,
118 : /// Toward larger `x`.
119 : Right,
120 : /// Toward smaller `y`.
121 : Top,
122 : /// Toward larger `y`.
123 : Bottom,
124 : }
125 :
126 : impl Side {
127 : /// The unit vector pointing out of the node.
128 438 : pub fn direction(self) -> (f32, f32) {
129 438 : match self {
130 217 : Side::Left => (-1.0, 0.0),
131 217 : Side::Right => (1.0, 0.0),
132 2 : Side::Top => (0.0, -1.0),
133 2 : Side::Bottom => (0.0, 1.0),
134 : }
135 438 : }
136 :
137 : /// The opposite side.
138 5272 : pub fn opposite(self) -> Side {
139 5272 : match self {
140 163 : Side::Left => Side::Right,
141 840 : Side::Right => Side::Left,
142 2141 : Side::Top => Side::Bottom,
143 2128 : Side::Bottom => Side::Top,
144 : }
145 5272 : }
146 :
147 : /// Whether a segment leaving this side is horizontal.
148 1 : pub fn is_horizontal(self) -> bool {
149 1 : matches!(self, Side::Left | Side::Right)
150 1 : }
151 :
152 : /// Its index as a search direction (0 to 3).
153 3538 : pub(crate) fn index(self) -> usize {
154 3538 : self as usize
155 3538 : }
156 :
157 : pub(crate) const ALL: [Side; 4] = [Side::Left, Side::Right, Side::Top, Side::Bottom];
158 : }
|