physdes/vector2.rs
1// #![no_std]
2
3#[cfg(any(test, feature = "std"))]
4// #[cfg_attr(test, macro_use)]
5// extern crate std;
6
7// use core::fmt;
8#[cfg(test)]
9use core::hash;
10// use core::iter::{Product, Sum};
11use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
12
13// use core::str::FromStr;
14#[cfg(feature = "std")]
15use std::error::Error;
16
17use num_traits::{Num, Signed, Zero};
18
19/// The code defines a generic struct called Vector2 with two fields, x_ and y_.
20///
21/// Properties:
22///
23/// * `x_`: The `x_` property represents the x-coordinate of the Vector2 object. It is of type `T`,
24/// which means it can be any type specified when creating an instance of the Vector2 struct.
25/// * `y_`: The `y_` property is the y-coordinate of the `Vector2` object. It represents the vertical
26/// position of the vector in a 2D coordinate system.
27#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug, Default)]
28// #[repr(C)]
29pub struct Vector2<T> {
30 /// x portion of the Vector2 object
31 pub x_: T,
32 /// y portion of the Vector2 object
33 pub y_: T,
34}
35
36impl<T> Vector2<T> {
37 /// The function `new` creates a new Vector2 with the given x and y values.
38 ///
39 /// Arguments:
40 ///
41 /// * `x_`: The parameter `x_` represents the x-coordinate of the Vector2.
42 /// * `y_`: The parameter `y_` represents the y-coordinate of the Vector2. It is of type `T`, which
43 /// means it can be any type that is specified when the Vector2 is created.
44 ///
45 /// Returns:
46 ///
47 /// The `new` function is returning a new instance of the `Vector2` struct with the provided `x_`
48 /// and `y_` values.
49 ///
50 /// # Example
51 ///
52 /// ```
53 /// use physdes::vector2::Vector2;
54 ///
55 /// assert_eq!(Vector2::new(1, 2), Vector2 { x_: 1, y_: 2 });
56 /// assert_eq!(Vector2::new(3, 4), Vector2 { x_: 3, y_: 4 });
57 /// ```
58 #[inline]
59 pub const fn new(x_: T, y_: T) -> Self {
60 Vector2 { x_, y_ }
61 }
62}
63
64impl<T: Clone + Num> Vector2<T> {
65 /// The `dot` function calculates the dot product of two vectors.
66 ///
67 /// Arguments:
68 ///
69 /// * `other`: The `other` parameter is of the same type as `self`, which means it is an instance of
70 /// the same struct or class that the `dot` method is defined in.
71 ///
72 /// Returns:
73 ///
74 /// The dot product of two vectors is being returned.
75 ///
76 /// # Example
77 ///
78 /// ```
79 /// use physdes::vector2::Vector2;
80 ///
81 /// assert_eq!(Vector2::new(1, 2).dot(&Vector2::new(3, 4)), 11);
82 /// assert_eq!(Vector2::new(3, 4).dot(&Vector2::new(1, 2)), 11);
83 /// ```
84 #[inline]
85 pub fn dot(&self, other: &Self) -> T {
86 self.x_.clone() * other.x_.clone() + self.y_.clone() * other.y_.clone()
87 }
88
89 /// The `cross` function calculates the cross product of two vectors.
90 ///
91 /// Arguments:
92 ///
93 /// * `other`: The `other` parameter is of type `Self`, which means it is the same type as the
94 /// current object.
95 ///
96 /// Returns:
97 ///
98 /// The cross product of two vectors is being returned.
99 /// Returns the cross product
100 ///
101 /// # Example
102 ///
103 /// ```
104 /// use physdes::vector2::Vector2;
105 ///
106 /// assert_eq!(Vector2::new(1, 2).cross(&Vector2::new(3, 4)), -2);
107 /// assert_eq!(Vector2::new(3, 4).cross(&Vector2::new(1, 2)), 2);
108 /// ```
109 #[inline]
110 pub fn cross(&self, other: &Self) -> T {
111 self.x_.clone() * other.y_.clone() - self.y_.clone() * other.x_.clone()
112 }
113
114 /// The `norm_sqr` function calculates the square of the norm of a vector.
115 ///
116 /// Returns:
117 ///
118 /// The `norm_sqr` function returns the squared norm of the object on which it is called.
119 ///
120 /// # Example
121 ///
122 /// ```
123 /// use physdes::vector2::Vector2;
124 ///
125 /// assert_eq!(Vector2::new(1, 2).norm_sqr(), 5);
126 /// assert_eq!(Vector2::new(3, 4).norm_sqr(), 25);
127 /// ```
128 #[inline]
129 pub fn norm_sqr(&self) -> T {
130 self.dot(self)
131 }
132
133 /// The `scale` function multiplies the vector by a scalar value.
134 ///
135 /// Arguments:
136 ///
137 /// * `t`: The parameter `t` is a scalar value that will be used to multiply each component of
138 /// `self`.
139 ///
140 /// Returns:
141 ///
142 /// The `scale` method returns a new instance of the same type as `self`.
143 /// Multiplies `self` by the scalar `t`.
144 ///
145 /// # Example
146 ///
147 /// ```
148 /// use physdes::vector2::Vector2;
149 ///
150 /// assert_eq!(Vector2::new(1, 2).scale(3), Vector2::new(3, 6));
151 /// assert_eq!(Vector2::new(3, 4).scale(2), Vector2::new(6, 8));
152 /// ```
153 #[inline]
154 pub fn scale(&self, t: T) -> Self {
155 Self::new(self.x_.clone() * t.clone(), self.y_.clone() * t)
156 }
157
158 /// The `unscale` function divides the coordinates of a vector by a scalar value.
159 ///
160 /// Arguments:
161 ///
162 /// * `t`: The parameter `t` is a scalar value that is used to divide the `self` object. It is of
163 /// type `T`, which is a generic type parameter. The division operation is performed on the `x_` and
164 /// `y_` fields of the `self` object.
165 ///
166 /// Returns:
167 ///
168 /// The `unscale` method returns a new instance of the same type as `self`.
169 /// Divides `self` by the scalar `t`.
170 ///
171 /// # Example
172 ///
173 /// ```
174 /// use physdes::vector2::Vector2;
175 ///
176 /// assert_eq!(Vector2::new(3, 6).unscale(3), Vector2::new(1, 2));
177 /// assert_eq!(Vector2::new(6, 8).unscale(2), Vector2::new(3, 4));
178 /// ```
179 #[inline]
180 pub fn unscale(&self, t: T) -> Self {
181 Self::new(self.x_.clone() / t.clone(), self.y_.clone() / t)
182 }
183}
184
185impl<T: Clone + Signed> Vector2<T> {
186 /// The `l1_norm` function calculates the Manhattan distance from the origin.
187 ///
188 /// [Manhattan distance]: https://en.wikipedia.org/wiki/Taxicab_geometry
189 ///
190 /// Returns:
191 ///
192 /// The L1 norm, which is the Manhattan distance from the origin.
193 /// Returns the L1 norm `|x_| + |y_|` -- the [Manhattan distance] from the origin.
194 ///
195 /// # Example
196 ///
197 /// ```
198 /// use physdes::vector2::Vector2;
199 ///
200 /// assert_eq!(Vector2::new(1, 2).l1_norm(), 3);
201 /// assert_eq!(Vector2::new(3, 4).l1_norm(), 7);
202 /// ```
203 #[inline]
204 pub fn l1_norm(&self) -> T {
205 self.x_.abs() + self.y_.abs()
206 }
207}
208
209impl<T: Clone + PartialOrd> Vector2<T> {
210 /// The `norm_inf` function returns the maximum absolute value between `x_` and `y_`.
211 ///
212 /// Returns:
213 ///
214 /// The `norm_inf` function returns the maximum value between `|x_|` and `|y_|`.
215 /// Returns the infinity norm `max(|x_| + |y_|)`
216 ///
217 /// # Example
218 ///
219 /// ```
220 /// use physdes::vector2::Vector2;
221 ///
222 /// assert_eq!(Vector2::new(1, 2).norm_inf(), 2);
223 /// assert_eq!(Vector2::new(3, 4).norm_inf(), 4);
224 /// ```
225 #[inline]
226 pub fn norm_inf(&self) -> T {
227 if self.x_ > self.y_ {
228 self.x_.clone()
229 } else {
230 self.y_.clone()
231 }
232 }
233}
234
235macro_rules! forward_xf_xf_binop {
236 (impl $imp:ident, $method:ident) => {
237 impl<'a, 'b, T: Clone + Num> $imp<&'b Vector2<T>> for &'a Vector2<T> {
238 type Output = Vector2<T>;
239
240 /// The function clones the input arguments and calls the specified method on them.
241 ///
242 /// Arguments:
243 ///
244 /// * `other`: A reference to another Vector2 object of the same type as self.
245 #[inline]
246 fn $method(self, other: &Vector2<T>) -> Self::Output {
247 self.clone().$method(other.clone())
248 }
249 }
250 };
251}
252
253macro_rules! forward_xf_val_binop {
254 (impl $imp:ident, $method:ident) => {
255 impl<'a, T: Clone + Num> $imp<Vector2<T>> for &'a Vector2<T> {
256 type Output = Vector2<T>;
257
258 #[inline]
259 fn $method(self, other: Vector2<T>) -> Self::Output {
260 self.clone().$method(other)
261 }
262 }
263 };
264}
265
266macro_rules! forward_val_xf_binop {
267 (impl $imp:ident, $method:ident) => {
268 impl<'a, T: Clone + Num> $imp<&'a Vector2<T>> for Vector2<T> {
269 type Output = Vector2<T>;
270
271 #[inline]
272 fn $method(self, other: &Vector2<T>) -> Self::Output {
273 self.$method(other.clone())
274 }
275 }
276 };
277}
278
279macro_rules! forward_all_binop {
280 (impl $imp:ident, $method:ident) => {
281 forward_xf_xf_binop!(impl $imp, $method);
282 forward_xf_val_binop!(impl $imp, $method);
283 forward_val_xf_binop!(impl $imp, $method);
284 };
285}
286
287// arithmetic
288forward_all_binop!(impl Add, add);
289
290// (a, b) + (c, d) == (a + c), (b + d)
291impl<T: Clone + Num> Add<Vector2<T>> for Vector2<T> {
292 type Output = Self;
293
294 /// The function `add` takes two values of the same type and returns their sum.
295 ///
296 /// Arguments:
297 ///
298 /// * `other`: The `other` parameter is of the same type as `self` and represents the other object
299 /// that you want to add to `self`.
300 ///
301 /// # Example
302 ///
303 /// ```
304 /// use physdes::vector2::Vector2;
305 /// use std::ops::Add;
306 ///
307 /// assert_eq!(Vector2::new(1, 2).add(Vector2::new(3, 4)), Vector2::new(4, 6));
308 /// assert_eq!(Vector2::new(3, 4).add(Vector2::new(1, 2)), Vector2::new(4, 6));
309 /// ```
310 #[inline]
311 fn add(self, other: Self) -> Self::Output {
312 Self::Output::new(self.x_ + other.x_, self.y_ + other.y_)
313 }
314}
315
316forward_all_binop!(impl Sub, sub);
317
318// (a, b) - (c, d) == (a - c), (b - d)
319impl<T: Clone + Num> Sub<Vector2<T>> for Vector2<T> {
320 type Output = Self;
321
322 /// The function subtracts the coordinates of two points and returns a new point.
323 ///
324 /// Arguments:
325 ///
326 /// * `other`: The `other` parameter is of the same type as `self` and represents the other value
327 /// that you want to subtract from `self`.
328 ///
329 /// # Example
330 ///
331 /// ```
332 /// use physdes::vector2::Vector2;
333 /// use std::ops::Sub;
334 ///
335 /// assert_eq!(Vector2::new(1, 2).sub(Vector2::new(3, 4)), Vector2::new(-2, -2));
336 /// assert_eq!(Vector2::new(3, 4).sub(Vector2::new(1, 2)), Vector2::new(2, 2));
337 /// ```
338 #[inline]
339 fn sub(self, other: Self) -> Self::Output {
340 Self::Output::new(self.x_ - other.x_, self.y_ - other.y_)
341 }
342}
343
344// Op Assign
345
346mod opassign {
347 use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
348
349 use num_traits::NumAssign;
350
351 use crate::Vector2;
352
353 impl<T: Clone + NumAssign> AddAssign for Vector2<T> {
354 /// The function `add_assign` adds the values of `other.x_` and `other.y_` to `self.x_` and
355 /// `self.y_` respectively.
356 ///
357 /// Arguments:
358 ///
359 /// * `other`: The "other" parameter is of type Self, which means it is a reference to another
360 /// instance of the same struct or class that the method is defined in. In this case, it
361 /// represents another instance of the struct or class that has the same fields or properties as
362 /// self.
363 ///
364 /// # Example
365 ///
366 /// ```
367 /// use physdes::vector2::Vector2;
368 /// use std::ops::AddAssign;
369 ///
370 /// let mut v = Vector2::new(1, 2);
371 /// let v2 = Vector2::new(3, 4);
372 /// v.add_assign(v2);
373 /// assert_eq!(v, Vector2::new(4, 6));
374 /// ```
375 fn add_assign(&mut self, other: Self) {
376 self.x_ += other.x_;
377 self.y_ += other.y_;
378 }
379 }
380
381 impl<T: Clone + NumAssign> SubAssign for Vector2<T> {
382 /// The function subtracts the values of another object from the values of the current object.
383 ///
384 /// Arguments:
385 ///
386 /// * `other`: The parameter "other" is of type Self, which means it is a reference to another
387 /// instance of the same struct or class that the method is defined in. In this case, it is a
388 /// reference to another instance of the struct or class that has the same fields as self (x_
389 /// and y
390 ///
391 /// # Example
392 ///
393 /// ```
394 /// use physdes::vector2::Vector2;
395 /// use std::ops::SubAssign;
396 /// let mut v = Vector2::new(1, 2);
397 /// let v2 = Vector2::new(3, 4);
398 /// v.sub_assign(v2);
399 /// assert_eq!(v, Vector2::new(-2, -2));
400 /// ```
401 fn sub_assign(&mut self, other: Self) {
402 self.x_ -= other.x_;
403 self.y_ -= other.y_;
404 }
405 }
406
407 impl<T: Clone + NumAssign> MulAssign<T> for Vector2<T> {
408 /// The function multiplies the values of self.x_ and self.y_ by the value of other.
409 ///
410 /// Arguments:
411 ///
412 /// * `other`: The parameter `other` is of type `T`, which means it can be any type that
413 /// implements the `Clone` trait.
414 ///
415 /// # Example
416 ///
417 /// ```
418 /// use physdes::vector2::Vector2;
419 /// use std::ops::MulAssign;
420 ///
421 /// let mut v = Vector2::new(1, 2);
422 /// v.mul_assign(3);
423 /// assert_eq!(v, Vector2::new(3, 6));
424 /// ```
425 fn mul_assign(&mut self, other: T) {
426 self.x_ *= other.clone();
427 self.y_ *= other;
428 }
429 }
430
431 impl<T: Clone + NumAssign> DivAssign<T> for Vector2<T> {
432 /// The function divides the values of self.x_ and self.y_ by the value of other.
433 ///
434 /// Arguments:
435 ///
436 /// * `other`: The parameter `other` is of type `T`, which means it can be any type that
437 /// implements the `Clone` trait.
438 ///
439 /// # Example
440 ///
441 /// ```
442 /// use physdes::vector2::Vector2;
443 /// use std::ops::DivAssign;
444 ///
445 /// let mut v = Vector2::new(3, 6);
446 /// v.div_assign(3);
447 /// assert_eq!(v, Vector2::new(1, 2));
448 /// ```
449 fn div_assign(&mut self, other: T) {
450 self.x_ /= other.clone();
451 self.y_ /= other;
452 }
453 }
454
455 macro_rules! forward_op_assign1 {
456 (impl $imp:ident, $method:ident) => {
457 impl<'a, T: Clone + NumAssign> $imp<&'a Vector2<T>> for Vector2<T> {
458 #[inline]
459 fn $method(&mut self, other: &Self) {
460 self.$method(other.clone())
461 }
462 }
463 };
464 }
465
466 macro_rules! forward_op_assign2 {
467 (impl $imp:ident, $method:ident) => {
468 impl<'a, T: Clone + NumAssign> $imp<&'a T> for Vector2<T> {
469 #[inline]
470 fn $method(&mut self, other: &T) {
471 self.$method(other.clone())
472 }
473 }
474 };
475 }
476
477 forward_op_assign1!(impl AddAssign, add_assign);
478 forward_op_assign1!(impl SubAssign, sub_assign);
479 forward_op_assign2!(impl MulAssign, mul_assign);
480 forward_op_assign2!(impl DivAssign, div_assign);
481}
482
483impl<T: Clone + Num + Neg<Output = T>> Neg for Vector2<T> {
484 type Output = Self;
485
486 /// The `neg` function returns a new instance of the same type with the negated values of `x_` and
487 /// `y_`.
488 ///
489 /// # Example
490 ///
491 /// ```
492 /// use physdes::vector2::Vector2;
493 /// use std::ops::Neg;
494 ///
495 /// let v = Vector2::new(1, 2);
496 /// assert_eq!(-v, Vector2::new(-1, -2));
497 /// ```
498 #[inline]
499 fn neg(self) -> Self::Output {
500 Self::Output::new(-self.x_, -self.y_)
501 }
502}
503
504impl<'a, T: Clone + Num + Neg<Output = T>> Neg for &'a Vector2<T> {
505 type Output = Vector2<T>;
506
507 #[inline]
508 fn neg(self) -> Self::Output {
509 -self.clone()
510 }
511}
512
513macro_rules! scalar_arithmetic {
514 (@forward $imp:ident::$method:ident for $($scalar:ident),*) => (
515 impl<'a, T: Clone + Num> $imp<&'a T> for Vector2<T> {
516 type Output = Vector2<T>;
517
518 #[inline]
519 fn $method(self, other: &T) -> Self::Output {
520 self.$method(other.clone())
521 }
522 }
523 impl<'a, T: Clone + Num> $imp<T> for &'a Vector2<T> {
524 type Output = Vector2<T>;
525
526 #[inline]
527 fn $method(self, other: T) -> Self::Output {
528 self.clone().$method(other)
529 }
530 }
531 impl<'a, 'b, T: Clone + Num> $imp<&'a T> for &'b Vector2<T> {
532 type Output = Vector2<T>;
533
534 #[inline]
535 fn $method(self, other: &T) -> Self::Output {
536 self.clone().$method(other.clone())
537 }
538 }
539 $(
540 impl<'a> $imp<&'a Vector2<$scalar>> for $scalar {
541 type Output = Vector2<$scalar>;
542
543 #[inline]
544 fn $method(self, other: &Vector2<$scalar>) -> Vector2<$scalar> {
545 self.$method(other.clone())
546 }
547 }
548 impl<'a> $imp<Vector2<$scalar>> for &'a $scalar {
549 type Output = Vector2<$scalar>;
550
551 #[inline]
552 fn $method(self, other: Vector2<$scalar>) -> Vector2<$scalar> {
553 self.clone().$method(other)
554 }
555 }
556 impl<'a, 'b> $imp<&'a Vector2<$scalar>> for &'b $scalar {
557 type Output = Vector2<$scalar>;
558
559 #[inline]
560 fn $method(self, other: &Vector2<$scalar>) -> Vector2<$scalar> {
561 self.clone().$method(other.clone())
562 }
563 }
564 )*
565 );
566 ($($scalar:ident),*) => (
567 scalar_arithmetic!(@forward Mul::mul for $($scalar),*);
568 // scalar_arithmetic!(@forward Div::div for $($scalar),*);
569 // scalar_arithmetic!(@forward Rem::rem for $($scalar),*);
570
571 $(
572 impl Mul<Vector2<$scalar>> for $scalar {
573 type Output = Vector2<$scalar>;
574
575 #[inline]
576 fn mul(self, other: Vector2<$scalar>) -> Self::Output {
577 Self::Output::new(self * other.x_, self * other.y_)
578 }
579 }
580
581 )*
582 );
583}
584
585impl<T: Clone + Num> Mul<T> for Vector2<T> {
586 type Output = Vector2<T>;
587
588 #[inline]
589 fn mul(self, other: T) -> Self::Output {
590 Self::Output::new(self.x_ * other.clone(), self.y_ * other)
591 }
592}
593
594impl<T: Clone + Num> Div<T> for Vector2<T> {
595 type Output = Self;
596
597 #[inline]
598 fn div(self, other: T) -> Self::Output {
599 Self::Output::new(self.x_ / other.clone(), self.y_ / other)
600 }
601}
602
603impl<T: Clone + Num> Rem<T> for Vector2<T> {
604 type Output = Vector2<T>;
605
606 #[inline]
607 fn rem(self, other: T) -> Self::Output {
608 Self::Output::new(self.x_ % other.clone(), self.y_ % other)
609 }
610}
611
612scalar_arithmetic!(usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64);
613
614// constants
615impl<T: Clone + Num> Zero for Vector2<T> {
616 #[inline]
617 fn zero() -> Self {
618 Self::new(Zero::zero(), Zero::zero())
619 }
620
621 #[inline]
622 fn is_zero(&self) -> bool {
623 self.x_.is_zero() && self.y_.is_zero()
624 }
625
626 #[inline]
627 fn set_zero(&mut self) {
628 self.x_.set_zero();
629 self.y_.set_zero();
630 }
631}
632
633#[cfg(test)]
634fn hash<T: hash::Hash>(x: &T) -> u64 {
635 use std::collections::hash_map::RandomState;
636 use std::hash::{BuildHasher, Hasher};
637 let mut hasher = <RandomState as BuildHasher>::Hasher::new();
638 x.hash(&mut hasher);
639 hasher.finish()
640}
641
642#[cfg(test)]
643mod test {
644 #![allow(non_upper_case_globals)]
645
646 use super::{hash, Vector2};
647 use core::f64;
648 use num_traits::Zero;
649
650 pub const _0_0v: Vector2<f64> = Vector2 { x_: 0.0, y_: 0.0 };
651 pub const _1_0v: Vector2<f64> = Vector2 { x_: 1.0, y_: 0.0 };
652 pub const _1_1v: Vector2<f64> = Vector2 { x_: 1.0, y_: 1.0 };
653 pub const _0_1v: Vector2<f64> = Vector2 { x_: 0.0, y_: 1.0 };
654 pub const _neg1_1v: Vector2<f64> = Vector2 { x_: -1.0, y_: 1.0 };
655 pub const _05_05v: Vector2<f64> = Vector2 { x_: 0.5, y_: 0.5 };
656 pub const all_consts: [Vector2<f64>; 5] = [_0_0v, _1_0v, _1_1v, _neg1_1v, _05_05v];
657 pub const _4_2v: Vector2<f64> = Vector2 { x_: 4.0, y_: 2.0 };
658
659 #[test]
660 fn test_consts() {
661 // check our constants are what Vector2::new creates
662 fn test(c: Vector2<f64>, r: f64, i: f64) {
663 assert_eq!(c, Vector2::new(r, i));
664 }
665 test(_0_0v, 0.0, 0.0);
666 test(_1_0v, 1.0, 0.0);
667 test(_1_1v, 1.0, 1.0);
668 test(_neg1_1v, -1.0, 1.0);
669 test(_05_05v, 0.5, 0.5);
670 assert_eq!(_0_0v, Zero::zero());
671 }
672
673 #[test]
674 fn test_scale_unscale() {
675 assert_eq!(_05_05v.scale(2.0), _1_1v);
676 assert_eq!(_1_1v.unscale(2.0), _05_05v);
677 for &c in all_consts.iter() {
678 assert_eq!(c.scale(2.0).unscale(2.0), c);
679 }
680 }
681
682 #[test]
683 fn test_hash() {
684 let a = Vector2::new(0i32, 0i32);
685 let b = Vector2::new(1i32, 0i32);
686 let c = Vector2::new(0i32, 1i32);
687 assert!(hash(&a) != hash(&b));
688 assert!(hash(&b) != hash(&c));
689 assert!(hash(&c) != hash(&a));
690 }
691}