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
13use pathfinder_simd::default::{F32x2, F32x4, I32x2};
14use std::hash::{Hash, Hasher};
15use 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)]
19pub struct Vector2F(pub F32x2);
20
21impl 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]
161pub fn vec2f(x: f32, y: f32) -> Vector2F {
162 Vector2F::new(x, y)
163}
164
165impl PartialEq for Vector2F {
166 #[inline]
167 fn eq(&self, other: &Vector2F) -> bool {
168 self.0.packed_eq(other.0).all_true()
169 }
170}
171
172impl 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
180impl 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
188impl AddAssign<Vector2F> for Vector2F {
189 #[inline]
190 fn add_assign(&mut self, other: Vector2F) {
191 *self = *self + other
192 }
193}
194
195impl 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
203impl 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
211impl SubAssign<Vector2F> for Vector2F {
212 #[inline]
213 fn sub_assign(&mut self, other: Vector2F) {
214 *self = *self - other
215 }
216}
217
218impl 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
226impl 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
234impl MulAssign<Vector2F> for Vector2F {
235 #[inline]
236 fn mul_assign(&mut self, other: Vector2F) {
237 *self = *self * other
238 }
239}
240
241impl MulAssign<f32> for Vector2F {
242 #[inline]
243 fn mul_assign(&mut self, other: f32) {
244 *self = *self * other
245 }
246}
247
248impl 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
256impl 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
264impl 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.
278pub trait IntoVector2F {
279 fn into_vector_2f(self) -> Vector2F;
280}
281
282impl IntoVector2F for Vector2F {
283 #[inline]
284 fn into_vector_2f(self) -> Vector2F {
285 self
286 }
287}
288
289impl 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)]
298pub struct Vector2I(pub I32x2);
299
300impl 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]
354pub fn vec2i(x: i32, y: i32) -> Vector2I {
355 Vector2I::new(x, y)
356}
357
358impl 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
366impl 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
374impl AddAssign<Vector2I> for Vector2I {
375 #[inline]
376 fn add_assign(&mut self, other: Vector2I) {
377 self.0 += other.0
378 }
379}
380
381impl Neg for Vector2I {
382 type Output = Vector2I;
383 #[inline]
384 fn neg(self) -> Vector2I {
385 Vector2I(-self.0)
386 }
387}
388
389impl 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
397impl 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
405impl 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
413impl 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
421impl PartialEq for Vector2I {
422 #[inline]
423 fn eq(&self, other: &Vector2I) -> bool {
424 self.0.packed_eq(other.0).all_true()
425 }
426}
427
428impl Eq for Vector2I {}
429
430impl 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)]
442pub struct Vector3F(pub F32x4);
443
444impl 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
513impl 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
521impl AddAssign for Vector3F {
522 #[inline]
523 fn add_assign(&mut self, other: Vector3F) {
524 self.0 += other.0
525 }
526}
527
528impl 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
536impl 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)]
546pub struct Vector4F(pub F32x4);
547
548impl 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
639impl 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
647impl AddAssign for Vector4F {
648 #[inline]
649 fn add_assign(&mut self, other: Vector4F) {
650 self.0 += other.0
651 }
652}
653
654impl 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
662impl 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
672impl 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
680impl 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