Remove single-implementation traits

This commit is contained in:
numzero 2024-06-25 13:20:52 +03:00
parent 0cddb8798d
commit 4caa260a34

View File

@ -3,7 +3,6 @@ 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 shape::Shape;
use crate::types::{FlatTraceResult, Hit, Location, Object, Ray}; use crate::types::{FlatTraceResult, Hit, Location, Object, Ray};
pub mod metric; pub mod metric;
@ -76,7 +75,7 @@ impl Space {
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 cell = basic_shapes::Rect { size: vec2(self.tube.outer_radius, self.tube.external_halflength) }; let cell = Rect { size: vec2(self.tube.outer_radius, self.tube.external_halflength) };
let objs = self.list_objects_outer(); let objs = self.list_objects_outer();
let lim = cell.trace_into(ray); let lim = cell.trace_into(ray);
let dist = lim.unwrap_or(f32::INFINITY); let dist = lim.unwrap_or(f32::INFINITY);
@ -163,107 +162,81 @@ impl Space {
} }
} }
mod basic_shapes { struct Rect {
use glam::{Vec2, vec2}; pub size: Vec2,
use crate::types::Ray; }
use super::shape::Shape;
pub struct Rect { impl Rect {
pub size: Vec2, /// Отражает луч, чтобы все координаты направления были положительны (допустимо благодаря симметрии Rect).
fn flip_ray(ray: Ray) -> Ray {
Ray { pos: ray.pos * ray.dir.signum(), dir: ray.dir.abs() }
} }
impl Rect { fn is_inside(&self, pt: Vec2) -> bool {
/// Отражает луч, чтобы все координаты направления были положительны (допустимо благодаря симметрии Rect). pt.abs().cmplt(self.size).all()
fn flip_ray(ray: Ray) -> Ray {
Ray { pos: ray.pos * ray.dir.signum(), dir: ray.dir.abs() }
}
} }
impl Shape for Rect { fn trace_into(&self, ray: Ray) -> Option<f32> {
fn is_inside(&self, pt: Vec2) -> bool { let ray = Self::flip_ray(ray);
pt.abs().cmplt(self.size).all() // ray.pos.x + t * ray.dir.x = size.x
} let ts = (-self.size - ray.pos) / ray.dir;
let t = ts.max_element();
fn trace_into(&self, ray: Ray) -> Option<f32> { let pt = ray.pos + t * ray.dir;
let ray = Self::flip_ray(ray); if t < 0.0 { return None; }
// ray.pos.x + t * ray.dir.x = size.x if pt.cmpgt(self.size).any() { return None; }
let ts = (-self.size - ray.pos) / ray.dir; Some(t)
let t = ts.max_element();
let pt = ray.pos + t * ray.dir;
if t < 0.0 { return None; }
if pt.cmpgt(self.size).any() { return None; }
Some(t)
}
fn trace_out_of(&self, ray: Ray) -> Option<f32> {
let ray = Self::flip_ray(ray);
// ray.pos.x + t * ray.dir.x = +size.x
let ts = (self.size - ray.pos) / ray.dir;
let t = ts.min_element();
Some(t)
}
fn visualise(&self) -> Vec<Vec2> {
vec![vec2(-self.size.x, -self.size.y), vec2(self.size.x, -self.size.y), vec2(self.size.x, self.size.y), vec2(-self.size.x, self.size.y)]
}
} }
#[test] fn trace_out_of(&self, ray: Ray) -> Option<f32> {
fn test_rect() { let ray = Self::flip_ray(ray);
assert_eq!(Rect::flip_ray(Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, 5.0) }), Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, 5.0) }); // ray.pos.x + t * ray.dir.x = +size.x
assert_eq!(Rect::flip_ray(Ray { pos: vec2(2.0, 3.0), dir: vec2(-4.0, 5.0) }), Ray { pos: vec2(-2.0, 3.0), dir: vec2(4.0, 5.0) }); let ts = (self.size - ray.pos) / ray.dir;
assert_eq!(Rect::flip_ray(Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, -5.0) }), Ray { pos: vec2(2.0, -3.0), dir: vec2(4.0, 5.0) }); let t = ts.min_element();
assert_eq!(Rect::flip_ray(Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, 0.0) }), Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, 0.0) }); Some(t)
}
let r = Rect { size: vec2(2.0, 3.0) }; fn visualise(&self) -> Vec<Vec2> {
vec![vec2(-self.size.x, -self.size.y), vec2(self.size.x, -self.size.y), vec2(self.size.x, self.size.y), vec2(-self.size.x, self.size.y)]
assert_eq!(r.trace_into(Ray { pos: vec2(3.0, 3.0), dir: vec2(1.0, 1.0) }), None);
assert_eq!(r.trace_into(Ray { pos: vec2(-3.0, 2.0), dir: vec2(1.0, 0.0) }), Some(1.0));
assert_eq!(r.trace_into(Ray { pos: vec2(-3.0, 2.0), dir: vec2(-1.0, 0.0) }), None);
assert_eq!(r.trace_into(Ray { pos: vec2(-3.0, 1.0), dir: vec2(2.0, 2.0) }), Some(0.5));
assert_eq!(r.trace_into(Ray { pos: vec2(-3.0, 2.1), dir: vec2(2.0, 2.0) }), None);
assert_eq!(r.trace_into(Ray { pos: vec2(2.0, 3.0), dir: vec2(1.0, 1.0) }), None);
assert_eq!(r.trace_into(Ray { pos: vec2(-2.0, 3.0), dir: vec2(-1.0, 1.0) }), None);
assert_eq!(r.trace_into(Ray { pos: vec2(2.0, 3.0), dir: vec2(-1.0, -1.0) }), Some(0.0));
assert_eq!(r.trace_into(Ray { pos: vec2(2.0, -3.0), dir: vec2(-1.0, 1.0) }), Some(0.0));
assert_eq!(r.trace_out_of(Ray { pos: vec2(0.0, 0.0), dir: vec2(1.0, 1.0) }), Some(2.0));
assert_eq!(r.trace_out_of(Ray { pos: vec2(0.0, 0.0), dir: vec2(0.0, 1.0) }), Some(3.0));
assert_eq!(r.trace_out_of(Ray { pos: vec2(0.0, 1.0), dir: vec2(0.0, -1.0) }), Some(4.0));
assert_eq!(r.trace_out_of(Ray { pos: vec2(1.0, 1.0), dir: vec2(0.0, -1.0) }), Some(4.0));
assert_eq!(r.trace_out_of(Ray { pos: vec2(2.0, 3.0), dir: vec2(1.0, 1.0) }), Some(0.0));
} }
} }
mod shape { #[test]
use glam::Vec2; fn test_rect() {
use crate::types::Ray; assert_eq!(Rect::flip_ray(Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, 5.0) }), Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, 5.0) });
assert_eq!(Rect::flip_ray(Ray { pos: vec2(2.0, 3.0), dir: vec2(-4.0, 5.0) }), Ray { pos: vec2(-2.0, 3.0), dir: vec2(4.0, 5.0) });
assert_eq!(Rect::flip_ray(Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, -5.0) }), Ray { pos: vec2(2.0, -3.0), dir: vec2(4.0, 5.0) });
assert_eq!(Rect::flip_ray(Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, 0.0) }), Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, 0.0) });
pub trait Shape { let r = Rect { size: vec2(2.0, 3.0) };
fn is_inside(&self, pt: Vec2) -> bool;
/// Ищет ближайшее пересечение луча с границей в направлении внутрь контура. Возвращает расстояние (в ray.dir). assert_eq!(r.trace_into(Ray { pos: vec2(3.0, 3.0), dir: vec2(1.0, 1.0) }), None);
fn trace_into(&self, ray: Ray) -> Option<f32>; assert_eq!(r.trace_into(Ray { pos: vec2(-3.0, 2.0), dir: vec2(1.0, 0.0) }), Some(1.0));
/// Ищет ближайшее пересечение луча с границей в направлении вовне контура. Возвращает расстояние (в ray.dir). assert_eq!(r.trace_into(Ray { pos: vec2(-3.0, 2.0), dir: vec2(-1.0, 0.0) }), None);
fn trace_out_of(&self, ray: Ray) -> Option<f32>; assert_eq!(r.trace_into(Ray { pos: vec2(-3.0, 1.0), dir: vec2(2.0, 2.0) }), Some(0.5));
assert_eq!(r.trace_into(Ray { pos: vec2(-3.0, 2.1), dir: vec2(2.0, 2.0) }), None);
/// Возвращает визуальное представление контура, для отладки. assert_eq!(r.trace_into(Ray { pos: vec2(2.0, 3.0), dir: vec2(1.0, 1.0) }), None);
fn visualise(&self) -> Vec<Vec2>; assert_eq!(r.trace_into(Ray { pos: vec2(-2.0, 3.0), dir: vec2(-1.0, 1.0) }), None);
} assert_eq!(r.trace_into(Ray { pos: vec2(2.0, 3.0), dir: vec2(-1.0, -1.0) }), Some(0.0));
assert_eq!(r.trace_into(Ray { pos: vec2(2.0, -3.0), dir: vec2(-1.0, 1.0) }), Some(0.0));
assert_eq!(r.trace_out_of(Ray { pos: vec2(0.0, 0.0), dir: vec2(1.0, 1.0) }), Some(2.0));
assert_eq!(r.trace_out_of(Ray { pos: vec2(0.0, 0.0), dir: vec2(0.0, 1.0) }), Some(3.0));
assert_eq!(r.trace_out_of(Ray { pos: vec2(0.0, 1.0), dir: vec2(0.0, -1.0) }), Some(4.0));
assert_eq!(r.trace_out_of(Ray { pos: vec2(1.0, 1.0), dir: vec2(0.0, -1.0) }), Some(4.0));
assert_eq!(r.trace_out_of(Ray { pos: vec2(2.0, 3.0), dir: vec2(1.0, 1.0) }), Some(0.0));
} }
trait FlatCell: std::fmt::Debug { #[derive(Debug)]
fn pos_to_global(&self, pos: Vec2) -> Vec2; struct TubeInside {
fn pos_to_local(&self, pos: Vec2) -> Vec2; tube: Tube,
fn ray_to_global(&self, ray: Ray) -> Ray; }
fn ray_to_local(&self, ray: Ray) -> Ray;
impl TubeInside {
fn is_inside(&self, pos: Vec2) -> bool { fn is_inside(&self, pos: Vec2) -> bool {
let bnd = self.local_bounds(); let bnd = self.local_bounds();
pos.cmpge(bnd.0).all() && pos.cmple(bnd.1).all() pos.cmpge(bnd.0).all() && pos.cmple(bnd.1).all()
} }
fn local_bounds(&self) -> (Vec2, Vec2);
fn to_boundary(&self, ray: Ray) -> Option<f32> { fn to_boundary(&self, ray: Ray) -> Option<f32> {
assert!(self.is_inside(ray.pos)); assert!(self.is_inside(ray.pos));
@ -288,14 +261,7 @@ trait FlatCell: std::fmt::Debug {
None None
} }
} }
}
#[derive(Debug)]
struct TubeInside {
tube: Tube,
}
impl FlatCell for TubeInside {
fn pos_to_global(&self, pos: Vec2) -> Vec2 { fn pos_to_global(&self, pos: Vec2) -> Vec2 {
vec2(pos.x, self.tube.y(pos.y)) vec2(pos.x, self.tube.y(pos.y))
} }