diff --git a/src/bin/flat/main.rs b/src/bin/flat/main.rs index c4f2a7b..6759c31 100644 --- a/src/bin/flat/main.rs +++ b/src/bin/flat/main.rs @@ -39,14 +39,15 @@ pub fn main() { 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 { + .map(|(k, &y)| Object { id: k as i32, loc: { let pos = vec2(0.0, y * tube.external_halflength); - let adj = tube.sqrt_at(pos).inverse().into(); + let adj: Mat2 = tube.sqrt_at(pos).inverse().into(); + let rot = Mat2::from_angle(y); Location { pos, - rot: adj, + rot: adj * rot, } }, r: 20.0, @@ -135,6 +136,11 @@ struct Hit { rel: Vec2, // положение в локальной ортонормированной СК объекта } +struct HitInternal<'a> { + object: &'a Object, + distance: f32, +} + struct FlatTraceResult { end: Option, objects: Vec, @@ -186,13 +192,17 @@ impl Space { assert_eq!(self.which_subspace(ray.pos), Inner); let cell = RectInside { rect: self.rect }; let ray = cell.ray_to_local(ray); - let objs = Self::trace_to_objects(self.list_objects_inner().as_slice(), ray); + let objs = self.list_objects_inner(); + let hits = Self::trace_to_objects(objs.as_slice(), ray); let dist = cell.to_boundary(ray).expect("Can't get outta here!"); - let ray = ray.forward(dist); FlatTraceResult { - end: Some(cell.ray_to_global(ray)), - objects: objs.into_iter().filter_map(|Hit { id, distance, pos, rel }| - if distance < dist { Some(Hit { id, distance, pos: cell.pos_to_global(pos), rel }) } else { None } + end: Some(cell.ray_to_global(ray.forward(dist))), + objects: hits.into_iter().filter_map(|HitInternal { object, distance }| + if distance < dist { + let pos = ray.forward(distance).pos; + let rel = object.loc.rot.inverse() * cell.ray_to_global(Ray { pos: object.loc.pos, dir: pos - object.loc.pos }).dir; + Some(Hit { id: object.id, distance, pos: cell.pos_to_global(pos), rel }) + } else { None } ).collect(), } } @@ -200,16 +210,27 @@ impl Space { 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) }; - let objs = Self::trace_to_objects(self.list_objects_outer().as_slice(), ray); + let objs = self.list_objects_outer(); + let hits = Self::trace_to_objects(objs.as_slice(), ray); if let Some(dist) = cell.trace_into(ray) { FlatTraceResult { end: Some(ray.forward(dist)), - objects: objs.into_iter().filter(|hit| hit.distance < dist).collect(), + objects: hits.into_iter().filter_map(|HitInternal { object, distance }| + if distance < dist { + let pos = ray.forward(distance).pos; + let rel = object.loc.rot.inverse() * (pos - object.loc.pos); + Some(Hit { id: object.id, distance, pos, rel }) + } else { None } + ).collect(), } } else { FlatTraceResult { end: None, - objects: objs, + objects: hits.into_iter().map(|HitInternal { object, distance }| { + let pos = ray.forward(distance).pos; + let rel = object.loc.rot.inverse() * (pos - object.loc.pos); + Hit { id: object.id, distance, pos, rel } + }).collect(), } } } @@ -228,11 +249,13 @@ impl Space { Inner => { let Vec2 { x, y } = obj.loc.pos; // в основной СК let y = self.rect.u(y) + y.signum() * (self.rect.external_halflength - self.rect.internal_halflength); + let dy = self.rect.du(y, 1.0); + let m = Mat2::from_cols_array(&[1.0, 0.0, 0.0, dy]); Object { id: obj.id, loc: Location { pos: vec2(x, y), // в плоском продолжении СК Outer на область Inner - rot: obj.loc.rot, + rot: m * obj.loc.rot, }, r: obj.r, } @@ -262,7 +285,7 @@ impl Space { }).collect() } - fn trace_to_objects(objs: &[Object], ray: Ray) -> Vec { + fn trace_to_objects(objs: &[Object], ray: Ray) -> Vec { objs.iter() .filter_map(|obj| { let rel = ray.pos - obj.loc.pos; @@ -271,7 +294,7 @@ impl Space { let t = (-rel.dot(ray.dir) - diff.sqrt()) / ray.dir.length_squared(); if t >= 0.0 { let pos = ray.forward(t).pos; - return Some(Hit { id: obj.id, distance: t, pos, rel: pos - obj.loc.pos }); + return Some(HitInternal { object: &obj, distance: t }); } } None