From e840b3f47be5e0e8817fcb0ce45c7141e48a7b58 Mon Sep 17 00:00:00 2001 From: numzero Date: Sun, 9 Jun 2024 21:47:25 +0300 Subject: [PATCH] Trace to objects --- src/bin/flat.rs | 60 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/src/bin/flat.rs b/src/bin/flat.rs index 70ebcf2..6f7a7ae 100644 --- a/src/bin/flat.rs +++ b/src/bin/flat.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::f32::consts::PI; use flo_draw::*; use flo_canvas::*; @@ -114,6 +115,12 @@ enum Subspace { Inner, } +enum FlatTraceResult { + Infinity(Vec2), + Edge(Ray), + Object(Ray, i32), +} + impl Space { fn which_subspace(&self, pt: Vec2) -> Subspace { if pt.y.abs() > self.rect.external_halflength { @@ -165,13 +172,21 @@ impl Space { cell.ray_to_global(ray) } - fn trace_outer(&self, ray: Ray) -> Option { + fn trace_outer(&self, ray: Ray) -> FlatTraceResult { assert_eq!(self.which_subspace(ray.pos), Outer); let cell = basic_shapes::Rect { size: vec2(self.rect.outer_radius, self.rect.external_halflength) }; - if let Some(dist) = cell.trace_into(ray) { - Some(Ray { pos: ray.pos + ray.dir * dist, dir: ray.dir }) - } else { - None + let obj = Self::trace_to_object(self.list_objects_outer(), ray); + let sub = cell.trace_into(ray); + let rray = |dist: f32| Ray { pos: ray.pos + ray.dir * dist, dir: ray.dir }; + match (sub, obj) { + (None, None) => FlatTraceResult::Infinity(ray.dir), + (Some(dist), None) => FlatTraceResult::Edge(rray(dist)), + (None, Some((id, dist))) => FlatTraceResult::Object(rray(dist), id), + (Some(sdist), Some((id, odist))) => if sdist < odist { + FlatTraceResult::Edge(rray(sdist)) + } else { + FlatTraceResult::Object(rray(odist), id) + } } } @@ -181,6 +196,26 @@ impl Space { .find(|&ray| self.which_subspace(ray.pos) != Boundary) .expect("Can't get outta the wall!") } + + fn list_objects_outer(&self) -> &[Object] { + self.objs.as_slice() + } + + fn trace_to_object(objs: &[Object], ray: Ray) -> Option<(i32, f32)> { + objs.iter() + .filter_map(|obj| { + let rel = ray.pos - obj.loc.pos; + let diff = rel.dot(ray.dir).powi(2) - ray.dir.length_squared() * (rel.length_squared() - obj.r.powi(2)); + if diff > 0.0 { + let t = (-rel.dot(ray.dir) - diff.sqrt()) / ray.dir.length_squared(); + if t >= 0.0 { + return Some((obj.id, t)); + } + } + None + }) + .min_by(|(_, d1), (_, d2)| f32::total_cmp(d1, d2)) + } } fn draw_ray_2(gc: &mut Vec, space: &Space, base: Vec2, dir: Vec2) { @@ -209,13 +244,22 @@ fn draw_ray_2(gc: &mut Vec, space: &Space, base: Vec2, dir: Vec2) { } Outer => { ray = match space.trace_outer(ray) { - Some(r) => r, - None => { - ray.pos += ray.dir * (1000.0 / DT); + FlatTraceResult::Edge(r) => r, + FlatTraceResult::Infinity(dir) => { + ray.pos += dir * (1000.0 / DT); gc.line_to(ray.pos.x, ray.pos.y); gc.stroke(); break; } + FlatTraceResult::Object(r, id) => { + gc.line_to(r.pos.x, r.pos.y); + gc.stroke(); + gc.new_path(); + gc.new_dash_pattern(); + gc.circle(r.pos.x, r.pos.y, 1.5); + gc.stroke(); + r + } }; } Boundary => panic!(),