diff --git a/src/bin/flat.rs b/src/bin/flat.rs index 3e33dfb..61b73db 100644 --- a/src/bin/flat.rs +++ b/src/bin/flat.rs @@ -34,10 +34,17 @@ pub fn main() { 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, &space, vec2(0.0, -0.5 * tube.internal_halflength), vec2(1.0, 1.0), 1.0); + draw_track(gc, &space, vec2(-500.0, 0.0), vec2(1.0, 0.2)); + draw_track(gc, &space, vec2(-500.0, 0.0), vec2(1.0, 0.5)); }); }); } +struct Location { + pos: Vec2, + rot: Mat2, +} + struct Space { rect: Rect, } @@ -61,6 +68,29 @@ impl Space { Inner } } + + fn flat_to_global(&self, at: Vec2, v: Vec2) -> Vec2 { + Mat2::from(self.rect.halfmetric(at).inverse()) * v + } + + fn global_to_flat(&self, at: Vec2, v: Vec2) -> Vec2 { + Mat2::from(self.rect.halfmetric(at)) * v + } + + /// Выполняет один шаг трассировки. Работает в любой части пространства, но вне Boundary доступны более эффективные методы. + fn trace_step(&self, ray: Ray) -> Ray { + let a: Vec2 = -riemann::convolute2(riemann::krist(&self.rect, ray.pos), ray.dir); + let v = ray.dir + a * DT; + let p = ray.pos + v * DT; + Ray { pos: p, dir: v } + } + + /// Выполняет один шаг перемещения. Работает в любой части пространства, но вне Boundary доступны более эффективные методы. + fn move_step(&self, loc: Location, off: Vec2) -> Location { + let corr = Mat2::IDENTITY - riemann::convolute(riemann::krist(&self.rect, loc.pos), loc.rot * off); + let p = loc.pos + corr * loc.rot * off; + Location { pos: p, rot: corr * loc.rot } + } } fn draw_ray_2(gc: &mut Vec, space: &Space, base: Vec2, dir: Vec2) { @@ -71,7 +101,7 @@ fn draw_ray_2(gc: &mut Vec, space: &Space, base: Vec2, dir: Vec2) { let mut p = base; let mut v = space.rect.normalize(base, dir); for _ in 0..10000 { - let a: Vec2 = -riemann::convolute(riemann::krist(&space.rect, p), v); + let a: Vec2 = -riemann::convolute2(riemann::krist(&space.rect, p), v); v = v + a * dt; p = p + v * dt; gc.line_to(p.x, p.y); @@ -139,6 +169,39 @@ fn draw_ray(gc: &mut Vec, space: &impl Metric, base: Vec2, dir: Vec2) { gc.stroke(); } +fn draw_track(gc: &mut Vec, space: &Space, start: Vec2, dir: Vec2) { + const SCALE: f32 = 5.0; + const STEP: f32 = 2.0 * SCALE; + // let mut loc = Location { pos: start, rot: Mat2::IDENTITY }; + // let dir = space.rect.globalize(start, dir); + // let v = space.rect.normalize(start, dir); + let mut loc = Location { pos: start, rot: mat2(dir, vec2(-dir.y, dir.x)) }; + let v = vec2(1.0, 0.0); + let mut draw = |loc: &Location| { + let p = loc.pos; + let ax = p + loc.rot.x_axis * SCALE; + let ay = p + loc.rot.y_axis * SCALE; + gc.new_path(); + gc.stroke_color(Color::Rgba(0.7, 0.0, 0.0, 1.0)); + gc.move_to(p.x, p.y); + gc.line_to(ax.x, ax.y); + gc.stroke(); + gc.new_path(); + gc.stroke_color(Color::Rgba(0.0, 0.7, 0.0, 1.0)); + gc.move_to(p.x, p.y); + gc.line_to(ay.x, ay.y); + gc.stroke(); + }; + draw(&loc); + for _ in 0..1000 { + let N = (STEP / DT).floor() as i32; + for _ in 0..N { + loc = space.move_step(loc, v * DT); + } + draw(&loc); + } +} + fn draw_fan(gc: &mut Vec, space: &impl Metric, base: Vec2, dir: Vec2, spread: f32) { let dir = dir.normalize(); let v = vec2(-dir.y, dir.x); @@ -421,7 +484,7 @@ mod riemann { } } - fn inverse(&self) -> Self { + pub(crate) fn inverse(&self) -> Self { Self { ortho: self.ortho, diag: Vec2::splat(1.0) / self.diag, @@ -476,7 +539,7 @@ mod riemann { type Item = Vec2; fn next(&mut self) -> Option { - let a: Vec2 = -convolute(krist(self.space, self.p), self.v); + let a: Vec2 = -convolute2(krist(self.space, self.p), self.v); self.v = self.v + a * self.dt; self.p = self.p + self.v * self.dt; Some(self.p) @@ -511,11 +574,14 @@ mod riemann { ] } - pub fn convolute(t: Tens2, v: Vec2) -> Vec2 { - vec2( - v.dot(t[0] * v), - v.dot(t[1] * v), - ) + /// Сворачивает тензор t с вектором u + pub fn convolute(t: Tens2, u: Vec2) -> Mat2 { + mat2(t[0] * u, t[1] * u).transpose() + } + + /// Сворачивает тензор t с вектором v дважды, по второму и третьему индексам. + pub fn convolute2(t: Tens2, v: Vec2) -> Vec2 { + convolute(t, v) * v } fn make_vec2(f: impl Fn(usize) -> f32) -> Vec2 {