Segmented space
This code works but boy it is ugly...
This commit is contained in:
parent
bcae0a4435
commit
577babdd91
191
src/bin/flat.rs
191
src/bin/flat.rs
|
|
@ -1,7 +1,9 @@
|
||||||
|
use std::rc::Rc;
|
||||||
use flo_draw::*;
|
use flo_draw::*;
|
||||||
use flo_canvas::*;
|
use flo_canvas::*;
|
||||||
use glam::*;
|
use glam::*;
|
||||||
use riemann::{Decomp2, Metric, trace_iter};
|
use riemann::{Decomp2, Metric, trace_iter};
|
||||||
|
use crate::boundary::Loop;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let space = Coil {
|
let space = Coil {
|
||||||
|
|
@ -20,10 +22,88 @@ pub fn main() {
|
||||||
canvas.draw(|gc| {
|
canvas.draw(|gc| {
|
||||||
gc.canvas_height(1000.0);
|
gc.canvas_height(1000.0);
|
||||||
space.render(gc);
|
space.render(gc);
|
||||||
|
|
||||||
|
let space = Rc::new(space);
|
||||||
|
let parts: Vec<Box<dyn SpacePart>> = 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<T: boundary::Boundary + Metric + SpaceVisual> 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<Draw>, space: &impl Metric, base: Vec2, dir: Vec2) {
|
fn draw_ray(gc: &mut Vec<Draw>, space: &impl Metric, base: Vec2, dir: Vec2) {
|
||||||
let dir = space.globalize(base, dir);
|
let dir = space.globalize(base, dir);
|
||||||
gc.new_path();
|
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<Rect>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Wall {
|
||||||
|
space: Rc<Rect>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Inside {
|
||||||
|
space: Rc<Rect>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
mod boundary {
|
||||||
use glam::*;
|
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)>;
|
fn next(&self, base: Vec2, dir: Vec2, limit: f32) -> Option<(Id, Vec2, Vec2)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Loop(Vec<Vec2>);
|
pub struct Loop(pub Vec<Vec2>);
|
||||||
|
|
||||||
impl Loop {
|
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)| {
|
self.0.iter().enumerate().filter_map(|(k, &a)| {
|
||||||
let b = self.0[(k + 1) % self.0.len()];
|
let b = self.0[(k + 1) % self.0.len()];
|
||||||
let u = mat2(a - base, dir).determinant();
|
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)
|
// Γ^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);
|
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]))
|
// 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::<f32>())
|
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::<f32>())
|
||||||
|
|
@ -270,7 +444,7 @@ mod riemann {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convolute(t: Tens2, v: Vec2) -> Vec2 {
|
pub fn convolute(t: Tens2, v: Vec2) -> Vec2 {
|
||||||
vec2(
|
vec2(
|
||||||
v.dot(t[0] * v),
|
v.dot(t[0] * v),
|
||||||
v.dot(t[1] * v),
|
v.dot(t[1] * v),
|
||||||
|
|
@ -313,9 +487,10 @@ mod riemann {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn smoothstep(x: f32) -> f32 {
|
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 {
|
fn smoothbox(val: f32, range: Vec2, pad: f32) -> f32 {
|
||||||
let slope1 = 1.0 + (val - range.x) / pad;
|
let slope1 = 1.0 + (val - range.x) / pad;
|
||||||
let slope2 = 1.0 - (val - range.y) / pad;
|
let slope2 = 1.0 - (val - range.y) / pad;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user