use nalgebra::{
Const, DefaultAllocator, DimNameAdd, DimNameSub, DimNameSum, OMatrix,
OVector, Point2, Point3, U1, Vector2, Vector3, allocator::Allocator,
};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct RegionSize<const N: usize>
where
Const<N>: DimNameAdd<U1>,
DefaultAllocator: Allocator<DimNameSum<Const<N>, U1>, DimNameSum<Const<N>, U1>>,
DefaultAllocator: Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>,
<Const<N> as DimNameAdd<Const<1>>>::Output: DimNameSub<Const<1>>,
OVector<u32, <<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>: Copy,
{
size: OVector<u32, <<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>,
}
impl<const N: usize> Default for RegionSize<N>
where
Const<N>: DimNameAdd<U1>,
DefaultAllocator: Allocator<DimNameSum<Const<N>, U1>, DimNameSum<Const<N>, U1>>,
DefaultAllocator: Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>,
<Const<N> as DimNameAdd<Const<1>>>::Output: DimNameSub<Const<1>>,
OVector<u32, <<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>: Copy,
{
fn default() -> Self {
Self {
size: OVector::<u32, <<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>::from_element(0)
}
}
}
impl<const N: usize> RegionSize<N>
where
Const<N>: DimNameAdd<U1>,
DefaultAllocator: Allocator<DimNameSum<Const<N>, U1>, DimNameSum<Const<N>, U1>>,
DefaultAllocator: Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>,
<Const<N> as DimNameAdd<Const<1>>>::Output: DimNameSub<Const<1>>,
<DefaultAllocator as nalgebra::allocator::Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>>::Buffer<u32>: std::marker::Copy,
{
pub fn screen_to_world(
&self,
) -> OMatrix<
f32,
<Const<N> as DimNameAdd<Const<1>>>::Output,
<Const<N> as DimNameAdd<Const<1>>>::Output,
> {
let mut center = self.size.cast::<f32>() / 2.0;
center[1] -= 1.0;
let scale = 2.0 / self.size.min() as f32;
let mut out = OMatrix::<
f32,
<Const<N> as DimNameAdd<Const<1>>>::Output,
<Const<N> as DimNameAdd<Const<1>>>::Output,
>::identity();
out.append_translation_mut(&(-center));
let mut scale = OVector::<f32, _>::from_element(scale);
scale[1] *= -1.0;
out.append_nonuniform_scaling_mut(&scale);
out
}
pub fn width(&self) -> u32 {
self.size[0]
}
pub fn height(&self) -> u32 {
self.size[1]
}
}
impl<const N: usize> From<u32> for RegionSize<N>
where
Const<N>: DimNameAdd<U1>,
DefaultAllocator: Allocator<DimNameSum<Const<N>, U1>, DimNameSum<Const<N>, U1>>,
DefaultAllocator: Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>,
<Const<N> as DimNameAdd<Const<1>>>::Output: DimNameSub<Const<1>>,
<DefaultAllocator as nalgebra::allocator::Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>>::Buffer<u32>: std::marker::Copy,
{
fn from(v: u32) -> Self {
Self {
size: OVector::<
u32,
<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<
Const<1>,
>>::Output,
>::from_element(v)
}
}
}
pub type ImageSize = RegionSize<2>;
impl ImageSize {
pub fn new(width: u32, height: u32) -> Self {
Self {
size: Vector2::new(width, height),
}
}
pub fn transform_point(&self, p: Point2<i32>) -> Point2<f32> {
self.screen_to_world().transform_point(&p.cast())
}
}
pub type VoxelSize = RegionSize<3>;
impl VoxelSize {
pub fn new(width: u32, height: u32, depth: u32) -> Self {
Self {
size: Vector3::new(width, height, depth),
}
}
pub fn depth(&self) -> u32 {
self.size.z
}
pub fn transform_point(&self, p: Point3<i32>) -> Point3<f32> {
self.screen_to_world().transform_point(&p.cast())
}
}
impl<const N: usize> std::ops::Index<usize> for RegionSize<N>
where
Const<N>: DimNameAdd<U1>,
DefaultAllocator: Allocator<DimNameSum<Const<N>, U1>, DimNameSum<Const<N>, U1>>,
DefaultAllocator: Allocator<<<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>,
<Const<N> as DimNameAdd<Const<1>>>::Output: DimNameSub<Const<1>>,
OVector<u32, <<Const<N> as DimNameAdd<Const<1>>>::Output as DimNameSub<Const<1>>>::Output>: Copy,
{
type Output = u32;
fn index(&self, i: usize) -> &Self::Output {
&self.size[i]
}
}
#[cfg(test)]
mod test {
use super::*;
use nalgebra::Point2;
#[test]
fn test_screen_size() {
let image_size = ImageSize::new(1000, 500);
let mat = image_size.screen_to_world();
let pt = mat.transform_point(&Point2::new(500.0, 249.0));
assert_eq!(pt.x, 0.0);
assert_eq!(pt.y, 0.0);
let pt = mat.transform_point(&Point2::new(500.0, -1.0));
assert_eq!(pt.x, 0.0);
assert_eq!(pt.y, 1.0);
let pt = mat.transform_point(&Point2::new(500.0, 499.0));
assert_eq!(pt.x, 0.0);
assert_eq!(pt.y, -1.0);
let pt = mat.transform_point(&Point2::new(0.0, 249.0));
assert_eq!(pt.x, -2.0);
assert_eq!(pt.y, 0.0);
let pt = mat.transform_point(&Point2::new(1000.0, 249.0));
assert_eq!(pt.x, 2.0);
assert_eq!(pt.y, 0.0);
}
}