pixelutil_image/
coordinate.rs

1use crate::index::ImageAxisIndex;
2
3/// Trait for types that can represent image coordinates
4pub trait ImageCoordinate {
5    /// Return the `(x, y)` pixel indices, or [`None`] if the coordinate is invalid.
6    fn image_coordinate(&self) -> Option<(u32, u32)>;
7
8    /// Return clamped `(x, y)` pixel indices within the given bounds.
9    /// Bounds are `(0, 0)` and `(right, bottom)`.
10    fn image_coordinate_clamped(&self, right: u32, bottom: u32) -> (u32, u32);
11}
12
13impl<T: ImageAxisIndex + Copy> ImageCoordinate for (T, T) {
14    #[inline]
15    fn image_coordinate(&self) -> Option<(u32, u32)> {
16        self.0
17            .to_image_axis_index()
18            .zip(self.1.to_image_axis_index())
19    }
20
21    #[inline]
22    fn image_coordinate_clamped(&self, right: u32, bottom: u32) -> (u32, u32) {
23        (
24            self.0.clamp_image_axis_index(right),
25            self.1.clamp_image_axis_index(bottom),
26        )
27    }
28}
29
30impl<T: ImageAxisIndex + Copy> ImageCoordinate for [T; 2] {
31    #[inline]
32    fn image_coordinate(&self) -> Option<(u32, u32)> {
33        unsafe { self.get_unchecked(0) }
34            .to_image_axis_index()
35            .zip(unsafe { self.get_unchecked(1) }.to_image_axis_index())
36    }
37
38    #[inline]
39    fn image_coordinate_clamped(&self, right: u32, bottom: u32) -> (u32, u32) {
40        (
41            unsafe { self.get_unchecked(0) }.clamp_image_axis_index(right),
42            unsafe { self.get_unchecked(1) }.clamp_image_axis_index(bottom),
43        )
44    }
45}
46
47impl<T: ImageAxisIndex + Clone> ImageCoordinate for &[T; 2] {
48    #[inline]
49    fn image_coordinate(&self) -> Option<(u32, u32)> {
50        unsafe { self.get_unchecked(0) }
51            .clone()
52            .to_image_axis_index()
53            .zip(
54                unsafe { self.get_unchecked(1) }
55                    .clone()
56                    .to_image_axis_index(),
57            )
58    }
59
60    #[inline]
61    fn image_coordinate_clamped(&self, right: u32, bottom: u32) -> (u32, u32) {
62        (
63            unsafe { self.get_unchecked(0) }
64                .clone()
65                .clamp_image_axis_index(right),
66            unsafe { self.get_unchecked(1) }
67                .clone()
68                .clamp_image_axis_index(bottom),
69        )
70    }
71}
72
73#[cfg(feature = "nalgebra")]
74impl<T: ImageAxisIndex + nalgebra::Scalar> ImageCoordinate for &nalgebra::Point2<T> {
75    #[inline]
76    fn image_coordinate(&self) -> Option<(u32, u32)> {
77        self.x
78            .clone()
79            .to_image_axis_index()
80            .zip(self.y.clone().to_image_axis_index())
81    }
82
83    #[inline]
84    fn image_coordinate_clamped(&self, right: u32, bottom: u32) -> (u32, u32) {
85        (
86            self.x.clone().clamp_image_axis_index(right),
87            self.y.clone().clamp_image_axis_index(bottom),
88        )
89    }
90}
91
92#[cfg(feature = "nalgebra")]
93impl<T: ImageAxisIndex + nalgebra::Scalar + Copy> ImageCoordinate for nalgebra::Point2<T> {
94    #[inline]
95    fn image_coordinate(&self) -> Option<(u32, u32)> {
96        self.x
97            .to_image_axis_index()
98            .zip(self.y.clone().to_image_axis_index())
99    }
100
101    #[inline]
102    fn image_coordinate_clamped(&self, right: u32, bottom: u32) -> (u32, u32) {
103        (
104            self.x.clamp_image_axis_index(right),
105            self.y.clamp_image_axis_index(bottom),
106        )
107    }
108}