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(x:0., y:0.);
222
223 /// The point at the origin; (0, 0).
224 pub const ORIGIN: Point = Point::new(x:0., y: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: f64, y: f64): (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: f64, y: f64): (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: f64, y: f64): (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: f64, y: f64): (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(p0:points.0, p1:points.1)
351 }
352}
353
354impl From<(Point, Size)> for Rect {
355 fn from(params: (Point, Size)) -> Rect {
356 Rect::from_origin_size(origin:params.0, size: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(width:0., height: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, "{:?}{:?}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(x:0., y: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}
867