hexga_math/geometry/vector/
mod.rs

1use std::ops::*;
2
3use crate::*;
4
5pub mod prelude;
6
7mod vector_iter;
8pub use vector_iter::*;
9
10///
11/// A wrapper for an array that applies binary operators component-wise.
12///
13/// Also supports scalar operation (e.g., `Vector<T,N> op T`).
14///
15/// ```rust
16/// use hexga_math::prelude::*;
17///
18/// assert_eq!(vec2(1.0, 2.0) + Vec2::ONE, vec2(2.0, 3.0));
19///
20/// assert_eq!(vector3(true, false, true) & Vector3::ZERO, vector3(false, false, false));
21/// ```
22pub struct Vector<T, const N : usize>
23{
24    // Not simd because we accept everythings.
25    pub array : [T; N]
26}
27impl<T, const N : usize> Default for Vector<T, N> where [T; N] : Default
28{
29    fn default() -> Self { Self { array: ___() } }
30}
31impl<T, const N : usize> Vector<T,N>
32{
33    pub fn from_fn<F>(f : F) -> Self where F : FnMut(usize) -> T { Self::from_array(std::array::from_fn(f)) }
34    pub const fn from_array(array : [T; N]) -> Self { Self { array }}
35    pub fn splat(val : T) -> Self where T: Clone { Self::from_fn(|_| val.clone()) }
36
37    pub fn iter(&self) -> impl Iterator<Item = &T> { self.array.iter() }
38    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> { self.array.iter_mut() }
39    pub fn into_iter(self) -> impl Iterator<Item = T> { self.array.into_iter() }
40}
41impl_generic_array_like_with_op!(Vector);
42
43impl<T, const N : usize> Position<T,N> for Vector<T, N> where Self : Copy, T : Copy
44{
45    fn pos(&self) -> Vector<T,N> {
46        *self
47    }
48
49    fn set_pos(&mut self, pos : Vector<T,N>) -> &mut Self {
50        *self = pos;
51        self
52    }
53}
54
55
56impl<T,const N : usize> Vector<T,N>
57{
58    // Vector related
59
60    /// Will always be >= 0.
61    ///
62    /// If any component is negative, return 0
63    pub fn area(self) -> T where T: Number
64    {
65        self.iter().fold(T::ONE,|a, b| a * (*b).max_partial(T::ZERO))
66    }
67    /// Will always be >= 0.
68    ///
69    /// If any component is negative, return 0
70    pub fn area_usize(self) -> usize where T: Integer
71    {
72        if T::PRIMITIVE_NUMBER_TYPE.is_integer_unsigned()
73        {
74            self.iter().map(|v| v.to_usize()).product()
75        }else
76        {
77            self.iter().fold(usize::ONE,|a, b| a * (*b).max_partial(T::ZERO).to_usize())
78        }
79    }
80
81    /// If any component is negative, return None,
82    /// If the multiplication overflow, return None
83    pub fn checked_area_usize(self) -> Option<usize> where T: Integer
84    {
85        let mut area = 1usize;
86        for v in self.iter()
87        {
88            if T::PRIMITIVE_NUMBER_TYPE.is_integer_signed() && v < &T::ZERO { return None; }
89            let dim : usize = v.to_usize();
90            area = area.checked_mul(dim)?;
91        }
92        Some(area)
93    }
94
95    /// Multiply each component
96    /// The result can be negative
97    pub unsafe fn area_signed(self) -> T where T: Number { self.into_iter().product() }
98
99    /// True is area() > 0
100    pub fn have_area(self) -> bool where T: Number { self.area().is_non_zero() }
101    /// True is area_usize() > 0
102    pub fn have_area_usize(self) -> bool where T: Integer { self.area_usize().is_non_zero() }
103
104    pub fn all_zero(self) -> bool where T: Zero + PartialEq { self.all(|v| v.is_zero()) }
105    pub fn all_non_zero(self) -> bool where T: Zero + PartialEq { self.all(|v| v.is_non_zero()) }
106
107    pub fn any_zero(self) -> bool where T: Zero + PartialEq { self.any(|v| v.is_zero()) }
108    pub fn any_non_zero(self) -> bool where T: Zero + PartialEq { self.any(|v| v.is_non_zero()) }
109
110    pub fn all_positive_or_zero(self) -> bool where T: PositiveOrNegative { self.all(|v| v.is_positive_or_zero()) }
111    pub fn any_positive_or_zero(self) -> bool where T: PositiveOrNegative { self.any(|v| v.is_positive_or_zero()) }
112
113    pub fn all_strictly_positive(self) -> bool where T: PositiveOrNegative { self.all(|v| v.is_strictly_positive()) }
114    pub fn any_strictly_negative(self) -> bool where T: PositiveOrNegative { self.any(|v| v.is_strictly_negative()) }
115
116    // Index :
117    #[inline(always)]
118    pub fn is_inside(self, size : Self) -> bool where T: Number
119    {
120        self.all_with(&size, |a, m| *a >= T::ZERO && a < m)
121    }
122    #[inline(always)]
123    pub fn is_outside(self, size : Self) -> bool where T: Number { !self.is_inside(size) }
124
125    #[inline(always)]
126    pub fn is_inside_rect(self, area : Rectangle<T,N>) -> bool where T: Number { area.is_inside(self) }
127
128
129    /// `x + y + z ...`
130    ///
131    /// ```rust
132    /// use hexga_math::prelude::*;
133    /// assert_eq!(point2(3,4).sum_axis(), 7);
134    /// ```
135    pub fn sum_axis(self) -> T where T: NumberArithmetic { self.into_iter().sum() }
136
137    /// [Manhattan distance](https://fr.wikipedia.org/wiki/Distance_de_Manhattan)
138    pub fn length_manhattan(self) -> T where T: NumberArithmetic, Self : Abs<Output=Self> + Copy { self.abs().sum_axis() }
139    pub fn length_squared(self) -> T where T: NumberArithmetic { self.into_iter().map(|v| v * v).sum() }
140    pub fn have_length(self) -> bool where T: Zero + PartialEq { self.into_iter().any(|c| c.is_non_zero()) }
141
142    /// The dot product : `x1 * x2 + y1 * y2 + z1 * z2 + ...`
143    pub fn dot(self, other : Self) -> T where T: NumberArithmetic
144    {
145        self.array.into_iter().zip(other.array.into_iter()).fold(T::ZERO, |acc,(a, b)| acc + a * b)
146    }
147
148    pub fn vector_to(self, target : Self) -> Self where Self : Sub<Self,Output = Self> { target - self }
149
150    /// Create a rectangle with the given size at position zero.
151    pub fn to_rect(self) -> Rectangle<T,N> where Self : Zero
152    {
153        Rectangle::new_sized(self)
154    }
155}
156
157/*
158pub trait IntegerIndex : Integer + CastInto<isize> + CastFrom<isize> + CastInto<usize> + CastFrom<usize> + Debug {}
159impl<T> IntegerIndex for T where T: Integer + CastInto<isize> + CastFrom<isize> + CastInto<usize> + CastFrom<usize> + Debug {}
160*/
161
162impl<Idx, const N : usize> Vector<Idx, N>
163    where Idx : Integer
164{
165    #[inline(always)]
166    pub fn to_index(self, size : Self) -> Option<usize> { self.is_inside(size).then(|| unsafe { self.to_index_unchecked(size) }) }
167
168    #[inline(always)]
169    /// # Safety
170    /// This function assuming that :
171    /// - The size is valid : (all axis size are >= 1)
172    /// - The self is valid (inside the grid : all axis are >= 0 and < current axis size )
173    ///
174    /// ```rust
175    /// use hexga_math::prelude::*;
176    /// assert_eq!(unsafe{ point2(0,0).to_index_unchecked(point2(10, 20)) }, 0);
177    /// assert_eq!(unsafe{ point2(3,0).to_index_unchecked(point2(10, 20)) }, 3);
178    /// assert_eq!(unsafe{ point2(3,1).to_index_unchecked(point2(10, 20)) }, 3+1*10);
179    /// assert_eq!(unsafe{ point2(3,5).to_index_unchecked(point2(10, 20)) }, 3+5*10);
180    /// ```
181    pub unsafe fn to_index_unchecked(self, size : Self) -> usize
182    {
183        debug_assert!(size.all(|v| *v >= Idx::ZERO));
184
185        let mut index_1d : usize = 0;
186        let mut area_cumulative : usize = 1;
187
188        let mut i = 0;
189        while i < N
190        {
191            let current_axis_len : usize = size[i].to_usize();
192            let current_value    : usize = self[i].to_usize();
193
194            index_1d        += current_value * area_cumulative;
195            area_cumulative *= current_axis_len;
196            i += 1;
197        }
198        index_1d
199    }
200
201    #[inline(always)]
202    pub fn from_index(index : usize, size : Self) -> Option<Self>
203    {
204        (index < size.area_usize()).then(|| unsafe { Self::from_index_unchecked(index, size) })
205    }
206
207    /// # Safety
208    /// This function assuming that :
209    /// - The size is valid : (all axis are >= 1)
210    /// - The index is valid (inside the grid : all axis are >= 0 and < current axis size )
211    ///
212    /// ```rust
213    /// use hexga_math::prelude::*;
214    /// unsafe
215    /// {
216    ///     let size = point2(10, 20);
217    ///     for point in [point2(0,0), point2(3,0), point2(3,1), point2(0,5)]
218    ///     {
219    ///         let index = point.to_index_unchecked(size);
220    ///         let point_back = Point2::from_index_unchecked(index, size);
221    ///         assert_eq!(point, point_back);
222    ///     }
223    /// }
224    /// ```
225    #[inline(always)]
226    pub unsafe fn from_index_unchecked(index : usize, size : Self) -> Self
227    {
228        debug_assert!(size.all(|v| *v >= Idx::ZERO));
229
230        let mut result = [Idx::ZERO; N];
231        let mut area_cumulative = usize::ONE;
232
233        let mut i = 0;
234        while i < N
235        {
236            let current_axis_len = size[i].to_usize();
237            result[i] = Idx::cast_from((index / area_cumulative) % current_axis_len);
238            area_cumulative *= current_axis_len;
239            i += 1;
240        }
241        Self::from_array(result)
242    }
243
244    pub fn to_grid<F,U>(self, f : F) -> GridBase<U,Idx,N> where F : FnMut(Self) -> U { GridBase::from_fn(self, f) }
245}
246
247
248
249impl<T, const N : usize> Vector<T,N> where Self : NumberArithmetic, T : Float
250{
251    pub fn distance_to(self, target : Self) -> T { self.vector_to(target).length() }
252
253    pub fn length(self) -> T { self.length_squared().sqrt() }
254
255    pub fn normalize(&mut self) -> &mut Self { *self = self.normalized(); self }
256    pub fn normalized(self) -> Self
257    {
258        if self.have_length()
259        {
260            self / Self::splat(self.length())
261        }
262        else
263        {
264            Self::ZERO
265        }
266    }
267
268    /// set the angle of the `(x, y)` axis
269    pub fn set_angle(&mut self, angle : AngleOf<T>) -> &mut Self where Self : HaveY<T>
270    {
271        let a = angle.to_vector2(self.length()); self.set_x(a.x).set_y(a.y);
272        self
273    }
274
275    /// Using the `(x, y)` axis
276    pub fn angle(self) -> AngleOf<T> where Self : HaveY<T> { AngleOf::from_radian(self.y().atan2(self.x())) }
277
278    pub fn set_length(&mut self, length : T) { *self = self.normalized() * Self::splat(length);  }
279    pub fn with_length(mut self, length : T) -> Self { self.set_length(length); self }
280
281
282
283    pub fn vector_to_limited_by_speed(self, target : Self, speed : T) -> Self where T: PartialOrd
284    {
285        let dif= self.vector_to(target);
286        if dif.is_zero() { return Self::ZERO; };
287
288        let min_dist = speed.min_partial(dif.length());
289        dif.normalized().with_length(min_dist)
290    }
291
292    /// return a bool to know if the point reached the destination
293    pub fn move_to(&mut self, target : Self, speed : T) -> bool where T: PartialOrd, Self : AddAssign<Self>
294    {
295        if self.distance_to(target) <= speed
296        {
297            *self = target;
298            return true;
299        }
300        let add = self.vector_to_limited_by_speed(target, speed);
301        *self += add;
302        add.is_zero()
303    }
304}