From 41448d2226d6c90fc62d755b192ab40b029c0a87 Mon Sep 17 00:00:00 2001 From: numzero Date: Fri, 28 Jun 2024 15:10:53 +0300 Subject: [PATCH] Unify flat coordinate system handling --- src/bin/flat/tube/mod.rs | 103 ++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/src/bin/flat/tube/mod.rs b/src/bin/flat/tube/mod.rs index 4e7b144..87341d4 100644 --- a/src/bin/flat/tube/mod.rs +++ b/src/bin/flat/tube/mod.rs @@ -3,7 +3,7 @@ use crate::riemann; use crate::riemann::Metric; use Subspace::{Boundary, Inner, Outer}; use metric::Tube; -use coords::{MapperInner, MapperOuter}; +use coords::{FlatCoordinateSystem, InnerCS, OuterCS}; use crate::types::{FlatTraceResult, Hit, Location, Object, Ray}; pub mod metric; @@ -64,22 +64,24 @@ impl Space { pub fn trace_inner(&self, ray: Ray) -> FlatTraceResult { assert_eq!(self.which_subspace(ray.pos), Inner); + let cs = InnerCS(self.tube); let inner = Rect { size: vec2(self.tube.inner_radius, self.tube.internal_halflength) }; - let ray = self.tube.global_to_inner(ray); + let ray = cs.global_to_flat(ray); assert!(inner.is_inside(ray.pos)); let dist = inner.trace_out_of(ray).expect("Can't get outta here!"); - let objs = self.list_objects(|loc| self.tube.global_to_inner(loc)); + let objs = self.list_objects(|loc| cs.global_to_flat(loc)); FlatTraceResult { - end: Some(self.tube.inner_to_global(ray.forward(dist))), - objects: Self::hit_objects(objs.as_slice(), ray, Some(dist), |pos| self.tube.inner_to_global(pos)), + end: Some(cs.flat_to_global(ray.forward(dist))), + objects: Self::hit_objects(objs.as_slice(), ray, Some(dist), |pos| cs.flat_to_global(pos)), } } pub fn trace_outer(&self, ray: Ray) -> FlatTraceResult { assert_eq!(self.which_subspace(ray.pos), Outer); + let cs = OuterCS(self.tube); let outer = Rect { size: vec2(self.tube.outer_radius, self.tube.external_halflength) }; let dist = outer.trace_into(ray); - let objs = self.list_objects(|loc| self.tube.global_to_outer(loc)); + let objs = self.list_objects(|loc| cs.global_to_flat(loc)); FlatTraceResult { end: dist.map(|dist| ray.forward(dist)), objects: Self::hit_objects(objs.as_slice(), ray, dist, |pos| pos), @@ -123,10 +125,11 @@ impl Space { match self.which_subspace(a) { Outer => vec![b], Inner => { + let cs = InnerCS(self.tube); let n = ((b - a).length() / step) as usize + 1; - let a = self.tube.global_to_inner(a); - let b = self.tube.global_to_inner(b); - (1..=n).map(|k| self.tube.inner_to_global(a.lerp(b, k as f32 / n as f32))).collect() + let a = cs.global_to_flat(a); + let b = cs.global_to_flat(b); + (1..=n).map(|k| cs.flat_to_global(a.lerp(b, k as f32 / n as f32))).collect() } Boundary => panic!("Can't draw a line here!"), } @@ -200,70 +203,68 @@ mod coords { use crate::types::{Location, Ray}; use super::{Rect, Tube}; - pub trait MapperInner { - fn inner_to_global(self, v: T) -> T; - fn global_to_inner(self, v: T) -> T; + pub trait FlatCoordinateSystem { + fn flat_to_global(&self, v: T) -> T; + fn global_to_flat(&self, v: T) -> T; } - pub trait MapperOuter { - fn outer_to_global(self, v: T) -> T; - fn global_to_outer(self, v: T) -> T; - } + pub struct InnerCS(pub Tube); - impl MapperInner for Tube { - fn inner_to_global(self, pos: Vec2) -> Vec2 { - vec2(pos.x, self.y(pos.y)) + impl FlatCoordinateSystem for InnerCS { + fn flat_to_global(&self, pos: Vec2) -> Vec2 { + vec2(pos.x, self.0.y(pos.y)) } - - fn global_to_inner(self, pos: Vec2) -> Vec2 { - vec2(pos.x, self.v(pos.y)) + fn global_to_flat(&self, pos: Vec2) -> Vec2 { + vec2(pos.x, self.0.v(pos.y)) } } - impl MapperInner for Tube { - fn inner_to_global(self, ray: Ray) -> Ray { + impl FlatCoordinateSystem for InnerCS { + fn flat_to_global(&self, ray: Ray) -> Ray { Ray { - pos: self.inner_to_global(ray.pos), - dir: vec2(ray.dir.x, self.dy(ray.pos.y) * ray.dir.y), + pos: self.flat_to_global(ray.pos), + dir: vec2(ray.dir.x, self.0.dy(ray.pos.y) * ray.dir.y), } } - fn global_to_inner(self, ray: Ray) -> Ray { + fn global_to_flat(&self, ray: Ray) -> Ray { Ray { - pos: self.global_to_inner(ray.pos), - dir: vec2(ray.dir.x, self.dv(ray.pos.y) * ray.dir.y), + pos: self.global_to_flat(ray.pos), + dir: vec2(ray.dir.x, self.0.dv(ray.pos.y) * ray.dir.y), } } } - impl MapperInner for Tube { - fn inner_to_global(self, loc: Location) -> Location { + impl FlatCoordinateSystem for InnerCS { + fn flat_to_global(&self, loc: Location) -> Location { todo!() } // NB: не работает для частей Outer с |y| < external_halflength. Но они и не нужны. - fn global_to_inner(self, loc: Location) -> Location { + fn global_to_flat(&self, loc: Location) -> Location { Location { - pos: vec2(loc.pos.x, self.v(loc.pos.y)), // в плоской СК для Inner или её продолжении на Outer - rot: Mat2::from(self.sqrt_at(loc.pos)) * loc.rot, + pos: vec2(loc.pos.x, self.0.v(loc.pos.y)), // в плоской СК для Inner или её продолжении на Outer + rot: Mat2::from(self.0.sqrt_at(loc.pos)) * loc.rot, } } } - impl MapperOuter for Tube { - fn outer_to_global(self, loc: Location) -> Location { + pub struct OuterCS(pub Tube); + + impl FlatCoordinateSystem for OuterCS { + fn flat_to_global(&self, loc: Location) -> Location { todo!() } // NB: имеет разрыв в области Inner на y = 0. - fn global_to_outer(self, loc: Location) -> Location { - let inner = Rect { size: vec2(self.inner_radius, self.external_halflength) }; + fn global_to_flat(&self, loc: Location) -> Location { + let inner = Rect { size: vec2(self.0.inner_radius, self.0.external_halflength) }; if inner.is_inside(loc.pos) { let Vec2 { x: u, y } = loc.pos; // в основной СК - let v = self.v(y) + y.signum() * (self.external_halflength - self.internal_halflength); + let v = self.0.v(y) + y.signum() * (self.0.external_halflength - self.0.internal_halflength); Location { pos: vec2(u, v), // в плоском продолжении СК Outer на область Inner - rot: Mat2::from(self.sqrt_at(loc.pos)) * loc.rot, + rot: Mat2::from(self.0.sqrt_at(loc.pos)) * loc.rot, } } else { loc @@ -273,31 +274,31 @@ mod coords { #[cfg(test)] mod test { - use super::{Location, Tube, MapperOuter}; + use super::{Location, Tube, OuterCS, FlatCoordinateSystem}; use glam::{Mat2, vec2}; use itertools_num::linspace; #[test] fn test_mapper_outer() { - let mapper = Tube { + let mapper = OuterCS(Tube { inner_radius: 30.0, outer_radius: 50.0, internal_halflength: 100.0, external_halflength: 300.0, - }; + }); // straight for x in linspace(-60., 60., 20) { for y in linspace(-320., 320., 20) { - assert_eq!(mapper.global_to_outer(Location { pos: vec2(x, y), rot: Mat2::IDENTITY }).pos.x, x); + assert_eq!(mapper.global_to_flat(Location { pos: vec2(x, y), rot: Mat2::IDENTITY }).pos.x, x); } } // symmetrical for x in linspace(0., 60., 20) { for y in linspace(0., 320., 20) { - let pp = mapper.global_to_outer(Location { pos: vec2(x, y), rot: Mat2::IDENTITY }).pos; - let np = mapper.global_to_outer(Location { pos: vec2(-x, y), rot: Mat2::IDENTITY }).pos; - let pn = mapper.global_to_outer(Location { pos: vec2(x, -y), rot: Mat2::IDENTITY }).pos; - let nn = mapper.global_to_outer(Location { pos: vec2(-x, -y), rot: Mat2::IDENTITY }).pos; + let pp = mapper.global_to_flat(Location { pos: vec2(x, y), rot: Mat2::IDENTITY }).pos; + let np = mapper.global_to_flat(Location { pos: vec2(-x, y), rot: Mat2::IDENTITY }).pos; + let pn = mapper.global_to_flat(Location { pos: vec2(x, -y), rot: Mat2::IDENTITY }).pos; + let nn = mapper.global_to_flat(Location { pos: vec2(-x, -y), rot: Mat2::IDENTITY }).pos; assert_eq!(np, vec2(-pp.x, pp.y)); assert_eq!(pn, vec2(pp.x, -pp.y)); assert_eq!(nn, vec2(-pp.x, -pp.y)); @@ -306,18 +307,18 @@ mod coords { // clean boundary for x in linspace(50., 60., 20) { for y in linspace(0., 320., 20) { - assert_eq!(mapper.global_to_outer(Location { pos: vec2(x, y), rot: Mat2::IDENTITY }).pos.y, y); + assert_eq!(mapper.global_to_flat(Location { pos: vec2(x, y), rot: Mat2::IDENTITY }).pos.y, y); } } for x in linspace(0., 60., 20) { for y in linspace(300., 320., 20) { - assert_eq!(mapper.global_to_outer(Location { pos: vec2(x, y), rot: Mat2::IDENTITY }).pos.y, y); + assert_eq!(mapper.global_to_flat(Location { pos: vec2(x, y), rot: Mat2::IDENTITY }).pos.y, y); } } // accelerating for x in linspace(-29., 29., 20) { for y in linspace(1., 299., 20) { - let v = mapper.global_to_outer(Location { pos: vec2(x, y), rot: Mat2::IDENTITY }).pos.y; + let v = mapper.global_to_flat(Location { pos: vec2(x, y), rot: Mat2::IDENTITY }).pos.y; assert!(v > 200.0); assert!(v > y); }