1use nalgebra::{
2 Const, DefaultAllocator, DimNameAdd, DimNameSub, DimNameSum, OMatrix,
3 OVector, Point2, Point3, U1, Vector2, Vector3, allocator::Allocator,
4};
5
6#[derive(Copy, Clone, Debug, Eq, PartialEq)]
48pub struct RegionSize<const N: usize>
49where
50 Const<N>: DimNameAdd<U1>,
51 DefaultAllocator: Allocator<DimNameSum<Const<N>, U1>, DimNameSum<Const<N>, U1>>,
52 DefaultAllocator: Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>,
53 <Const<N> as DimNameAdd<Const<1>>>::Output: DimNameSub<Const<1>>,
54 OVector<u32, <<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>: Copy,
55{
56 size: OVector<u32, <<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>,
57}
58
59impl<const N: usize> Default for RegionSize<N>
60where
61 Const<N>: DimNameAdd<U1>,
62 DefaultAllocator: Allocator<DimNameSum<Const<N>, U1>, DimNameSum<Const<N>, U1>>,
63 DefaultAllocator: Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>,
64 <Const<N> as DimNameAdd<Const<1>>>::Output: DimNameSub<Const<1>>,
65 OVector<u32, <<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>: Copy,
66{
67 fn default() -> Self {
68 Self {
69 size: OVector::<u32, <<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>::from_element(0)
70 }
71 }
72}
73
74impl<const N: usize> RegionSize<N>
77where
78 Const<N>: DimNameAdd<U1>,
79 DefaultAllocator: Allocator<DimNameSum<Const<N>, U1>, DimNameSum<Const<N>, U1>>,
80 DefaultAllocator: Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>,
81 <Const<N> as DimNameAdd<Const<1>>>::Output: DimNameSub<Const<1>>,
82 <DefaultAllocator as nalgebra::allocator::Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>>::Buffer<u32>: std::marker::Copy,
83{
84 pub fn screen_to_world(
88 &self,
89 ) -> OMatrix<
90 f32,
91 <Const<N> as DimNameAdd<Const<1>>>::Output,
92 <Const<N> as DimNameAdd<Const<1>>>::Output,
93 > {
94 let mut center = self.size.cast::<f32>() / 2.0;
95 center[1] -= 1.0;
96 let scale = 2.0 / self.size.min() as f32;
97
98 let mut out = OMatrix::<
99 f32,
100 <Const<N> as DimNameAdd<Const<1>>>::Output,
101 <Const<N> as DimNameAdd<Const<1>>>::Output,
102 >::identity();
103 out.append_translation_mut(&(-center));
104 let mut scale = OVector::<f32, _>::from_element(scale);
105 scale[1] *= -1.0;
106 out.append_nonuniform_scaling_mut(&scale);
107 out
108 }
109
110 pub fn width(&self) -> u32 {
112 self.size[0]
113 }
114
115 pub fn height(&self) -> u32 {
117 self.size[1]
118 }
119}
120
121impl<const N: usize> From<u32> for RegionSize<N>
123where
124 Const<N>: DimNameAdd<U1>,
125 DefaultAllocator: Allocator<DimNameSum<Const<N>, U1>, DimNameSum<Const<N>, U1>>,
126 DefaultAllocator: Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>,
127 <Const<N> as DimNameAdd<Const<1>>>::Output: DimNameSub<Const<1>>,
128 <DefaultAllocator as nalgebra::allocator::Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>>::Buffer<u32>: std::marker::Copy,
129{
130 fn from(v: u32) -> Self {
131 Self {
132 size: OVector::<
133 u32,
134 <<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<
135 Const<1>,
136 >>::Output,
137 >::from_element(v)
138 }
139 }
140}
141
142pub type ImageSize = RegionSize<2>;
144impl ImageSize {
145 pub fn new(width: u32, height: u32) -> Self {
147 Self {
148 size: Vector2::new(width, height),
149 }
150 }
151
152 pub fn transform_point(&self, p: Point2<i32>) -> Point2<f32> {
154 self.screen_to_world().transform_point(&p.cast())
155 }
156}
157
158pub type VoxelSize = RegionSize<3>;
160impl VoxelSize {
161 pub fn new(width: u32, height: u32, depth: u32) -> Self {
163 Self {
164 size: Vector3::new(width, height, depth),
165 }
166 }
167
168 pub fn depth(&self) -> u32 {
170 self.size.z
171 }
172
173 pub fn transform_point(&self, p: Point3<i32>) -> Point3<f32> {
175 self.screen_to_world().transform_point(&p.cast())
176 }
177}
178
179impl<const N: usize> std::ops::Index<usize> for RegionSize<N>
180where
181 Const<N>: DimNameAdd<U1>,
182 DefaultAllocator: Allocator<DimNameSum<Const<N>, U1>, DimNameSum<Const<N>, U1>>,
183 DefaultAllocator: Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>,
184 <Const<N> as DimNameAdd<Const<1>>>::Output: DimNameSub<Const<1>>,
185 OVector<u32, <<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>: Copy,
186{
187 type Output = u32;
188 fn index(&self, i: usize) -> &Self::Output {
189 &self.size[i]
190 }
191}
192
193#[cfg(test)]
194mod test {
195 use super::*;
196 use nalgebra::Point2;
197
198 #[test]
199 fn test_screen_size() {
200 let image_size = ImageSize::new(1000, 500);
201 let mat = image_size.screen_to_world();
202
203 let pt = mat.transform_point(&Point2::new(500.0, 249.0));
204 assert_eq!(pt.x, 0.0);
205 assert_eq!(pt.y, 0.0);
206
207 let pt = mat.transform_point(&Point2::new(500.0, -1.0));
208 assert_eq!(pt.x, 0.0);
209 assert_eq!(pt.y, 1.0);
210
211 let pt = mat.transform_point(&Point2::new(500.0, 499.0));
212 assert_eq!(pt.x, 0.0);
213 assert_eq!(pt.y, -1.0);
214
215 let pt = mat.transform_point(&Point2::new(0.0, 249.0));
216 assert_eq!(pt.x, -2.0);
217 assert_eq!(pt.y, 0.0);
218
219 let pt = mat.transform_point(&Point2::new(1000.0, 249.0));
220 assert_eq!(pt.x, 2.0);
221 assert_eq!(pt.y, 0.0);
222 }
223}