From 0ba6d597f74f61251fe2a923fc251257d2194126 Mon Sep 17 00:00:00 2001 From: numzero Date: Tue, 7 May 2024 14:08:15 +0300 Subject: [PATCH] Awful... temp comit --- src/bin/flat.rs | 165 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 111 insertions(+), 54 deletions(-) diff --git a/src/bin/flat.rs b/src/bin/flat.rs index c54ac5c..65b8a96 100644 --- a/src/bin/flat.rs +++ b/src/bin/flat.rs @@ -13,9 +13,10 @@ pub fn main() { m: 10.0, }; let space = Rect { - scale: 3.0, - r: vec2(30.0, 300.0), - m: vec2(20.0, 50.0), + 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"); @@ -30,7 +31,9 @@ pub fn main() { Box::new(Inside { space: space.clone() }), ]; - parts.draw_fan(gc, vec2(-500.0, 0.0), vec2(1.0, 0.0), 1.0); + //parts.draw_fan(gc, vec2(-500.0, 0.0), vec2(1.0, 0.0), 1.0); + // parts.draw_fan(gc, vec2(-20.0, -500.0), vec2(0.1, 0.9), 1.0); + //parts.draw_ray(gc, vec2(-20.0, -500.0), vec2(0.1, 0.9)); }); }); } @@ -70,7 +73,15 @@ impl SpaceVisual for Inside { } fn globalize_loc(&self, pos: Vec2) -> Vec2 { - vec2(pos.x, pos.y * self.space.scale) + todo!() + // let off = self.space.r.y + self.space.m - self.space.r.y / self.space.scale - self.space.m / (self.space.scale + 1.0) * 2.0; + // if pos.y.abs() * self.space.scale <= self.space.r.y { + // vec2(pos.x, pos.y * self.space.scale) + // } else { + // let t = pos.y.abs() - self.space.r.y / self.space.scale; + // let f = t + (self.space.scale - 1.0) * t * t * t + 0.5 * (1.0 - self.space.scale) * t * t * t * t; + // vec2(0.0, 0.0) + // } } } @@ -162,8 +173,8 @@ impl Renderable for Coil { impl Renderable for Rect { fn render(&self, gc: &mut Vec) { gc.new_path(); - gc.rect(-self.r.x - self.m.x, -self.r.y - self.m.y, self.r.x + self.m.x, self.r.y + self.m.y); - gc.rect(-self.r.x, -self.r.y, self.r.x, self.r.y); + gc.rect(-self.outer_radius, -self.external_halflength, self.outer_radius, self.external_halflength); + gc.rect(-self.inner_radius, -self.external_halflength, self.inner_radius, self.external_halflength); gc.winding_rule(WindingRule::EvenOdd); gc.fill_color(Color::Rgba(0.8, 0.8, 0.8, 1.0)); gc.fill(); @@ -171,7 +182,9 @@ impl Renderable for Rect { gc.stroke_color(Color::Rgba(1.0, 0.5, 0.0, 1.0)); self.draw_fan(gc, 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)); - self.draw_fan(gc, vec2(0.0, -0.5 * self.r.y), vec2(1.0, 1.0), 1.0); + self.draw_fan(gc, vec2(0.0, -0.5 * self.external_halflength), vec2(1.0, 1.0), 1.0); + gc.stroke_color(Color::Rgba(0.2, 0.7, 0.0, 1.0)); + self.draw_fan(gc, vec2(-0.5 * self.inner_radius, -1.2 * self.external_halflength), vec2(0.0, 1.0), 1.0); } } @@ -201,17 +214,42 @@ impl Metric for Coil { } struct Rect { - scale: f32, - r: Vec2, - m: Vec2, + outer_radius: f32, + inner_radius: f32, + external_halflength: f32, + internal_halflength: f32, +} + +impl Rect { + fn γ(&self) -> f32 { self.external_halflength / self.internal_halflength } + fn ri(&self) -> f32 { self.internal_halflength } + fn re(&self) -> f32 { self.external_halflength } + fn a(&self) -> f32 { (1.0 - self.γ()) / self.ri() } + fn b(&self) -> f32 { 2.0 * self.γ() - 1.0 } + + fn root(&self, x: f32) -> f32 { ((2.0 * self.γ() - 1.0).powi(2) + 4.0 * (1.0 - self.γ()) * x / self.ri()).sqrt() } + fn x(&self, u: f32) -> f32 { (self.a() * u.abs() + self.b()) * u } + fn u(&self, x: f32) -> f32 { 0.5 * self.ri() * (1.0 - 2.0 * self.γ() + self.root(x.abs())) / (1.0 - self.γ()) * x.signum() } } impl Metric for Rect { fn halfmetric(&self, pos: Vec2) -> Decomp2 { - let s = smoothbox(pos.x, vec2(-self.r.x, self.r.x), self.m.x) * smoothbox(pos.y, vec2(-self.r.y, self.r.y), self.m.y); + let γ = self.γ(); + let re = self.re(); + let ri = self.ri(); + let a = self.a(); + let b = self.b(); + let x = pos.y.abs(); + let u = 0.5 * ri * (1.0 - 2.0 * γ + self.root(x)) / (1.0 - γ); + let sx = ((pos.x.abs() - self.inner_radius) / (self.outer_radius - self.inner_radius)).clamp(0.0, 1.0); + let sy = if x <= re { 1.0 / (2.0 * a * u + b) } else { 1.0 }; + let sy = if x <= re { 1.0 / self.root(x) } else { 1.0 }; + assert!(sx.is_finite()); + assert!(sy.is_finite()); + assert!(sy > 0.0); Decomp2 { ortho: Mat2::IDENTITY, - diag: vec2(1.0, 1.0.lerp(1.0 / self.scale, s)), + diag: vec2(1.0, sy.lerp(1.0, sx)), } } } @@ -241,13 +279,25 @@ struct Inside { 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 + todo!() + // let osize = self.space.r + self.space.m; + // let isize = self.space.r; + // let bnd = Loop(vec![ + // vec2(-osize.x, -osize.y), vec2(-isize.x, -osize.y), vec2(isize.x, -osize.y), vec2(osize.x, -osize.y), + // vec2(osize.x, osize.y), vec2(isize.x, osize.y), vec2(-isize.x, osize.y), vec2(-osize.x, osize.y), + // ]); + // let (side, dist) = bnd.hit(base, dir)?; + // if dist <= limit { + // let bnds = [0, 1, 0, 0, 0, 2, 0, 0]; + // let off = self.space.r.y + self.space.m - self.space.r.y / self.space.scale - self.space.m / (self.space.scale + 1.0) * 2.0; + // return match bnds[side] { + // 0 => Some((boundary::Id(1), base + dist * dir, dir)), + // 1 => Some((boundary::Id(2), base + dist * dir + vec2(0.0, off), dir)), + // 2 => Some((boundary::Id(2), base + dist * dir - vec2(0.0, off), dir)), + // _ => panic!(), + // }; + // } + // None } } @@ -259,25 +309,26 @@ impl Metric for Outside { 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 + todo!() + // 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 } } @@ -289,18 +340,19 @@ impl Metric for Wall { 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 + todo!() + // 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 } } @@ -502,10 +554,15 @@ fn smoothstep(x: f32) -> f32 { 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 { +/// 1.0 for val∈[range.x, range.y], 0.0 for val∉[range.x−pad, range.y+pad], linear in-between. +fn trapezoid(val: f32, range: Vec2, pad: f32) -> f32 { let slope1 = 1.0 + (val - range.x) / pad; let slope2 = 1.0 - (val - range.y) / pad; let lin = slope1.min(slope2); - smoothstep(lin.clamp(0.0, 1.0)) + lin.clamp(0.0, 1.0) +} + +/// 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 { + smoothstep(trapezoid(val, range, pad)) }