2024-06-03 19:46:50 +00:00
|
|
|
|
use crate::Dir2;
|
|
|
|
|
#[cfg(feature = "bevy_reflect")]
|
|
|
|
|
use bevy_reflect::Reflect;
|
|
|
|
|
#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
|
|
|
|
|
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
|
|
|
|
|
|
|
|
|
/// A compass enum with 4 directions.
|
2024-07-11 13:08:31 +00:00
|
|
|
|
/// ```text
|
2024-06-10 17:31:11 +00:00
|
|
|
|
/// N (North)
|
|
|
|
|
/// ▲
|
|
|
|
|
/// │
|
|
|
|
|
/// │
|
|
|
|
|
/// W (West) ┼─────► E (East)
|
|
|
|
|
/// │
|
|
|
|
|
/// │
|
|
|
|
|
/// ▼
|
|
|
|
|
/// S (South)
|
|
|
|
|
/// ```
|
2024-06-03 19:46:50 +00:00
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
|
|
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))]
|
|
|
|
|
#[cfg_attr(
|
|
|
|
|
all(feature = "serialize", feature = "bevy_reflect"),
|
|
|
|
|
reflect(Deserialize, Serialize)
|
|
|
|
|
)]
|
|
|
|
|
pub enum CompassQuadrant {
|
|
|
|
|
/// Corresponds to [`Dir2::Y`] and [`Dir2::NORTH`]
|
|
|
|
|
North,
|
|
|
|
|
/// Corresponds to [`Dir2::X`] and [`Dir2::EAST`]
|
|
|
|
|
East,
|
|
|
|
|
/// Corresponds to [`Dir2::NEG_X`] and [`Dir2::SOUTH`]
|
|
|
|
|
South,
|
|
|
|
|
/// Corresponds to [`Dir2::NEG_Y`] and [`Dir2::WEST`]
|
|
|
|
|
West,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A compass enum with 8 directions.
|
2024-07-11 13:08:31 +00:00
|
|
|
|
/// ```text
|
2024-06-10 17:31:11 +00:00
|
|
|
|
/// N (North)
|
|
|
|
|
/// ▲
|
|
|
|
|
/// NW │ NE
|
|
|
|
|
/// ╲ │ ╱
|
|
|
|
|
/// W (West) ┼─────► E (East)
|
|
|
|
|
/// ╱ │ ╲
|
|
|
|
|
/// SW │ SE
|
|
|
|
|
/// ▼
|
|
|
|
|
/// S (South)
|
|
|
|
|
/// ```
|
2024-06-03 19:46:50 +00:00
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
|
|
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
|
|
|
|
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))]
|
|
|
|
|
#[cfg_attr(
|
|
|
|
|
all(feature = "serialize", feature = "bevy_reflect"),
|
|
|
|
|
reflect(Deserialize, Serialize)
|
|
|
|
|
)]
|
|
|
|
|
pub enum CompassOctant {
|
|
|
|
|
/// Corresponds to [`Dir2::Y`] and [`Dir2::NORTH`]
|
|
|
|
|
North,
|
|
|
|
|
/// Corresponds to [`Dir2::NORTH_EAST`]
|
|
|
|
|
NorthEast,
|
|
|
|
|
/// Corresponds to [`Dir2::X`] and [`Dir2::EAST`]
|
|
|
|
|
East,
|
|
|
|
|
/// Corresponds to [`Dir2::SOUTH_EAST`]
|
|
|
|
|
SouthEast,
|
|
|
|
|
/// Corresponds to [`Dir2::NEG_X`] and [`Dir2::SOUTH`]
|
|
|
|
|
South,
|
|
|
|
|
/// Corresponds to [`Dir2::SOUTH_WEST`]
|
|
|
|
|
SouthWest,
|
|
|
|
|
/// Corresponds to [`Dir2::NEG_Y`] and [`Dir2::WEST`]
|
|
|
|
|
West,
|
|
|
|
|
/// Corresponds to [`Dir2::NORTH_WEST`]
|
|
|
|
|
NorthWest,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<CompassQuadrant> for Dir2 {
|
|
|
|
|
fn from(q: CompassQuadrant) -> Self {
|
|
|
|
|
match q {
|
|
|
|
|
CompassQuadrant::North => Dir2::NORTH,
|
|
|
|
|
CompassQuadrant::East => Dir2::EAST,
|
|
|
|
|
CompassQuadrant::South => Dir2::SOUTH,
|
|
|
|
|
CompassQuadrant::West => Dir2::WEST,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<Dir2> for CompassQuadrant {
|
|
|
|
|
/// Converts a [`Dir2`] to a [`CompassQuadrant`] in a lossy manner.
|
|
|
|
|
/// Converting back to a [`Dir2`] is not guaranteed to yield the same value.
|
|
|
|
|
fn from(dir: Dir2) -> Self {
|
|
|
|
|
let angle = dir.to_angle().to_degrees();
|
|
|
|
|
|
|
|
|
|
match angle {
|
|
|
|
|
-135.0..=-45.0 => Self::South,
|
|
|
|
|
-45.0..=45.0 => Self::East,
|
|
|
|
|
45.0..=135.0 => Self::North,
|
|
|
|
|
135.0..=180.0 | -180.0..=-135.0 => Self::West,
|
|
|
|
|
_ => unreachable!(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<CompassOctant> for Dir2 {
|
|
|
|
|
fn from(o: CompassOctant) -> Self {
|
|
|
|
|
match o {
|
|
|
|
|
CompassOctant::North => Dir2::NORTH,
|
|
|
|
|
CompassOctant::NorthEast => Dir2::NORTH_EAST,
|
|
|
|
|
CompassOctant::East => Dir2::EAST,
|
|
|
|
|
CompassOctant::SouthEast => Dir2::SOUTH_EAST,
|
|
|
|
|
CompassOctant::South => Dir2::SOUTH,
|
|
|
|
|
CompassOctant::SouthWest => Dir2::SOUTH_WEST,
|
|
|
|
|
CompassOctant::West => Dir2::WEST,
|
|
|
|
|
CompassOctant::NorthWest => Dir2::NORTH_WEST,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<Dir2> for CompassOctant {
|
|
|
|
|
/// Converts a [`Dir2`] to a [`CompassOctant`] in a lossy manner.
|
|
|
|
|
/// Converting back to a [`Dir2`] is not guaranteed to yield the same value.
|
|
|
|
|
fn from(dir: Dir2) -> Self {
|
|
|
|
|
let angle = dir.to_angle().to_degrees();
|
|
|
|
|
|
|
|
|
|
match angle {
|
|
|
|
|
-112.5..=-67.5 => Self::South,
|
|
|
|
|
-67.5..=-22.5 => Self::SouthEast,
|
|
|
|
|
-22.5..=22.5 => Self::East,
|
|
|
|
|
22.5..=67.5 => Self::NorthEast,
|
|
|
|
|
67.5..=112.5 => Self::North,
|
|
|
|
|
112.5..=157.5 => Self::NorthWest,
|
|
|
|
|
157.5..=180.0 | -180.0..=-157.5 => Self::West,
|
|
|
|
|
-157.5..=-112.5 => Self::SouthWest,
|
|
|
|
|
_ => unreachable!(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod test_compass_quadrant {
|
|
|
|
|
use crate::{CompassQuadrant, Dir2, Vec2};
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_cardinal_directions() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(1.0, 0.0)).unwrap(),
|
|
|
|
|
CompassQuadrant::East,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.0, 1.0)).unwrap(),
|
|
|
|
|
CompassQuadrant::North,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-1.0, 0.0)).unwrap(),
|
|
|
|
|
CompassQuadrant::West,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.0, -1.0)).unwrap(),
|
|
|
|
|
CompassQuadrant::South,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassQuadrant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_north_pie_slice() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.1, 0.9)).unwrap(),
|
|
|
|
|
CompassQuadrant::North,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.1, 0.9)).unwrap(),
|
|
|
|
|
CompassQuadrant::North,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassQuadrant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_east_pie_slice() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.9, 0.1)).unwrap(),
|
|
|
|
|
CompassQuadrant::East,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.9, -0.1)).unwrap(),
|
|
|
|
|
CompassQuadrant::East,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassQuadrant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_south_pie_slice() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.1, -0.9)).unwrap(),
|
|
|
|
|
CompassQuadrant::South,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.1, -0.9)).unwrap(),
|
|
|
|
|
CompassQuadrant::South,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassQuadrant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_west_pie_slice() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.9, -0.1)).unwrap(),
|
|
|
|
|
CompassQuadrant::West,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.9, 0.1)).unwrap(),
|
|
|
|
|
CompassQuadrant::West,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassQuadrant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod test_compass_octant {
|
|
|
|
|
use crate::{CompassOctant, Dir2, Vec2};
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_cardinal_directions() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.5, 0.5)).unwrap(),
|
|
|
|
|
CompassOctant::NorthWest,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.0, 1.0)).unwrap(),
|
|
|
|
|
CompassOctant::North,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.5, 0.5)).unwrap(),
|
|
|
|
|
CompassOctant::NorthEast,
|
|
|
|
|
),
|
|
|
|
|
(Dir2::new(Vec2::new(1.0, 0.0)).unwrap(), CompassOctant::East),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.5, -0.5)).unwrap(),
|
|
|
|
|
CompassOctant::SouthEast,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.0, -1.0)).unwrap(),
|
|
|
|
|
CompassOctant::South,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.5, -0.5)).unwrap(),
|
|
|
|
|
CompassOctant::SouthWest,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-1.0, 0.0)).unwrap(),
|
|
|
|
|
CompassOctant::West,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassOctant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_north_pie_slice() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.1, 0.9)).unwrap(),
|
|
|
|
|
CompassOctant::North,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.1, 0.9)).unwrap(),
|
|
|
|
|
CompassOctant::North,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassOctant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_north_east_pie_slice() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.4, 0.6)).unwrap(),
|
|
|
|
|
CompassOctant::NorthEast,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.6, 0.4)).unwrap(),
|
|
|
|
|
CompassOctant::NorthEast,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassOctant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_east_pie_slice() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(Dir2::new(Vec2::new(0.9, 0.1)).unwrap(), CompassOctant::East),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.9, -0.1)).unwrap(),
|
|
|
|
|
CompassOctant::East,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassOctant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_south_east_pie_slice() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.4, -0.6)).unwrap(),
|
|
|
|
|
CompassOctant::SouthEast,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.6, -0.4)).unwrap(),
|
|
|
|
|
CompassOctant::SouthEast,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassOctant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_south_pie_slice() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.1, -0.9)).unwrap(),
|
|
|
|
|
CompassOctant::South,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(0.1, -0.9)).unwrap(),
|
|
|
|
|
CompassOctant::South,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassOctant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_south_west_pie_slice() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.4, -0.6)).unwrap(),
|
|
|
|
|
CompassOctant::SouthWest,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.6, -0.4)).unwrap(),
|
|
|
|
|
CompassOctant::SouthWest,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassOctant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_west_pie_slice() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.9, -0.1)).unwrap(),
|
|
|
|
|
CompassOctant::West,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.9, 0.1)).unwrap(),
|
|
|
|
|
CompassOctant::West,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassOctant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_north_west_pie_slice() {
|
|
|
|
|
let tests = vec![
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.4, 0.6)).unwrap(),
|
|
|
|
|
CompassOctant::NorthWest,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
Dir2::new(Vec2::new(-0.6, 0.4)).unwrap(),
|
|
|
|
|
CompassOctant::NorthWest,
|
|
|
|
|
),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (dir, expected) in tests {
|
|
|
|
|
assert_eq!(CompassOctant::from(dir), expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|