1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use crate::{Angle, Vector};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::{convert::TryFrom, ops::Neg};
use strum_macros::EnumIter;

#[derive(Clone, Copy, Debug, EnumIter, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Cardinal {
    North,
    East,
    South,
    West,
}

impl Cardinal {
    pub fn angle<T: en::Float>(self) -> Angle<T> {
        Direction::from(self).angle()
    }

    pub fn unit_vector<T: en::Float>(self) -> Vector<T> {
        Direction::from(self).unit_vector()
    }
}

impl Neg for Cardinal {
    type Output = Self;

    fn neg(self) -> Self::Output {
        use Cardinal::*;
        match self {
            North => South,
            South => North,
            East => West,
            West => East,
        }
    }
}

#[derive(Clone, Copy, Debug, EnumIter, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Direction {
    North,
    Northeast,
    East,
    Southeast,
    South,
    Southwest,
    West,
    Northwest,
}

impl Direction {
    pub fn angle<T: en::Float>(self) -> Angle<T> {
        use Direction::*;
        match self {
            North => Angle::FRAC_PI_2(),
            South => Angle::FRAC_3PI_2(),
            East => Angle::ZERO(),
            West => Angle::PI(),
            Northeast => Angle::FRAC_PI_4(),
            Southeast => Angle::FRAC_7PI_4(),
            Southwest => Angle::FRAC_5PI_4(),
            Northwest => Angle::FRAC_3PI_4(),
        }
    }

    pub fn unit_vector<T: en::Float>(self) -> Vector<T> {
        self.angle().unit_vector()
    }
}

impl Neg for Direction {
    type Output = Self;

    fn neg(self) -> Self::Output {
        use Direction::*;
        match self {
            North => South,
            Northeast => Southwest,
            East => West,
            Southeast => Northwest,
            South => North,
            Southwest => Northeast,
            West => East,
            Northwest => Southeast,
        }
    }
}

impl From<Cardinal> for Direction {
    fn from(cardinal: Cardinal) -> Self {
        match cardinal {
            Cardinal::North => Direction::North,
            Cardinal::South => Direction::South,
            Cardinal::East => Direction::East,
            Cardinal::West => Direction::West,
        }
    }
}

impl TryFrom<Direction> for Cardinal {
    type Error = ();

    fn try_from(direction: Direction) -> Result<Self, Self::Error> {
        match direction {
            Direction::North => Ok(Cardinal::North),
            Direction::East => Ok(Cardinal::East),
            Direction::South => Ok(Cardinal::South),
            Direction::West => Ok(Cardinal::West),
            _ => Err(()),
        }
    }
}