1#![doc = include_str!("../README.md")]
2
3mod area;
4mod direction;
5mod grid;
6mod lines;
7
8pub use area::*;
9pub use direction::*;
10pub use grid::*;
11pub use lines::*;
12
13pub use enumflags2::{BitFlag, BitFlags};
14
15use std::{
16 convert::{TryFrom, TryInto},
17 fmt::Display,
18 num::TryFromIntError,
19 ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign},
20};
21
22#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub struct Coord {
26 pub x: u32,
27 pub y: u32,
28}
29
30impl Coord {
31 pub const ZERO: Coord = Coord::new(0, 0);
32
33 pub const fn new(x: u32, y: u32) -> Self {
35 Self { x, y }
36 }
37
38 pub fn to_2d_idx(self, width: u32) -> u32 {
42 self.y * width + self.x
44 }
45
46 pub fn to_icoord(self) -> CoordVec {
48 self.into()
49 }
50
51 pub fn neighbors4(self) -> Vec<Coord> {
64 Direction4::DIRECTIONS
65 .iter()
66 .filter_map(|dir| {
67 let iself = self.to_icoord();
68 let ineighbor = iself + *dir;
69 ineighbor.to_coord() })
71 .collect()
72 }
73
74 pub fn neighbors8(self) -> Vec<Coord> {
86 Direction8::DIRECTIONS
87 .iter()
88 .filter_map(|dir| {
89 let iself = self.to_icoord();
90 let ineighbor = iself + *dir;
91 ineighbor.to_coord() })
93 .collect()
94 }
95
96 pub fn area(self, width: u32, height: u32) -> Area {
97 Area::new(self, width, height)
98 }
99
100 pub fn offset4(self, offset: Direction4) -> Option<Self> {
101 let deltas = offset.deltas();
102 let x = (self.x as i32 + deltas.x).try_into().ok()?;
103 let y = (self.y as i32 + deltas.y).try_into().ok()?;
104 Some(Coord::new(x, y))
105 }
106
107 pub fn offset8(self, offset: Direction8) -> Option<Self> {
108 let deltas = offset.deltas();
109 let x = (self.x as i32 + deltas.x).try_into().ok()?;
110 let y = (self.y as i32 + deltas.y).try_into().ok()?;
111 Some(Coord::new(x, y))
112 }
113
114 pub fn offset9(self, offset: Direction9) -> Option<Self> {
115 let deltas = offset.deltas();
116 let x = (self.x as i32 + deltas.x).try_into().ok()?;
117 let y = (self.y as i32 + deltas.y).try_into().ok()?;
118 Some(Coord::new(x, y))
119 }
120}
121
122impl Add for Coord {
123 type Output = Self;
124 fn add(self, rhs: Self) -> Self::Output {
125 Self {
126 x: self.x + rhs.x,
127 y: self.y + rhs.y,
128 }
129 }
130}
131
132impl AddAssign for Coord {
133 fn add_assign(&mut self, rhs: Self) {
134 self.x += rhs.x;
135 self.y += rhs.y;
136 }
137}
138
139impl Sub for Coord {
140 type Output = Self;
141 fn sub(self, rhs: Self) -> Self::Output {
142 Self {
143 x: self.x - rhs.x,
144 y: self.y - rhs.y,
145 }
146 }
147}
148
149impl SubAssign for Coord {
150 fn sub_assign(&mut self, rhs: Self) {
151 self.x -= rhs.x;
152 self.y -= rhs.y;
153 }
154}
155
156impl Mul<u32> for Coord {
157 type Output = Self;
158 fn mul(self, rhs: u32) -> Self::Output {
159 Self {
160 x: self.x * rhs,
161 y: self.y * rhs,
162 }
163 }
164}
165
166impl MulAssign<u32> for Coord {
167 fn mul_assign(&mut self, rhs: u32) {
168 self.x *= rhs;
169 self.y *= rhs;
170 }
171}
172
173impl Mul<Coord> for Coord {
174 type Output = Self;
175 fn mul(self, rhs: Coord) -> Self::Output {
176 Self {
177 x: self.x * rhs.x,
178 y: self.y * rhs.y,
179 }
180 }
181}
182
183impl MulAssign<Coord> for Coord {
184 fn mul_assign(&mut self, rhs: Coord) {
185 self.x *= rhs.x;
186 self.y *= rhs.y;
187 }
188}
189
190impl TryFrom<CoordVec> for Coord {
193 type Error = TryFromIntError;
194 fn try_from(value: CoordVec) -> Result<Self, Self::Error> {
195 Ok(Self {
196 x: value.x.try_into()?,
197 y: value.y.try_into()?,
198 })
199 }
200}
201
202impl Display for Coord {
203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204 write!(f, "({}, {})", self.x, self.y)
205 }
206}
207
208#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
210#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
211pub struct CoordVec {
212 pub x: i32,
213 pub y: i32,
214}
215
216impl CoordVec {
217 pub fn new(x: i32, y: i32) -> Self {
219 Self { x, y }
220 }
221
222 pub fn quadrant(self) -> u32 {
231 match (self.x >= 0, self.y >= 0) {
232 (true, true) => 1,
233 (false, true) => 2,
234 (false, false) => 3,
235 (true, false) => 4,
236 }
237 }
238
239 pub fn to_coord(self) -> Option<Coord> {
242 self.try_into().ok()
243 }
244
245 pub fn neighbors4(self) -> [CoordVec; 4] {
251 [
252 self + Direction4::North,
253 self + Direction4::East,
254 self + Direction4::South,
255 self + Direction4::West,
256 ]
257 }
258
259 pub fn neighbors8(self) -> [CoordVec; 8] {
265 [
266 self + Direction8::North,
267 self + Direction8::NorthEast,
268 self + Direction8::East,
269 self + Direction8::SouthEast,
270 self + Direction8::South,
271 self + Direction8::SouthWest,
272 self + Direction8::West,
273 self + Direction8::NorthWest,
274 ]
275 }
276
277 pub fn point9(self) -> Direction9 {
281 if self.x == 0 && self.y == 0 {
282 return Direction9::Center;
283 }
284 let angle =
286 (-self.y as f32).atan2(self.x as f32) + std::f32::consts::PI;
287 match angle / std::f32::consts::TAU * 16.0 {
288 a if a < 1.0 => Direction9::East,
289 a if a < 3.0 => Direction9::NorthEast,
290 a if a < 5.0 => Direction9::North,
291 a if a < 7.0 => Direction9::NorthWest,
292 a if a < 9.0 => Direction9::West,
293 a if a < 11.0 => Direction9::SouthWest,
294 a if a < 13.0 => Direction9::South,
295 a if a < 15.0 => Direction9::SouthEast,
296 _ => Direction9::East,
297 }
298 }
299}
300
301impl Add for CoordVec {
302 type Output = Self;
303 fn add(self, rhs: Self) -> Self::Output {
304 Self {
305 x: self.x + rhs.x,
306 y: self.y + rhs.y,
307 }
308 }
309}
310
311impl AddAssign for CoordVec {
312 fn add_assign(&mut self, rhs: Self) {
313 self.x += rhs.x;
314 self.y += rhs.y;
315 }
316}
317
318impl Sub for CoordVec {
319 type Output = Self;
320 fn sub(self, rhs: Self) -> Self::Output {
321 Self {
322 x: self.x - rhs.x,
323 y: self.y - rhs.y,
324 }
325 }
326}
327
328impl SubAssign for CoordVec {
329 fn sub_assign(&mut self, rhs: Self) {
330 self.x -= rhs.x;
331 self.y -= rhs.y;
332 }
333}
334
335impl Add<Direction4> for CoordVec {
336 type Output = Self;
337 fn add(self, rhs: Direction4) -> Self::Output {
338 self + rhs.deltas()
339 }
340}
341
342impl AddAssign<Direction4> for CoordVec {
343 fn add_assign(&mut self, rhs: Direction4) {
344 *self += rhs.deltas();
345 }
346}
347
348impl Add<Direction8> for CoordVec {
349 type Output = Self;
350 fn add(self, rhs: Direction8) -> Self::Output {
351 self + rhs.deltas()
352 }
353}
354
355impl AddAssign<Direction8> for CoordVec {
356 fn add_assign(&mut self, rhs: Direction8) {
357 *self += rhs.deltas();
358 }
359}
360
361impl Mul<i32> for CoordVec {
362 type Output = Self;
363 fn mul(self, rhs: i32) -> Self::Output {
364 Self {
365 x: self.x * rhs,
366 y: self.y * rhs,
367 }
368 }
369}
370
371impl MulAssign<i32> for CoordVec {
372 fn mul_assign(&mut self, rhs: i32) {
373 self.x *= rhs;
374 self.y *= rhs;
375 }
376}
377
378impl From<Coord> for CoordVec {
379 fn from(value: Coord) -> Self {
380 Self {
381 x: value.x as i32,
382 y: value.y as i32,
383 }
384 }
385}
386
387impl Display for CoordVec {
388 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
389 write!(f, "({}, {})", self.x, self.y)
390 }
391}