v / vlib / math / vec / vec3.v
412 lines · 354 sloc · 10.39 KB · 7690cbfbaf547f6875dbc20550409b943c5a776a
Raw
1// Copyright(C) 2020-2024 Lars Pontoppidan. All rights reserved.
2// Use of this source code is governed by an MIT license file distributed with this software package
3module vec
4
5import math
6
7// Vec3[T] is a generic struct representing a vector in 3D space.
8pub struct Vec3[T] {
9pub mut:
10 x T
11 y T
12 z T
13}
14
15// vec3[T] returns a `Vec3` of type `T`, with `x`,`y` and `z` fields set.
16pub fn vec3[T](x T, y T, z T) Vec3[T] {
17 return Vec3[T]{
18 x: x
19 y: y
20 z: z
21 }
22}
23
24// zero sets the `x`,`y` and `z` fields to 0.
25pub fn (mut v Vec3[T]) zero() {
26 v.x = 0
27 v.y = 0
28 v.z = 0
29}
30
31// one sets the `x`,`y` and `z` fields to 1.
32pub fn (mut v Vec3[T]) one() {
33 v.x = 1
34 v.y = 1
35 v.z = 1
36}
37
38// copy returns a copy of this vector.
39pub fn (mut v Vec3[T]) copy() Vec3[T] {
40 return Vec3[T]{v.x, v.y, v.z}
41}
42
43// from sets the `x`,`y` and `z` fields from `u`.
44pub fn (mut v Vec3[T]) from(u Vec3[T]) {
45 v.x = u.x
46 v.y = u.y
47 v.z = u.z
48}
49
50// from_vec2 sets the `x` and `y` fields from `u`.
51pub fn (mut v Vec3[T]) from_vec2[U](u Vec2[U]) {
52 v.x = T(u.x)
53 v.y = T(u.y)
54}
55
56// as_vec2 returns a Vec2 with `x` and `y` fields set from `v`.
57pub fn (mut v Vec3[T]) as_vec2[T]() Vec2[T] {
58 return Vec2[T]{v.x, v.y}
59}
60
61// from_vec4 sets the `x`,`y` and `z` fields from `u`.
62pub fn (mut v Vec3[T]) from_vec4[U](u Vec4[U]) {
63 v.x = T(u.x)
64 v.y = T(u.y)
65 v.z = T(u.z)
66}
67
68// as_vec4 returns a Vec4 with `x`,`y` and `z` fields set from `v`, `w` is set to 0.
69pub fn (mut v Vec3[T]) as_vec4[T]() Vec4[T] {
70 return Vec4[T]{v.x, v.y, v.z, 0}
71}
72
73//
74// Addition
75//
76
77// + returns the resulting vector of the addition of `v` and `u`.
78@[inline]
79pub fn (v Vec3[T]) + (u Vec3[T]) Vec3[T] {
80 return Vec3[T]{v.x + u.x, v.y + u.y, v.z + u.z}
81}
82
83// add returns the resulting vector of the addition of `v` + `u`.
84pub fn (v Vec3[T]) add(u Vec3[T]) Vec3[T] {
85 return v + u
86}
87
88// add_vec2 returns the resulting vector of the addition of the
89// `x` and `y` fields of `u`, `z` is left untouched.
90pub fn (v Vec3[T]) add_vec2[U](u Vec2[U]) Vec3[T] {
91 return Vec3[T]{v.x + T(u.x), v.y + T(u.y), v.z}
92}
93
94// add_scalar returns the resulting vector of the addition of the `scalar` value.
95pub fn (v Vec3[T]) add_scalar[U](scalar U) Vec3[T] {
96 return Vec3[T]{v.x + T(scalar), v.y + T(scalar), v.z + T(scalar)}
97}
98
99// plus adds vector `u` to the vector.
100pub fn (mut v Vec3[T]) plus(u Vec3[T]) {
101 v.x += u.x
102 v.y += u.y
103 v.z += u.z
104}
105
106// plus_vec2 adds `x` and `y` fields of vector `u` to the vector, `z` is left untouched.
107pub fn (mut v Vec3[T]) plus_vec2[U](u Vec2[U]) {
108 v.x += T(u.x)
109 v.y += T(u.y)
110}
111
112// plus_scalar adds the scalar `scalar` to the vector.
113pub fn (mut v Vec3[T]) plus_scalar[U](scalar U) {
114 v.x += T(scalar)
115 v.y += T(scalar)
116 v.z += T(scalar)
117}
118
119//
120// Subtraction
121//
122
123// - returns the resulting vector of the subtraction of `v` and `u`.
124@[inline]
125pub fn (v Vec3[T]) - (u Vec3[T]) Vec3[T] {
126 return Vec3[T]{v.x - u.x, v.y - u.y, v.z - u.z}
127}
128
129// sub returns the resulting vector of the subtraction of `v` - `u`.
130pub fn (v Vec3[T]) sub(u Vec3[T]) Vec3[T] {
131 return v - u
132}
133
134// sub_scalar returns the resulting vector of the subtraction of the `scalar` value.
135pub fn (v Vec3[T]) sub_scalar[U](scalar U) Vec3[T] {
136 return Vec3[T]{v.x - T(scalar), v.y - T(scalar), v.z - T(scalar)}
137}
138
139// subtract subtracts vector `u` from the vector.
140pub fn (mut v Vec3[T]) subtract(u Vec3[T]) {
141 v.x -= u.x
142 v.y -= u.y
143 v.z -= u.z
144}
145
146// subtract_scalar subtracts the scalar `scalar` from the vector.
147pub fn (mut v Vec3[T]) subtract_scalar[U](scalar U) {
148 v.x -= T(scalar)
149 v.y -= T(scalar)
150 v.z -= T(scalar)
151}
152
153// * returns the resulting vector of the multiplication of `v` and `u`.
154@[inline]
155pub fn (v Vec3[T]) * (u Vec3[T]) Vec3[T] {
156 return Vec3[T]{v.x * u.x, v.y * u.y, v.z * u.z}
157}
158
159// mul returns the resulting vector of the multiplication of `v` * `u`.
160@[inline]
161pub fn (v Vec3[T]) mul(u Vec3[T]) Vec3[T] {
162 return v * u
163}
164
165// mul_scalar returns the resulting vector of the multiplication of the `scalar` value.
166@[inline]
167pub fn (v Vec3[T]) mul_scalar[U](scalar U) Vec3[T] {
168 return Vec3[T]{v.x * T(scalar), v.y * T(scalar), v.z * T(scalar)}
169}
170
171// multiply multiplies the vector with `u`.
172pub fn (mut v Vec3[T]) multiply(u Vec3[T]) {
173 v.x *= u.x
174 v.y *= u.y
175 v.z *= u.z
176}
177
178// multiply_scalar multiplies the vector with `scalar`.
179pub fn (mut v Vec3[T]) multiply_scalar[U](scalar U) {
180 v.x *= T(scalar)
181 v.y *= T(scalar)
182 v.z *= T(scalar)
183}
184
185//
186// Division
187//
188
189// / returns the resulting vector of the division of `v` and `u`.
190@[inline]
191pub fn (v Vec3[T]) / (u Vec3[T]) Vec3[T] {
192 return Vec3[T]{v.x / u.x, v.y / u.y, v.z / u.z}
193}
194
195// div returns the resulting vector of the division of `v` / `u`.
196pub fn (v Vec3[T]) div(u Vec3[T]) Vec3[T] {
197 return v / u
198}
199
200// div_scalar returns the resulting vector of the division by the `scalar` value.
201pub fn (v Vec3[T]) div_scalar[U](scalar U) Vec3[T] {
202 return Vec3[T]{v.x / T(scalar), v.y / T(scalar), v.z / T(scalar)}
203}
204
205// divide divides the vector by `u`.
206pub fn (mut v Vec3[T]) divide(u Vec3[T]) {
207 v.x /= u.x
208 v.y /= u.y
209 v.z /= u.z
210}
211
212// divide_scalar divides the vector by `scalar`.
213pub fn (mut v Vec3[T]) divide_scalar[U](scalar U) {
214 v.x /= T(scalar)
215 v.y /= T(scalar)
216 v.z /= T(scalar)
217}
218
219//
220// Utility
221//
222
223// magnitude returns the magnitude, also known as the length, of the vector.
224@[inline]
225pub fn (v Vec3[T]) magnitude() T {
226 if v.x == 0 && v.y == 0 && v.z == 0 {
227 return T(0)
228 }
229 return T(math.sqrt((v.x * v.x) + (v.y * v.y) + (v.z * v.z)))
230}
231
232// dot returns the dot product of `v` and `u`.
233@[inline]
234pub fn (v Vec3[T]) dot(u Vec3[T]) T {
235 return T((v.x * u.x) + (v.y * u.y) + (v.z * u.z))
236}
237
238// cross returns the cross product of `v` and `u`.
239@[inline]
240pub fn (v Vec3[T]) cross(u Vec3[T]) Vec3[T] {
241 return Vec3[T]{
242 x: (v.y * u.z) - (v.z * u.y)
243 y: (v.z * u.x) - (v.x * u.z)
244 z: (v.x * u.y) - (v.y * u.x)
245 }
246}
247
248// unit returns the unit vector. unit vectors always have a magnitude, or length, of exactly 1.
249@[inline]
250pub fn (v Vec3[T]) unit() Vec3[T] {
251 m := v.magnitude()
252 invm := 1 / m
253 return Vec3[T]{v.x * invm, v.y * invm, v.z * invm}
254}
255
256// perpendicular returns the `v` projected perpendicular vector to the 'u' vector.
257@[inline]
258pub fn (v Vec3[T]) perpendicular(u Vec3[T]) Vec3[T] {
259 return v - v.project(u)
260}
261
262// project returns the projected vector.
263// The projection of vector `v` onto vector `u` is the orthogonal projection
264// of `v` onto a straight line parallel to `u` that passes through the origin.
265// This is equivalent to the vector projection of `v` onto the unit vector in the direction of `u`.
266// and is given by the formula: proj_v(u) = (v · u / |u|^2) * u
267// where "·" denotes the dot product and |u| is the magnitude of vector `u`.
268// If `v` is a zero vector, the result will also be a zero vector.
269// example:
270// TODO: add examples
271pub fn (v Vec3[T]) project(u Vec3[T]) Vec3[T] {
272 scale := T(v.dot(u) / u.dot(u))
273 return u.mul_scalar(scale)
274}
275
276// eq returns a bool indicating if the two vectors are equal.
277@[inline]
278pub fn (v Vec3[T]) eq(u Vec3[T]) bool {
279 return v.x == u.x && v.y == u.y && v.z == u.z
280}
281
282// eq_epsilon returns a bool indicating if the two vectors are equal within the module `vec_epsilon` const.
283pub fn (v Vec3[T]) eq_epsilon(u Vec3[T]) bool {
284 return v.eq_approx[T, T](u, T(vec_epsilon))
285}
286
287// eq_approx returns whether these vectors are approximately equal within `tolerance`.
288pub fn (v Vec3[T]) eq_approx[T, U](u Vec3[T], tolerance U) bool {
289 diff_x := math.abs(v.x - u.x)
290 diff_y := math.abs(v.y - u.y)
291 diff_z := math.abs(v.z - u.z)
292 if diff_x <= tolerance && diff_y <= tolerance && diff_z <= tolerance {
293 return true
294 }
295
296 max_x := math.max(math.abs(v.x), math.abs(u.x))
297 max_y := math.max(math.abs(v.y), math.abs(u.y))
298 max_z := math.max(math.abs(v.z), math.abs(u.z))
299 if diff_x < max_x * tolerance && diff_y < max_y * tolerance && diff_z < max_z * tolerance {
300 return true
301 }
302 return false
303}
304
305// is_approx_zero returns whether this vector is equal to zero within `tolerance`.
306pub fn (v Vec3[T]) is_approx_zero(tolerance f64) bool {
307 if math.abs(v.x) <= tolerance && math.abs(v.y) <= tolerance && math.abs(v.z) <= tolerance {
308 return true
309 }
310 return false
311}
312
313// eq_scalar returns a bool indicating if the `x`,`y` and `z` fields all equals `scalar`.
314@[inline]
315pub fn (v Vec3[T]) eq_scalar[U](scalar U) bool {
316 return v.x == T(scalar) && v.y == T(scalar) && v.z == T(scalar)
317}
318
319// distance returns the distance to the vector `u`.
320@[inline]
321pub fn (v Vec3[T]) distance(u Vec3[T]) f64 {
322 return math.sqrt((v.x - u.x) * (v.x - u.x) + (v.y - u.y) * (v.y - u.y) +
323 (v.z - u.z) * (v.z - u.z))
324}
325
326// manhattan_distance returns the Manhattan distance to the vector `u`.
327@[inline]
328pub fn (v Vec3[T]) manhattan_distance(u Vec3[T]) f64 {
329 return math.abs(v.x - u.x) + math.abs(v.y - u.y) + math.abs(v.z - u.z)
330}
331
332// angle_between returns the angle in radians to the vector `u`.
333pub fn (v Vec3[T]) angle_between(u Vec3[T]) T {
334 $if T is f64 {
335 return math.acos(((v.x * u.x) + (v.y * u.y) + (v.z * u.z)) / math.sqrt((v.x * v.x) +
336 (v.y * v.y) + (v.z * v.z)) * math.sqrt((u.x * u.x) + (u.y * u.y) + (u.z * u.z)))
337 } $else {
338 return T(math.acos(f64((v.x * u.x) + (v.y * u.y) + (v.z * u.z)) / math.sqrt(
339 f64(v.x * v.x) + (v.y * v.y) + (v.z * v.z)) * math.sqrt(f64(u.x * u.x) + (u.y * u.y) +
340 (u.z * u.z))))
341 }
342}
343
344// abs sets `x`, `y` and `z` field values to their absolute values.
345pub fn (mut v Vec3[T]) abs() {
346 if v.x < 0 {
347 v.x = math.abs(v.x)
348 }
349 if v.y < 0 {
350 v.y = math.abs(v.y)
351 }
352 if v.z < 0 {
353 v.z = math.abs(v.z)
354 }
355}
356
357// clean returns a vector with all fields of this vector set to zero (0) if they fall within `tolerance`.
358pub fn (v Vec3[T]) clean[U](tolerance U) Vec3[T] {
359 mut r := v.copy()
360 if math.abs(v.x) < tolerance {
361 r.x = 0
362 }
363 if math.abs(v.y) < tolerance {
364 r.y = 0
365 }
366 if math.abs(v.z) < tolerance {
367 r.z = 0
368 }
369 return r
370}
371
372// clean_tolerance sets all fields to zero (0) if they fall within `tolerance`.
373pub fn (mut v Vec3[T]) clean_tolerance[U](tolerance U) {
374 if math.abs(v.x) < tolerance {
375 v.x = 0
376 }
377 if math.abs(v.y) < tolerance {
378 v.y = 0
379 }
380 if math.abs(v.z) < tolerance {
381 v.z = 0
382 }
383}
384
385// inv returns the inverse, or reciprocal, of the vector.
386pub fn (v Vec3[T]) inv() Vec3[T] {
387 return Vec3[T]{
388 x: if v.x != 0 { T(1) / v.x } else { 0 }
389 y: if v.y != 0 { T(1) / v.y } else { 0 }
390 z: if v.z != 0 { T(1) / v.z } else { 0 }
391 }
392}
393
394// normalize normalizes the vector.
395@[inline]
396pub fn (v Vec3[T]) normalize() Vec3[T] {
397 m := v.magnitude()
398 if m == 0 {
399 return vec3[T](0, 0, 0)
400 }
401 return Vec3[T]{
402 x: v.x / m
403 y: v.y / m
404 z: v.z / m
405 }
406}
407
408// sum returns a sum of all the fields.
409@[inline]
410pub fn (v Vec3[T]) sum() T {
411 return v.x + v.y + v.z
412}
413