Unify flat coordinate system handling
This commit is contained in:
parent
64344659e3
commit
41448d2226
|
|
@ -3,7 +3,7 @@ use crate::riemann;
|
||||||
use crate::riemann::Metric;
|
use crate::riemann::Metric;
|
||||||
use Subspace::{Boundary, Inner, Outer};
|
use Subspace::{Boundary, Inner, Outer};
|
||||||
use metric::Tube;
|
use metric::Tube;
|
||||||
use coords::{MapperInner, MapperOuter};
|
use coords::{FlatCoordinateSystem, InnerCS, OuterCS};
|
||||||
use crate::types::{FlatTraceResult, Hit, Location, Object, Ray};
|
use crate::types::{FlatTraceResult, Hit, Location, Object, Ray};
|
||||||
|
|
||||||
pub mod metric;
|
pub mod metric;
|
||||||
|
|
@ -64,22 +64,24 @@ impl Space {
|
||||||
|
|
||||||
pub fn trace_inner(&self, ray: Ray) -> FlatTraceResult {
|
pub fn trace_inner(&self, ray: Ray) -> FlatTraceResult {
|
||||||
assert_eq!(self.which_subspace(ray.pos), Inner);
|
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 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));
|
assert!(inner.is_inside(ray.pos));
|
||||||
let dist = inner.trace_out_of(ray).expect("Can't get outta here!");
|
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 {
|
FlatTraceResult {
|
||||||
end: Some(self.tube.inner_to_global(ray.forward(dist))),
|
end: Some(cs.flat_to_global(ray.forward(dist))),
|
||||||
objects: Self::hit_objects(objs.as_slice(), ray, Some(dist), |pos| self.tube.inner_to_global(pos)),
|
objects: Self::hit_objects(objs.as_slice(), ray, Some(dist), |pos| cs.flat_to_global(pos)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace_outer(&self, ray: Ray) -> FlatTraceResult {
|
pub fn trace_outer(&self, ray: Ray) -> FlatTraceResult {
|
||||||
assert_eq!(self.which_subspace(ray.pos), Outer);
|
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 outer = Rect { size: vec2(self.tube.outer_radius, self.tube.external_halflength) };
|
||||||
let dist = outer.trace_into(ray);
|
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 {
|
FlatTraceResult {
|
||||||
end: dist.map(|dist| ray.forward(dist)),
|
end: dist.map(|dist| ray.forward(dist)),
|
||||||
objects: Self::hit_objects(objs.as_slice(), ray, dist, |pos| pos),
|
objects: Self::hit_objects(objs.as_slice(), ray, dist, |pos| pos),
|
||||||
|
|
@ -123,10 +125,11 @@ impl Space {
|
||||||
match self.which_subspace(a) {
|
match self.which_subspace(a) {
|
||||||
Outer => vec![b],
|
Outer => vec![b],
|
||||||
Inner => {
|
Inner => {
|
||||||
|
let cs = InnerCS(self.tube);
|
||||||
let n = ((b - a).length() / step) as usize + 1;
|
let n = ((b - a).length() / step) as usize + 1;
|
||||||
let a = self.tube.global_to_inner(a);
|
let a = cs.global_to_flat(a);
|
||||||
let b = self.tube.global_to_inner(b);
|
let b = cs.global_to_flat(b);
|
||||||
(1..=n).map(|k| self.tube.inner_to_global(a.lerp(b, k as f32 / n as f32))).collect()
|
(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!"),
|
Boundary => panic!("Can't draw a line here!"),
|
||||||
}
|
}
|
||||||
|
|
@ -200,70 +203,68 @@ mod coords {
|
||||||
use crate::types::{Location, Ray};
|
use crate::types::{Location, Ray};
|
||||||
use super::{Rect, Tube};
|
use super::{Rect, Tube};
|
||||||
|
|
||||||
pub trait MapperInner<T> {
|
pub trait FlatCoordinateSystem<T> {
|
||||||
fn inner_to_global(self, v: T) -> T;
|
fn flat_to_global(&self, v: T) -> T;
|
||||||
fn global_to_inner(self, v: T) -> T;
|
fn global_to_flat(&self, v: T) -> T;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MapperOuter<T> {
|
pub struct InnerCS(pub Tube);
|
||||||
fn outer_to_global(self, v: T) -> T;
|
|
||||||
fn global_to_outer(self, v: T) -> T;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MapperInner<Vec2> for Tube {
|
impl FlatCoordinateSystem<Vec2> for InnerCS {
|
||||||
fn inner_to_global(self, pos: Vec2) -> Vec2 {
|
fn flat_to_global(&self, pos: Vec2) -> Vec2 {
|
||||||
vec2(pos.x, self.y(pos.y))
|
vec2(pos.x, self.0.y(pos.y))
|
||||||
}
|
}
|
||||||
|
fn global_to_flat(&self, pos: Vec2) -> Vec2 {
|
||||||
fn global_to_inner(self, pos: Vec2) -> Vec2 {
|
vec2(pos.x, self.0.v(pos.y))
|
||||||
vec2(pos.x, self.v(pos.y))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapperInner<Ray> for Tube {
|
impl FlatCoordinateSystem<Ray> for InnerCS {
|
||||||
fn inner_to_global(self, ray: Ray) -> Ray {
|
fn flat_to_global(&self, ray: Ray) -> Ray {
|
||||||
Ray {
|
Ray {
|
||||||
pos: self.inner_to_global(ray.pos),
|
pos: self.flat_to_global(ray.pos),
|
||||||
dir: vec2(ray.dir.x, self.dy(ray.pos.y) * ray.dir.y),
|
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 {
|
Ray {
|
||||||
pos: self.global_to_inner(ray.pos),
|
pos: self.global_to_flat(ray.pos),
|
||||||
dir: vec2(ray.dir.x, self.dv(ray.pos.y) * ray.dir.y),
|
dir: vec2(ray.dir.x, self.0.dv(ray.pos.y) * ray.dir.y),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapperInner<Location> for Tube {
|
impl FlatCoordinateSystem<Location> for InnerCS {
|
||||||
fn inner_to_global(self, loc: Location) -> Location {
|
fn flat_to_global(&self, loc: Location) -> Location {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NB: не работает для частей Outer с |y| < external_halflength. Но они и не нужны.
|
// NB: не работает для частей Outer с |y| < external_halflength. Но они и не нужны.
|
||||||
fn global_to_inner(self, loc: Location) -> Location {
|
fn global_to_flat(&self, loc: Location) -> Location {
|
||||||
Location {
|
Location {
|
||||||
pos: vec2(loc.pos.x, self.v(loc.pos.y)), // в плоской СК для Inner или её продолжении на Outer
|
pos: vec2(loc.pos.x, self.0.v(loc.pos.y)), // в плоской СК для Inner или её продолжении на Outer
|
||||||
rot: Mat2::from(self.sqrt_at(loc.pos)) * loc.rot,
|
rot: Mat2::from(self.0.sqrt_at(loc.pos)) * loc.rot,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MapperOuter<Location> for Tube {
|
pub struct OuterCS(pub Tube);
|
||||||
fn outer_to_global(self, loc: Location) -> Location {
|
|
||||||
|
impl FlatCoordinateSystem<Location> for OuterCS {
|
||||||
|
fn flat_to_global(&self, loc: Location) -> Location {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NB: имеет разрыв в области Inner на y = 0.
|
// NB: имеет разрыв в области Inner на y = 0.
|
||||||
fn global_to_outer(self, loc: Location) -> Location {
|
fn global_to_flat(&self, loc: Location) -> Location {
|
||||||
let inner = Rect { size: vec2(self.inner_radius, self.external_halflength) };
|
let inner = Rect { size: vec2(self.0.inner_radius, self.0.external_halflength) };
|
||||||
if inner.is_inside(loc.pos) {
|
if inner.is_inside(loc.pos) {
|
||||||
let Vec2 { x: u, y } = 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 {
|
Location {
|
||||||
pos: vec2(u, v), // в плоском продолжении СК Outer на область Inner
|
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 {
|
} else {
|
||||||
loc
|
loc
|
||||||
|
|
@ -273,31 +274,31 @@ mod coords {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::{Location, Tube, MapperOuter};
|
use super::{Location, Tube, OuterCS, FlatCoordinateSystem};
|
||||||
use glam::{Mat2, vec2};
|
use glam::{Mat2, vec2};
|
||||||
use itertools_num::linspace;
|
use itertools_num::linspace;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mapper_outer() {
|
fn test_mapper_outer() {
|
||||||
let mapper = Tube {
|
let mapper = OuterCS(Tube {
|
||||||
inner_radius: 30.0,
|
inner_radius: 30.0,
|
||||||
outer_radius: 50.0,
|
outer_radius: 50.0,
|
||||||
internal_halflength: 100.0,
|
internal_halflength: 100.0,
|
||||||
external_halflength: 300.0,
|
external_halflength: 300.0,
|
||||||
};
|
});
|
||||||
// straight
|
// straight
|
||||||
for x in linspace(-60., 60., 20) {
|
for x in linspace(-60., 60., 20) {
|
||||||
for y in linspace(-320., 320., 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
|
// symmetrical
|
||||||
for x in linspace(0., 60., 20) {
|
for x in linspace(0., 60., 20) {
|
||||||
for y in linspace(0., 320., 20) {
|
for y in linspace(0., 320., 20) {
|
||||||
let pp = 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_outer(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_outer(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_outer(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!(np, vec2(-pp.x, pp.y));
|
||||||
assert_eq!(pn, vec2(pp.x, -pp.y));
|
assert_eq!(pn, vec2(pp.x, -pp.y));
|
||||||
assert_eq!(nn, vec2(-pp.x, -pp.y));
|
assert_eq!(nn, vec2(-pp.x, -pp.y));
|
||||||
|
|
@ -306,18 +307,18 @@ mod coords {
|
||||||
// clean boundary
|
// clean boundary
|
||||||
for x in linspace(50., 60., 20) {
|
for x in linspace(50., 60., 20) {
|
||||||
for y in linspace(0., 320., 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 x in linspace(0., 60., 20) {
|
||||||
for y in linspace(300., 320., 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
|
// accelerating
|
||||||
for x in linspace(-29., 29., 20) {
|
for x in linspace(-29., 29., 20) {
|
||||||
for y in linspace(1., 299., 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 > 200.0);
|
||||||
assert!(v > y);
|
assert!(v > y);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user