148 lines
4.0 KiB
Rust
148 lines
4.0 KiB
Rust
use glam::*;
|
|
use itertools::{chain, iproduct};
|
|
|
|
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<Ray>),
|
|
Loop(Vec<Ray>),
|
|
}
|
|
|
|
pub struct FancyLine {
|
|
pub color: Vec3,
|
|
pub pts: Vec<Ray>,
|
|
}
|
|
|
|
fn paint(onto: &mut Vec<FancyLine>, color: Vec3, lines: Vec<Line>) {
|
|
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_rect(center: Vec3, u: Vec3, v: Vec3) -> Vec<Line> {
|
|
let a = center - u - v;
|
|
let b = center + u - v;
|
|
let c = center + u + v;
|
|
let d = center - u + v;
|
|
vec![draw_line(a, b), draw_line(b, c), draw_line(c, d), draw_line(d, a)]
|
|
}
|
|
|
|
fn draw_ellipse(center: Vec3, u: Vec3, v: Vec3) -> Line {
|
|
let segments = 47;
|
|
let step = 2. * std::f32::consts::PI / segments as f32;
|
|
Line::Loop(
|
|
(0..segments)
|
|
.map(|k| k as f32 * step)
|
|
.map(Vec2::from_angle)
|
|
.map(|d| Ray {
|
|
pos: center + d.x * u + d.y * v,
|
|
dir: -d.y * u + d.x * v,
|
|
})
|
|
.collect(),
|
|
)
|
|
}
|
|
|
|
pub fn build() -> Vec<FancyLine> {
|
|
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 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![];
|
|
paint(&mut gc, vec3(0.6, 0.6, 0.6), tube.render());
|
|
paint(&mut gc, vec3(0.0, 0.6, 1.0), draw_fan_2(&space, cam3, 1.0));
|
|
paint(&mut gc, vec3(0.2, 1.0, 0.0), draw_fan_2(&space, cam2, 1.0));
|
|
paint(&mut gc, vec3(1.0, 0.2, 0.0), draw_fan_2(&space, cam1, 1.0));
|
|
gc
|
|
}
|
|
|
|
fn draw_ray_2(gc: &mut Vec<Line>, space: &Space, camera: Location, dir: Vec3) {
|
|
let pos = vec3(0., 0., 0.);
|
|
let (hits, path) = space.trace_dbg(camera, Ray { pos, dir });
|
|
let hits2 = space.trace(camera, Ray { pos, dir });
|
|
for (a, b) in hits.into_iter().zip(hits2.into_iter()) {
|
|
assert_eq!(a.id, b.id);
|
|
assert_eq!(a.pos, b.pos);
|
|
assert_eq!(a.rel, b.rel);
|
|
}
|
|
|
|
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: f32) -> Vec<Line> {
|
|
let mut gc = vec![];
|
|
for y in itertools_num::linspace(-spread, spread, 101) {
|
|
draw_ray_2(&mut gc, space, camera, vec3(1., y, 0.));
|
|
}
|
|
gc
|
|
}
|
|
|
|
trait Renderable {
|
|
fn render(&self) -> Vec<Line>;
|
|
}
|
|
|
|
impl Renderable for Tube {
|
|
fn render(&self) -> Vec<Line> {
|
|
let lines = 4;
|
|
let step = 2. * std::f32::consts::PI / lines as f32;
|
|
let r = 0.5 * (self.outer_radius + self.inner_radius);
|
|
let w = 0.5 * (self.outer_radius - self.inner_radius);
|
|
let l = vec3(0., self.external_halflength, 0.);
|
|
let along = (0..lines)
|
|
.map(|k| k as f32 * step)
|
|
.map(Vec2::from_angle)
|
|
.map(|d| vec3(d.x, 0., d.y))
|
|
.flat_map(|d| draw_rect(r * d, w * d, l));
|
|
let caps = iproduct!([self.inner_radius, self.outer_radius], [-l, l])
|
|
.map(|(r, l)| draw_ellipse(l, vec3(r, 0., 0.), vec3(0., 0., r)));
|
|
chain!(along, caps).collect()
|
|
}
|
|
}
|