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