use glam::*; use itertools::chain; use refraction::ifaces::{DebugTraceable, Traceable}; use refraction::tube::metric::Tube; use refraction::tube::Space; use refraction::types::{Location, Object, Ray}; use refraction::utils::put_object; pub enum Line { Strip(Vec), Loop(Vec), } pub struct FancyLine { pub color: Vec3, pub pts: Vec, } pub type Face = (Vec3, Vec3, Vec3); pub enum Mesh { List(Vec), } pub struct FancyMesh { pub color: Vec4, pub tris: Vec, } fn paint(onto: &mut Vec, color: Vec3, lines: Vec) { onto.extend(lines.into_iter().map(move |line| FancyLine { color, pts: match line { Line::Strip(pts) => pts, Line::Loop(mut pts) => { pts.push(*pts.first().unwrap()); pts } }, })) } fn draw_line(a: Vec3, b: Vec3) -> Line { let dir = (b - a).normalize(); Line::Strip(vec![Ray { pos: a, dir }, Ray { pos: b, dir }]) } fn draw_mark(pos: Vec3) -> Vec { [ vec3(1., 1., 1.), vec3(1., 1., -1.), vec3(1., -1., 1.), vec3(1., -1., -1.), ] .into_iter() .map(|off| draw_line(pos - off, pos + off)) .collect() } pub fn build() -> (Vec, Vec) { let tube = Tube { inner_radius: 30.0, outer_radius: 50.0, internal_halflength: 100.0, external_halflength: 300.0, }; let objs: Vec<_> = [-1.25, -1.00, -0.85, -0.50, 0.00, 0.40, 0.70, 0.95, 1.05] .iter() .enumerate() .map(|(k, &y)| Object { id: k as i32, loc: put_object( &tube, vec3(0.0, y * tube.external_halflength, 0.0), Mat3::from_mat2(Mat2::from_angle(y)), ), r: 20.0, }) .collect(); let space = Space { tube, objs }; let cam1 = put_object(&space.tube, vec3(-500., 0., 0.), Mat3::IDENTITY); let cam2 = put_object( &space.tube, vec3(-2.5 * tube.outer_radius, 1.25 * tube.external_halflength, 0.), mat3(vec3(1., -1., 0.), vec3(1., 1., 0.), vec3(0., 0., 1.)), ); let cam2l = put_object( &space.tube, vec3(-2.5 * tube.outer_radius, 1.25 * tube.external_halflength, 0.), mat3(vec3(1., -0.825, 0.), vec3(1., 1., 0.), vec3(0., 0., 1.)), ); let cam3 = put_object( &space.tube, vec3(0.25 * tube.inner_radius, 0.25 * tube.external_halflength, 0.), mat3(vec3(0., -1., 0.), vec3(1., 0., 0.), vec3(0., 0., 1.)), ); let mut gc = vec![]; gc.push(FancyMesh { color: vec4(0.3, 0.5, 1.0, 1.0) * 0.2, tris: tube.render(), }); let meshes = gc; let mut gc = vec![]; paint(&mut gc, vec3(0.0, 0.6, 1.0), draw_fan_2(&space, cam3, vec3(0., 1., 0.))); paint(&mut gc, vec3(0.2, 1.0, 0.0), draw_fan_2(&space, cam2, vec3(0., 1., 0.))); paint( &mut gc, vec3(0.0, 1.0, 0.6), draw_fan_2(&space, cam2l, vec3(0., 0., 1.)), ); paint(&mut gc, vec3(1.0, 0.2, 0.0), draw_fan_2(&space, cam1, vec3(0., 1., 0.))); let lines = gc; (meshes, lines) } fn draw_ray_2(gc: &mut Vec, space: &Space, camera: Location, dir: Vec3) { let pos = vec3(0., 0., 0.); let (hits, path) = space.trace_dbg(camera, Ray { pos, dir }); if true { let hits2 = space.trace(camera, Ray { pos, dir }); for (a, b) in hits.iter().zip(hits2.into_iter()) { assert_eq!(a.id, b.id); assert_eq!(a.pos, b.pos); assert_eq!(a.rel, b.rel); } } for hit in hits { gc.extend(draw_mark(hit.pos)); } let mut pts = path.points; let end_pos = *pts.last().expect("the starting point is always in the path"); pts.extend(itertools::iterate(end_pos, |r| r.forward(100.0)).take(1000)); gc.push(Line::Strip(pts)); } fn draw_fan_2(space: &Space, camera: Location, spread: Vec3) -> Vec { let mut gc = vec![]; for δ in itertools_num::linspace(-1., 1., 101) { draw_ray_2(&mut gc, space, camera, vec3(1., 0., 0.) + δ * spread); } gc } trait Renderable { fn render(&self) -> Vec; } impl Renderable for Tube { fn render(&self) -> Vec { let sides = 42; let step = 2. * std::f32::consts::PI / sides as f32; let dir = |k| { let d = Vec2::from_angle(k as f32 * step); vec3(d.x, 0., d.y) }; let side = vec3(0., self.external_halflength, 0.); let r1 = self.inner_radius; let r2 = self.outer_radius; let inner = (0..sides).flat_map(|k| { let a = r1 * dir(k); let b = r1 * dir(k + 1); [(a - side, b - side, a + side), (b - side, b + side, a + side)] }); let outer = (0..sides).flat_map(|k| { let a = r2 * dir(k); let b = r2 * dir(k + 1); [(a - side, b - side, a + side), (b - side, b + side, a + side)] }); let cap = (0..sides).flat_map(|k| { let a = r1 * dir(k); let b = r1 * dir(k + 1); let c = r2 * dir(k + 1); let d = r2 * dir(k); [ (a - side, b - side, c - side), (a - side, c - side, d - side), (a + side, b + side, c + side), (a + side, c + side, d + side), ] }); chain!(inner, outer, cap).collect() } }