1 | // pathfinder/geometry/src/basic/point.rs |
2 | // |
3 | // Copyright © 2019 The Pathfinder Project Developers. |
4 | // |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
8 | // option. This file may not be copied, modified, or distributed |
9 | // except according to those terms. |
10 | |
11 | //! A SIMD-optimized point type. |
12 | |
13 | use pathfinder_simd::default::{F32x2, F32x4, I32x2}; |
14 | use std::hash::{Hash, Hasher}; |
15 | use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub, SubAssign}; |
16 | |
17 | /// 2D points with 32-bit floating point coordinates. |
18 | #[derive (Clone, Copy, Debug, Default)] |
19 | pub struct Vector2F(pub F32x2); |
20 | |
21 | impl Vector2F { |
22 | #[inline ] |
23 | pub fn new(x: f32, y: f32) -> Vector2F { |
24 | Vector2F(F32x2::new(x, y)) |
25 | } |
26 | |
27 | #[inline ] |
28 | pub fn splat(value: f32) -> Vector2F { |
29 | Vector2F(F32x2::splat(value)) |
30 | } |
31 | |
32 | #[inline ] |
33 | pub fn zero() -> Vector2F { |
34 | Vector2F::default() |
35 | } |
36 | |
37 | #[inline ] |
38 | pub fn to_3d(self) -> Vector3F { |
39 | Vector3F(self.0.to_f32x4().concat_xy_zw(F32x4::new(0.0, 0.0, 0.0, 0.0))) |
40 | } |
41 | |
42 | #[inline ] |
43 | pub fn to_4d(self) -> Vector4F { |
44 | Vector4F(self.0.to_f32x4().concat_xy_zw(F32x4::new(0.0, 0.0, 0.0, 1.0))) |
45 | } |
46 | |
47 | #[inline ] |
48 | pub fn x(self) -> f32 { |
49 | self.0[0] |
50 | } |
51 | |
52 | #[inline ] |
53 | pub fn y(self) -> f32 { |
54 | self.0[1] |
55 | } |
56 | |
57 | #[inline ] |
58 | pub fn set_x(&mut self, x: f32) { |
59 | self.0[0] = x; |
60 | } |
61 | |
62 | #[inline ] |
63 | pub fn set_y(&mut self, y: f32) { |
64 | self.0[1] = y; |
65 | } |
66 | |
67 | #[inline ] |
68 | pub fn min(self, other: Vector2F) -> Vector2F { |
69 | Vector2F(self.0.min(other.0)) |
70 | } |
71 | |
72 | #[inline ] |
73 | pub fn max(self, other: Vector2F) -> Vector2F { |
74 | Vector2F(self.0.max(other.0)) |
75 | } |
76 | |
77 | #[inline ] |
78 | pub fn clamp(self, min_val: Vector2F, max_val: Vector2F) -> Vector2F { |
79 | self.max(min_val).min(max_val) |
80 | } |
81 | |
82 | #[inline ] |
83 | pub fn det(self, other: Vector2F) -> f32 { |
84 | self.x() * other.y() - self.y() * other.x() |
85 | } |
86 | |
87 | #[inline ] |
88 | pub fn dot(self, other: Vector2F) -> f32 { |
89 | let xy = self.0 * other.0; |
90 | xy.x() + xy.y() |
91 | } |
92 | |
93 | #[inline ] |
94 | pub fn floor(self) -> Vector2F { |
95 | Vector2F(self.0.floor()) |
96 | } |
97 | |
98 | #[inline ] |
99 | pub fn ceil(self) -> Vector2F { |
100 | Vector2F(self.0.ceil()) |
101 | } |
102 | |
103 | /// Rounds both coordinates to the nearest integer. |
104 | #[inline ] |
105 | pub fn round(self) -> Vector2F { |
106 | Vector2F(self.0.to_i32x2().to_f32x2()) |
107 | } |
108 | |
109 | /// Treats this point as a vector and calculates its squared length. |
110 | #[inline ] |
111 | pub fn square_length(self) -> f32 { |
112 | let squared = self.0 * self.0; |
113 | squared[0] + squared[1] |
114 | } |
115 | |
116 | /// Treats this point as a vector and calculates its length. |
117 | #[inline ] |
118 | pub fn length(self) -> f32 { |
119 | f32::sqrt(self.square_length()) |
120 | } |
121 | |
122 | /// Treats this point as a vector and normalizes it. |
123 | #[inline ] |
124 | pub fn normalize(self) -> Vector2F { |
125 | self * (1.0 / self.length()) |
126 | } |
127 | |
128 | /// Swaps y and x. |
129 | #[inline ] |
130 | pub fn yx(self) -> Vector2F { |
131 | Vector2F(self.0.yx()) |
132 | } |
133 | |
134 | /// Returns the coefficient when the given vector `a` is projected onto this one. |
135 | /// |
136 | /// That is, if this vector is `v` and this function returns `c`, then `proj_v a = cv`. In |
137 | /// other words, this function computes `(a⋅v) / (v⋅v)`. |
138 | #[inline ] |
139 | pub fn projection_coefficient(self, a: Vector2F) -> f32 { |
140 | a.dot(self) / self.square_length() |
141 | } |
142 | |
143 | #[inline ] |
144 | pub fn is_zero(self) -> bool { |
145 | self == Vector2F::zero() |
146 | } |
147 | |
148 | #[inline ] |
149 | pub fn lerp(self, other: Vector2F, t: f32) -> Vector2F { |
150 | self + (other - self) * t |
151 | } |
152 | |
153 | #[inline ] |
154 | pub fn to_i32(self) -> Vector2I { |
155 | Vector2I(self.0.to_i32x2()) |
156 | } |
157 | } |
158 | |
159 | /// A convenience alias for `Vector2F::new()`. |
160 | #[inline ] |
161 | pub fn vec2f(x: f32, y: f32) -> Vector2F { |
162 | Vector2F::new(x, y) |
163 | } |
164 | |
165 | impl PartialEq for Vector2F { |
166 | #[inline ] |
167 | fn eq(&self, other: &Vector2F) -> bool { |
168 | self.0.packed_eq(other.0).all_true() |
169 | } |
170 | } |
171 | |
172 | impl Add<Vector2F> for Vector2F { |
173 | type Output = Vector2F; |
174 | #[inline ] |
175 | fn add(self, other: Vector2F) -> Vector2F { |
176 | Vector2F(self.0 + other.0) |
177 | } |
178 | } |
179 | |
180 | impl Add<f32> for Vector2F { |
181 | type Output = Vector2F; |
182 | #[inline ] |
183 | fn add(self, other: f32) -> Vector2F { |
184 | self + Vector2F::splat(other) |
185 | } |
186 | } |
187 | |
188 | impl AddAssign<Vector2F> for Vector2F { |
189 | #[inline ] |
190 | fn add_assign(&mut self, other: Vector2F) { |
191 | *self = *self + other |
192 | } |
193 | } |
194 | |
195 | impl Sub<Vector2F> for Vector2F { |
196 | type Output = Vector2F; |
197 | #[inline ] |
198 | fn sub(self, other: Vector2F) -> Vector2F { |
199 | Vector2F(self.0 - other.0) |
200 | } |
201 | } |
202 | |
203 | impl Sub<f32> for Vector2F { |
204 | type Output = Vector2F; |
205 | #[inline ] |
206 | fn sub(self, other: f32) -> Vector2F { |
207 | self - Vector2F::splat(other) |
208 | } |
209 | } |
210 | |
211 | impl SubAssign<Vector2F> for Vector2F { |
212 | #[inline ] |
213 | fn sub_assign(&mut self, other: Vector2F) { |
214 | *self = *self - other |
215 | } |
216 | } |
217 | |
218 | impl Mul<Vector2F> for Vector2F { |
219 | type Output = Vector2F; |
220 | #[inline ] |
221 | fn mul(self, other: Vector2F) -> Vector2F { |
222 | Vector2F(self.0 * other.0) |
223 | } |
224 | } |
225 | |
226 | impl Mul<f32> for Vector2F { |
227 | type Output = Vector2F; |
228 | #[inline ] |
229 | fn mul(self, other: f32) -> Vector2F { |
230 | self * Vector2F::splat(other) |
231 | } |
232 | } |
233 | |
234 | impl MulAssign<Vector2F> for Vector2F { |
235 | #[inline ] |
236 | fn mul_assign(&mut self, other: Vector2F) { |
237 | *self = *self * other |
238 | } |
239 | } |
240 | |
241 | impl MulAssign<f32> for Vector2F { |
242 | #[inline ] |
243 | fn mul_assign(&mut self, other: f32) { |
244 | *self = *self * other |
245 | } |
246 | } |
247 | |
248 | impl Div<Vector2F> for Vector2F { |
249 | type Output = Vector2F; |
250 | #[inline ] |
251 | fn div(self, other: Vector2F) -> Vector2F { |
252 | Vector2F(self.0 / other.0) |
253 | } |
254 | } |
255 | |
256 | impl Div<f32> for Vector2F { |
257 | type Output = Vector2F; |
258 | #[inline ] |
259 | fn div(self, other: f32) -> Vector2F { |
260 | self / Vector2F::splat(other) |
261 | } |
262 | } |
263 | |
264 | impl Neg for Vector2F { |
265 | type Output = Vector2F; |
266 | #[inline ] |
267 | fn neg(self) -> Vector2F { |
268 | Vector2F(-self.0) |
269 | } |
270 | } |
271 | |
272 | /// Either a scalar or a `Vector2F`. |
273 | /// |
274 | /// Scalars will be automatically splatted (i.e. `x` becomes `vec2f(x, x)`). |
275 | /// |
276 | /// Be judicious with the use of this trait. Only use it if it will aid readability without the |
277 | /// potential to introduce bugs. |
278 | pub trait IntoVector2F { |
279 | fn into_vector_2f(self) -> Vector2F; |
280 | } |
281 | |
282 | impl IntoVector2F for Vector2F { |
283 | #[inline ] |
284 | fn into_vector_2f(self) -> Vector2F { |
285 | self |
286 | } |
287 | } |
288 | |
289 | impl IntoVector2F for f32 { |
290 | #[inline ] |
291 | fn into_vector_2f(self) -> Vector2F { |
292 | Vector2F::splat(self) |
293 | } |
294 | } |
295 | |
296 | /// 2D points with 32-bit signed integer coordinates. |
297 | #[derive (Clone, Copy, Debug, Default)] |
298 | pub struct Vector2I(pub I32x2); |
299 | |
300 | impl Vector2I { |
301 | #[inline ] |
302 | pub fn new(x: i32, y: i32) -> Vector2I { |
303 | Vector2I(I32x2::new(x, y)) |
304 | } |
305 | |
306 | #[inline ] |
307 | pub fn splat(value: i32) -> Vector2I { |
308 | Vector2I(I32x2::splat(value)) |
309 | } |
310 | |
311 | #[inline ] |
312 | pub fn zero() -> Vector2I { |
313 | Vector2I::default() |
314 | } |
315 | |
316 | #[inline ] |
317 | pub fn x(self) -> i32 { |
318 | self.0[0] |
319 | } |
320 | |
321 | #[inline ] |
322 | pub fn y(self) -> i32 { |
323 | self.0[1] |
324 | } |
325 | |
326 | #[inline ] |
327 | pub fn set_x(&mut self, x: i32) { |
328 | self.0[0] = x; |
329 | } |
330 | |
331 | #[inline ] |
332 | pub fn set_y(&mut self, y: i32) { |
333 | self.0[1] = y; |
334 | } |
335 | |
336 | #[inline ] |
337 | pub fn min(self, other: Vector2I) -> Vector2I { |
338 | Vector2I(self.0.min(other.0)) |
339 | } |
340 | |
341 | #[inline ] |
342 | pub fn max(self, other: Vector2I) -> Vector2I { |
343 | Vector2I(self.0.max(other.0)) |
344 | } |
345 | |
346 | #[inline ] |
347 | pub fn to_f32(self) -> Vector2F { |
348 | Vector2F(self.0.to_f32x2()) |
349 | } |
350 | } |
351 | |
352 | /// A convenience alias for `Vector2I::new()`. |
353 | #[inline ] |
354 | pub fn vec2i(x: i32, y: i32) -> Vector2I { |
355 | Vector2I::new(x, y) |
356 | } |
357 | |
358 | impl Add<Vector2I> for Vector2I { |
359 | type Output = Vector2I; |
360 | #[inline ] |
361 | fn add(self, other: Vector2I) -> Vector2I { |
362 | Vector2I(self.0 + other.0) |
363 | } |
364 | } |
365 | |
366 | impl Add<i32> for Vector2I { |
367 | type Output = Vector2I; |
368 | #[inline ] |
369 | fn add(self, other: i32) -> Vector2I { |
370 | self + Vector2I::splat(other) |
371 | } |
372 | } |
373 | |
374 | impl AddAssign<Vector2I> for Vector2I { |
375 | #[inline ] |
376 | fn add_assign(&mut self, other: Vector2I) { |
377 | self.0 += other.0 |
378 | } |
379 | } |
380 | |
381 | impl Neg for Vector2I { |
382 | type Output = Vector2I; |
383 | #[inline ] |
384 | fn neg(self) -> Vector2I { |
385 | Vector2I(-self.0) |
386 | } |
387 | } |
388 | |
389 | impl Sub<Vector2I> for Vector2I { |
390 | type Output = Vector2I; |
391 | #[inline ] |
392 | fn sub(self, other: Vector2I) -> Vector2I { |
393 | Vector2I(self.0 - other.0) |
394 | } |
395 | } |
396 | |
397 | impl Sub<i32> for Vector2I { |
398 | type Output = Vector2I; |
399 | #[inline ] |
400 | fn sub(self, other: i32) -> Vector2I { |
401 | self - Vector2I::splat(other) |
402 | } |
403 | } |
404 | |
405 | impl Mul<Vector2I> for Vector2I { |
406 | type Output = Vector2I; |
407 | #[inline ] |
408 | fn mul(self, other: Vector2I) -> Vector2I { |
409 | Vector2I(self.0 * other.0) |
410 | } |
411 | } |
412 | |
413 | impl Mul<i32> for Vector2I { |
414 | type Output = Vector2I; |
415 | #[inline ] |
416 | fn mul(self, other: i32) -> Vector2I { |
417 | self * Vector2I::splat(other) |
418 | } |
419 | } |
420 | |
421 | impl PartialEq for Vector2I { |
422 | #[inline ] |
423 | fn eq(&self, other: &Vector2I) -> bool { |
424 | self.0.packed_eq(other.0).all_true() |
425 | } |
426 | } |
427 | |
428 | impl Eq for Vector2I {} |
429 | |
430 | impl Hash for Vector2I { |
431 | #[inline ] |
432 | fn hash<H>(&self, state: &mut H) where H: Hasher { |
433 | self.x().hash(state); |
434 | self.y().hash(state); |
435 | } |
436 | } |
437 | |
438 | /// 3D points. |
439 | /// |
440 | /// The w value in the SIMD vector is always 0.0. |
441 | #[derive (Clone, Copy, Debug, Default, PartialEq)] |
442 | pub struct Vector3F(pub F32x4); |
443 | |
444 | impl Vector3F { |
445 | #[inline ] |
446 | pub fn new(x: f32, y: f32, z: f32) -> Vector3F { |
447 | Vector3F(F32x4::new(x, y, z, 0.0)) |
448 | } |
449 | |
450 | #[inline ] |
451 | pub fn splat(x: f32) -> Vector3F { |
452 | let mut vector = F32x4::splat(x); |
453 | vector.set_w(0.0); |
454 | Vector3F(vector) |
455 | } |
456 | |
457 | /// Truncates this vector to 2D. |
458 | #[inline ] |
459 | pub fn to_2d(self) -> Vector2F { |
460 | Vector2F(self.0.xy()) |
461 | } |
462 | |
463 | /// Converts this vector to an equivalent 3D homogeneous one with a w component of 1.0. |
464 | #[inline ] |
465 | pub fn to_4d(self) -> Vector4F { |
466 | let mut vector = self.0; |
467 | vector.set_w(1.0); |
468 | Vector4F(vector) |
469 | } |
470 | |
471 | #[inline ] |
472 | pub fn cross(self, other: Vector3F) -> Vector3F { |
473 | Vector3F(self.0.yzxw() * other.0.zxyw() - self.0.zxyw() * other.0.yzxw()) |
474 | } |
475 | |
476 | #[inline ] |
477 | pub fn square_length(self) -> f32 { |
478 | let squared = self.0 * self.0; |
479 | squared[0] + squared[1] + squared[2] |
480 | } |
481 | |
482 | #[inline ] |
483 | pub fn length(self) -> f32 { |
484 | f32::sqrt(self.square_length()) |
485 | } |
486 | |
487 | #[inline ] |
488 | pub fn normalize(self) -> Vector3F { |
489 | Vector3F(self.0 * F32x4::splat(1.0 / self.length())) |
490 | } |
491 | |
492 | #[inline ] |
493 | pub fn x(self) -> f32 { |
494 | self.0[0] |
495 | } |
496 | |
497 | #[inline ] |
498 | pub fn y(self) -> f32 { |
499 | self.0[1] |
500 | } |
501 | |
502 | #[inline ] |
503 | pub fn z(self) -> f32 { |
504 | self.0[2] |
505 | } |
506 | |
507 | #[inline ] |
508 | pub fn scale(self, factor: f32) -> Vector3F { |
509 | Vector3F(self.0 * F32x4::splat(factor)) |
510 | } |
511 | } |
512 | |
513 | impl Add<Vector3F> for Vector3F { |
514 | type Output = Vector3F; |
515 | #[inline ] |
516 | fn add(self, other: Vector3F) -> Vector3F { |
517 | Vector3F(self.0 + other.0) |
518 | } |
519 | } |
520 | |
521 | impl AddAssign for Vector3F { |
522 | #[inline ] |
523 | fn add_assign(&mut self, other: Vector3F) { |
524 | self.0 += other.0 |
525 | } |
526 | } |
527 | |
528 | impl Neg for Vector3F { |
529 | type Output = Vector3F; |
530 | #[inline ] |
531 | fn neg(self) -> Vector3F { |
532 | Vector3F(self.0 * F32x4::new(a:-1.0, b:-1.0, c:-1.0, d:0.0)) |
533 | } |
534 | } |
535 | |
536 | impl Sub<Vector3F> for Vector3F { |
537 | type Output = Vector3F; |
538 | #[inline ] |
539 | fn sub(self, other: Vector3F) -> Vector3F { |
540 | Vector3F(self.0 - other.0) |
541 | } |
542 | } |
543 | |
544 | /// 3D homogeneous points. |
545 | #[derive (Clone, Copy, Debug, PartialEq)] |
546 | pub struct Vector4F(pub F32x4); |
547 | |
548 | impl Vector4F { |
549 | #[inline ] |
550 | pub fn new(x: f32, y: f32, z: f32, w: f32) -> Vector4F { |
551 | Vector4F(F32x4::new(x, y, z, w)) |
552 | } |
553 | |
554 | #[inline ] |
555 | pub fn splat(value: f32) -> Vector4F { |
556 | Vector4F(F32x4::splat(value)) |
557 | } |
558 | |
559 | #[inline ] |
560 | pub fn to_2d(self) -> Vector2F { |
561 | self.to_3d().to_2d() |
562 | } |
563 | |
564 | /// Performs perspective division to convert this vector to 3D. |
565 | #[inline ] |
566 | pub fn to_3d(self) -> Vector3F { |
567 | let mut vector = self.0 * F32x4::splat(1.0 / self.w()); |
568 | vector.set_w(0.0); |
569 | Vector3F(vector) |
570 | } |
571 | |
572 | #[inline ] |
573 | pub fn x(self) -> f32 { |
574 | self.0[0] |
575 | } |
576 | |
577 | #[inline ] |
578 | pub fn y(self) -> f32 { |
579 | self.0[1] |
580 | } |
581 | |
582 | #[inline ] |
583 | pub fn z(self) -> f32 { |
584 | self.0[2] |
585 | } |
586 | |
587 | #[inline ] |
588 | pub fn w(self) -> f32 { |
589 | self.0[3] |
590 | } |
591 | |
592 | #[inline ] |
593 | pub fn scale(self, x: f32) -> Vector4F { |
594 | let mut factors = F32x4::splat(x); |
595 | factors[3] = 1.0; |
596 | Vector4F(self.0 * factors) |
597 | } |
598 | |
599 | #[inline ] |
600 | pub fn set_x(&mut self, x: f32) { |
601 | self.0[0] = x |
602 | } |
603 | |
604 | #[inline ] |
605 | pub fn set_y(&mut self, y: f32) { |
606 | self.0[1] = y |
607 | } |
608 | |
609 | #[inline ] |
610 | pub fn set_z(&mut self, z: f32) { |
611 | self.0[2] = z |
612 | } |
613 | |
614 | #[inline ] |
615 | pub fn set_w(&mut self, w: f32) { |
616 | self.0[3] = w |
617 | } |
618 | |
619 | #[inline ] |
620 | pub fn approx_eq(self, other: Vector4F, epsilon: f32) -> bool { |
621 | self.0.approx_eq(other.0, epsilon) |
622 | } |
623 | |
624 | /// Checks to see whether this *homogeneous* coordinate equals zero. |
625 | /// |
626 | /// Note that since this treats the coordinate as a homogeneous coordinate, the `w` is ignored. |
627 | // TODO(pcwalton): Optimize with SIMD. |
628 | #[inline ] |
629 | pub fn is_zero(self) -> bool { |
630 | self.x() == 0.0 && self.y() == 0.0 && self.z() == 0.0 |
631 | } |
632 | |
633 | #[inline ] |
634 | pub fn lerp(self, other: Vector4F, t: f32) -> Vector4F { |
635 | Vector4F(self.0 + (other.0 - self.0) * F32x4::splat(t)) |
636 | } |
637 | } |
638 | |
639 | impl Add<Vector4F> for Vector4F { |
640 | type Output = Vector4F; |
641 | #[inline ] |
642 | fn add(self, other: Vector4F) -> Vector4F { |
643 | Vector4F(self.0 + other.0) |
644 | } |
645 | } |
646 | |
647 | impl AddAssign for Vector4F { |
648 | #[inline ] |
649 | fn add_assign(&mut self, other: Vector4F) { |
650 | self.0 += other.0 |
651 | } |
652 | } |
653 | |
654 | impl Mul<Vector4F> for Vector4F { |
655 | type Output = Vector4F; |
656 | #[inline ] |
657 | fn mul(self, other: Vector4F) -> Vector4F { |
658 | Vector4F(self.0 * other.0) |
659 | } |
660 | } |
661 | |
662 | impl Neg for Vector4F { |
663 | type Output = Vector4F; |
664 | /// NB: This does not negate w, because that is rarely what you what for homogeneous |
665 | /// coordinates. |
666 | #[inline ] |
667 | fn neg(self) -> Vector4F { |
668 | Vector4F(self.0 * F32x4::new(a:-1.0, b:-1.0, c:-1.0, d:1.0)) |
669 | } |
670 | } |
671 | |
672 | impl Sub<Vector4F> for Vector4F { |
673 | type Output = Vector4F; |
674 | #[inline ] |
675 | fn sub(self, other: Vector4F) -> Vector4F { |
676 | Vector4F(self.0 - other.0) |
677 | } |
678 | } |
679 | |
680 | impl Default for Vector4F { |
681 | #[inline ] |
682 | fn default() -> Vector4F { |
683 | let mut point: F32x4 = F32x4::default(); |
684 | point.set_w(1.0); |
685 | Vector4F(point) |
686 | } |
687 | } |
688 | |