1use crate::point::{Point2D, Point3D};
11use crate::vector::{Vector2D, Vector3D};
12
13use crate::num::{One, Zero};
14
15use core::cmp::{Eq, PartialEq};
16use core::fmt;
17use core::hash::Hash;
18use core::marker::PhantomData;
19use core::ops::Div;
20#[cfg(feature = "serde")]
21use serde;
22
23#[repr(C)]
25pub struct HomogeneousVector<T, U> {
26 pub x: T,
27 pub y: T,
28 pub z: T,
29 pub w: T,
30 #[doc(hidden)]
31 pub _unit: PhantomData<U>,
32}
33
34impl<T: Copy, U> Copy for HomogeneousVector<T, U> {}
35
36impl<T: Clone, U> Clone for HomogeneousVector<T, U> {
37 fn clone(&self) -> Self {
38 HomogeneousVector {
39 x: self.x.clone(),
40 y: self.y.clone(),
41 z: self.z.clone(),
42 w: self.w.clone(),
43 _unit: PhantomData,
44 }
45 }
46}
47
48#[cfg(feature = "serde")]
49impl<'de, T, U> serde::Deserialize<'de> for HomogeneousVector<T, U>
50where
51 T: serde::Deserialize<'de>,
52{
53 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
54 where
55 D: serde::Deserializer<'de>,
56 {
57 let (x, y, z, w) = serde::Deserialize::deserialize(deserializer)?;
58 Ok(HomogeneousVector {
59 x,
60 y,
61 z,
62 w,
63 _unit: PhantomData,
64 })
65 }
66}
67
68#[cfg(feature = "serde")]
69impl<T, U> serde::Serialize for HomogeneousVector<T, U>
70where
71 T: serde::Serialize,
72{
73 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
74 where
75 S: serde::Serializer,
76 {
77 (&self.x, &self.y, &self.z, &self.w).serialize(serializer)
78 }
79}
80
81impl<T, U> Eq for HomogeneousVector<T, U> where T: Eq {}
82
83impl<T, U> PartialEq for HomogeneousVector<T, U>
84where
85 T: PartialEq,
86{
87 fn eq(&self, other: &Self) -> bool {
88 self.x == other.x && self.y == other.y && self.z == other.z && self.w == other.w
89 }
90}
91
92impl<T, U> Hash for HomogeneousVector<T, U>
93where
94 T: Hash,
95{
96 fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
97 self.x.hash(h);
98 self.y.hash(h);
99 self.z.hash(h);
100 self.w.hash(h);
101 }
102}
103
104impl<T, U> HomogeneousVector<T, U> {
105 #[inline]
107 pub const fn new(x: T, y: T, z: T, w: T) -> Self {
108 HomogeneousVector {
109 x,
110 y,
111 z,
112 w,
113 _unit: PhantomData,
114 }
115 }
116}
117
118impl<T: Copy + Div<T, Output = T> + Zero + PartialOrd, U> HomogeneousVector<T, U> {
119 #[inline]
123 pub fn to_point2d(self) -> Option<Point2D<T, U>> {
124 if self.w > T::zero() {
125 Some(Point2D::new(self.x / self.w, self.y / self.w))
126 } else {
127 None
128 }
129 }
130
131 #[inline]
135 pub fn to_point3d(self) -> Option<Point3D<T, U>> {
136 if self.w > T::zero() {
137 Some(Point3D::new(
138 self.x / self.w,
139 self.y / self.w,
140 self.z / self.w,
141 ))
142 } else {
143 None
144 }
145 }
146}
147
148impl<T: Zero, U> From<Vector2D<T, U>> for HomogeneousVector<T, U> {
149 #[inline]
150 fn from(v: Vector2D<T, U>) -> Self {
151 HomogeneousVector::new(v.x, v.y, T::zero(), T::zero())
152 }
153}
154
155impl<T: Zero, U> From<Vector3D<T, U>> for HomogeneousVector<T, U> {
156 #[inline]
157 fn from(v: Vector3D<T, U>) -> Self {
158 HomogeneousVector::new(v.x, v.y, v.z, T::zero())
159 }
160}
161
162impl<T: Zero + One, U> From<Point2D<T, U>> for HomogeneousVector<T, U> {
163 #[inline]
164 fn from(p: Point2D<T, U>) -> Self {
165 HomogeneousVector::new(p.x, p.y, T::zero(), T::one())
166 }
167}
168
169impl<T: One, U> From<Point3D<T, U>> for HomogeneousVector<T, U> {
170 #[inline]
171 fn from(p: Point3D<T, U>) -> Self {
172 HomogeneousVector::new(p.x, p.y, p.z, T::one())
173 }
174}
175
176impl<T: fmt::Debug, U> fmt::Debug for HomogeneousVector<T, U> {
177 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
178 f.debug_tuple("")
179 .field(&self.x)
180 .field(&self.y)
181 .field(&self.z)
182 .field(&self.w)
183 .finish()
184 }
185}
186
187#[cfg(test)]
188mod homogeneous {
189 use super::HomogeneousVector;
190 use crate::default::{Point2D, Point3D};
191
192 #[test]
193 fn roundtrip() {
194 assert_eq!(
195 Some(Point2D::new(1.0, 2.0)),
196 HomogeneousVector::from(Point2D::new(1.0, 2.0)).to_point2d()
197 );
198 assert_eq!(
199 Some(Point3D::new(1.0, -2.0, 0.1)),
200 HomogeneousVector::from(Point3D::new(1.0, -2.0, 0.1)).to_point3d()
201 );
202 }
203
204 #[test]
205 fn negative() {
206 assert_eq!(
207 None,
208 HomogeneousVector::<f32, ()>::new(1.0, 2.0, 3.0, 0.0).to_point2d()
209 );
210 assert_eq!(
211 None,
212 HomogeneousVector::<f32, ()>::new(1.0, -2.0, -3.0, -2.0).to_point3d()
213 );
214 }
215}