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 | |
12 | use 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)] |
22 | pub struct Affine([f64; 6]); |
23 | |
24 | impl 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 | |
163 | impl Default for Affine { |
164 | #[inline ] |
165 | fn default() -> Affine { |
166 | Affine::IDENTITY |
167 | } |
168 | } |
169 | |
170 | impl 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 | |
182 | impl 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 | |
198 | impl MulAssign for Affine { |
199 | #[inline ] |
200 | fn mul_assign(&mut self, other: Affine) { |
201 | *self = self.mul(other); |
202 | } |
203 | } |
204 | |
205 | impl 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)] |
226 | pub struct Point { |
227 | /// The x coordinate. |
228 | pub x: f64, |
229 | /// The y coordinate. |
230 | pub y: f64, |
231 | } |
232 | |
233 | impl 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 | |
253 | impl 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 | |
260 | impl From<Point> for (f64, f64) { |
261 | #[inline ] |
262 | fn from(v: Point) -> (f64, f64) { |
263 | (v.x, v.y) |
264 | } |
265 | } |
266 | |
267 | impl 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 | |
276 | impl 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 | |
283 | impl 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 | |
292 | impl 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 | |
299 | impl 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 | |
308 | impl 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 | |
315 | impl 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 | |
324 | impl 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 | |
331 | impl 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 | |
340 | impl 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)] |
351 | pub 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 | |
362 | impl 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 | |
368 | impl 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 | |
374 | impl 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 | |
383 | impl 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 | |
392 | impl 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 | |
411 | impl 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)] |
585 | pub struct Size { |
586 | /// The width. |
587 | pub width: f64, |
588 | /// The height. |
589 | pub height: f64, |
590 | } |
591 | |
592 | impl 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 | |
610 | impl 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 | |
616 | impl 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 | |
626 | impl Mul<Size> for f64 { |
627 | type Output = Size; |
628 | |
629 | #[inline ] |
630 | fn mul(self, other: Size) -> Size { |
631 | other * self |
632 | } |
633 | } |
634 | |
635 | impl 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 | |
647 | impl 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 | |
657 | impl 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 | |
669 | impl 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 | |
680 | impl AddAssign<Size> for Size { |
681 | #[inline ] |
682 | fn add_assign(&mut self, other: Size) { |
683 | *self = *self + other; |
684 | } |
685 | } |
686 | |
687 | impl 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 | |
698 | impl SubAssign<Size> for Size { |
699 | #[inline ] |
700 | fn sub_assign(&mut self, other: Size) { |
701 | *self = *self - other; |
702 | } |
703 | } |
704 | |
705 | impl 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 | |
715 | impl 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)] |
731 | pub struct Vec2 { |
732 | /// The x-coordinate. |
733 | pub x: f64, |
734 | /// The y-coordinate. |
735 | pub y: f64, |
736 | } |
737 | |
738 | impl 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 | |
761 | impl 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 | |
768 | impl From<Vec2> for (f64, f64) { |
769 | #[inline ] |
770 | fn from(v: Vec2) -> (f64, f64) { |
771 | (v.x, v.y) |
772 | } |
773 | } |
774 | |
775 | impl 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 | |
787 | impl 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 | |
797 | impl 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 | |
809 | impl 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 | |
819 | impl 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 | |
831 | impl 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 | |
841 | impl Mul<Vec2> for f64 { |
842 | type Output = Vec2; |
843 | |
844 | #[inline ] |
845 | fn mul(self, other: Vec2) -> Vec2 { |
846 | other * self |
847 | } |
848 | } |
849 | |
850 | impl 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 | |
863 | impl DivAssign<f64> for Vec2 { |
864 | #[inline ] |
865 | fn div_assign(&mut self, other: f64) { |
866 | self.mul_assign(other.recip()); |
867 | } |
868 | } |
869 | |
870 | impl 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 | |