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 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)] |
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`](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 | |
149 | impl Default for Affine { |
150 | #[inline ] |
151 | fn default() -> Affine { |
152 | Affine::IDENTITY |
153 | } |
154 | } |
155 | |
156 | impl 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 | |
168 | impl 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 | |
184 | impl MulAssign for Affine { |
185 | #[inline ] |
186 | fn mul_assign(&mut self, other: Affine) { |
187 | *self = self.mul(other); |
188 | } |
189 | } |
190 | |
191 | impl 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)] |
212 | pub struct Point { |
213 | /// The x coordinate. |
214 | pub x: f64, |
215 | /// The y coordinate. |
216 | pub y: f64, |
217 | } |
218 | |
219 | impl 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 | |
239 | impl 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 | |
246 | impl From<Point> for (f64, f64) { |
247 | #[inline ] |
248 | fn from(v: Point) -> (f64, f64) { |
249 | (v.x, v.y) |
250 | } |
251 | } |
252 | |
253 | impl 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 | |
262 | impl 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 | |
269 | impl 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 | |
278 | impl 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 | |
285 | impl 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 | |
294 | impl 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 | |
301 | impl 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 | |
310 | impl 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 | |
317 | impl 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 | |
326 | impl 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)] |
337 | pub 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 | |
348 | impl 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 | |
354 | impl 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 | |
360 | impl 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 | |
369 | impl 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 | |
378 | impl 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 | |
397 | impl 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)] |
571 | pub struct Size { |
572 | /// The width. |
573 | pub width: f64, |
574 | /// The height. |
575 | pub height: f64, |
576 | } |
577 | |
578 | impl 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 | |
596 | impl fmt::Debug for Size { |
597 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
598 | write!(f, " {:?}W× {:?}H" , self.width, self.height) |
599 | } |
600 | } |
601 | |
602 | impl 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 | |
612 | impl Mul<Size> for f64 { |
613 | type Output = Size; |
614 | |
615 | #[inline ] |
616 | fn mul(self, other: Size) -> Size { |
617 | other * self |
618 | } |
619 | } |
620 | |
621 | impl 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 | |
633 | impl 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 | |
643 | impl 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 | |
655 | impl 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 | |
666 | impl AddAssign<Size> for Size { |
667 | #[inline ] |
668 | fn add_assign(&mut self, other: Size) { |
669 | *self = *self + other; |
670 | } |
671 | } |
672 | |
673 | impl 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 | |
684 | impl SubAssign<Size> for Size { |
685 | #[inline ] |
686 | fn sub_assign(&mut self, other: Size) { |
687 | *self = *self - other; |
688 | } |
689 | } |
690 | |
691 | impl 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 | |
701 | impl 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)] |
717 | pub struct Vec2 { |
718 | /// The x-coordinate. |
719 | pub x: f64, |
720 | /// The y-coordinate. |
721 | pub y: f64, |
722 | } |
723 | |
724 | impl 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 | |
747 | impl 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 | |
754 | impl From<Vec2> for (f64, f64) { |
755 | #[inline ] |
756 | fn from(v: Vec2) -> (f64, f64) { |
757 | (v.x, v.y) |
758 | } |
759 | } |
760 | |
761 | impl 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 | |
773 | impl 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 | |
783 | impl 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 | |
795 | impl 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 | |
805 | impl 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 | |
817 | impl 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 | |
827 | impl Mul<Vec2> for f64 { |
828 | type Output = Vec2; |
829 | |
830 | #[inline ] |
831 | fn mul(self, other: Vec2) -> Vec2 { |
832 | other * self |
833 | } |
834 | } |
835 | |
836 | impl 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 | |
849 | impl DivAssign<f64> for Vec2 { |
850 | #[inline ] |
851 | fn div_assign(&mut self, other: f64) { |
852 | self.mul_assign(other.recip()); |
853 | } |
854 | } |
855 | |
856 | impl 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 | |