iron_shapes/
vector.rs

1// Copyright (c) 2018-2020 Thomas Kramer.
2// SPDX-FileCopyrightText: 2018-2022 Thomas Kramer
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later
5
6//! Two dimensional vectors are a core data type for Euclidean geometry in the plane.
7//! `Vector`s consist of an `x` and `y` coordinate value and describe a translation in the plane.
8
9use std::fmt;
10use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
11
12pub use num_traits::Zero;
13use num_traits::{Float, NumCast};
14
15use crate::point::Point;
16use crate::traits::{MapPointwise, TryCastCoord};
17pub use crate::traits::{Mirror, RotateOrtho};
18pub use crate::types::Angle;
19pub use crate::types::Orientation;
20pub use crate::CoordinateType;
21
22/// [`Vector`] defines a two dimensional vector with x and y components in the Euclidean plane.
23#[derive(Copy, Clone, Default, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25pub struct Vector<T> {
26    /// `x` coordinate.
27    pub x: T,
28    /// `y` coordinate.
29    pub y: T,
30}
31
32/// Shorthand notation for creating a vector.
33///
34/// # Example
35/// ```
36/// # #[macro_use]
37/// # extern crate iron_shapes;
38/// # fn main() {
39/// use iron_shapes::prelude::*;
40/// let v = vector!(1, 2);
41/// assert_eq!(v, Vector::new(1, 2));
42/// # }
43/// ```
44#[macro_export]
45macro_rules! vector {
46    ($x:expr, $y:expr) => {
47        Vector::new($x, $y)
48    };
49}
50
51impl<T: Copy> From<Vector<T>> for (T, T) {
52    #[inline]
53    fn from(v: Vector<T>) -> Self {
54        (v.x, v.y)
55    }
56}
57
58impl<T: Copy> From<&Vector<T>> for (T, T) {
59    #[inline]
60    fn from(v: &Vector<T>) -> Self {
61        (v.x, v.y)
62    }
63}
64
65impl<T: Copy> From<(T, T)> for Vector<T> {
66    #[inline]
67    fn from(coords: (T, T)) -> Self {
68        Vector::new(coords.0, coords.1)
69    }
70}
71
72impl<'a, T: Copy> From<&'a (T, T)> for Vector<T> {
73    #[inline]
74    fn from(coords: &'a (T, T)) -> Self {
75        Vector::new(coords.0, coords.1)
76    }
77}
78
79impl<'a, T: Copy> From<&'a Vector<T>> for Vector<T> {
80    #[inline]
81    fn from(v: &'a Vector<T>) -> Self {
82        Vector::new(v.x, v.y)
83    }
84}
85
86impl<T: Copy> From<[T; 2]> for Vector<T> {
87    #[inline]
88    fn from(coords: [T; 2]) -> Self {
89        Vector::new(coords[0], coords[1])
90    }
91}
92
93impl<T> fmt::Debug for Vector<T>
94where
95    T: fmt::Debug,
96{
97    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98        write!(f, "({:?}, {:?})", &self.x, &self.y)
99    }
100}
101
102impl<T> fmt::Display for Vector<T>
103where
104    T: fmt::Display + Copy,
105{
106    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107        write!(f, "({}, {})", self.x, self.y)
108    }
109}
110
111impl<T: Zero> Zero for Vector<T> {
112    /// Get zero-vector.
113    ///
114    /// # Examples
115    /// ```
116    /// use iron_shapes::vector::{Vector, Zero};
117    ///
118    /// let a = Vector::zero();
119    /// let b = Vector::new(0, 0);
120    ///
121    /// assert_eq!(a, b);
122    /// ```
123    #[inline]
124    fn zero() -> Self {
125        Vector {
126            x: T::zero(),
127            y: T::zero(),
128        }
129    }
130
131    /// Check if this is the zero-vector.
132    ///
133    /// # Examples
134    /// ```
135    /// use iron_shapes::vector::{Vector, Zero};
136    ///
137    /// assert!(Vector::<usize>::zero().is_zero());
138    /// ```
139    #[inline]
140    fn is_zero(&self) -> bool {
141        self.x.is_zero() && self.y.is_zero()
142    }
143}
144
145impl<T> Vector<T> {
146    /// Create a new vector with `x` and `y` coordinates.
147    /// # Examples
148    /// ```
149    /// use iron_shapes::vector::Vector;
150    /// let a = Vector::new(2, 3);
151    /// assert_eq!(a.x, 2);
152    /// assert_eq!(a.y, 3);
153    /// ```
154    pub fn new(x: T, y: T) -> Self {
155        Vector { x, y }
156    }
157}
158
159impl<T: Copy + Zero + PartialOrd + Sub<Output = T>> Vector<T> {
160    /// Get 1-norm of vector, i.e. the sum of the absolute values of its components.
161    ///
162    /// # Examples
163    /// ```
164    /// use iron_shapes::vector::Vector;
165    /// let a = Vector::new(-2, 3);
166    /// assert_eq!(a.norm1(), 5);
167    /// ```
168    #[inline]
169    pub fn norm1(&self) -> T {
170        let xabs = if self.x < T::zero() {
171            T::zero() - self.x
172        } else {
173            self.x
174        };
175        let yabs = if self.y < T::zero() {
176            T::zero() - self.y
177        } else {
178            self.y
179        };
180        xabs + yabs
181    }
182}
183
184impl<T: Copy + Zero + PartialOrd + Mul<Output = T> + Sub<Output = T>> Vector<T> {
185    /// Check if `other` is oriented clockwise or counter-clockwise respective to `self`.
186    ///
187    /// # Examples
188    ///
189    /// ```
190    /// use iron_shapes::vector::Vector;
191    /// use iron_shapes::types::Orientation;
192    ///
193    /// let a = Vector::new(1, 0);
194    /// let b = Vector::new(1, 1);
195    /// let c = Vector::new(1, -1);
196    /// let d = Vector::new(2, 0);
197    ///
198    /// assert_eq!(a.orientation_of(b), Orientation::CounterClockWise);
199    /// assert_eq!(a.orientation_of(c), Orientation::ClockWise);
200    /// assert_eq!(a.orientation_of(d), Orientation::Straight);
201    /// ```
202    pub fn orientation_of(&self, other: Self) -> Orientation {
203        let p = self.cross_prod(other);
204
205        if p < T::zero() {
206            Orientation::ClockWise
207        } else if p > T::zero() {
208            Orientation::CounterClockWise
209        } else {
210            Orientation::Straight
211        }
212    }
213}
214
215impl<T: Copy + Mul<Output = T> + Add<Output = T>> Vector<T> {
216    /// Get squared 2-norm of vector.
217    ///
218    /// # Examples
219    /// ```
220    /// use iron_shapes::vector::Vector;
221    /// let a = Vector::new(2, 3);
222    /// assert_eq!(a.norm2_squared(), 2*2+3*3);
223    /// ```
224    #[inline]
225    pub fn norm2_squared(&self) -> T {
226        self.x * self.x + self.y * self.y
227    }
228
229    /// Calculate scalar product.
230    ///
231    /// # Examples
232    ///
233    /// ```
234    /// use iron_shapes::vector::Vector;
235    ///
236    /// let a = Vector::new(1, 2);
237    /// let b = Vector::new(3, 4);
238    ///
239    /// assert_eq!(a.dot(b), 1*3 + 2*4);
240    /// ```
241    pub fn dot(&self, other: Self) -> T {
242        self.x * other.x + self.y * other.y
243    }
244}
245
246impl<T: Copy + Mul<Output = T> + Sub<Output = T>> Vector<T> {
247    /// Calculate cross product.
248    ///
249    /// # Examples
250    ///
251    /// ```
252    /// use iron_shapes::vector::Vector;
253    ///
254    /// let a = Vector::new(2, 0);
255    /// let b = Vector::new(0, 2);
256    ///
257    /// assert_eq!(a.cross_prod(b), 4);
258    /// assert_eq!(b.cross_prod(a), -4);
259    /// ```
260    #[inline]
261    pub fn cross_prod(&self, other: Self) -> T {
262        self.x * other.y - other.x * self.y
263    }
264}
265
266impl<T> Vector<T>
267where
268    T: Copy + NumCast,
269{
270    /// Convert vector into a vector with floating point data type.
271    #[inline]
272    pub fn cast_to_float<F>(&self) -> Vector<F>
273    where
274        F: Float + NumCast,
275    {
276        // TODO: find conversion that does not panic for sure.
277        Vector {
278            x: F::from(self.x).unwrap(),
279            y: F::from(self.y).unwrap(),
280        }
281    }
282}
283
284impl<T: Copy + NumCast, Dst: Copy + NumCast> TryCastCoord<T, Dst> for Vector<T> {
285    type Output = Vector<Dst>;
286
287    /// Try to cast to vector of target data type.
288    ///
289    /// Conversion from float to int can fail and will return `None`.
290    /// Float values like infinity or non-a-number
291    /// have no integer representation.
292    ///
293    /// # Examples
294    ///
295    /// ```
296    /// use iron_shapes::vector::Vector;
297    /// use iron_shapes::traits::TryCastCoord;
298    ///
299    /// let v_int = Vector::new(1,2);
300    /// let maybe_v_float: Option<Vector<f64>> = v_int.try_cast();
301    ///
302    /// assert_eq!(maybe_v_float, Some(Vector::new(1.0, 2.0)));
303    ///
304    /// // Conversion from float to int can fail.
305    ///
306    /// let w_float = Vector::new(42.0, 0. / 0.);
307    /// let maybe_w_int: Option<Vector<i32>> = w_float.try_cast();
308    ///
309    /// assert_eq!(maybe_w_int, None);
310    /// ```
311    #[inline]
312    fn try_cast(&self) -> Option<Self::Output> {
313        match (Dst::from(self.x), Dst::from(self.y)) {
314            (Some(x), Some(y)) => Some(Vector::new(x, y)),
315            _ => None,
316        }
317    }
318}
319
320impl<T> Vector<T>
321where
322    T: Copy + Float + Mul<Output = T> + Add<Output = T>,
323{
324    /// Get 2-norm of vector (length of vector).
325    ///
326    /// # Examples
327    /// ```
328    /// use iron_shapes::vector::Vector;
329    /// let a = Vector::new(2.0, 3.0);
330    /// let norm2 = a.norm2();
331    /// let norm2_sq = norm2 * norm2;
332    /// let expected = a.norm2_squared();
333    /// assert!(norm2_sq < expected + 1e-12);
334    /// assert!(norm2_sq > expected - 1e-12);
335    /// ```
336    #[inline]
337    pub fn norm2(&self) -> T {
338        (self.norm2_squared()).sqrt()
339    }
340
341    /// Return a vector with the same direction but length 1.
342    ///
343    /// # Panics
344    /// Panics if the vector has length 0.
345    #[inline]
346    pub fn normalized(&self) -> Self {
347        *self / self.norm2()
348    }
349
350    /// Return the normal vector onto this vector.
351    /// The normal has length `1`.
352    ///
353    /// # Panics
354    /// Panics if the vector has length 0.
355    #[inline]
356    pub fn normal(&self) -> Self {
357        self.normalized().rotate_ortho(Angle::R90)
358    }
359}
360
361impl<T: Copy + NumCast> Vector<T> {
362    /// Calculate length of vector.
363    ///
364    /// Similar to `Vector::norm2` but does potentially return another data type for the length.
365    ///
366    /// # Examples
367    /// ```
368    /// use iron_shapes::vector::Vector;
369    /// let a = Vector::new(2.0, 3.0);
370    /// let length: f64 = a.length();
371    /// let norm2_sq = length * length;
372    /// let expected = a.norm2_squared();
373    /// assert!(norm2_sq < expected + 1e-12);
374    /// assert!(norm2_sq > expected - 1e-12);
375    /// ```
376    #[inline]
377    pub fn length<F: Float>(&self) -> F {
378        let x = F::from(self.x).unwrap();
379        let y = F::from(self.y).unwrap();
380
381        x.hypot(y)
382    }
383}
384
385/// Vector addition.
386impl<T> Add for Vector<T>
387where
388    T: Add<Output = T>,
389{
390    type Output = Self;
391
392    #[inline]
393    fn add(self, rhs: Self) -> Self {
394        Vector {
395            x: self.x + rhs.x,
396            y: self.y + rhs.y,
397        }
398    }
399}
400
401impl<T> AddAssign for Vector<T>
402where
403    T: AddAssign,
404{
405    #[inline]
406    fn add_assign(&mut self, rhs: Self) {
407        self.x += rhs.x;
408        self.y += rhs.y;
409    }
410}
411
412/// Vector subtraction.
413impl<T> Sub for Vector<T>
414where
415    T: Sub<Output = T>,
416{
417    type Output = Self;
418
419    #[inline]
420    fn sub(self, rhs: Self) -> Self {
421        Vector {
422            x: self.x - rhs.x,
423            y: self.y - rhs.y,
424        }
425    }
426}
427
428impl<T> SubAssign for Vector<T>
429where
430    T: SubAssign,
431{
432    #[inline]
433    fn sub_assign(&mut self, rhs: Self) {
434        self.x -= rhs.x;
435        self.y -= rhs.y;
436    }
437}
438
439impl<T> Neg for Vector<T>
440where
441    T: Neg<Output = T>,
442{
443    type Output = Self;
444
445    #[inline]
446    fn neg(self) -> Self {
447        Vector {
448            x: -self.x,
449            y: -self.y,
450        }
451    }
452}
453
454/// Scalar multiplication.
455impl<T, M> Mul<M> for Vector<T>
456where
457    T: Mul<M, Output = T>,
458    M: Copy,
459{
460    type Output = Self;
461
462    fn mul(self, rhs: M) -> Self {
463        Vector {
464            x: self.x * rhs,
465            y: self.y * rhs,
466        }
467    }
468}
469
470/// In-place scalar multiplication.
471impl<T, M> MulAssign<M> for Vector<T>
472where
473    T: Copy + MulAssign<M>,
474    M: Copy,
475{
476    #[inline]
477    fn mul_assign(&mut self, rhs: M) {
478        self.x *= rhs;
479        self.y *= rhs;
480    }
481}
482
483/// Scalar division.
484impl<T, D> Div<D> for Vector<T>
485where
486    T: Copy + Div<D, Output = T>,
487    D: Copy,
488{
489    type Output = Self;
490
491    #[inline]
492    fn div(self, rhs: D) -> Self {
493        Vector {
494            x: self.x / rhs,
495            y: self.y / rhs,
496        }
497    }
498}
499
500/// Assigning scalar division.
501impl<T, D> DivAssign<D> for Vector<T>
502where
503    T: Copy + DivAssign<D>,
504    D: Copy,
505{
506    #[inline]
507    fn div_assign(&mut self, rhs: D) {
508        self.x /= rhs;
509        self.y /= rhs;
510    }
511}
512
513impl<T> MapPointwise<T> for Vector<T>
514where
515    T: Copy,
516{
517    #[inline]
518    fn transform<F>(&self, transformation: F) -> Self
519    where
520        F: Fn(Point<T>) -> Point<T>,
521    {
522        *transformation(Point::from(self))
523    }
524}
525
526/// Compute the sum of all vectors in the iterator.
527/// If the iterator is empty, (0, 0) is returned.
528impl<T> std::iter::Sum for Vector<T>
529where
530    T: Zero + Add<Output = T>,
531{
532    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
533        iter.fold(Self::zero(), |acc, v| acc + v)
534    }
535}
536
537#[cfg(test)]
538mod tests {
539    use super::*;
540    use num_rational::Rational64;
541    use num_traits::Zero;
542
543    #[test]
544    fn test_rational_vector() {
545        let _ = Vector::new(Rational64::zero(), Rational64::zero());
546    }
547}