siege_math/vector/
direction.rs

1
2use std::ops::{Deref, Neg};
3use float_cmp::{Ulps, ApproxEq};
4use super::{Vec2, Vec3, Vec4};
5use {Angle, FullFloat};
6
7/// Direction vector in 2-dimensions (normalized)
8#[repr(C)]
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10#[derive(Serialize, Deserialize)]
11pub struct Direction2<F>(Vec2<F>);
12
13/// Direction vector in 3-dimensions (normalized)
14#[repr(C)]
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16#[derive(Serialize, Deserialize)]
17pub struct Direction3<F>(Vec3<F>);
18
19pub const X_AXIS_F32: Direction3<f32> = Direction3::<f32>(
20    Vec3::<f32> { x: 1.0, y: 0.0, z: 0.0 }
21);
22pub const Y_AXIS_F32: Direction3<f32> = Direction3::<f32>(
23    Vec3::<f32> { x: 0.0, y: 1.0, z: 0.0 }
24);
25pub const Z_AXIS_F32: Direction3<f32> = Direction3::<f32>(
26    Vec3::<f32> { x: 0.0, y: 0.0, z: 1.0 }
27);
28pub const X_AXIS_F64: Direction3<f64> = Direction3::<f64>(
29    Vec3::<f64> { x: 1.0, y: 0.0, z: 0.0 }
30);
31pub const Y_AXIS_F64: Direction3<f64> = Direction3::<f64>(
32    Vec3::<f64> { x: 0.0, y: 1.0, z: 0.0 }
33);
34pub const Z_AXIS_F64: Direction3<f64> = Direction3::<f64>(
35    Vec3::<f64> { x: 0.0, y: 0.0, z: 1.0 }
36);
37
38impl<F: FullFloat> Direction2<F> {
39    #[inline]
40    pub fn new_isnormal(x: F, y: F) -> Direction2<F> {
41        let d = Direction2(Vec2::new(x,y));
42        assert!(d.0.is_normal());
43        d
44    }
45}
46
47impl<F: FullFloat> Direction3<F> {
48    #[inline]
49    pub fn new_isnormal(x: F, y: F, z: F) -> Direction3<F> {
50        let d = Direction3(Vec3::new(x,y,z));
51        assert!(d.0.is_normal());
52        d
53    }
54}
55
56impl<F: FullFloat> Deref for Direction2<F> {
57    type Target = Vec2<F>;
58
59    fn deref(&self) -> &Vec2<F>
60    {
61        &self.0
62    }
63}
64
65impl<F: FullFloat> Deref for Direction3<F> {
66    type Target = Vec3<F>;
67
68    fn deref(&self) -> &Vec3<F>
69    {
70        &self.0
71    }
72}
73
74impl<F: FullFloat> From<Direction2<F>> for Vec2<F> {
75    fn from(v: Direction2<F>) -> Vec2<F> {
76        v.0
77    }
78}
79impl<F: FullFloat> From<Direction3<F>> for Vec3<F> {
80    fn from(v: Direction3<F>) -> Vec3<F> {
81        v.0
82    }
83}
84impl<F: FullFloat> From<Direction3<F>> for Vec4<F> {
85    fn from(v: Direction3<F>) -> Vec4<F> {
86        Vec4::new(v.0.x, v.0.y, v.0.z, F::zero())
87    }
88}
89
90impl<F: FullFloat> From<Vec2<F>> for Direction2<F> {
91    fn from(mut v: Vec2<F>) -> Direction2<F> {
92        let mag = v.magnitude();
93        v.x /= mag;
94        v.y /= mag;
95        Direction2(v)
96    }
97}
98impl<F: FullFloat> From<Vec3<F>> for Direction3<F> {
99    fn from(mut v: Vec3<F>) -> Direction3<F> {
100        let mag = v.magnitude();
101        v.x /= mag;
102        v.y /= mag;
103        v.z /= mag;
104        Direction3(v)
105    }
106}
107
108impl<F: FullFloat> Direction3<F> {
109    #[allow(dead_code)]
110    #[inline]
111    fn from_vec4(v: Vec4<F>) -> Option<Direction3<F>> {
112        if v.w != F::zero() { return None; }
113        Some(Direction3(v.truncate_w()))
114    }
115}
116
117impl<F: FullFloat> Direction3<F> {
118    #[inline]
119    pub fn cross(&self, rhs: Direction3<F>) -> Vec3<F> {
120        self.0.cross(rhs.0)
121    }
122}
123
124impl<F: FullFloat> Direction3<F> {
125    #[inline]
126    pub fn dot(&self, rhs: Direction3<F>) -> F {
127        self.0.dot(rhs.0)
128    }
129}
130
131impl<F: FullFloat> Neg for Direction3<F> {
132    type Output = Direction3<F>;
133
134    #[inline]
135    fn neg(self) -> Direction3<F> {
136        Direction3(-self.0)
137    }
138}
139
140impl<F: FullFloat> ApproxEq for Direction2<F> {
141    type Flt = F;
142
143    fn approx_eq(&self, other: &Self,
144                 epsilon: <F as ApproxEq>::Flt,
145                 ulps: <<F as ApproxEq>::Flt as Ulps>::U) -> bool
146    {
147        self.0.approx_eq(&other.0, epsilon, ulps)
148    }
149}
150
151impl<F: FullFloat> ApproxEq for Direction3<F> {
152    type Flt = F;
153
154    fn approx_eq(&self, other: &Self,
155                 epsilon: <F as ApproxEq>::Flt,
156                 ulps: <<F as ApproxEq>::Flt as Ulps>::U) -> bool
157    {
158        self.0.approx_eq(&other.0, epsilon, ulps)
159    }
160}
161
162impl<F: FullFloat> Direction3<F> {
163    pub fn from_lat_long(latitude: Angle<F>, longitude: Angle<F>) -> Direction3<F>
164    {
165        let (slat,clat) = latitude.as_radians().sin_cos();
166        let (slon,clon) = longitude.as_radians().sin_cos();
167        Direction3(Vec3 {
168            x: clat * slon,
169            y: slat,
170            z: slat * clon,
171        })
172    }
173
174    pub fn to_lat_long(&self) -> (Angle<F>, Angle<F>) {
175        let lat = self.0.y.acos();
176        let lon = (self.0.z / self.0.y).acos();
177        (Angle::from_radians(lat), Angle::from_radians(lon))
178    }
179}