blockworx/document_ng/
coord.rs1#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
5pub struct GridPos {
6 pub x: i32,
7 pub y: i32,
8}
9
10#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
11pub struct GridSize {
12 pub w: u32,
13 pub h: u32,
14}
15
16#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
17pub struct GridVec {
18 pub dx: i32,
19 pub dy: i32,
20}
21
22#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
23pub struct GridRect {
24 pub min: GridPos,
25 pub size: GridSize,
26}
27
28impl GridPos {
29 pub const ZERO: GridPos = GridPos { x: 0, y: 0 };
30
31 pub const fn new(x: i32, y: i32) -> Self {
32 Self { x, y }
33 }
34}
35
36impl GridSize {
37 pub const ZERO: GridSize = GridSize { w: 0, h: 0 };
38
39 pub const fn new(w: u32, h: u32) -> Self {
40 Self { w, h }
41 }
42}
43
44impl GridVec {
45 pub const ZERO: GridVec = GridVec { dx: 0, dy: 0 };
46
47 pub const fn new(dx: i32, dy: i32) -> Self {
48 Self { dx, dy }
49 }
50}
51
52impl GridRect {
53 pub const fn new(min: GridPos, size: GridSize) -> Self {
54 Self { min, size }
55 }
56
57 pub fn from_min_size(min: GridPos, size: GridSize) -> Self {
58 Self { min, size }
59 }
60
61 pub fn from_two_pos(a: GridPos, b: GridPos) -> Self {
62 let min_x = a.x.min(b.x);
63 let min_y = a.y.min(b.y);
64 let max_x = a.x.max(b.x);
65 let max_y = a.y.max(b.y);
66 Self {
67 min: GridPos::new(min_x, min_y),
68 size: GridSize::new((max_x - min_x) as u32, (max_y - min_y) as u32),
69 }
70 }
71
72 pub fn max(self) -> GridPos {
73 GridPos::new(
74 self.min.x + self.size.w as i32,
75 self.min.y + self.size.h as i32,
76 )
77 }
78
79 pub fn width(self) -> u32 {
80 self.size.w
81 }
82
83 pub fn height(self) -> u32 {
84 self.size.h
85 }
86
87 pub fn left(self) -> i32 {
88 self.min.x
89 }
90
91 pub fn top(self) -> i32 {
92 self.min.y
93 }
94
95 pub fn right(self) -> i32 {
96 self.min.x + self.size.w as i32
97 }
98
99 pub fn bottom(self) -> i32 {
100 self.min.y + self.size.h as i32
101 }
102
103 pub fn left_top(self) -> GridPos {
104 self.min
105 }
106
107 pub fn right_top(self) -> GridPos {
108 GridPos::new(self.right(), self.top())
109 }
110
111 pub fn left_bottom(self) -> GridPos {
112 GridPos::new(self.left(), self.bottom())
113 }
114
115 pub fn right_bottom(self) -> GridPos {
116 self.max()
117 }
118
119 pub fn contains(self, p: GridPos) -> bool {
120 p.x >= self.left() && p.x <= self.right() && p.y >= self.top() && p.y <= self.bottom()
121 }
122
123 pub fn intersects(self, other: GridRect) -> bool {
124 self.left() < other.right()
125 && other.left() < self.right()
126 && self.top() < other.bottom()
127 && other.top() < self.bottom()
128 }
129
130 pub fn translate(self, delta: GridVec) -> Self {
131 Self {
132 min: GridPos::new(self.min.x + delta.dx, self.min.y + delta.dy),
133 size: self.size,
134 }
135 }
136}
137
138impl std::ops::Add<GridVec> for GridPos {
139 type Output = GridPos;
140 fn add(self, rhs: GridVec) -> GridPos {
141 GridPos::new(self.x + rhs.dx, self.y + rhs.dy)
142 }
143}
144
145impl std::ops::Sub<GridPos> for GridPos {
146 type Output = GridVec;
147 fn sub(self, rhs: GridPos) -> GridVec {
148 GridVec::new(self.x - rhs.x, self.y - rhs.y)
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn gridrect_intersects_matches_rect_semantics() {
158 let a = GridRect::new(GridPos::new(0, 0), GridSize::new(2, 2));
159 let b = GridRect::new(GridPos::new(2, 0), GridSize::new(2, 2));
160 assert!(!a.intersects(b));
162 let c = GridRect::new(GridPos::new(1, 0), GridSize::new(2, 2));
163 assert!(a.intersects(c));
164 }
165}