Skip to main content

parry2d/math/
vector_ext.rs

1//! Vector extension trait for glam types.
2
3use crate::math::{IVector, Int, Matrix, Real, Vector};
4
5#[cfg(not(feature = "std"))]
6use simba::scalar::ComplexField;
7
8/// Extension trait for glam vector types to provide additional functionality.
9pub trait VectorExt: Sized + Copy {
10    /// Creates a vector with the i-th component set to `val` and all others to zero.
11    fn ith(i: usize, val: Real) -> Self;
12
13    /// Computes the angle between two vectors in radians.
14    fn angle(self, other: Self) -> Real;
15
16    /// Computes the kronecker product between two vectors.
17    fn kronecker(self, other: Self) -> Matrix;
18
19    /// Gets the i-th component of the vector by index.
20    ///
21    /// This is a SPIR-V compatible replacement for bracket indexing (`v[i]`),
22    /// which is not supported on glam types when targeting SPIR-V.
23    fn vget(&self, i: usize) -> Real;
24
25    /// Sets the i-th component of the vector by index.
26    ///
27    /// This is a SPIR-V compatible replacement for bracket indexing (`v[i] = val`),
28    /// which is not supported on glam types when targeting SPIR-V.
29    fn vset(&mut self, i: usize, val: Real);
30}
31
32impl VectorExt for Vector {
33    #[inline]
34    #[cfg(feature = "dim2")]
35    fn ith(i: usize, val: Real) -> Self {
36        match i {
37            0 => Self::new(val, 0.0),
38            1 => Self::new(0.0, val),
39            _ => Self::ZERO,
40        }
41    }
42
43    #[inline]
44    #[cfg(feature = "dim3")]
45    fn ith(i: usize, val: Real) -> Self {
46        match i {
47            0 => Self::new(val, 0.0, 0.0),
48            1 => Self::new(0.0, val, 0.0),
49            2 => Self::new(0.0, 0.0, val),
50            _ => Self::ZERO,
51        }
52    }
53
54    #[inline]
55    fn angle(self, other: Self) -> Real {
56        let dot = self.dot(other);
57        let len_self = self.length();
58        let len_other = other.length();
59        if len_self > 0.0 && len_other > 0.0 {
60            (dot / (len_self * len_other)).clamp(-1.0, 1.0).acos()
61        } else {
62            0.0
63        }
64    }
65
66    #[inline]
67    #[cfg(feature = "dim2")]
68    fn kronecker(self, other: Self) -> Matrix {
69        Matrix::from_cols(self * other.x, self * other.y)
70    }
71
72    #[inline]
73    #[cfg(feature = "dim3")]
74    fn kronecker(self, other: Self) -> Matrix {
75        Matrix::from_cols(self * other.x, self * other.y, self * other.z)
76    }
77
78    #[inline]
79    fn vget(&self, i: usize) -> Real {
80        #[cfg(target_arch = "spirv")]
81        return match i {
82            0 => self.x,
83            1 => self.y,
84            #[cfg(feature = "dim3")]
85            2 => self.z,
86            _ => panic!("Index out of bounds for 2D vector: {i}"),
87        };
88        #[cfg(not(target_arch = "spirv"))]
89        {
90            self[i]
91        }
92    }
93
94    #[inline]
95    fn vset(&mut self, i: usize, val: Real) {
96        #[cfg(target_arch = "spirv")]
97        match i {
98            0 => self.x = val,
99            1 => self.y = val,
100            #[cfg(feature = "dim3")]
101            2 => self.z = val,
102            _ => panic!("Index out of bounds for 2D vector: {i}"),
103        };
104        #[cfg(not(target_arch = "spirv"))]
105        {
106            self[i] = val;
107        }
108    }
109}
110
111/// Extension trait for integer vector types with index-based component access.
112///
113/// Provides SPIR-V compatible replacement for bracket indexing on glam integer vectors.
114pub trait IVectorExt: Sized + Copy {
115    /// Gets the i-th component of the integer vector by index.
116    fn ivget(&self, i: usize) -> Int;
117
118    /// Sets the i-th component of the integer vector by index.
119    fn ivset(&mut self, i: usize, val: Int);
120}
121
122impl IVectorExt for IVector {
123    #[inline]
124    fn ivget(&self, i: usize) -> Int {
125        #[cfg(target_arch = "spirv")]
126        return match i {
127            0 => self.x,
128            1 => self.y,
129            #[cfg(feature = "dim3")]
130            2 => self.z,
131            _ => panic!("Index out of bounds for 2D integer vector: {i}"),
132        };
133        #[cfg(not(target_arch = "spirv"))]
134        {
135            self[i]
136        }
137    }
138
139    #[inline]
140    fn ivset(&mut self, i: usize, val: Int) {
141        #[cfg(target_arch = "spirv")]
142        match i {
143            0 => self.x = val,
144            1 => self.y = val,
145            #[cfg(feature = "dim3")]
146            2 => self.z = val,
147            _ => panic!("Index out of bounds for 2D integer vector: {i}"),
148        }
149        #[cfg(not(target_arch = "spirv"))]
150        {
151            self[i] = val;
152        }
153    }
154}