vector_traits/vector2.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2// Copyright (c) 2023, 2025 lacklustr@protonmail.com https://github.com/eadf
3
4// This file is part of vector-traits.
5
6use crate::prelude::*;
7use std::fmt::Debug;
8
9/// A workaround for Rust's limitations where external traits cannot be implemented for external types.
10///
11/// The `Approx` trait provides methods for performing approximate equality comparisons on types.
12/// It serves as a workaround for Rust's limitations, allowing you to implement approximate
13/// equality checks for types not originally designed with this capability.
14///
15/// This trait leverages the `approx` crate and its traits to perform approximate equality
16/// comparisons. The methods in this trait are wrappers around the corresponding methods provided
17/// by the `approx` crate.
18///
19pub trait Approx: HasXY {
20 /// Checks if two instances are nearly equal within a specified tolerance in ULPs (Units in the Last Place).
21 ///
22 /// This method delegates to the `approx::UlpsEq::ulps_eq` method, performing approximate equality checks
23 /// one time per coordinate axis.
24 fn is_ulps_eq(
25 self,
26 other: Self,
27 epsilon: <Self::Scalar as approx::AbsDiffEq>::Epsilon,
28 max_ulps: u32,
29 ) -> bool;
30
31 /// Checks if two instances are nearly equal within a specified absolute difference tolerance.
32 ///
33 /// This method delegates to the `approx::AbsDiffEq::abs_diff_eq` method, performing approximate equality checks
34 /// one time per coordinate axis.
35 fn is_abs_diff_eq(
36 self,
37 other: Self,
38 epsilon: <Self::Scalar as approx::AbsDiffEq>::Epsilon,
39 ) -> bool;
40}
41
42/// A basic two-dimensional vector trait, designed for flexibility in precision.
43///
44/// The `HasXY` trait abstracts over two-dimensional vectors, allowing for easy
45/// transition between different precisions (e.g., `f32` and `f64`) without necessitating
46/// significant codebase modifications. It only provides the most basic vector interface.
47/// It is intended to be used in situations where you need a custom storage type of vectors.
48/// For example an FFI type.
49///
50/// Implementors of this trait can benefit from the ability to switch between different
51/// precision representations seamlessly, making it ideal for applications where varying
52/// precision levels might be desirable at different stages or configurations.
53///
54/// The associated `Scalar` type represents the scalar type (e.g., `f32` or `f64`) used
55/// by the vector.
56///
57pub trait HasXY: Sync + Send + Copy + Debug + Sized {
58 type Scalar: GenericScalar;
59 /// create a new instance of Self, note that this
60 /// creates a 3d vector if the instanced type is a 3d type
61 fn new_2d(x: Self::Scalar, y: Self::Scalar) -> Self;
62 fn x(self) -> Self::Scalar;
63 fn x_mut(&mut self) -> &mut Self::Scalar;
64 fn set_x(&mut self, val: Self::Scalar);
65 fn y(self) -> Self::Scalar;
66 fn y_mut(&mut self) -> &mut Self::Scalar;
67 fn set_y(&mut self, val: Self::Scalar);
68}
69
70/// A generic two-dimensional vector trait.
71///
72/// The `GenericVector2` trait abstracts over two-dimensional vectors, allowing for easy
73/// transition between different precisions (e.g., `f32` and `f64`) without necessitating
74/// significant codebase modifications. It provides the common operations one would expect
75/// for 2D vectors, such as dot products, cross products, and normalization.
76///
77/// Implementors of this trait can benefit from the ability to switch between different
78/// precision representations seamlessly, making it ideal for applications where varying
79/// precision levels might be desirable at different stages or configurations.
80///
81/// The associated `Scalar` type represents the scalar type (e.g., `f32` or `f64`) used
82/// by the vector, and `Vector3` is the corresponding three-dimensional vector type.
83///
84/// Note: The actual trait functionality might vary based on the concrete implementations.
85pub trait GenericVector2:
86 HasXY
87 + Copy
88 + Approx
89 + PartialEq
90 + std::ops::Index<usize, Output = Self::Scalar>
91 + std::ops::IndexMut<usize, Output = Self::Scalar>
92 + std::ops::AddAssign
93 + std::ops::SubAssign
94 + std::ops::Neg<Output = Self>
95 + std::ops::Add<Self, Output = Self>
96 + std::ops::Sub<Self, Output = Self>
97 + std::ops::Mul<Self::Scalar, Output = Self>
98 + std::ops::Div<Self::Scalar, Output = Self>
99 + Into<[Self::Scalar; 2]>
100 + From<[Self::Scalar; 2]>
101{
102 // Associated constants
103 const ZERO: Self;
104 const ONE: Self;
105
106 type Vector3: GenericVector3<Scalar = Self::Scalar, Vector2 = Self>;
107 type Affine: Affine2D<Vector2 = Self>;
108 type Aabb: Aabb2<Vector = Self> + Into<Vec<Self>>;
109
110 fn new(x: Self::Scalar, y: Self::Scalar) -> Self;
111 fn splat(value: Self::Scalar) -> Self;
112 fn to_3d(self, z: Self::Scalar) -> Self::Vector3;
113 fn magnitude(self) -> Self::Scalar;
114 fn magnitude_sq(self) -> Self::Scalar;
115 fn dot(self, other: Self) -> Self::Scalar;
116 fn perp_dot(self, rhs: Self) -> Self::Scalar;
117 fn distance(self, rhs: Self) -> Self::Scalar;
118 fn distance_sq(self, rhs: Self) -> Self::Scalar;
119 fn normalize(self) -> Self;
120 fn try_normalize(self, epsilon: Self::Scalar) -> Option<Self>;
121 fn min(self, rhs: Self) -> Self;
122 fn max(self, rhs: Self) -> Self;
123 /// Clamps the vector's components to be within the range defined by `min` and `max`.
124 ///
125 /// # Note
126 /// This implementation does **not** follow `nalgebra`'s convention for `clamp`.
127 /// In `nalgebra`, `clamp` is symmetric around zero.
128 /// In this implementation, `clamp` ensures that `self` is bounded by `min` and `max`
129 /// in a non-symmetric way: `self.min(max).max(min)`.
130 fn clamp(self, min: Self, max: Self) -> Self;
131 /// returns false on all inf or NaN values
132 fn is_finite(self) -> bool;
133}