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(x:0., y:0.);
236
237 /// The point at the origin; (0, 0).
238 pub const ORIGIN: Point = Point::new(x:0., y: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: f64, y: f64): (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: f64, y: f64): (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: f64, y: f64): (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: f64, y: f64): (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(p0:points.0, p1:points.1)
365 }
366}
367
368impl From<(Point, Size)> for Rect {
369 fn from(params: (Point, Size)) -> Rect {
370 Rect::from_origin_size(origin:params.0, size: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(width:0., height: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, "{:?}{:?}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(x:0., y: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}
881