Skip to main content

kas_core/geom/
vector.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! Vector types
7//!
8//! For drawing operations, all dimensions use the `f32` type.
9
10use crate::cast::*;
11use crate::dir::Directional;
12use crate::geom::{Coord, Offset, Rect, Size};
13use std::cmp::{Ordering, PartialOrd};
14use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
15
16/// Axis-aligned 2D cuboid, specified via two corners `a` and `b`
17///
18/// Typically it is expected that `a <= b`, although this is not required.
19#[repr(C)]
20#[derive(Clone, Copy, Debug, Default, PartialEq)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub struct Quad {
23    pub a: Vec2,
24    pub b: Vec2,
25}
26
27impl Quad {
28    /// Zero
29    pub const ZERO: Quad = Quad::from_coords(Vec2::ZERO, Vec2::ZERO);
30
31    /// Negative infinity to positive infinity (everything)
32    pub const INFINITY: Quad = Quad::from_coords(Vec2::NEG_INFINITY, Vec2::INFINITY);
33
34    /// Not a Number (NaN)
35    pub const NAN: Quad = Quad::from_coords(Vec2::NAN, Vec2::NAN);
36
37    /// Construct with two coords
38    #[inline]
39    pub const fn from_coords(a: Vec2, b: Vec2) -> Self {
40        Quad { a, b }
41    }
42
43    /// Construct with position and size
44    #[inline]
45    pub fn from_pos_and_size(pos: Vec2, size: Vec2) -> Self {
46        Quad {
47            a: pos,
48            b: pos + size,
49        }
50    }
51
52    /// Construct with center and radius
53    #[inline]
54    pub fn from_center(pos: Vec2, r: f32) -> Self {
55        let v = Vec2::splat(r);
56        Quad {
57            a: pos - v,
58            b: pos + v,
59        }
60    }
61
62    /// Get the size
63    #[inline]
64    pub fn size(&self) -> Vec2 {
65        self.b - self.a
66    }
67
68    /// Get the center
69    #[inline]
70    pub fn center(&self) -> Vec2 {
71        (self.a + self.b) * 0.5
72    }
73
74    /// Swizzle coordinates: x from first, y from second point
75    #[inline]
76    pub fn ab(&self) -> Vec2 {
77        Vec2(self.a.0, self.b.1)
78    }
79
80    /// Swizzle coordinates: x from second, y from first point
81    #[inline]
82    pub fn ba(&self) -> Vec2 {
83        Vec2(self.b.0, self.a.1)
84    }
85
86    /// Shrink self in all directions by the given `value`
87    #[inline]
88    #[must_use = "method does not modify self but returns a new value"]
89    pub fn shrink(&self, value: f32) -> Quad {
90        let a = self.a + value;
91        let b = self.b - value;
92        Quad { a, b }
93    }
94
95    /// Grow self in all directions by the given `value`
96    #[inline]
97    #[must_use = "method does not modify self but returns a new value"]
98    pub fn grow(&self, value: f32) -> Quad {
99        let a = self.a - value;
100        let b = self.b + value;
101        Quad { a, b }
102    }
103
104    /// Shrink self in all directions by the given `value`
105    #[inline]
106    #[must_use = "method does not modify self but returns a new value"]
107    pub fn shrink_vec(&self, value: Vec2) -> Quad {
108        let a = self.a + value;
109        let b = self.b - value;
110        Quad { a, b }
111    }
112
113    /// Calculate the intersection of two quads
114    pub fn intersection(&self, rhs: &Quad) -> Option<Quad> {
115        let a = Vec2(self.a.0.max(rhs.a.0), self.a.1.max(rhs.a.1));
116        let b = Vec2(self.b.0.min(rhs.b.0), self.b.1.min(rhs.b.1));
117        if a <= b { Some(Quad::from_coords(a, b)) } else { None }
118    }
119}
120
121impl AddAssign<Vec2> for Quad {
122    #[inline]
123    fn add_assign(&mut self, rhs: Vec2) {
124        self.a += rhs;
125        self.b += rhs;
126    }
127}
128
129impl SubAssign<Vec2> for Quad {
130    #[inline]
131    fn sub_assign(&mut self, rhs: Vec2) {
132        self.a -= rhs;
133        self.b -= rhs;
134    }
135}
136
137impl Add<Vec2> for Quad {
138    type Output = Quad;
139    #[inline]
140    fn add(mut self, rhs: Vec2) -> Self::Output {
141        self += rhs;
142        self
143    }
144}
145
146impl Sub<Vec2> for Quad {
147    type Output = Quad;
148    #[inline]
149    fn sub(mut self, rhs: Vec2) -> Self::Output {
150        self -= rhs;
151        self
152    }
153}
154
155impl Conv<Rect> for Quad {
156    #[inline]
157    fn try_conv(rect: Rect) -> Result<Self> {
158        let a = Vec2::try_conv(rect.pos)?;
159        let b = a + Vec2::try_conv(rect.size)?;
160        Ok(Quad { a, b })
161    }
162}
163
164/// 2D vector
165///
166/// Usually used as either a coordinate or a difference of coordinates, but
167/// may have some other uses.
168///
169/// `Vec2` implements [`PartialOrd`] such that the comparison must be true of
170/// all components: for example `a < b == a.0 < b.0 && a.1 < b.1`.
171/// If `c == Vec2(0, 1)` and `d == Vec2(1, 0)` then
172/// `c != d && !(c < d) && !(c > d)`. `Vec2` does not implement [`Ord`].
173#[repr(C)]
174#[derive(Clone, Copy, Debug, Default, PartialEq)]
175#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
176pub struct Vec2(pub f32, pub f32);
177
178/// 2D vector (double precision)
179///
180/// Usually used as either a coordinate or a difference of coordinates, but
181/// may have some other uses.
182///
183/// `DVec2` implements [`PartialOrd`] such that the comparison must be true of
184/// all components: for example `a < b == a.0 < b.0 && a.1 < b.1`.
185/// If `c == DVec2(0, 1)` and `d == DVec2(1, 0)` then
186/// `c != d && !(c < d) && !(c > d)`. `DVec2` does not implement [`Ord`].
187#[repr(C)]
188#[derive(Clone, Copy, Debug, Default, PartialEq)]
189#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
190pub struct DVec2(pub f64, pub f64);
191
192macro_rules! impl_vec2 {
193    ($T:ident, $f:ty) => {
194        impl $T {
195            /// Zero
196            pub const ZERO: $T = $T::splat(0.0);
197
198            /// One
199            pub const ONE: $T = $T::splat(1.0);
200
201            /// Negative infinity
202            pub const NEG_INFINITY: $T = $T::splat(<$f>::NEG_INFINITY);
203
204            /// Positive infinity
205            pub const INFINITY: $T = $T::splat(<$f>::INFINITY);
206
207            /// Not a Number (NaN)
208            pub const NAN: $T = $T::splat(<$f>::NAN);
209
210            /// Constructs a new instance with each element initialized to `value`.
211            #[inline]
212            pub const fn splat(value: $f) -> Self {
213                $T(value, value)
214            }
215
216            /// Take the minimum component
217            #[inline]
218            pub fn min_comp(self) -> $f {
219                self.0.min(self.1)
220            }
221
222            /// Take the maximum component
223            #[inline]
224            pub fn max_comp(self) -> $f {
225                self.0.max(self.1)
226            }
227
228            /// Return the minimum, componentwise
229            #[inline]
230            #[must_use = "method does not modify self but returns a new value"]
231            pub fn min(self, other: Self) -> Self {
232                $T(self.0.min(other.0), self.1.min(other.1))
233            }
234
235            /// Return the maximum, componentwise
236            #[inline]
237            #[must_use = "method does not modify self but returns a new value"]
238            pub fn max(self, other: Self) -> Self {
239                $T(self.0.max(other.0), self.1.max(other.1))
240            }
241
242            /// Restrict a value to a certain interval unless it is NaN
243            ///
244            /// Returns `max` if `self` is greater than `max`, and `min` if
245            /// `self` is less than `min`. Otherwise this returns `self`.
246            ///
247            /// Note that this function returns NaN if the initial value was NaN
248            /// as well.
249            ///
250            /// # Panics
251            ///
252            /// Panics if `min > max`, `min` is NaN, or `max` is NaN.
253            #[inline]
254            #[must_use = "method does not modify self but returns a new value"]
255            pub fn clamp(mut self, min: Self, max: Self) -> Self {
256                assert!(min <= max);
257                if self < min {
258                    self = min;
259                }
260                if self > max {
261                    self = max;
262                }
263                self
264            }
265
266            /// Take the absolute value of each component
267            #[inline]
268            #[must_use = "method does not modify self but returns a new value"]
269            pub fn abs(self) -> Self {
270                $T(self.0.abs(), self.1.abs())
271            }
272
273            /// Take the floor of each component
274            #[inline]
275            #[must_use = "method does not modify self but returns a new value"]
276            pub fn floor(self) -> Self {
277                $T(self.0.floor(), self.1.floor())
278            }
279
280            /// Take the ceiling of each component
281            #[inline]
282            #[must_use = "method does not modify self but returns a new value"]
283            pub fn ceil(self) -> Self {
284                $T(self.0.ceil(), self.1.ceil())
285            }
286
287            /// Round each component to the nearest integer
288            #[inline]
289            #[must_use = "method does not modify self but returns a new value"]
290            pub fn round(self) -> Self {
291                $T(self.0.round(), self.1.round())
292            }
293
294            /// Take the trunc of each component
295            #[inline]
296            #[must_use = "method does not modify self but returns a new value"]
297            pub fn trunc(self) -> Self {
298                $T(self.0.trunc(), self.1.trunc())
299            }
300
301            /// Take the fract of each component
302            #[inline]
303            #[must_use = "method does not modify self but returns a new value"]
304            pub fn fract(self) -> Self {
305                $T(self.0.fract(), self.1.fract())
306            }
307
308            /// For each component, return `±1` with the same sign as `self`.
309            #[inline]
310            #[must_use = "method does not modify self but returns a new value"]
311            pub fn sign(self) -> Self {
312                let one: $f = 1.0;
313                $T(one.copysign(self.0), one.copysign(self.1))
314            }
315            /// Multiply two vectors as if they are complex numbers
316            #[inline]
317            #[must_use = "method does not modify self but returns a new value"]
318            pub fn complex_mul(self, rhs: Self) -> Self {
319                $T(
320                    self.0 * rhs.0 - self.1 * rhs.1,
321                    self.0 * rhs.1 + self.1 * rhs.0,
322                )
323            }
324
325            /// Divide by a second vector as if they are complex numbers
326            #[inline]
327            #[must_use = "method does not modify self but returns a new value"]
328            pub fn complex_div(self, rhs: Self) -> Self {
329                self.complex_mul(rhs.complex_inv())
330            }
331
332            /// Take the complex reciprocal
333            ///
334            /// If both components are zero then the result will not be finite.
335            #[inline]
336            #[must_use = "method does not modify self but returns a new value"]
337            pub fn complex_inv(self) -> Self {
338                let ssi = 1.0 / self.sum_square();
339                $T(self.0 * ssi, -self.1 * ssi)
340            }
341
342            /// Return the sum of the terms
343            #[inline]
344            pub fn sum(self) -> $f {
345                self.0 + self.1
346            }
347
348            /// Return the sum of the square of the terms
349            #[inline]
350            pub fn sum_square(self) -> $f {
351                self.0 * self.0 + self.1 * self.1
352            }
353
354            /// Return the L1 norm: (rectilinear / taxicab) distance
355            #[inline]
356            pub fn distance_l1(self) -> $f {
357                self.0.abs() + self.1.abs()
358            }
359
360            /// Return the L2 norm: (Euclidean) distance
361            #[inline]
362            pub fn distance_l2(self) -> $f {
363                self.sum_square().sqrt()
364            }
365
366            /// Return the L-inf norm: max absolute value of components
367            #[inline]
368            pub fn distance_l_inf(self) -> $f {
369                self.0.abs().max(self.1.abs())
370            }
371
372            /// Extract one component, based on a direction
373            ///
374            /// This merely extracts the horizontal or vertical component.
375            /// It never negates it, even if the axis is reversed.
376            #[inline]
377            pub fn extract<D: Directional>(self, dir: D) -> $f {
378                match dir.is_vertical() {
379                    false => self.0,
380                    true => self.1,
381                }
382            }
383
384            /// Returns `true` if all components are neither infinite nor NaN
385            #[inline]
386            pub fn is_finite(self) -> bool {
387                self.0.is_finite() && self.1.is_finite()
388            }
389
390            /// Returns `true` if no components are zero, infinite, submormal or NaN
391            #[inline]
392            pub fn is_normal(self) -> bool {
393                self.0.is_normal() && self.1.is_normal()
394            }
395        }
396
397        impl Neg for $T {
398            type Output = $T;
399            #[inline]
400            fn neg(self) -> Self::Output {
401                $T(-self.0, -self.1)
402            }
403        }
404
405        impl Add<$T> for $T {
406            type Output = $T;
407            #[inline]
408            fn add(self, rhs: $T) -> Self::Output {
409                $T(self.0 + rhs.0, self.1 + rhs.1)
410            }
411        }
412
413        impl Add<$f> for $T {
414            type Output = $T;
415            #[inline]
416            fn add(self, rhs: $f) -> Self::Output {
417                $T(self.0 + rhs, self.1 + rhs)
418            }
419        }
420
421        impl AddAssign<$T> for $T {
422            #[inline]
423            fn add_assign(&mut self, rhs: $T) {
424                self.0 += rhs.0;
425                self.1 += rhs.1;
426            }
427        }
428
429        impl AddAssign<$f> for $T {
430            #[inline]
431            fn add_assign(&mut self, rhs: $f) {
432                self.0 += rhs;
433                self.1 += rhs;
434            }
435        }
436
437        impl Sub<$T> for $T {
438            type Output = $T;
439            #[inline]
440            fn sub(self, rhs: $T) -> Self::Output {
441                $T(self.0 - rhs.0, self.1 - rhs.1)
442            }
443        }
444
445        impl Sub<$f> for $T {
446            type Output = $T;
447            #[inline]
448            fn sub(self, rhs: $f) -> Self::Output {
449                $T(self.0 - rhs, self.1 - rhs)
450            }
451        }
452
453        impl SubAssign<$T> for $T {
454            #[inline]
455            fn sub_assign(&mut self, rhs: $T) {
456                self.0 -= rhs.0;
457                self.1 -= rhs.1;
458            }
459        }
460
461        impl SubAssign<$f> for $T {
462            #[inline]
463            fn sub_assign(&mut self, rhs: $f) {
464                self.0 -= rhs;
465                self.1 -= rhs;
466            }
467        }
468
469        impl Mul<$T> for $T {
470            type Output = $T;
471            #[inline]
472            fn mul(self, rhs: $T) -> Self::Output {
473                $T(self.0 * rhs.0, self.1 * rhs.1)
474            }
475        }
476
477        impl MulAssign<$T> for $T {
478            #[inline]
479            fn mul_assign(&mut self, rhs: $T) {
480                self.0 *= rhs.0;
481                self.1 *= rhs.1;
482            }
483        }
484
485        impl Mul<$f> for $T {
486            type Output = $T;
487            #[inline]
488            fn mul(self, rhs: $f) -> Self::Output {
489                $T(self.0 * rhs, self.1 * rhs)
490            }
491        }
492
493        impl MulAssign<$f> for $T {
494            #[inline]
495            fn mul_assign(&mut self, rhs: $f) {
496                self.0 *= rhs;
497                self.1 *= rhs;
498            }
499        }
500
501        impl Div<$T> for $T {
502            type Output = $T;
503            #[inline]
504            fn div(self, rhs: $T) -> Self::Output {
505                $T(self.0 / rhs.0, self.1 / rhs.1)
506            }
507        }
508
509        impl Div<$f> for $T {
510            type Output = $T;
511            #[inline]
512            fn div(self, rhs: $f) -> Self::Output {
513                $T(self.0 / rhs, self.1 / rhs)
514            }
515        }
516
517        impl DivAssign<$f> for $T {
518            #[inline]
519            fn div_assign(&mut self, rhs: $f) {
520                self.0 /= rhs;
521                self.1 /= rhs;
522            }
523        }
524
525        impl PartialOrd for $T {
526            fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
527                if self == rhs {
528                    Some(Ordering::Equal)
529                } else if self.0 < rhs.0 && self.1 < rhs.1 {
530                    Some(Ordering::Less)
531                } else if self.0 > rhs.0 && self.1 > rhs.1 {
532                    Some(Ordering::Greater)
533                } else {
534                    None
535                }
536            }
537
538            #[inline]
539            fn lt(&self, rhs: &Self) -> bool {
540                self.0 < rhs.0 && self.1 < rhs.1
541            }
542
543            #[inline]
544            fn le(&self, rhs: &Self) -> bool {
545                self.0 <= rhs.0 && self.1 <= rhs.1
546            }
547
548            #[inline]
549            fn ge(&self, rhs: &Self) -> bool {
550                self.0 >= rhs.0 && self.1 >= rhs.1
551            }
552
553            #[inline]
554            fn gt(&self, rhs: &Self) -> bool {
555                self.0 > rhs.0 && self.1 > rhs.1
556            }
557        }
558
559        impl PartialEq<Coord> for $T {
560            fn eq(&self, rhs: &Coord) -> bool {
561                DVec2::from(*self) == DVec2::conv(*rhs)
562            }
563        }
564
565        impl PartialOrd<Coord> for $T {
566            fn partial_cmp(&self, rhs: &Coord) -> Option<Ordering> {
567                DVec2::from(*self).partial_cmp(&DVec2::conv(*rhs))
568            }
569
570            #[inline]
571            fn lt(&self, rhs: &Coord) -> bool {
572                DVec2::from(*self) < DVec2::conv(*rhs)
573            }
574
575            #[inline]
576            fn le(&self, rhs: &Coord) -> bool {
577                DVec2::from(*self) <= DVec2::conv(*rhs)
578            }
579
580            #[inline]
581            fn ge(&self, rhs: &Coord) -> bool {
582                DVec2::from(*self) >= DVec2::conv(*rhs)
583            }
584
585            #[inline]
586            fn gt(&self, rhs: &Coord) -> bool {
587                DVec2::from(*self) > DVec2::conv(*rhs)
588            }
589        }
590
591        impl From<($f, $f)> for $T {
592            #[inline]
593            fn from(arg: ($f, $f)) -> Self {
594                $T(arg.0, arg.1)
595            }
596        }
597        impl Conv<($f, $f)> for $T {
598            #[inline]
599            fn conv(arg: ($f, $f)) -> Self {
600                $T(arg.0, arg.1)
601            }
602            #[inline]
603            fn try_conv(v: ($f, $f)) -> Result<Self> {
604                Ok(Self::conv(v))
605            }
606        }
607
608        impl From<$T> for ($f, $f) {
609            #[inline]
610            fn from(v: $T) -> Self {
611                (v.0, v.1)
612            }
613        }
614        impl Conv<$T> for ($f, $f) {
615            #[inline]
616            fn conv(v: $T) -> Self {
617                (v.0, v.1)
618            }
619            #[inline]
620            fn try_conv(v: $T) -> Result<Self> {
621                Ok(Self::conv(v))
622            }
623        }
624
625        impl From<winit::dpi::PhysicalPosition<$f>> for $T {
626            #[inline]
627            fn from(pos: winit::dpi::PhysicalPosition<$f>) -> Self {
628                $T(pos.x, pos.y)
629            }
630        }
631
632        impl From<winit::dpi::PhysicalSize<$f>> for $T {
633            #[inline]
634            fn from(size: winit::dpi::PhysicalSize<$f>) -> Self {
635                $T(size.width, size.height)
636            }
637        }
638    };
639}
640
641impl From<kas_text::Vec2> for Vec2 {
642    #[inline]
643    fn from(size: kas_text::Vec2) -> Self {
644        Vec2(size.0, size.1)
645    }
646}
647impl Conv<kas_text::Vec2> for Vec2 {
648    #[inline]
649    fn conv(size: kas_text::Vec2) -> Self {
650        Vec2(size.0, size.1)
651    }
652    #[inline]
653    fn try_conv(v: kas_text::Vec2) -> Result<Self> {
654        Ok(Self::conv(v))
655    }
656}
657
658impl From<Vec2> for kas_text::Vec2 {
659    #[inline]
660    fn from(size: Vec2) -> kas_text::Vec2 {
661        kas_text::Vec2(size.0, size.1)
662    }
663}
664impl Conv<Vec2> for kas_text::Vec2 {
665    #[inline]
666    fn conv(size: Vec2) -> kas_text::Vec2 {
667        kas_text::Vec2(size.0, size.1)
668    }
669    #[inline]
670    fn try_conv(v: Vec2) -> Result<Self> {
671        Ok(Self::conv(v))
672    }
673}
674
675impl From<Vec2> for DVec2 {
676    #[inline]
677    fn from(v: Vec2) -> DVec2 {
678        DVec2(v.0.into(), v.1.into())
679    }
680}
681impl Conv<Vec2> for DVec2 {
682    #[inline]
683    fn try_conv(v: Vec2) -> Result<DVec2> {
684        Ok(DVec2(v.0.into(), v.1.into()))
685    }
686}
687impl ConvApprox<DVec2> for Vec2 {
688    fn try_conv_approx(size: DVec2) -> Result<Vec2> {
689        Ok(Vec2(size.0.try_cast_approx()?, size.1.try_cast_approx()?))
690    }
691}
692
693impl_vec2!(Vec2, f32);
694impl_vec2!(DVec2, f64);
695
696macro_rules! impl_conv_vec2 {
697    ($S:ty, $T:ty) => {
698        impl Conv<$S> for $T {
699            #[inline]
700            fn try_conv(arg: $S) -> Result<Self> {
701                Ok(Self(arg.0.try_cast()?, arg.1.try_cast()?))
702            }
703        }
704
705        impl ConvApprox<$T> for $S {
706            #[inline]
707            fn try_conv_approx(arg: $T) -> Result<Self> {
708                Ok(Self(arg.0.try_cast_approx()?, arg.1.try_cast_approx()?))
709            }
710        }
711
712        impl ConvFloat<$T> for $S {
713            #[inline]
714            fn try_conv_trunc(x: $T) -> Result<Self> {
715                Ok(Self(i32::try_conv_trunc(x.0)?, i32::try_conv_trunc(x.1)?))
716            }
717            #[inline]
718            fn try_conv_nearest(x: $T) -> Result<Self> {
719                Ok(Self(
720                    i32::try_conv_nearest(x.0)?,
721                    i32::try_conv_nearest(x.1)?,
722                ))
723            }
724            #[inline]
725            fn try_conv_floor(x: $T) -> Result<Self> {
726                Ok(Self(i32::try_conv_floor(x.0)?, i32::try_conv_floor(x.1)?))
727            }
728            #[inline]
729            fn try_conv_ceil(x: $T) -> Result<Self> {
730                Ok(Self(i32::try_conv_ceil(x.0)?, i32::try_conv_ceil(x.1)?))
731            }
732        }
733    };
734}
735
736impl_conv_vec2!(Coord, Vec2);
737impl_conv_vec2!(Size, Vec2);
738impl_conv_vec2!(Offset, Vec2);
739impl_conv_vec2!(Coord, DVec2);
740impl_conv_vec2!(Size, DVec2);
741impl_conv_vec2!(Offset, DVec2);
742
743/// 3D vector
744///
745/// Usually used for a 2D coordinate with a depth value.
746#[repr(C)]
747#[derive(Clone, Copy, Debug, Default, PartialEq)]
748#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
749pub struct Vec3(pub f32, pub f32, pub f32);
750
751impl Vec3 {
752    /// Construct from a [`Vec2`] and third value
753    #[inline]
754    pub fn from2(v: Vec2, z: f32) -> Self {
755        Vec3(v.0, v.1, z)
756    }
757}