accesskit/
geometry.rs

1// Copyright 2023 The AccessKit Authors. All rights reserved.
2// Licensed under the Apache License, Version 2.0 (found in
3// the LICENSE-APACHE file) or the MIT license (found in
4// the LICENSE-MIT file), at your option.
5
6// Derived from kurbo.
7// Copyright 2018 The kurbo Authors.
8// Licensed under the Apache License, Version 2.0 (found in
9// the LICENSE-APACHE file) or the MIT license (found in
10// the LICENSE-MIT file), at your option.
11
12use core::{
13    fmt,
14    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
15};
16
17/// A 2D affine transform. Derived from [kurbo](https://github.com/linebender/kurbo).
18#[derive(Clone, Copy, Debug, PartialEq)]
19#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21#[repr(C)]
22pub struct Affine([f64; 6]);
23
24impl Affine {
25    /// The identity transform.
26    pub const IDENTITY: Affine = Affine::scale(1.0);
27
28    /// A transform that is flipped on the y-axis. Useful for converting between
29    /// y-up and y-down spaces.
30    pub const FLIP_Y: Affine = Affine::new([1.0, 0., 0., -1.0, 0., 0.]);
31
32    /// A transform that is flipped on the x-axis.
33    pub const FLIP_X: Affine = Affine::new([-1.0, 0., 0., 1.0, 0., 0.]);
34
35    /// Construct an affine transform from coefficients.
36    ///
37    /// If the coefficients are `(a, b, c, d, e, f)`, then the resulting
38    /// transformation represents this augmented matrix:
39    ///
40    /// ```text
41    /// | a c e |
42    /// | b d f |
43    /// | 0 0 1 |
44    /// ```
45    ///
46    /// Note that this convention is transposed from PostScript and
47    /// Direct2D, but is consistent with the
48    /// [Wikipedia](https://en.wikipedia.org/wiki/Affine_transformation)
49    /// formulation of affine transformation as augmented matrix. The
50    /// idea is that `(A * B) * v == A * (B * v)`, where `*` is the
51    /// [`Mul`](core::ops::Mul) trait.
52    #[inline]
53    pub const fn new(c: [f64; 6]) -> Affine {
54        Affine(c)
55    }
56
57    /// An affine transform representing uniform scaling.
58    #[inline]
59    pub const fn scale(s: f64) -> Affine {
60        Affine([s, 0.0, 0.0, s, 0.0, 0.0])
61    }
62
63    /// An affine transform representing non-uniform scaling
64    /// with different scale values for x and y
65    #[inline]
66    pub const fn scale_non_uniform(s_x: f64, s_y: f64) -> Affine {
67        Affine([s_x, 0.0, 0.0, s_y, 0.0, 0.0])
68    }
69
70    /// An affine transform representing translation.
71    #[inline]
72    pub fn translate<V: Into<Vec2>>(p: V) -> Affine {
73        let p = p.into();
74        Affine([1.0, 0.0, 0.0, 1.0, p.x, p.y])
75    }
76
77    /// Creates an affine transformation that takes the unit square to the given rectangle.
78    ///
79    /// Useful when you want to draw into the unit square but have your output fill any rectangle.
80    /// In this case push the `Affine` onto the transform stack.
81    pub fn map_unit_square(rect: Rect) -> Affine {
82        Affine([rect.width(), 0., 0., rect.height(), rect.x0, rect.y0])
83    }
84
85    /// Get the coefficients of the transform.
86    #[inline]
87    pub fn as_coeffs(self) -> [f64; 6] {
88        self.0
89    }
90
91    /// Compute the determinant of this transform.
92    pub fn determinant(self) -> f64 {
93        self.0[0] * self.0[3] - self.0[1] * self.0[2]
94    }
95
96    /// Compute the inverse transform.
97    ///
98    /// Produces NaN values when the determinant is zero.
99    pub fn inverse(self) -> Affine {
100        let inv_det = self.determinant().recip();
101        Affine([
102            inv_det * self.0[3],
103            -inv_det * self.0[1],
104            -inv_det * self.0[2],
105            inv_det * self.0[0],
106            inv_det * (self.0[2] * self.0[5] - self.0[3] * self.0[4]),
107            inv_det * (self.0[1] * self.0[4] - self.0[0] * self.0[5]),
108        ])
109    }
110
111    /// Compute the bounding box of a transformed rectangle.
112    ///
113    /// Returns the minimal `Rect` that encloses the given `Rect` after affine transformation.
114    /// If the transform is axis-aligned, then this bounding box is "tight", in other words the
115    /// returned `Rect` is the transformed rectangle.
116    ///
117    /// The returned rectangle always has non-negative width and height.
118    pub fn transform_rect_bbox(self, rect: Rect) -> Rect {
119        let p00 = self * Point::new(rect.x0, rect.y0);
120        let p01 = self * Point::new(rect.x0, rect.y1);
121        let p10 = self * Point::new(rect.x1, rect.y0);
122        let p11 = self * Point::new(rect.x1, rect.y1);
123        Rect::from_points(p00, p01).union(Rect::from_points(p10, p11))
124    }
125
126    /// Is this map finite?
127    #[inline]
128    pub fn is_finite(&self) -> bool {
129        self.0[0].is_finite()
130            && self.0[1].is_finite()
131            && self.0[2].is_finite()
132            && self.0[3].is_finite()
133            && self.0[4].is_finite()
134            && self.0[5].is_finite()
135    }
136
137    /// Is this map NaN?
138    #[inline]
139    pub fn is_nan(&self) -> bool {
140        self.0[0].is_nan()
141            || self.0[1].is_nan()
142            || self.0[2].is_nan()
143            || self.0[3].is_nan()
144            || self.0[4].is_nan()
145            || self.0[5].is_nan()
146    }
147}
148
149impl Default for Affine {
150    #[inline]
151    fn default() -> Affine {
152        Affine::IDENTITY
153    }
154}
155
156impl Mul<Point> for Affine {
157    type Output = Point;
158
159    #[inline]
160    fn mul(self, other: Point) -> Point {
161        Point::new(
162            self.0[0] * other.x + self.0[2] * other.y + self.0[4],
163            self.0[1] * other.x + self.0[3] * other.y + self.0[5],
164        )
165    }
166}
167
168impl Mul for Affine {
169    type Output = Affine;
170
171    #[inline]
172    fn mul(self, other: Affine) -> Affine {
173        Affine([
174            self.0[0] * other.0[0] + self.0[2] * other.0[1],
175            self.0[1] * other.0[0] + self.0[3] * other.0[1],
176            self.0[0] * other.0[2] + self.0[2] * other.0[3],
177            self.0[1] * other.0[2] + self.0[3] * other.0[3],
178            self.0[0] * other.0[4] + self.0[2] * other.0[5] + self.0[4],
179            self.0[1] * other.0[4] + self.0[3] * other.0[5] + self.0[5],
180        ])
181    }
182}
183
184impl MulAssign for Affine {
185    #[inline]
186    fn mul_assign(&mut self, other: Affine) {
187        *self = self.mul(other);
188    }
189}
190
191impl Mul<Affine> for f64 {
192    type Output = Affine;
193
194    #[inline]
195    fn mul(self, other: Affine) -> Affine {
196        Affine([
197            self * other.0[0],
198            self * other.0[1],
199            self * other.0[2],
200            self * other.0[3],
201            self * other.0[4],
202            self * other.0[5],
203        ])
204    }
205}
206
207/// A 2D point. Derived from [kurbo](https://github.com/linebender/kurbo).
208#[derive(Clone, Copy, Default, PartialEq)]
209#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
210#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
211#[repr(C)]
212pub struct Point {
213    /// The x coordinate.
214    pub x: f64,
215    /// The y coordinate.
216    pub y: f64,
217}
218
219impl Point {
220    /// The point (0, 0).
221    pub const ZERO: Point = Point::new(0., 0.);
222
223    /// The point at the origin; (0, 0).
224    pub const ORIGIN: Point = Point::new(0., 0.);
225
226    /// Create a new `Point` with the provided `x` and `y` coordinates.
227    #[inline]
228    pub const fn new(x: f64, y: f64) -> Self {
229        Point { x, y }
230    }
231
232    /// Convert this point into a `Vec2`.
233    #[inline]
234    pub const fn to_vec2(self) -> Vec2 {
235        Vec2::new(self.x, self.y)
236    }
237}
238
239impl From<(f64, f64)> for Point {
240    #[inline]
241    fn from(v: (f64, f64)) -> Point {
242        Point { x: v.0, y: v.1 }
243    }
244}
245
246impl From<Point> for (f64, f64) {
247    #[inline]
248    fn from(v: Point) -> (f64, f64) {
249        (v.x, v.y)
250    }
251}
252
253impl Add<Vec2> for Point {
254    type Output = Point;
255
256    #[inline]
257    fn add(self, other: Vec2) -> Self {
258        Point::new(self.x + other.x, self.y + other.y)
259    }
260}
261
262impl AddAssign<Vec2> for Point {
263    #[inline]
264    fn add_assign(&mut self, other: Vec2) {
265        *self = Point::new(self.x + other.x, self.y + other.y);
266    }
267}
268
269impl Sub<Vec2> for Point {
270    type Output = Point;
271
272    #[inline]
273    fn sub(self, other: Vec2) -> Self {
274        Point::new(self.x - other.x, self.y - other.y)
275    }
276}
277
278impl SubAssign<Vec2> for Point {
279    #[inline]
280    fn sub_assign(&mut self, other: Vec2) {
281        *self = Point::new(self.x - other.x, self.y - other.y);
282    }
283}
284
285impl Add<(f64, f64)> for Point {
286    type Output = Point;
287
288    #[inline]
289    fn add(self, (x, y): (f64, f64)) -> Self {
290        Point::new(self.x + x, self.y + y)
291    }
292}
293
294impl AddAssign<(f64, f64)> for Point {
295    #[inline]
296    fn add_assign(&mut self, (x, y): (f64, f64)) {
297        *self = Point::new(self.x + x, self.y + y);
298    }
299}
300
301impl Sub<(f64, f64)> for Point {
302    type Output = Point;
303
304    #[inline]
305    fn sub(self, (x, y): (f64, f64)) -> Self {
306        Point::new(self.x - x, self.y - y)
307    }
308}
309
310impl SubAssign<(f64, f64)> for Point {
311    #[inline]
312    fn sub_assign(&mut self, (x, y): (f64, f64)) {
313        *self = Point::new(self.x - x, self.y - y);
314    }
315}
316
317impl Sub<Point> for Point {
318    type Output = Vec2;
319
320    #[inline]
321    fn sub(self, other: Point) -> Vec2 {
322        Vec2::new(self.x - other.x, self.y - other.y)
323    }
324}
325
326impl fmt::Debug for Point {
327    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
328        write!(f, "({:?}, {:?})", self.x, self.y)
329    }
330}
331
332/// A rectangle. Derived from [kurbo](https://github.com/linebender/kurbo).
333#[derive(Clone, Copy, Default, PartialEq)]
334#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
335#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
336#[repr(C)]
337pub struct Rect {
338    /// The minimum x coordinate (left edge).
339    pub x0: f64,
340    /// The minimum y coordinate (top edge in y-down spaces).
341    pub y0: f64,
342    /// The maximum x coordinate (right edge).
343    pub x1: f64,
344    /// The maximum y coordinate (bottom edge in y-down spaces).
345    pub y1: f64,
346}
347
348impl From<(Point, Point)> for Rect {
349    fn from(points: (Point, Point)) -> Rect {
350        Rect::from_points(points.0, points.1)
351    }
352}
353
354impl From<(Point, Size)> for Rect {
355    fn from(params: (Point, Size)) -> Rect {
356        Rect::from_origin_size(params.0, params.1)
357    }
358}
359
360impl Add<Vec2> for Rect {
361    type Output = Rect;
362
363    #[inline]
364    fn add(self, v: Vec2) -> Rect {
365        Rect::new(self.x0 + v.x, self.y0 + v.y, self.x1 + v.x, self.y1 + v.y)
366    }
367}
368
369impl Sub<Vec2> for Rect {
370    type Output = Rect;
371
372    #[inline]
373    fn sub(self, v: Vec2) -> Rect {
374        Rect::new(self.x0 - v.x, self.y0 - v.y, self.x1 - v.x, self.y1 - v.y)
375    }
376}
377
378impl fmt::Debug for Rect {
379    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
380        if f.alternate() {
381            write!(
382                f,
383                "Rect {{ origin: {:?}, size: {:?} }}",
384                self.origin(),
385                self.size()
386            )
387        } else {
388            write!(
389                f,
390                "Rect {{ x0: {:?}, y0: {:?}, x1: {:?}, y1: {:?} }}",
391                self.x0, self.y0, self.x1, self.y1
392            )
393        }
394    }
395}
396
397impl Rect {
398    /// The empty rectangle at the origin.
399    pub const ZERO: Rect = Rect::new(0., 0., 0., 0.);
400
401    /// A new rectangle from minimum and maximum coordinates.
402    #[inline]
403    pub const fn new(x0: f64, y0: f64, x1: f64, y1: f64) -> Rect {
404        Rect { x0, y0, x1, y1 }
405    }
406
407    /// A new rectangle from two points.
408    ///
409    /// The result will have non-negative width and height.
410    #[inline]
411    pub fn from_points(p0: impl Into<Point>, p1: impl Into<Point>) -> Rect {
412        let p0 = p0.into();
413        let p1 = p1.into();
414        Rect::new(p0.x, p0.y, p1.x, p1.y).abs()
415    }
416
417    /// A new rectangle from origin and size.
418    ///
419    /// The result will have non-negative width and height.
420    #[inline]
421    pub fn from_origin_size(origin: impl Into<Point>, size: impl Into<Size>) -> Rect {
422        let origin = origin.into();
423        Rect::from_points(origin, origin + size.into().to_vec2())
424    }
425
426    /// Create a new `Rect` with the same size as `self` and a new origin.
427    #[inline]
428    pub fn with_origin(self, origin: impl Into<Point>) -> Rect {
429        Rect::from_origin_size(origin, self.size())
430    }
431
432    /// Create a new `Rect` with the same origin as `self` and a new size.
433    #[inline]
434    pub fn with_size(self, size: impl Into<Size>) -> Rect {
435        Rect::from_origin_size(self.origin(), size)
436    }
437
438    /// The width of the rectangle.
439    ///
440    /// Note: nothing forbids negative width.
441    #[inline]
442    pub fn width(&self) -> f64 {
443        self.x1 - self.x0
444    }
445
446    /// The height of the rectangle.
447    ///
448    /// Note: nothing forbids negative height.
449    #[inline]
450    pub fn height(&self) -> f64 {
451        self.y1 - self.y0
452    }
453
454    /// Returns the minimum value for the x-coordinate of the rectangle.
455    #[inline]
456    pub fn min_x(&self) -> f64 {
457        self.x0.min(self.x1)
458    }
459
460    /// Returns the maximum value for the x-coordinate of the rectangle.
461    #[inline]
462    pub fn max_x(&self) -> f64 {
463        self.x0.max(self.x1)
464    }
465
466    /// Returns the minimum value for the y-coordinate of the rectangle.
467    #[inline]
468    pub fn min_y(&self) -> f64 {
469        self.y0.min(self.y1)
470    }
471
472    /// Returns the maximum value for the y-coordinate of the rectangle.
473    #[inline]
474    pub fn max_y(&self) -> f64 {
475        self.y0.max(self.y1)
476    }
477
478    /// The origin of the rectangle.
479    ///
480    /// This is the top left corner in a y-down space and with
481    /// non-negative width and height.
482    #[inline]
483    pub fn origin(&self) -> Point {
484        Point::new(self.x0, self.y0)
485    }
486
487    /// The size of the rectangle.
488    #[inline]
489    pub fn size(&self) -> Size {
490        Size::new(self.width(), self.height())
491    }
492
493    /// Take absolute value of width and height.
494    ///
495    /// The resulting rect has the same extents as the original, but is
496    /// guaranteed to have non-negative width and height.
497    #[inline]
498    pub fn abs(&self) -> Rect {
499        let Rect { x0, y0, x1, y1 } = *self;
500        Rect::new(x0.min(x1), y0.min(y1), x0.max(x1), y0.max(y1))
501    }
502
503    /// The area of the rectangle.
504    #[inline]
505    pub fn area(&self) -> f64 {
506        self.width() * self.height()
507    }
508
509    /// Whether this rectangle has zero area.
510    ///
511    /// Note: a rectangle with negative area is not considered empty.
512    #[inline]
513    pub fn is_empty(&self) -> bool {
514        self.area() == 0.0
515    }
516
517    /// Returns `true` if `point` lies within `self`.
518    #[inline]
519    pub fn contains(&self, point: Point) -> bool {
520        point.x >= self.x0 && point.x < self.x1 && point.y >= self.y0 && point.y < self.y1
521    }
522
523    /// The smallest rectangle enclosing two rectangles.
524    ///
525    /// Results are valid only if width and height are non-negative.
526    #[inline]
527    pub fn union(&self, other: Rect) -> Rect {
528        Rect::new(
529            self.x0.min(other.x0),
530            self.y0.min(other.y0),
531            self.x1.max(other.x1),
532            self.y1.max(other.y1),
533        )
534    }
535
536    /// Compute the union with one point.
537    ///
538    /// This method includes the perimeter of zero-area rectangles.
539    /// Thus, a succession of `union_pt` operations on a series of
540    /// points yields their enclosing rectangle.
541    ///
542    /// Results are valid only if width and height are non-negative.
543    pub fn union_pt(&self, pt: Point) -> Rect {
544        Rect::new(
545            self.x0.min(pt.x),
546            self.y0.min(pt.y),
547            self.x1.max(pt.x),
548            self.y1.max(pt.y),
549        )
550    }
551
552    /// The intersection of two rectangles.
553    ///
554    /// The result is zero-area if either input has negative width or
555    /// height. The result always has non-negative width and height.
556    #[inline]
557    pub fn intersect(&self, other: Rect) -> Rect {
558        let x0 = self.x0.max(other.x0);
559        let y0 = self.y0.max(other.y0);
560        let x1 = self.x1.min(other.x1);
561        let y1 = self.y1.min(other.y1);
562        Rect::new(x0, y0, x1.max(x0), y1.max(y0))
563    }
564}
565
566/// A 2D size. Derived from [kurbo](https://github.com/linebender/kurbo).
567#[derive(Clone, Copy, Default, PartialEq)]
568#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
569#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
570#[repr(C)]
571pub struct Size {
572    /// The width.
573    pub width: f64,
574    /// The height.
575    pub height: f64,
576}
577
578impl Size {
579    /// A size with zero width or height.
580    pub const ZERO: Size = Size::new(0., 0.);
581
582    /// Create a new `Size` with the provided `width` and `height`.
583    #[inline]
584    pub const fn new(width: f64, height: f64) -> Self {
585        Size { width, height }
586    }
587
588    /// Convert this size into a [`Vec2`], with `width` mapped to `x` and `height`
589    /// mapped to `y`.
590    #[inline]
591    pub const fn to_vec2(self) -> Vec2 {
592        Vec2::new(self.width, self.height)
593    }
594}
595
596impl fmt::Debug for Size {
597    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
598        write!(f, "{:?}W×{:?}H", self.width, self.height)
599    }
600}
601
602impl MulAssign<f64> for Size {
603    #[inline]
604    fn mul_assign(&mut self, other: f64) {
605        *self = Size {
606            width: self.width * other,
607            height: self.height * other,
608        };
609    }
610}
611
612impl Mul<Size> for f64 {
613    type Output = Size;
614
615    #[inline]
616    fn mul(self, other: Size) -> Size {
617        other * self
618    }
619}
620
621impl Mul<f64> for Size {
622    type Output = Size;
623
624    #[inline]
625    fn mul(self, other: f64) -> Size {
626        Size {
627            width: self.width * other,
628            height: self.height * other,
629        }
630    }
631}
632
633impl DivAssign<f64> for Size {
634    #[inline]
635    fn div_assign(&mut self, other: f64) {
636        *self = Size {
637            width: self.width / other,
638            height: self.height / other,
639        };
640    }
641}
642
643impl Div<f64> for Size {
644    type Output = Size;
645
646    #[inline]
647    fn div(self, other: f64) -> Size {
648        Size {
649            width: self.width / other,
650            height: self.height / other,
651        }
652    }
653}
654
655impl Add<Size> for Size {
656    type Output = Size;
657    #[inline]
658    fn add(self, other: Size) -> Size {
659        Size {
660            width: self.width + other.width,
661            height: self.height + other.height,
662        }
663    }
664}
665
666impl AddAssign<Size> for Size {
667    #[inline]
668    fn add_assign(&mut self, other: Size) {
669        *self = *self + other;
670    }
671}
672
673impl Sub<Size> for Size {
674    type Output = Size;
675    #[inline]
676    fn sub(self, other: Size) -> Size {
677        Size {
678            width: self.width - other.width,
679            height: self.height - other.height,
680        }
681    }
682}
683
684impl SubAssign<Size> for Size {
685    #[inline]
686    fn sub_assign(&mut self, other: Size) {
687        *self = *self - other;
688    }
689}
690
691impl From<(f64, f64)> for Size {
692    #[inline]
693    fn from(v: (f64, f64)) -> Size {
694        Size {
695            width: v.0,
696            height: v.1,
697        }
698    }
699}
700
701impl From<Size> for (f64, f64) {
702    #[inline]
703    fn from(v: Size) -> (f64, f64) {
704        (v.width, v.height)
705    }
706}
707
708/// A 2D vector. Derived from [kurbo](https://github.com/linebender/kurbo).
709///
710/// This is intended primarily for a vector in the mathematical sense,
711/// but it can be interpreted as a translation, and converted to and
712/// from a point (vector relative to the origin) and size.
713#[derive(Clone, Copy, Default, Debug, PartialEq)]
714#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
715#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
716#[repr(C)]
717pub struct Vec2 {
718    /// The x-coordinate.
719    pub x: f64,
720    /// The y-coordinate.
721    pub y: f64,
722}
723
724impl Vec2 {
725    /// The vector (0, 0).
726    pub const ZERO: Vec2 = Vec2::new(0., 0.);
727
728    /// Create a new vector.
729    #[inline]
730    pub const fn new(x: f64, y: f64) -> Vec2 {
731        Vec2 { x, y }
732    }
733
734    /// Convert this vector into a `Point`.
735    #[inline]
736    pub const fn to_point(self) -> Point {
737        Point::new(self.x, self.y)
738    }
739
740    /// Convert this vector into a `Size`.
741    #[inline]
742    pub const fn to_size(self) -> Size {
743        Size::new(self.x, self.y)
744    }
745}
746
747impl From<(f64, f64)> for Vec2 {
748    #[inline]
749    fn from(v: (f64, f64)) -> Vec2 {
750        Vec2 { x: v.0, y: v.1 }
751    }
752}
753
754impl From<Vec2> for (f64, f64) {
755    #[inline]
756    fn from(v: Vec2) -> (f64, f64) {
757        (v.x, v.y)
758    }
759}
760
761impl Add for Vec2 {
762    type Output = Vec2;
763
764    #[inline]
765    fn add(self, other: Vec2) -> Vec2 {
766        Vec2 {
767            x: self.x + other.x,
768            y: self.y + other.y,
769        }
770    }
771}
772
773impl AddAssign for Vec2 {
774    #[inline]
775    fn add_assign(&mut self, other: Vec2) {
776        *self = Vec2 {
777            x: self.x + other.x,
778            y: self.y + other.y,
779        }
780    }
781}
782
783impl Sub for Vec2 {
784    type Output = Vec2;
785
786    #[inline]
787    fn sub(self, other: Vec2) -> Vec2 {
788        Vec2 {
789            x: self.x - other.x,
790            y: self.y - other.y,
791        }
792    }
793}
794
795impl SubAssign for Vec2 {
796    #[inline]
797    fn sub_assign(&mut self, other: Vec2) {
798        *self = Vec2 {
799            x: self.x - other.x,
800            y: self.y - other.y,
801        }
802    }
803}
804
805impl Mul<f64> for Vec2 {
806    type Output = Vec2;
807
808    #[inline]
809    fn mul(self, other: f64) -> Vec2 {
810        Vec2 {
811            x: self.x * other,
812            y: self.y * other,
813        }
814    }
815}
816
817impl MulAssign<f64> for Vec2 {
818    #[inline]
819    fn mul_assign(&mut self, other: f64) {
820        *self = Vec2 {
821            x: self.x * other,
822            y: self.y * other,
823        };
824    }
825}
826
827impl Mul<Vec2> for f64 {
828    type Output = Vec2;
829
830    #[inline]
831    fn mul(self, other: Vec2) -> Vec2 {
832        other * self
833    }
834}
835
836impl Div<f64> for Vec2 {
837    type Output = Vec2;
838
839    /// Note: division by a scalar is implemented by multiplying by the reciprocal.
840    ///
841    /// This is more efficient but has different roundoff behavior than division.
842    #[inline]
843    #[allow(clippy::suspicious_arithmetic_impl)]
844    fn div(self, other: f64) -> Vec2 {
845        self * other.recip()
846    }
847}
848
849impl DivAssign<f64> for Vec2 {
850    #[inline]
851    fn div_assign(&mut self, other: f64) {
852        self.mul_assign(other.recip());
853    }
854}
855
856impl Neg for Vec2 {
857    type Output = Vec2;
858
859    #[inline]
860    fn neg(self) -> Vec2 {
861        Vec2 {
862            x: -self.x,
863            y: -self.y,
864        }
865    }
866}