Skip to main content

box2d_rust/math_functions/
vector.rs

1// Vec2 arithmetic, length/normalize, and closely related helpers.
2// Part of the math_functions module.
3
4use super::*;
5
6/// Compute the rotation between two unit vectors
7pub fn compute_rotation_between_unit_vectors(v1: Vec2, v2: Vec2) -> Rot {
8    debug_assert!(abs_float(1.0 - length(v1)) < 100.0 * f32::EPSILON);
9    debug_assert!(abs_float(1.0 - length(v2)) < 100.0 * f32::EPSILON);
10
11    let rot = Rot {
12        c: dot(v1, v2),
13        s: cross(v1, v2),
14    };
15    normalize_rot(rot)
16}
17
18/// Vector dot product
19pub fn dot(a: Vec2, b: Vec2) -> f32 {
20    a.x * b.x + a.y * b.y
21}
22
23/// Vector cross product. In 2D this yields a scalar.
24pub fn cross(a: Vec2, b: Vec2) -> f32 {
25    a.x * b.y - a.y * b.x
26}
27
28/// Perform the cross product on a vector and a scalar. In 2D this produces a vector.
29pub fn cross_vs(v: Vec2, s: f32) -> Vec2 {
30    Vec2 {
31        x: s * v.y,
32        y: -s * v.x,
33    }
34}
35
36/// Perform the cross product on a scalar and a vector. In 2D this produces a vector.
37pub fn cross_sv(s: f32, v: Vec2) -> Vec2 {
38    Vec2 {
39        x: -s * v.y,
40        y: s * v.x,
41    }
42}
43
44/// Get a left pointing perpendicular vector. Equivalent to cross_sv(1.0, v)
45pub fn left_perp(v: Vec2) -> Vec2 {
46    Vec2 { x: -v.y, y: v.x }
47}
48
49/// Get a right pointing perpendicular vector. Equivalent to cross_vs(v, 1.0)
50pub fn right_perp(v: Vec2) -> Vec2 {
51    Vec2 { x: v.y, y: -v.x }
52}
53
54/// Vector addition
55pub fn add(a: Vec2, b: Vec2) -> Vec2 {
56    Vec2 {
57        x: a.x + b.x,
58        y: a.y + b.y,
59    }
60}
61
62/// Vector subtraction
63pub fn sub(a: Vec2, b: Vec2) -> Vec2 {
64    Vec2 {
65        x: a.x - b.x,
66        y: a.y - b.y,
67    }
68}
69
70/// Vector negation
71pub fn neg(a: Vec2) -> Vec2 {
72    Vec2 { x: -a.x, y: -a.y }
73}
74
75/// Vector linear interpolation
76/// <https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/>
77pub fn lerp(a: Vec2, b: Vec2, t: f32) -> Vec2 {
78    Vec2 {
79        x: (1.0 - t) * a.x + t * b.x,
80        y: (1.0 - t) * a.y + t * b.y,
81    }
82}
83
84/// Component-wise multiplication
85pub fn mul(a: Vec2, b: Vec2) -> Vec2 {
86    Vec2 {
87        x: a.x * b.x,
88        y: a.y * b.y,
89    }
90}
91
92/// Multiply a scalar and vector
93pub fn mul_sv(s: f32, v: Vec2) -> Vec2 {
94    Vec2 {
95        x: s * v.x,
96        y: s * v.y,
97    }
98}
99
100/// a + s * b
101pub fn mul_add(a: Vec2, s: f32, b: Vec2) -> Vec2 {
102    Vec2 {
103        x: a.x + s * b.x,
104        y: a.y + s * b.y,
105    }
106}
107
108/// a - s * b
109pub fn mul_sub(a: Vec2, s: f32, b: Vec2) -> Vec2 {
110    Vec2 {
111        x: a.x - s * b.x,
112        y: a.y - s * b.y,
113    }
114}
115
116/// Component-wise absolute vector
117pub fn abs(a: Vec2) -> Vec2 {
118    Vec2 {
119        x: abs_float(a.x),
120        y: abs_float(a.y),
121    }
122}
123
124/// Component-wise minimum vector
125pub fn min(a: Vec2, b: Vec2) -> Vec2 {
126    Vec2 {
127        x: min_float(a.x, b.x),
128        y: min_float(a.y, b.y),
129    }
130}
131
132/// Component-wise maximum vector
133pub fn max(a: Vec2, b: Vec2) -> Vec2 {
134    Vec2 {
135        x: max_float(a.x, b.x),
136        y: max_float(a.y, b.y),
137    }
138}
139
140/// Component-wise clamp vector v into the range [a, b]
141pub fn clamp(v: Vec2, a: Vec2, b: Vec2) -> Vec2 {
142    Vec2 {
143        x: clamp_float(v.x, a.x, b.x),
144        y: clamp_float(v.y, a.y, b.y),
145    }
146}
147
148/// Get the length of this vector (the norm)
149pub fn length(v: Vec2) -> f32 {
150    (v.x * v.x + v.y * v.y).sqrt()
151}
152
153/// Get the distance between two points
154pub fn distance(a: Vec2, b: Vec2) -> f32 {
155    let dx = b.x - a.x;
156    let dy = b.y - a.y;
157    (dx * dx + dy * dy).sqrt()
158}
159
160/// Convert a vector into a unit vector if possible, otherwise returns the zero vector.
161pub fn normalize(v: Vec2) -> Vec2 {
162    let length = (v.x * v.x + v.y * v.y).sqrt();
163    if length < f32::EPSILON {
164        return Vec2 { x: 0.0, y: 0.0 };
165    }
166
167    let inv_length = 1.0 / length;
168    Vec2 {
169        x: inv_length * v.x,
170        y: inv_length * v.y,
171    }
172}
173
174/// Determines if the provided vector is normalized (norm(a) == 1).
175pub fn is_normalized(a: Vec2) -> bool {
176    let aa = dot(a, a);
177    abs_float(1.0 - aa) < 100.0 * f32::EPSILON
178}
179
180/// Convert a vector into a unit vector if possible, otherwise returns the zero vector. Also
181/// outputs the length.
182pub fn get_length_and_normalize(length: &mut f32, v: Vec2) -> Vec2 {
183    *length = (v.x * v.x + v.y * v.y).sqrt();
184    if *length < f32::EPSILON {
185        return Vec2 { x: 0.0, y: 0.0 };
186    }
187
188    let inv_length = 1.0 / *length;
189    Vec2 {
190        x: inv_length * v.x,
191        y: inv_length * v.y,
192    }
193}
194
195/// Normalize rotation
196pub fn normalize_rot(q: Rot) -> Rot {
197    let mag = (q.s * q.s + q.c * q.c).sqrt();
198    let inv_mag = if mag > 0.0 { 1.0 / mag } else { 0.0 };
199    Rot {
200        c: q.c * inv_mag,
201        s: q.s * inv_mag,
202    }
203}
204
205/// Integrate rotation from angular velocity
206/// * `q1` - initial rotation
207/// * `delta_angle` - the angular displacement in radians
208pub fn integrate_rotation(q1: Rot, delta_angle: f32) -> Rot {
209    // dc/dt = -omega * sin(t)
210    // ds/dt = omega * cos(t)
211    // c2 = c1 - omega * h * s1
212    // s2 = s1 + omega * h * c1
213    let q2 = Rot {
214        c: q1.c - delta_angle * q1.s,
215        s: q1.s + delta_angle * q1.c,
216    };
217    let mag = (q2.s * q2.s + q2.c * q2.c).sqrt();
218    let inv_mag = if mag > 0.0 { 1.0 / mag } else { 0.0 };
219    Rot {
220        c: q2.c * inv_mag,
221        s: q2.s * inv_mag,
222    }
223}
224
225/// Get the length squared of this vector
226pub fn length_squared(v: Vec2) -> f32 {
227    v.x * v.x + v.y * v.y
228}
229
230/// Get the distance squared between points
231pub fn distance_squared(a: Vec2, b: Vec2) -> f32 {
232    let c = Vec2 {
233        x: b.x - a.x,
234        y: b.y - a.y,
235    };
236    c.x * c.x + c.y * c.y
237}