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