1use core::{
2 convert::{TryFrom, TryInto},
3 fmt,
4 ops::{Add, AddAssign, Div, DivAssign, Index, Mul, MulAssign, Neg, Sub, SubAssign},
5};
6
7use crate::geometry::Size;
8
9#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
68#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
69pub struct Point {
70 pub x: i32,
72
73 pub y: i32,
75}
76
77impl Point {
78 pub const fn new(x: i32, y: i32) -> Self {
80 Point { x, y }
81 }
82
83 pub const fn new_equal(value: i32) -> Self {
95 Point { x: value, y: value }
96 }
97
98 pub const fn zero() -> Self {
100 Point { x: 0, y: 0 }
101 }
102
103 pub const fn x_axis(self) -> Self {
121 Self { x: self.x, y: 0 }
122 }
123
124 pub const fn y_axis(self) -> Self {
142 Self { x: 0, y: self.y }
143 }
144
145 pub const fn abs(self) -> Self {
157 Point::new(self.x.abs(), self.y.abs())
158 }
159
160 pub(crate) const fn sub_size(self, other: Size) -> Point {
169 let width = other.width as i32;
170 let height = other.height as i32;
171
172 debug_assert!(width >= 0, "width is too large");
173 debug_assert!(height >= 0, "height is too large");
174
175 Point::new(self.x - width, self.y - height)
176 }
177
178 pub fn component_min(self, other: Self) -> Self {
190 Self::new(self.x.min(other.x), self.y.min(other.y))
191 }
192
193 pub fn component_max(self, other: Self) -> Self {
205 Self::new(self.x.max(other.x), self.y.max(other.y))
206 }
207
208 pub const fn component_mul(self, other: Self) -> Self {
218 Self::new(self.x * other.x, self.y * other.y)
219 }
220
221 pub const fn component_div(self, other: Self) -> Self {
235 Self::new(self.x / other.x, self.y / other.y)
236 }
237}
238
239impl Add for Point {
240 type Output = Point;
241
242 fn add(self, other: Point) -> Point {
243 Point::new(self.x + other.x, self.y + other.y)
244 }
245}
246
247impl Add<Size> for Point {
248 type Output = Point;
249
250 fn add(self, other: Size) -> Point {
257 let width = other.width as i32;
258 let height = other.height as i32;
259
260 debug_assert!(width >= 0, "width is too large");
261 debug_assert!(height >= 0, "height is too large");
262
263 Point::new(self.x + width, self.y + height)
264 }
265}
266
267impl AddAssign for Point {
268 fn add_assign(&mut self, other: Point) {
269 self.x += other.x;
270 self.y += other.y;
271 }
272}
273
274impl AddAssign<Size> for Point {
275 fn add_assign(&mut self, other: Size) {
282 let width = other.width as i32;
283 let height = other.height as i32;
284
285 debug_assert!(width >= 0, "width is too large");
286 debug_assert!(height >= 0, "height is too large");
287
288 self.x += width;
289 self.y += height;
290 }
291}
292
293impl Sub for Point {
294 type Output = Point;
295
296 fn sub(self, other: Point) -> Point {
297 Point::new(self.x - other.x, self.y - other.y)
298 }
299}
300
301impl Sub<Size> for Point {
302 type Output = Point;
303
304 fn sub(self, other: Size) -> Point {
311 self.sub_size(other)
312 }
313}
314
315impl SubAssign for Point {
316 fn sub_assign(&mut self, other: Point) {
317 self.x -= other.x;
318 self.y -= other.y;
319 }
320}
321
322impl SubAssign<Size> for Point {
323 fn sub_assign(&mut self, other: Size) {
330 let width = other.width as i32;
331 let height = other.height as i32;
332
333 debug_assert!(width >= 0, "width is too large");
334 debug_assert!(height >= 0, "height is too large");
335
336 self.x -= width;
337 self.y -= height;
338 }
339}
340
341impl Mul<i32> for Point {
342 type Output = Point;
343
344 fn mul(self, rhs: i32) -> Point {
345 Point::new(self.x * rhs, self.y * rhs)
346 }
347}
348
349impl MulAssign<i32> for Point {
350 fn mul_assign(&mut self, rhs: i32) {
351 self.x *= rhs;
352 self.y *= rhs;
353 }
354}
355
356impl Div<i32> for Point {
357 type Output = Point;
358
359 fn div(self, rhs: i32) -> Point {
360 Point::new(self.x / rhs, self.y / rhs)
361 }
362}
363
364impl DivAssign<i32> for Point {
365 fn div_assign(&mut self, rhs: i32) {
366 self.x /= rhs;
367 self.y /= rhs;
368 }
369}
370
371impl Index<usize> for Point {
372 type Output = i32;
373
374 fn index(&self, idx: usize) -> &i32 {
375 match idx {
376 0 => &self.x,
377 1 => &self.y,
378 _ => panic!("index out of bounds: the len is 2 but the index is {}", idx),
379 }
380 }
381}
382
383impl Neg for Point {
384 type Output = Point;
385
386 fn neg(self) -> Self::Output {
387 Point::new(-self.x, -self.y)
388 }
389}
390
391impl From<(i32, i32)> for Point {
392 fn from(other: (i32, i32)) -> Self {
393 Point::new(other.0, other.1)
394 }
395}
396
397impl From<[i32; 2]> for Point {
398 fn from(other: [i32; 2]) -> Self {
399 Point::new(other[0], other[1])
400 }
401}
402
403impl From<&[i32; 2]> for Point {
404 fn from(other: &[i32; 2]) -> Self {
405 Point::new(other[0], other[1])
406 }
407}
408
409impl From<Point> for (i32, i32) {
410 fn from(other: Point) -> (i32, i32) {
411 (other.x, other.y)
412 }
413}
414
415impl From<Point> for [i32; 2] {
416 fn from(other: Point) -> [i32; 2] {
417 [other.x, other.y]
418 }
419}
420
421impl From<&Point> for (i32, i32) {
422 fn from(other: &Point) -> (i32, i32) {
423 (other.x, other.y)
424 }
425}
426
427impl TryFrom<Point> for (u32, u32) {
428 type Error = core::num::TryFromIntError;
429
430 fn try_from(point: Point) -> Result<Self, Self::Error> {
431 Ok((point.x.try_into()?, point.y.try_into()?))
432 }
433}
434
435impl TryFrom<(u32, u32)> for Point {
436 type Error = core::num::TryFromIntError;
437
438 fn try_from(point: (u32, u32)) -> Result<Self, Self::Error> {
439 let x = point.0.try_into()?;
440 let y = point.1.try_into()?;
441
442 Ok(Point::new(x, y))
443 }
444}
445
446impl TryFrom<Point> for [u32; 2] {
447 type Error = core::num::TryFromIntError;
448
449 fn try_from(point: Point) -> Result<Self, Self::Error> {
450 Ok([point.x.try_into()?, point.y.try_into()?])
451 }
452}
453
454impl TryFrom<[u32; 2]> for Point {
455 type Error = core::num::TryFromIntError;
456
457 fn try_from(point: [u32; 2]) -> Result<Self, Self::Error> {
458 let x = point[0].try_into()?;
459 let y = point[1].try_into()?;
460
461 Ok(Point::new(x, y))
462 }
463}
464
465impl TryFrom<&[u32; 2]> for Point {
466 type Error = core::num::TryFromIntError;
467
468 fn try_from(point: &[u32; 2]) -> Result<Self, Self::Error> {
469 let x = point[0].try_into()?;
470 let y = point[1].try_into()?;
471
472 Ok(Point::new(x, y))
473 }
474}
475
476impl fmt::Display for Point {
477 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
478 write!(f, "{}, {}", self.x, self.y)
479 }
480}
481
482#[cfg(feature = "nalgebra_support")]
483use nalgebra::{base::Scalar, Vector2};
484
485#[cfg(feature = "nalgebra_support")]
486impl<N> From<Vector2<N>> for Point
487where
488 N: Into<i32> + Scalar + Copy,
489{
490 fn from(other: Vector2<N>) -> Self {
491 Self::new(other[0].into(), other[1].into())
492 }
493}
494
495#[cfg(feature = "nalgebra_support")]
496impl<N> From<&Vector2<N>> for Point
497where
498 N: Into<i32> + Scalar + Copy,
499{
500 fn from(other: &Vector2<N>) -> Self {
501 Self::new(other[0].into(), other[1].into())
502 }
503}
504
505#[cfg(test)]
506mod tests {
507 use super::*;
508
509 use core::fmt::Write;
510
511 #[test]
512 fn convert_positive_to_u32_tuple() {
513 let p = Point::new(10, 20);
514
515 let tuple: (u32, u32) = p.try_into().unwrap();
516 let array: [u32; 2] = p.try_into().unwrap();
517
518 assert_eq!(tuple, (10, 20));
519 assert_eq!(array, [10, 20]);
520 }
521
522 #[test]
523 fn convert_i32_max_to_u32_tuple() {
524 let p = Point::new(i32::max_value(), i32::max_value());
525
526 let tuple: (u32, u32) = p.try_into().unwrap();
527 let array: [u32; 2] = p.try_into().unwrap();
528
529 assert_eq!(tuple, (2147483647, 2147483647));
531 assert_eq!(array, [2147483647, 2147483647]);
532 }
533
534 #[test]
535 fn convert_negative_to_u32_tuple() {
536 let p = Point::new(-50, -10);
537
538 let tuple: Result<(u32, u32), _> = p.try_into();
539 let array: Result<[u32; 2], _> = p.try_into();
540
541 assert!(tuple.is_err());
542 assert!(array.is_err());
543 }
544
545 #[test]
546 fn convert_i32_min_to_u32_tuple() {
547 let p = Point::new(i32::min_value(), i32::min_value());
548
549 let tuple: Result<(u32, u32), _> = p.try_into();
550 let array: Result<[u32; 2], _> = p.try_into();
551
552 assert!(tuple.is_err());
553 assert!(array.is_err());
554 }
555
556 #[test]
557 fn points_can_be_added() {
558 let mut left = Point::new(10, 20);
559 let right = Point::new(30, 40);
560
561 assert_eq!(left + right, Point::new(40, 60));
562
563 left += right;
564 assert_eq!(left, Point::new(40, 60));
565 }
566
567 #[test]
568 fn point_and_size_can_be_added() {
569 let mut left = Point::new(11, 21);
570 let right = Size::new(30, 40);
571
572 assert_eq!(left + right, Point::new(41, 61));
573
574 left += right;
575 assert_eq!(left, Point::new(41, 61));
576 }
577
578 #[test]
579 fn points_can_be_subtracted() {
580 let mut left = Point::new(30, 50);
581 let right = Point::new(10, 20);
582
583 assert_eq!(left - right, Point::new(20, 30));
584
585 left -= right;
586 assert_eq!(left, Point::new(20, 30));
587 }
588
589 #[test]
590 fn point_and_size_can_be_subtracted() {
591 let mut left = Point::new(30, 40);
592 let right = Size::new(11, 22);
593
594 assert_eq!(left - right, Point::new(19, 18));
595
596 left -= right;
597 assert_eq!(left, Point::new(19, 18));
598 }
599
600 #[test]
601 fn points_can_be_negative_after_subtraction() {
602 let left = Point::new(10, 20);
603 let right = Point::new(30, 50);
604
605 assert_eq!(left - right, Point::new(-20, -30));
606
607 let left = Point::new(10, 20);
608 let right = Size::new(31, 42);
609
610 assert_eq!(left - right, Point::new(-21, -22));
611 }
612
613 #[test]
614 fn points_can_be_multiplied_by_scalar() {
615 let p = Point::new(1, 2);
616 assert_eq!(p * 3, Point::new(3, 6));
617
618 let mut p = Point::new(3, 4);
619 p *= -5;
620 assert_eq!(p, Point::new(-15, -20));
621 }
622
623 #[test]
624 fn points_can_be_divided_by_scalar() {
625 let p = Point::new(10, 20);
626 assert_eq!(p / 2, Point::new(5, 10));
627
628 let mut p = Point::new(-10, 10);
629 p /= -5;
630 assert_eq!(p, Point::new(2, -2));
631 }
632
633 #[test]
634 #[should_panic(expected = "width is too large")]
635 #[cfg(debug_assertions)]
636 fn too_large_width_can_not_be_added() {
637 let p = Point::zero();
638 let _ = p + Size::new(u32::max_value(), 0);
639 }
640
641 #[test]
642 #[should_panic(expected = "width is too large")]
643 #[cfg(debug_assertions)]
644 fn too_large_width_can_not_be_add_assigned() {
645 let mut p = Point::zero();
646 p += Size::new(u32::max_value(), 0);
647 }
648
649 #[test]
650 #[should_panic(expected = "height is too large")]
651 #[cfg(debug_assertions)]
652 fn too_large_height_can_not_be_added() {
653 let p = Point::zero();
654 let _ = p + Size::new(0, 0x80000000);
655 }
656
657 #[test]
658 #[should_panic(expected = "height is too large")]
659 #[cfg(debug_assertions)]
660 fn too_large_height_can_not_be_add_assigned() {
661 let mut p = Point::zero();
662 p += Size::new(0, 0x80000000);
663 }
664
665 #[test]
666 #[should_panic(expected = "width is too large")]
667 #[cfg(debug_assertions)]
668 fn too_large_width_can_not_be_subtracted() {
669 let p = Point::zero();
670 let _ = p - Size::new(u32::max_value(), 0);
671 }
672
673 #[test]
674 #[should_panic(expected = "width is too large")]
675 #[cfg(debug_assertions)]
676 fn too_large_width_can_not_be_sub_assigned() {
677 let mut p = Point::zero();
678 p -= Size::new(u32::max_value(), 0);
679 }
680
681 #[test]
682 #[should_panic(expected = "height is too large")]
683 #[cfg(debug_assertions)]
684 fn too_large_height_can_not_be_subtracted() {
685 let p = Point::zero();
686 let _ = p - Size::new(0, 0x80000000);
687 }
688
689 #[test]
690 #[should_panic(expected = "height is too large")]
691 #[cfg(debug_assertions)]
692 fn too_large_height_can_not_be_sub_assigned() {
693 let mut p = Point::zero();
694 p -= Size::new(0, 0x80000000);
695 }
696
697 #[test]
698 fn from_tuple() {
699 assert_eq!(Point::from((20i32, 30i32)), Point::new(20, 30));
700 assert_eq!(Point::from((20i32, 30i32)), Point::new(20, 30));
701 }
702
703 #[test]
704 fn from_array() {
705 assert_eq!(Point::from([20i32, 30i32]), Point::new(20, 30));
706 assert_eq!(Point::from([20i32, 30i32]), Point::new(20, 30));
707 }
708
709 #[test]
710 fn from_array_ref() {
711 assert_eq!(Point::from(&[20i32, 30i32]), Point::new(20, 30));
712 assert_eq!(Point::from(&[20i32, 30i32]), Point::new(20, 30));
713 }
714
715 #[test]
716 fn neg() {
717 assert_eq!(-Point::new(10, 20), Point::new(-10, -20));
718 assert_eq!(-Point::new(-40, -50), Point::new(40, 50));
719 }
720
721 #[test]
722 fn index() {
723 let point = Point::new(12, -34);
724
725 assert_eq!(point.x, point[0]);
726 assert_eq!(point.y, point[1]);
727 }
728
729 #[test]
730 #[should_panic]
731 fn index_out_of_bounds() {
732 let point = Point::new(1, 2);
733 let _ = point[2];
734 }
735
736 #[test]
737 #[cfg(feature = "nalgebra_support")]
738 fn nalgebra_support() {
739 let left = nalgebra::Vector2::new(30, 40);
740 let right = nalgebra::Vector2::new(10, 20);
741
742 assert_eq!(Point::from(left - right), Point::new(20, 20));
743 }
744
745 #[test]
746 #[cfg(feature = "nalgebra_support")]
747 fn convert_ref() {
748 let left = nalgebra::Vector2::new(30, 40);
749 let right = nalgebra::Vector2::new(10, 20);
750
751 let c = left - right;
752
753 assert_eq!(Point::from(&c), Point::new(20, 20));
754 }
755
756 #[test]
757 fn component_min_max() {
758 let a = Point::new(20, 30);
759 let b = Point::new(15, 50);
760
761 assert_eq!(a.component_min(b), Point::new(15, 30));
762 assert_eq!(a.component_max(b), Point::new(20, 50));
763 }
764
765 #[test]
766 fn display() {
767 let mut buffer = arrayvec::ArrayString::<32>::new();
768 write!(buffer, "{}", Point::new(123, -456)).unwrap();
769
770 assert_eq!(&buffer, "123, -456");
771 }
772}