From 6f77a31727875fc447eda52faaf24cb13f2b1566 Mon Sep 17 00:00:00 2001 From: numzero Date: Fri, 10 May 2024 15:46:49 +0300 Subject: [PATCH] Areaed! --- src/bin/flat.rs | 224 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 203 insertions(+), 21 deletions(-) diff --git a/src/bin/flat.rs b/src/bin/flat.rs index 57e56d0..aad0287 100644 --- a/src/bin/flat.rs +++ b/src/bin/flat.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use flo_draw::*; use flo_canvas::*; use glam::*; @@ -6,33 +7,147 @@ use riemann::{Decomp2, Metric, trace_iter}; #[cfg(test)] use approx::assert_abs_diff_eq; +const DT: f32 = 0.1; + pub fn main() { - let space = Coil { - scale: 3.0, - r: 300.0, - w: 50.0, - m: 10.0, - }; - let space = Rect { - inner_radius: 30.0, - outer_radius: 50.0, - internal_halflength: 100.0, - external_halflength: 300.0, - }; with_2d_graphics(move || { let canvas = create_drawing_window("Refraction"); canvas.draw(|gc| { + let space = Coil { + scale: 3.0, + r: 300.0, + w: 50.0, + m: 10.0, + }; + let tube = Rect { + inner_radius: 30.0, + outer_radius: 50.0, + internal_halflength: 100.0, + external_halflength: 300.0, + }; + let mut grid = Grid { + hlines: vec![-tube.external_halflength, tube.external_halflength], + vlines: vec![-tube.outer_radius, -tube.inner_radius, tube.inner_radius, tube.outer_radius], + cells: HashMap::new(), + }; + fn take(k: i32, data: &[f32]) -> f32 { + if k < 0 { + -f32::INFINITY + } else if k as usize >= data.len() { + f32::INFINITY + } else { + data[k as usize] + } + } + for (i, j) in [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (0, 1), (4, 1), (0, 2), (1, 2), (2, 2), (3, 2), (4, 2)] { + grid.cells.insert((i as usize, j as usize), + Box::new(FlatRect { + min: vec2(take(i - 1, grid.vlines.as_slice()), take(j - 1, grid.hlines.as_slice())), + max: vec2(take(i, grid.vlines.as_slice()), take(j, grid.hlines.as_slice())), + })); + } + grid.cells.insert((2, 1), Box::new(RectInside { rect: tube })); + println!("{:?}", grid.cells); gc.canvas_height(1000.0); - space.render(gc); + tube.render(gc); + gc.line_width(0.5); + gc.stroke_color(Color::Rgba(1.0, 0.5, 0.0, 0.5)); + draw_fan(gc, &tube, vec2(-500.0, 0.0), vec2(1.0, 0.0), 1.0); + gc.stroke_color(Color::Rgba(1.0, 0.5, 0.0, 1.0)); + draw_fan_2(gc, &tube, &grid, vec2(-500.0, 0.0), vec2(1.0, 0.0), 1.0); + gc.stroke_color(Color::Rgba(0.0, 0.5, 1.0, 0.5)); + draw_fan(gc, &tube, vec2(0.0, -0.5 * tube.internal_halflength), vec2(1.0, 1.0), 1.0); + gc.stroke_color(Color::Rgba(0.0, 0.5, 1.0, 1.0)); + draw_fan_2(gc, &tube, &grid, vec2(0.0, -0.5 * tube.internal_halflength), vec2(1.0, 1.0), 1.0); + + gc.new_path(); + for ((i, j), cell) in &grid.cells { + let (a, b) = cell.local_bounds(); + gc.rect(a.x.clamp(-1000.0, 1000.0), a.y.clamp(-1000.0, 1000.0), b.x.clamp(-1000.0, 1000.0), b.y.clamp(-1000.0, 1000.0)); + } + gc.fill_color(Color::Rgba(0.0, 1.0, 0.0, 0.3)); + gc.fill(); + + gc.new_dash_pattern(); + gc.dash_length(6.0); + gc.new_dash_pattern(); + gc.new_path(); + gc.stroke_color(Color::Rgba(0.0, 0.0, 0.0, 0.5)); + gc.line_width(1.0); + for hline in grid.hlines { + gc.move_to(-1000.0, hline); + gc.line_to(1000.0, hline); + } + for vline in grid.vlines { + gc.move_to(vline, -1000.0); + gc.line_to(vline, 1000.0); + } + gc.stroke(); }); }); } +fn find_bucket(val: f32, splits: &[f32]) -> usize { + for (k, &split) in splits.iter().enumerate() { + if val < split { + return k; + } + } + splits.len() +} + +fn draw_ray_2(gc: &mut Vec, space: &impl Metric, grid: &Grid, base: Vec2, dir: Vec2) { + let dir = space.globalize(base, dir); + gc.new_path(); + gc.move_to(base.x, base.y); + let dt = DT; + let mut p = base; + let mut v = space.normalize(base, dir); + for _ in 0..10000 { + let a: Vec2 = -riemann::convolute(riemann::krist(space, p), v); + v = v + a * dt; + p = p + v * dt; + gc.line_to(p.x, p.y); + if p.abs().cmpgt(Vec2::splat(1000.0)).any() { + break; + } + let i = find_bucket(p.x, grid.vlines.as_slice()); + let j = find_bucket(p.y, grid.hlines.as_slice()); + if let Some(cell) = grid.cells.get(&(i, j)) { + gc.stroke(); + gc.new_dash_pattern(); + gc.dash_length(6.0); + gc.new_path(); + gc.move_to(p.x, p.y); + let mut ray = cell.ray_to_local(Ray { pos: p, dir: v }); + while cell.is_inside(ray.pos) && !ray.pos.abs().cmpgt(Vec2::splat(1000.0)).any() { + ray = Ray { pos: ray.pos + ray.dir * dt, dir: ray.dir }; + p = cell.pos_to_global(ray.pos); + gc.line_to(p.x, p.y); + } + Ray { pos: p, dir: v } = cell.ray_to_global(ray); + gc.stroke(); + gc.new_dash_pattern(); + gc.new_path(); + gc.move_to(p.x, p.y); + } + } + gc.stroke(); +} + +fn draw_fan_2(gc: &mut Vec, space: &impl Metric, grid: &Grid, base: Vec2, dir: Vec2, spread: f32) { + let dir = dir.normalize(); + let v = vec2(-dir.y, dir.x); + for y in itertools_num::linspace(-spread, spread, 101) { + draw_ray_2(gc, space, grid, base, dir + y * v); + } +} + fn draw_ray(gc: &mut Vec, space: &impl Metric, base: Vec2, dir: Vec2) { let dir = space.globalize(base, dir); gc.new_path(); gc.move_to(base.x, base.y); - for pt in trace_iter(space, base, dir, 1.0).take(10000) { + for pt in trace_iter(space, base, dir, DT).take(10000) { gc.line_to(pt.x, pt.y); if pt.abs().cmpgt(Vec2::splat(1000.0)).any() { break; @@ -79,11 +194,6 @@ impl Renderable for Rect { gc.winding_rule(WindingRule::EvenOdd); gc.fill_color(Color::Rgba(0.8, 0.8, 0.8, 1.0)); gc.fill(); - gc.line_width(0.5); - gc.stroke_color(Color::Rgba(1.0, 0.5, 0.0, 1.0)); - draw_fan(gc, self, vec2(-500.0, 0.0), vec2(1.0, 0.0), 1.0); - gc.stroke_color(Color::Rgba(0.0, 0.5, 1.0, 1.0)); - draw_fan(gc, self, vec2(0.0, -0.5 * self.internal_halflength), vec2(1.0, 1.0), 1.0); } } @@ -112,6 +222,78 @@ impl Metric for Coil { } } +struct Ray { + pos: Vec2, + dir: Vec2, +} + +struct Grid { + hlines: Vec, + vlines: Vec, + cells: HashMap<(usize, usize), Box>, +} + +trait FlatCell: std::fmt::Debug { + fn pos_to_global(&self, pos: Vec2) -> Vec2; + fn pos_to_local(&self, pos: Vec2) -> Vec2; + fn ray_to_global(&self, ray: Ray) -> Ray; + fn ray_to_local(&self, ray: Ray) -> Ray; + + fn is_inside(&self, pos: Vec2) -> bool { + let bnd = self.local_bounds(); + pos.cmpge(bnd.0).all() && pos.cmple(bnd.1).all() + } + fn local_bounds(&self) -> (Vec2, Vec2); +} + +#[derive(Debug)] +struct FlatRect { + min: Vec2, + max: Vec2, +} + +impl FlatCell for FlatRect { + fn pos_to_global(&self, pos: Vec2) -> Vec2 { pos } + fn pos_to_local(&self, pos: Vec2) -> Vec2 { pos } + fn ray_to_global(&self, ray: Ray) -> Ray { ray } + fn ray_to_local(&self, ray: Ray) -> Ray { ray } + fn local_bounds(&self) -> (Vec2, Vec2) { (self.min, self.max) } +} + +#[derive(Debug)] +struct RectInside { + rect: Rect, +} + +impl FlatCell for RectInside { + fn pos_to_global(&self, pos: Vec2) -> Vec2 { + vec2(pos.x, self.rect.x(pos.y)) + } + + fn pos_to_local(&self, pos: Vec2) -> Vec2 { + vec2(pos.x, self.rect.u(pos.y)) + } + + fn ray_to_global(&self, ray: Ray) -> Ray { + Ray { + pos: self.pos_to_global(ray.pos), + dir: vec2(ray.dir.x, self.rect.dx(ray.pos.y, ray.dir.y)), + } + } + + fn ray_to_local(&self, ray: Ray) -> Ray { + Ray { + pos: self.pos_to_local(ray.pos), + dir: vec2(ray.dir.x, self.rect.du(ray.pos.y, ray.dir.y)), + } + } + + fn local_bounds(&self) -> (Vec2, Vec2) { + (vec2(-self.rect.inner_radius, -self.rect.internal_halflength), vec2(self.rect.inner_radius, self.rect.internal_halflength)) + } +} + +#[derive(Copy, Clone, Debug)] struct Rect { outer_radius: f32, inner_radius: f32, @@ -275,7 +457,7 @@ mod riemann { } } - fn krist(space: &impl Metric, pos: Vec2) -> Tens2 { + pub fn krist(space: &impl Metric, 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 d = space.dmetric(pos); @@ -294,7 +476,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),