From 577babdd916b78f6589e79e4937f8f182d68f77b Mon Sep 17 00:00:00 2001 From: numzero Date: Mon, 6 May 2024 14:01:37 +0300 Subject: [PATCH] Segmented space This code works but boy it is ugly... --- src/bin/flat.rs | 191 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 183 insertions(+), 8 deletions(-) diff --git a/src/bin/flat.rs b/src/bin/flat.rs index 58bfc74..1b9c7c3 100644 --- a/src/bin/flat.rs +++ b/src/bin/flat.rs @@ -1,7 +1,9 @@ +use std::rc::Rc; use flo_draw::*; use flo_canvas::*; use glam::*; use riemann::{Decomp2, Metric, trace_iter}; +use crate::boundary::Loop; pub fn main() { let space = Coil { @@ -20,10 +22,88 @@ pub fn main() { canvas.draw(|gc| { gc.canvas_height(1000.0); space.render(gc); + + let space = Rc::new(space); + let parts: Vec> = vec![ + Box::new(Outside { space: space.clone() }), + Box::new(Wall { space: space.clone() }), + Box::new(Inside { space: space.clone() }), + ]; + + gc.new_path(); + let dt = 1.0; + let mut s = boundary::Id(0); + let mut p = vec2(-500.0, 0.0); + let mut v = vec2(3.0, 1.0).normalize(); + let part = &*parts[s.0 as usize]; + gc.stroke_color(part.color()); + gc.move_to(p.x, p.y); + for _ in 0..10000 { + let part = &*parts[s.0 as usize]; + let a: Vec2 = -riemann::convolute(riemann::krist(part, p), v); + v = v + a * dt; + if let Some((id, base, dir)) = part.next(p, v, dt) { + gc.stroke(); + gc.new_path(); + let pt = part.globalize_loc(p); + gc.move_to(pt.x, pt.y); + s = id; + p = base; + v = dir; + let part = &*parts[s.0 as usize]; + let pt = part.globalize_loc(p); + gc.stroke_color(part.color()); + gc.line_to(pt.x, pt.y); + } else { + p = p + v * dt; + let pt = part.globalize_loc(p); + gc.line_to(pt.x, pt.y); + } + } + gc.stroke(); }); }); } +trait SpacePart: boundary::Boundary + Metric + SpaceVisual {} + +impl SpacePart for T {} + +trait SpaceVisual { + fn color(&self) -> Color; + fn globalize_loc(&self, pos: Vec2) -> Vec2; +} + +impl SpaceVisual for Outside { + fn color(&self) -> Color { + Color::Rgba(0.7, 0.7, 0.7, 1.0) + } + + fn globalize_loc(&self, pos: Vec2) -> Vec2 { + pos + } +} + +impl SpaceVisual for Wall { + fn color(&self) -> Color { + Color::Rgba(1.0, 0.0, 0.0, 1.0) + } + + fn globalize_loc(&self, pos: Vec2) -> Vec2 { + pos + } +} + +impl SpaceVisual for Inside { + fn color(&self) -> Color { + Color::Rgba(0.0, 0.7, 0.0, 1.0) + } + + fn globalize_loc(&self, pos: Vec2) -> Vec2 { + vec2(pos.x, pos.y * self.space.scale) + } +} + fn draw_ray(gc: &mut Vec, space: &impl Metric, base: Vec2, dir: Vec2) { let dir = space.globalize(base, dir); gc.new_path(); @@ -124,19 +204,113 @@ impl Metric for Rect { } } +struct Flat; + +impl Metric for Flat { + fn halfmetric(&self, pos: Vec2) -> Decomp2 { + Decomp2 { + ortho: Mat2::IDENTITY, + diag: Vec2::splat(1.0), + } + } +} + +struct Outside { + space: Rc, +} + +struct Wall { + space: Rc, +} + +struct Inside { + space: Rc, +} + +impl boundary::Boundary for Outside { + fn next(&self, base: Vec2, dir: Vec2, limit: f32) -> Option<(boundary::Id, Vec2, Vec2)> { + let size = self.space.r + self.space.m; + let bnd = Loop(vec![vec2(-size.x, -size.y), vec2(size.x, -size.y), vec2(size.x, size.y), vec2(-size.x, size.y)]); + let (_, dist) = bnd.hit(base, dir)?; + if dist <= limit { + return Some((boundary::Id(1), base + dist * dir, dir)); + } + None + } +} + +impl Metric for Outside { + fn halfmetric(&self, pos: Vec2) -> Decomp2 { + Flat {}.halfmetric(pos) + } +} + +impl boundary::Boundary for Wall { + fn next(&self, base: Vec2, dir: Vec2, limit: f32) -> Option<(boundary::Id, Vec2, Vec2)> { + let osize = self.space.r + self.space.m; + let isize = self.space.r; + let obnd = Loop(vec![vec2(-osize.x, -osize.y), vec2(-osize.x, osize.y), vec2(osize.x, osize.y), vec2(osize.x, -osize.y)]); + let ibnd = Loop(vec![vec2(-isize.x, -isize.y), vec2(isize.x, -isize.y), vec2(isize.x, isize.y), vec2(-isize.x, isize.y)]); + if let Some((_, dist)) = ibnd.hit(base, dir) { + if dist <= limit { + let p = base + dist * dir; + let v = dir; + let p = vec2(p.x, p.y / self.space.scale); + let v = vec2(v.x, v.y / self.space.scale); + return Some((boundary::Id(2), p, v)); + } + } + if let Some((_, dist)) = obnd.hit(base, dir) { + if dist <= limit { + return Some((boundary::Id(0), base + dist * dir, dir)); + } + } + None + } +} + +impl Metric for Wall { + fn halfmetric(&self, pos: Vec2) -> Decomp2 { + self.space.halfmetric(pos) + } +} + +impl boundary::Boundary for Inside { + fn next(&self, base: Vec2, dir: Vec2, limit: f32) -> Option<(boundary::Id, Vec2, Vec2)> { + let size = self.space.r; + let size = vec2(size.x, size.y / self.space.scale); + let bnd = Loop(vec![vec2(-size.x, -size.y), vec2(-size.x, size.y), vec2(size.x, size.y), vec2(size.x, -size.y)]); + let (_, dist) = bnd.hit(base, dir)?; + if dist <= limit { + let p = base + dist * dir; + let v = dir; + let p = vec2(p.x, p.y * self.space.scale); + let v = vec2(v.x, v.y * self.space.scale); + return Some((boundary::Id(1), p, v)); + } + None + } +} + +impl Metric for Inside { + fn halfmetric(&self, pos: Vec2) -> Decomp2 { + Flat {}.halfmetric(pos) + } +} + mod boundary { use glam::*; - struct Id(u8); + pub struct Id(pub u8); - trait Boundary { + pub trait Boundary { fn next(&self, base: Vec2, dir: Vec2, limit: f32) -> Option<(Id, Vec2, Vec2)>; } - struct Loop(Vec); + pub struct Loop(pub Vec); impl Loop { - fn hit(&self, base: Vec2, dir: Vec2) -> Option<(usize, f32)> { + pub fn hit(&self, base: Vec2, dir: Vec2) -> Option<(usize, f32)> { self.0.iter().enumerate().filter_map(|(k, &a)| { let b = self.0[(k + 1) % self.0.len()]; let u = mat2(a - base, dir).determinant(); @@ -251,9 +425,9 @@ mod riemann { } } - fn krist(space: &impl Metric, pos: Vec2) -> Tens2 { + pub fn krist(space: &(impl Metric + ?Sized), pos: Vec2) -> Tens2 { // Γ^i_k_l = .5 * g^i^m * (g_m_k,l + g_m_l,k - g_k_l,m) - let g = &space.invmetric(pos); // с верхними индексами + let g = space.invmetric(pos); // с верхними индексами let d = space.dmetric(pos); // ret[i][l][k] = sum((m) => .5f * g[m][i] * (d[k][l][m] + d[l][k][m] - d[m][k][l])) make_tens2(|i, l, k| 0.5 * (0..2).map(|m| g.col(m)[i] * (d[l].col(k)[m] + d[k].col(m)[l] - d[m].col(k)[l])).sum::()) @@ -270,7 +444,7 @@ mod riemann { ] } - fn convolute(t: Tens2, v: Vec2) -> Vec2 { + pub fn convolute(t: Tens2, v: Vec2) -> Vec2 { vec2( v.dot(t[0] * v), v.dot(t[1] * v), @@ -313,9 +487,10 @@ mod riemann { } fn smoothstep(x: f32) -> f32 { - return 3.0 * x * x - 2.0 * x * x * x; + 3.0 * x * x - 2.0 * x * x * x } +/// 1.0 for val∈[range.x, range.y], 0.0 for val∉[range.x−pad, range.y+pad], smoothstep in-between. fn smoothbox(val: f32, range: Vec2, pad: f32) -> f32 { let slope1 = 1.0 + (val - range.x) / pad; let slope2 = 1.0 - (val - range.y) / pad;