use super::ICoord;
use enum_map::Enum;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Enum)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Direction4 {
North,
East,
South,
West,
}
impl Direction4 {
pub const DIRECTIONS: [Direction4; 4] = [
Direction4::North,
Direction4::East,
Direction4::South,
Direction4::West,
];
pub fn rotate(self, rot: Rotation) -> Self {
self.rotate_by(rot.steps_clockwise())
}
pub fn rotate_by(self, steps_clockwise: isize) -> Self {
let idx = self as isize;
let new_idx =
((idx + steps_clockwise).rem_euclid(Self::DIRECTIONS.len() as isize)) as usize;
Self::DIRECTIONS[new_idx]
}
pub fn flip(self) -> Self {
self.rotate_by(2)
}
pub fn radians(self) -> f32 {
((self as i8) - 1).rem_euclid(4) as f32 * std::f32::consts::TAU / 4.0
}
pub fn deltas(self) -> ICoord {
let (x, y) = match self {
Direction4::North => (0, -1),
Direction4::East => (1, 0),
Direction4::South => (0, 1),
Direction4::West => (-1, 0),
};
ICoord { x, y }
}
pub fn is_horizontal(self) -> bool {
matches!(self, Direction4::East | Direction4::West)
}
pub fn is_vertical(self) -> bool {
matches!(self, Direction4::North | Direction4::South)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Enum)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Direction8 {
North,
NorthEast,
East,
SouthEast,
South,
SouthWest,
West,
NorthWest,
}
impl Direction8 {
pub const DIRECTIONS: [Direction8; 8] = [
Direction8::North,
Direction8::NorthEast,
Direction8::East,
Direction8::SouthEast,
Direction8::South,
Direction8::SouthWest,
Direction8::West,
Direction8::NorthWest,
];
pub fn rotate(self, rot: Rotation) -> Self {
self.rotate_by(rot.steps_clockwise())
}
pub fn rotate_by(self, steps_clockwise: isize) -> Self {
let idx = self as isize;
let new_idx =
((idx + steps_clockwise).rem_euclid(Self::DIRECTIONS.len() as isize)) as usize;
Self::DIRECTIONS[new_idx]
}
pub fn flip(self) -> Self {
self.rotate_by(4)
}
pub fn radians(self) -> f32 {
((self as i8) - 2).rem_euclid(8) as f32 * std::f32::consts::TAU / 8.0
}
pub fn deltas(self) -> ICoord {
let (x, y) = match self {
Direction8::North => (0, -1),
Direction8::NorthEast => (1, -1),
Direction8::East => (1, 0),
Direction8::SouthEast => (1, 1),
Direction8::South => (0, 1),
Direction8::SouthWest => (-1, 1),
Direction8::West => (-1, 0),
Direction8::NorthWest => (-1, -1),
};
ICoord { x, y }
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Enum)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Rotation {
Clockwise,
CounterClockwise,
}
impl Rotation {
pub fn steps_clockwise(&self) -> isize {
match self {
Rotation::Clockwise => 1,
Rotation::CounterClockwise => -1,
}
}
}