Compare commits
7 Commits
e57692587a
...
dbdcdde80d
| Author | SHA1 | Date | |
|---|---|---|---|
| dbdcdde80d | |||
| 8e7a57761e | |||
| 6da6944fa3 | |||
| 122085b9ee | |||
| b6b95b1c94 | |||
| 7b0c09c3d7 | |||
| ecb112794d |
|
|
@ -25,6 +25,7 @@ fn prepare_scene(device: &wgpu::Device) -> Vec<lines::Line> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any())]
|
||||||
mod camctl {
|
mod camctl {
|
||||||
use glam::{vec3, Mat4, Quat, Vec3};
|
use glam::{vec3, Mat4, Quat, Vec3};
|
||||||
|
|
||||||
|
|
@ -49,15 +50,48 @@ mod camctl {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rotate_rel_ypr(&mut self, ypr: Vec3) {
|
pub fn rotate_rel_ypr(&mut self, ypr: Vec3) {
|
||||||
self.rotate_rel_quat(Quat::from_euler(glam::EulerRot::XYZ, ypr.x, ypr.y, ypr.z));
|
self.rotate_rel_quat(Quat::from_euler(glam::EulerRot::ZYX, ypr.x, ypr.y, ypr.z));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rotate_rel_quat(&mut self, rot: Quat) {
|
fn rotate_rel_quat(&mut self, rot: Quat) {
|
||||||
self.rot *= rot;
|
self.rot *= rot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod camctl {
|
||||||
|
use glam::{vec3, Mat4, Quat, Vec3};
|
||||||
|
|
||||||
|
pub struct CameraLocation {
|
||||||
|
pos: Vec3,
|
||||||
|
rot: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rot_quat(rot: Vec3) -> Quat {
|
||||||
|
Quat::from_euler(glam::EulerRot::XYZ, rot.z, rot.y, rot.x)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CameraLocation {
|
||||||
|
pub fn new() -> CameraLocation {
|
||||||
|
let rot = vec3(std::f32::consts::FRAC_PI_4, 0., 0.);
|
||||||
|
let pos = rot_quat(rot) * vec3(-200., 0., 50.);
|
||||||
|
CameraLocation { pos, rot }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn view_mtx(&self) -> Mat4 {
|
||||||
|
Mat4::from_quat(rot_quat(-self.rot)) * Mat4::from_translation(-self.pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_rel(&mut self, offset: Vec3) {
|
||||||
|
self.pos += rot_quat(vec3(self.rot.x, 0., 0.)) * offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotate_rel_ypr(&mut self, ypr: Vec3) {
|
||||||
|
self.rot += ypr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod keyctl {
|
mod keyctl {
|
||||||
use std::{collections::HashSet, iter::Sum};
|
use std::{collections::HashSet, iter::Sum};
|
||||||
use winit::{event::ElementState, keyboard::PhysicalKey};
|
use winit::{event::ElementState, keyboard::PhysicalKey};
|
||||||
|
|
@ -101,15 +135,17 @@ static KEYS_MOVE: &'static [(PhysicalKey, Vec3)] = &[
|
||||||
(PhysicalKey::Code(KeyCode::KeyD), vec3(0., -1., 0.)),
|
(PhysicalKey::Code(KeyCode::KeyD), vec3(0., -1., 0.)),
|
||||||
(PhysicalKey::Code(KeyCode::KeyE), vec3(0., 0., 1.)),
|
(PhysicalKey::Code(KeyCode::KeyE), vec3(0., 0., 1.)),
|
||||||
(PhysicalKey::Code(KeyCode::KeyQ), vec3(0., 0., -1.)),
|
(PhysicalKey::Code(KeyCode::KeyQ), vec3(0., 0., -1.)),
|
||||||
|
(PhysicalKey::Code(KeyCode::Space), vec3(0., 0., 1.)),
|
||||||
|
(PhysicalKey::Code(KeyCode::ShiftLeft), vec3(0., 0., -1.)),
|
||||||
];
|
];
|
||||||
|
|
||||||
static KEYS_ROTATE: &'static [(PhysicalKey, Vec3)] = &[
|
static KEYS_ROTATE: &'static [(PhysicalKey, Vec3)] = &[
|
||||||
(PhysicalKey::Code(KeyCode::Numpad9), vec3(1., 0., 0.)),
|
(PhysicalKey::Code(KeyCode::Numpad4), vec3(1., 0., 0.)),
|
||||||
(PhysicalKey::Code(KeyCode::Numpad7), vec3(-1., 0., 0.)),
|
(PhysicalKey::Code(KeyCode::Numpad6), vec3(-1., 0., 0.)),
|
||||||
(PhysicalKey::Code(KeyCode::Numpad5), vec3(0., 1., 0.)),
|
(PhysicalKey::Code(KeyCode::Numpad5), vec3(0., 1., 0.)),
|
||||||
(PhysicalKey::Code(KeyCode::Numpad8), vec3(0., -1., 0.)),
|
(PhysicalKey::Code(KeyCode::Numpad8), vec3(0., -1., 0.)),
|
||||||
(PhysicalKey::Code(KeyCode::Numpad4), vec3(0., 0., 1.)),
|
(PhysicalKey::Code(KeyCode::Numpad9), vec3(0., 0., 1.)),
|
||||||
(PhysicalKey::Code(KeyCode::Numpad6), vec3(0., 0., -1.)),
|
(PhysicalKey::Code(KeyCode::Numpad7), vec3(0., 0., -1.)),
|
||||||
];
|
];
|
||||||
|
|
||||||
struct State<'a> {
|
struct State<'a> {
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,18 @@ fn draw_ellipse(center: Vec3, u: Vec3, v: Vec3) -> Line {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_mark(pos: Vec3) -> Vec<Line> {
|
||||||
|
[
|
||||||
|
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<FancyLine> {
|
pub fn build() -> Vec<FancyLine> {
|
||||||
let tube = Tube {
|
let tube = Tube {
|
||||||
inner_radius: 30.0,
|
inner_radius: 30.0,
|
||||||
|
|
@ -86,6 +98,11 @@ pub fn build() -> Vec<FancyLine> {
|
||||||
vec3(-2.5 * tube.outer_radius, 1.25 * tube.external_halflength, 0.),
|
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.)),
|
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(
|
let cam3 = put_object(
|
||||||
&space.tube,
|
&space.tube,
|
||||||
vec3(0.25 * tube.inner_radius, 0.25 * tube.external_halflength, 0.),
|
vec3(0.25 * tube.inner_radius, 0.25 * tube.external_halflength, 0.),
|
||||||
|
|
@ -96,7 +113,11 @@ pub fn build() -> Vec<FancyLine> {
|
||||||
paint(&mut gc, vec3(0.6, 0.6, 0.6), tube.render());
|
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, vec3(0., 1., 0.)));
|
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.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, cam2, vec3(0., 0., 1.)));
|
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.)));
|
paint(&mut gc, vec3(1.0, 0.2, 0.0), draw_fan_2(&space, cam1, vec3(0., 1., 0.)));
|
||||||
gc
|
gc
|
||||||
}
|
}
|
||||||
|
|
@ -104,12 +125,18 @@ pub fn build() -> Vec<FancyLine> {
|
||||||
fn draw_ray_2(gc: &mut Vec<Line>, space: &Space, camera: Location, dir: Vec3) {
|
fn draw_ray_2(gc: &mut Vec<Line>, space: &Space, camera: Location, dir: Vec3) {
|
||||||
let pos = vec3(0., 0., 0.);
|
let pos = vec3(0., 0., 0.);
|
||||||
let (hits, path) = space.trace_dbg(camera, Ray { pos, dir });
|
let (hits, path) = space.trace_dbg(camera, Ray { pos, dir });
|
||||||
|
if true {
|
||||||
let hits2 = space.trace(camera, Ray { pos, dir });
|
let hits2 = space.trace(camera, Ray { pos, dir });
|
||||||
for (a, b) in hits.into_iter().zip(hits2.into_iter()) {
|
for (a, b) in hits.iter().zip(hits2.into_iter()) {
|
||||||
assert_eq!(a.id, b.id);
|
assert_eq!(a.id, b.id);
|
||||||
assert_eq!(a.pos, b.pos);
|
assert_eq!(a.pos, b.pos);
|
||||||
assert_eq!(a.rel, b.rel);
|
assert_eq!(a.rel, b.rel);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for hit in hits {
|
||||||
|
gc.extend(draw_mark(hit.pos));
|
||||||
|
}
|
||||||
|
|
||||||
let mut pts = path.points;
|
let mut pts = path.points;
|
||||||
let end_pos = *pts.last().expect("the starting point is always in the path");
|
let end_pos = *pts.last().expect("the starting point is always in the path");
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ pub mod mathx;
|
||||||
pub mod mesh_loader;
|
pub mod mesh_loader;
|
||||||
pub mod mesh_tracer;
|
pub mod mesh_tracer;
|
||||||
pub mod riemann;
|
pub mod riemann;
|
||||||
|
pub mod shape;
|
||||||
pub mod tube;
|
pub mod tube;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
|
||||||
240
src/shape/cylinder.rs
Normal file
240
src/shape/cylinder.rs
Normal file
|
|
@ -0,0 +1,240 @@
|
||||||
|
use glam::{Vec3, Vec3Swizzles as _};
|
||||||
|
|
||||||
|
use crate::types::Ray;
|
||||||
|
|
||||||
|
pub struct Cylinder {
|
||||||
|
pub center: Vec3,
|
||||||
|
pub semiaxis: Vec3,
|
||||||
|
pub radius: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cylinder {
|
||||||
|
/// Split a vector into a component along the axis and one orthogonal to it.
|
||||||
|
fn split(&self, dir: Vec3) -> (f32, Vec3) {
|
||||||
|
let along = dir.dot(self.semiaxis) / self.semiaxis.length_squared();
|
||||||
|
(along, dir - along * self.semiaxis)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cap_inout(p: f32, d: f32) -> (f32, f32) {
|
||||||
|
((-d.signum() - p) / d.abs(), (d.signum() - p) / d.abs())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_inside(&self, pt: Vec3) -> bool {
|
||||||
|
let (along, ortho) = self.split(pt - self.center);
|
||||||
|
along.abs() < 1. && ortho.length_squared() < self.radius.powi(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trace_inout(&self, ray: Ray) -> Option<(f32, f32)> {
|
||||||
|
let (pos_along, pos_ortho) = self.split(ray.pos - self.center);
|
||||||
|
let (dir_along, dir_ortho) = self.split(ray.dir);
|
||||||
|
let (t_cap_in, t_cap_out) = Self::cap_inout(pos_along, dir_along);
|
||||||
|
if dir_ortho.length_squared() < 1e-3 {
|
||||||
|
if pos_ortho.length_squared() >= self.radius.powi(2) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return Some((t_cap_in, t_cap_out));
|
||||||
|
}
|
||||||
|
let (t_side_in, t_side_out) = solve_quadratic(
|
||||||
|
dir_ortho.length_squared(),
|
||||||
|
pos_ortho.dot(dir_ortho),
|
||||||
|
pos_ortho.length_squared() - self.radius.powi(2),
|
||||||
|
)?;
|
||||||
|
let t_in = f32::max(t_cap_in, t_side_in);
|
||||||
|
let t_out = f32::min(t_cap_out, t_side_out);
|
||||||
|
if t_out <= t_in {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some((t_in, t_out))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trace_into(&self, ray: Ray) -> Option<f32> {
|
||||||
|
let (t, _) = self.trace_inout(ray)?;
|
||||||
|
if t < 0. {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trace_out_of(&self, ray: Ray) -> Option<f32> {
|
||||||
|
let (_, t) = self
|
||||||
|
.trace_inout(ray)
|
||||||
|
.expect("the ray starts inside so *has* to cross the boundary");
|
||||||
|
Some(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Цилиндр с центром в начале координат и осью вдоль оси Y.
|
||||||
|
pub struct YCylinder {
|
||||||
|
pub half_length: f32,
|
||||||
|
pub radius: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl YCylinder {
|
||||||
|
/// Отражает луч, чтобы все координаты направления были положительны (допустимо благодаря симметрии YCylinder).
|
||||||
|
fn flip_ray(ray: Ray) -> Ray {
|
||||||
|
Ray {
|
||||||
|
pos: ray.pos * ray.dir.signum(),
|
||||||
|
dir: ray.dir.abs(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_inside(&self, pt: Vec3) -> bool {
|
||||||
|
let r = f32::hypot(pt.x, pt.z);
|
||||||
|
pt.y.abs() < self.half_length && r < self.radius
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trace_into(&self, ray: Ray) -> Option<f32> {
|
||||||
|
let ray = Self::flip_ray(ray);
|
||||||
|
|
||||||
|
// 1. ray.pos.y + t * ray.dir.y = −half_length
|
||||||
|
let t_cap_in = (-self.half_length - ray.pos.y) / ray.dir.y;
|
||||||
|
let t_cap_out = (self.half_length - ray.pos.y) / ray.dir.y;
|
||||||
|
|
||||||
|
// 2. (ray.pos.x + t * ray.dir.x)² + (ray.pos.z + t * ray.dir.z)² = radius²
|
||||||
|
let pos = ray.pos.xz();
|
||||||
|
let dir = ray.dir.xz();
|
||||||
|
if dir.length_squared() < 1e-6 * ray.dir.length_squared() {
|
||||||
|
if pos.length_squared() >= self.radius.powi(2) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return Some(t_cap_in).filter(|&t| t > 0.);
|
||||||
|
}
|
||||||
|
let (t_side_in, t_side_out) = solve_quadratic(
|
||||||
|
dir.length_squared(),
|
||||||
|
pos.dot(dir),
|
||||||
|
pos.length_squared() - self.radius.powi(2),
|
||||||
|
)?;
|
||||||
|
let t = f32::max(t_cap_in, t_side_in);
|
||||||
|
if t < 0. {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if t >= t_cap_out || t >= t_side_out {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trace_out_of(&self, ray: Ray) -> Option<f32> {
|
||||||
|
let ray = Self::flip_ray(ray);
|
||||||
|
let t_cap_out = (self.half_length - ray.pos.y) / ray.dir.y;
|
||||||
|
let pos = ray.pos.xz();
|
||||||
|
let dir = ray.dir.xz();
|
||||||
|
if dir.length_squared() < 1e-3 {
|
||||||
|
return Some(t_cap_out);
|
||||||
|
}
|
||||||
|
let (_t_side_in, t_side_out) = solve_quadratic(
|
||||||
|
dir.length_squared(),
|
||||||
|
pos.dot(dir),
|
||||||
|
pos.length_squared() - self.radius.powi(2),
|
||||||
|
)
|
||||||
|
.expect("the ray starts inside and is not along the axis so *has* to cross the side");
|
||||||
|
Some(t_side_out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_quadratic(a: f32, half_b: f32, c: f32) -> Option<(f32, f32)> {
|
||||||
|
let base = -half_b / a;
|
||||||
|
let d = base * base - c / a;
|
||||||
|
if d < 0. {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let δ = d.sqrt();
|
||||||
|
Some((base - δ, base + δ))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::types::ray;
|
||||||
|
use approx::assert_abs_diff_eq;
|
||||||
|
use glam::vec3;
|
||||||
|
use rand::{Rng, SeedableRng};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_split() {
|
||||||
|
let mut rng = rand_pcg::Pcg64Mcg::seed_from_u64(17);
|
||||||
|
let cyl = Cylinder {
|
||||||
|
center: vec3(1., 2., 3.),
|
||||||
|
semiaxis: vec3(4., 5., 6.),
|
||||||
|
radius: 7.,
|
||||||
|
};
|
||||||
|
for _ in 0..100 {
|
||||||
|
let dir = vec3(rng.gen(), rng.gen(), rng.gen());
|
||||||
|
let (along, ortho) = cyl.split(dir);
|
||||||
|
assert_abs_diff_eq!(along * cyl.semiaxis + ortho, dir, epsilon = 1e-5);
|
||||||
|
assert_abs_diff_eq!(cyl.semiaxis.dot(ortho), 0., epsilon = 1e-5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cylinder() {
|
||||||
|
assert_eq!(
|
||||||
|
YCylinder::flip_ray(ray(vec3(2., 3., 2.), vec3(4., 5., 4.))),
|
||||||
|
ray(vec3(2., 3., 2.), vec3(4., 5., 4.)),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
YCylinder::flip_ray(ray(vec3(2., 3., 2.), vec3(-4., 5., -4.))),
|
||||||
|
ray(vec3(-2., 3., -2.), vec3(4., 5., 4.)),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
YCylinder::flip_ray(ray(vec3(2., 3., 2.), vec3(4., -5., 4.))),
|
||||||
|
ray(vec3(2., -3., 2.), vec3(4., 5., 4.)),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
YCylinder::flip_ray(ray(vec3(2., 3., 2.), vec3(4., 0., 4.))),
|
||||||
|
ray(vec3(2., 3., 2.), vec3(4., 0., 4.)),
|
||||||
|
);
|
||||||
|
|
||||||
|
let r = YCylinder {
|
||||||
|
half_length: 3.,
|
||||||
|
radius: 2.,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(3., 4., 3.), vec3(0., -1., 0.))), None);
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(1., 4., 1.), vec3(0., -1., 0.))), Some(1.));
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(3., 3., 3.), vec3(1., 1., 1.))), None);
|
||||||
|
assert_abs_diff_eq!(
|
||||||
|
r.trace_into(ray(vec3(-3., 2., -3.), vec3(1., 0., 1.))).unwrap(),
|
||||||
|
1.5857864
|
||||||
|
);
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(-3., 2., -3.), vec3(-1., 0., -1.))), None);
|
||||||
|
assert_abs_diff_eq!(
|
||||||
|
r.trace_into(ray(vec3(-3., 1., -3.), vec3(2., 2., 2.))).unwrap(),
|
||||||
|
0.7928932
|
||||||
|
);
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(-3., 2.1, -3.), vec3(2., 2., 2.))), None);
|
||||||
|
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(2., 3., 2.), vec3(1., 1., 1.))), None);
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(-2., 3., -2.), vec3(-1., 1., -1.))), None);
|
||||||
|
assert_eq!(
|
||||||
|
r.trace_into(ray(vec3(1.4142135, 3., 1.4142135), vec3(-1., -1., -1.))),
|
||||||
|
Some(0.)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
r.trace_into(ray(vec3(1.4142135, -3., 1.4142135), vec3(-1., 1., -1.))),
|
||||||
|
Some(0.)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
YCylinder {
|
||||||
|
half_length: 300.,
|
||||||
|
radius: 50.
|
||||||
|
}
|
||||||
|
.trace_into(ray(vec3(-125., 375., 0.), vec3(3., -11., 0.) / 1024.)),
|
||||||
|
Some(25600.)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_abs_diff_eq!(
|
||||||
|
r.trace_out_of(ray(vec3(0., 0., 0.), vec3(1., 1., 1.))).unwrap(),
|
||||||
|
1.4142135
|
||||||
|
);
|
||||||
|
assert_eq!(r.trace_out_of(ray(vec3(0., 0., 0.), vec3(0., 1., 0.))), Some(3.));
|
||||||
|
assert_eq!(r.trace_out_of(ray(vec3(0., 1., 0.), vec3(0., -1., 0.))), Some(4.));
|
||||||
|
assert_eq!(r.trace_out_of(ray(vec3(1., 1., 1.), vec3(0., -1., 0.))), Some(4.));
|
||||||
|
assert_abs_diff_eq!(
|
||||||
|
r.trace_out_of(ray(vec3(1.4142135, 3., 1.4142135), vec3(1., 1., 1.)))
|
||||||
|
.unwrap(),
|
||||||
|
0.
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/shape/mod.rs
Normal file
5
src/shape/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
pub mod cylinder;
|
||||||
|
pub mod rect;
|
||||||
|
|
||||||
|
pub use cylinder::YCylinder;
|
||||||
|
pub use rect::Rect;
|
||||||
90
src/shape/rect.rs
Normal file
90
src/shape/rect.rs
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
use glam::Vec3;
|
||||||
|
|
||||||
|
use crate::types::Ray;
|
||||||
|
|
||||||
|
pub struct Rect {
|
||||||
|
pub size: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rect {
|
||||||
|
/// Отражает луч, чтобы все координаты направления были положительны (допустимо благодаря симметрии Rect).
|
||||||
|
fn flip_ray(ray: Ray) -> Ray {
|
||||||
|
Ray {
|
||||||
|
pos: ray.pos * ray.dir.signum(),
|
||||||
|
dir: ray.dir.abs(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_inside(&self, pt: Vec3) -> bool {
|
||||||
|
pt.abs().cmplt(self.size).all()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trace_into(&self, ray: Ray) -> Option<f32> {
|
||||||
|
let ray = Self::flip_ray(ray);
|
||||||
|
// ray.pos.x + t * ray.dir.x = −size.x
|
||||||
|
let ts = (-self.size - ray.pos) / ray.dir;
|
||||||
|
let t = ts.max_element();
|
||||||
|
let pt = ray.pos + t * ray.dir;
|
||||||
|
if t < 0.0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if pt.cmpgt(self.size).any() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trace_out_of(&self, ray: Ray) -> Option<f32> {
|
||||||
|
let ray = Self::flip_ray(ray);
|
||||||
|
// ray.pos.x + t * ray.dir.x = +size.x
|
||||||
|
let ts = (self.size - ray.pos) / ray.dir;
|
||||||
|
let t = ts.min_element();
|
||||||
|
Some(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::types::ray;
|
||||||
|
use glam::vec3;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rect() {
|
||||||
|
assert_eq!(
|
||||||
|
Rect::flip_ray(ray(vec3(2., 3., 2.), vec3(4., 5., 4.))),
|
||||||
|
ray(vec3(2., 3., 2.), vec3(4., 5., 4.)),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Rect::flip_ray(ray(vec3(2., 3., 2.), vec3(-4., 5., -4.))),
|
||||||
|
ray(vec3(-2., 3., -2.), vec3(4., 5., 4.)),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Rect::flip_ray(ray(vec3(2., 3., 2.), vec3(4., -5., 4.))),
|
||||||
|
ray(vec3(2., -3., 2.), vec3(4., 5., 4.)),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Rect::flip_ray(ray(vec3(2., 3., 2.), vec3(4., 0., 4.))),
|
||||||
|
ray(vec3(2., 3., 2.), vec3(4., 0., 4.)),
|
||||||
|
);
|
||||||
|
|
||||||
|
let r = Rect { size: vec3(2., 3., 2.) };
|
||||||
|
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(3., 3., 3.), vec3(1., 1., 1.))), None);
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(-3., 2., -3.), vec3(1., 0., 1.))), Some(1.));
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(-3., 2., -3.), vec3(-1., 0., -1.))), None);
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(-3., 1., -3.), vec3(2., 2., 2.))), Some(0.5));
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(-3., 2.1, -3.), vec3(2., 2., 2.))), None);
|
||||||
|
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(2., 3., 2.), vec3(1., 1., 1.))), None);
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(-2., 3., -2.), vec3(-1., 1., -1.))), None);
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(2., 3., 2.), vec3(-1., -1., -1.))), Some(0.));
|
||||||
|
assert_eq!(r.trace_into(ray(vec3(2., -3., 2.), vec3(-1., 1., -1.))), Some(0.));
|
||||||
|
|
||||||
|
assert_eq!(r.trace_out_of(ray(vec3(0., 0., 0.), vec3(1., 1., 1.))), Some(2.));
|
||||||
|
assert_eq!(r.trace_out_of(ray(vec3(0., 0., 0.), vec3(0., 1., 0.))), Some(3.));
|
||||||
|
assert_eq!(r.trace_out_of(ray(vec3(0., 1., 0.), vec3(0., -1., 0.))), Some(4.));
|
||||||
|
assert_eq!(r.trace_out_of(ray(vec3(1., 1., 1.), vec3(0., -1., 0.))), Some(4.));
|
||||||
|
assert_eq!(r.trace_out_of(ray(vec3(2., 3., 2.), vec3(1., 1., 1.))), Some(0.));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
use glam::{vec3, Mat3, Vec3};
|
use glam::{vec3, Mat3, Vec3};
|
||||||
|
|
||||||
use crate::riemann::Metric;
|
use crate::riemann::Metric;
|
||||||
|
use crate::shape::YCylinder;
|
||||||
use crate::types::{Location, Ray};
|
use crate::types::{Location, Ray};
|
||||||
|
|
||||||
use super::{Tube, YCylinder};
|
use super::Tube;
|
||||||
|
|
||||||
pub trait FlatCoordinateSystem<T> {
|
pub trait FlatCoordinateSystem<T> {
|
||||||
fn flat_to_global(&self, v: T) -> T;
|
fn flat_to_global(&self, v: T) -> T;
|
||||||
|
|
|
||||||
233
src/tube/mod.rs
233
src/tube/mod.rs
|
|
@ -1,4 +1,4 @@
|
||||||
use glam::{bool, f32, Mat3, Vec3, Vec3Swizzles};
|
use glam::{f32, Mat3, Vec3};
|
||||||
|
|
||||||
use crate::ifaces::{DebugTraceable, RayPath, Traceable};
|
use crate::ifaces::{DebugTraceable, RayPath, Traceable};
|
||||||
use coords::{FlatCoordinateSystem, InnerCS, OuterCS};
|
use coords::{FlatCoordinateSystem, InnerCS, OuterCS};
|
||||||
|
|
@ -226,234 +226,3 @@ impl DebugTraceable for Space {
|
||||||
panic!("tracing didn't terminate");
|
panic!("tracing didn't terminate");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Rect {
|
|
||||||
pub size: Vec3,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Rect {
|
|
||||||
/// Отражает луч, чтобы все координаты направления были положительны (допустимо благодаря симметрии Rect).
|
|
||||||
fn flip_ray(ray: Ray) -> Ray {
|
|
||||||
Ray {
|
|
||||||
pos: ray.pos * ray.dir.signum(),
|
|
||||||
dir: ray.dir.abs(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_inside(&self, pt: Vec3) -> bool {
|
|
||||||
pt.abs().cmplt(self.size).all()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trace_into(&self, ray: Ray) -> Option<f32> {
|
|
||||||
let ray = Self::flip_ray(ray);
|
|
||||||
// ray.pos.x + t * ray.dir.x = −size.x
|
|
||||||
let ts = (-self.size - ray.pos) / ray.dir;
|
|
||||||
let t = ts.max_element();
|
|
||||||
let pt = ray.pos + t * ray.dir;
|
|
||||||
if t < 0.0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if pt.cmpgt(self.size).any() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trace_out_of(&self, ray: Ray) -> Option<f32> {
|
|
||||||
let ray = Self::flip_ray(ray);
|
|
||||||
// ray.pos.x + t * ray.dir.x = +size.x
|
|
||||||
let ts = (self.size - ray.pos) / ray.dir;
|
|
||||||
let t = ts.min_element();
|
|
||||||
Some(t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn solve_quadratic(a: f32, half_b: f32, c: f32) -> Option<(f32, f32)> {
|
|
||||||
let base = -half_b / a;
|
|
||||||
let d = base * base - c / a;
|
|
||||||
if d < 0. {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let δ = d.sqrt();
|
|
||||||
Some((base - δ, base + δ))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Цилиндр с центром в начале координат и осью вдоль оси Y.
|
|
||||||
struct YCylinder {
|
|
||||||
pub half_length: f32,
|
|
||||||
pub radius: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl YCylinder {
|
|
||||||
/// Отражает луч, чтобы все координаты направления были положительны (допустимо благодаря симметрии YCylinder).
|
|
||||||
fn flip_ray(ray: Ray) -> Ray {
|
|
||||||
Ray {
|
|
||||||
pos: ray.pos * ray.dir.signum(),
|
|
||||||
dir: ray.dir.abs(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_inside(&self, pt: Vec3) -> bool {
|
|
||||||
let r = f32::hypot(pt.x, pt.z);
|
|
||||||
pt.y.abs() < self.half_length && r < self.radius
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trace_into(&self, ray: Ray) -> Option<f32> {
|
|
||||||
let ray = Self::flip_ray(ray);
|
|
||||||
|
|
||||||
// 1. ray.pos.y + t * ray.dir.y = −half_length
|
|
||||||
let t_cap_in = (-self.half_length - ray.pos.y) / ray.dir.y;
|
|
||||||
let t_cap_out = (self.half_length - ray.pos.y) / ray.dir.y;
|
|
||||||
|
|
||||||
// 2. (ray.pos.x + t * ray.dir.x)² + (ray.pos.z + t * ray.dir.z)² = radius²
|
|
||||||
let pos = ray.pos.xz();
|
|
||||||
let dir = ray.dir.xz();
|
|
||||||
if dir.length_squared() < 1e-3 {
|
|
||||||
if pos.length_squared() >= self.radius.powi(2) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
return Some(t_cap_in).filter(|&t| t > 0.);
|
|
||||||
}
|
|
||||||
let (t_side_in, t_side_out) = solve_quadratic(
|
|
||||||
dir.length_squared(),
|
|
||||||
pos.dot(dir),
|
|
||||||
pos.length_squared() - self.radius.powi(2),
|
|
||||||
)?;
|
|
||||||
let t = f32::max(t_cap_in, t_side_in);
|
|
||||||
if t < 0. {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if t >= t_cap_out || t >= t_side_out {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trace_out_of(&self, ray: Ray) -> Option<f32> {
|
|
||||||
let ray = Self::flip_ray(ray);
|
|
||||||
let t_cap_out = (self.half_length - ray.pos.y) / ray.dir.y;
|
|
||||||
let pos = ray.pos.xz();
|
|
||||||
let dir = ray.dir.xz();
|
|
||||||
if dir.length_squared() < 1e-3 {
|
|
||||||
return Some(t_cap_out);
|
|
||||||
}
|
|
||||||
let (_t_side_in, t_side_out) = solve_quadratic(
|
|
||||||
dir.length_squared(),
|
|
||||||
pos.dot(dir),
|
|
||||||
pos.length_squared() - self.radius.powi(2),
|
|
||||||
)
|
|
||||||
.expect("the ray starts inside and is not along the axis so *has* to cross the side");
|
|
||||||
Some(t_side_out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::types::ray;
|
|
||||||
use approx::assert_abs_diff_eq;
|
|
||||||
use glam::vec3;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rect() {
|
|
||||||
assert_eq!(
|
|
||||||
Rect::flip_ray(ray(vec3(2., 3., 2.), vec3(4., 5., 4.))),
|
|
||||||
ray(vec3(2., 3., 2.), vec3(4., 5., 4.)),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Rect::flip_ray(ray(vec3(2., 3., 2.), vec3(-4., 5., -4.))),
|
|
||||||
ray(vec3(-2., 3., -2.), vec3(4., 5., 4.)),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Rect::flip_ray(ray(vec3(2., 3., 2.), vec3(4., -5., 4.))),
|
|
||||||
ray(vec3(2., -3., 2.), vec3(4., 5., 4.)),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Rect::flip_ray(ray(vec3(2., 3., 2.), vec3(4., 0., 4.))),
|
|
||||||
ray(vec3(2., 3., 2.), vec3(4., 0., 4.)),
|
|
||||||
);
|
|
||||||
|
|
||||||
let r = Rect { size: vec3(2., 3., 2.) };
|
|
||||||
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(3., 3., 3.), vec3(1., 1., 1.))), None);
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(-3., 2., -3.), vec3(1., 0., 1.))), Some(1.));
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(-3., 2., -3.), vec3(-1., 0., -1.))), None);
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(-3., 1., -3.), vec3(2., 2., 2.))), Some(0.5));
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(-3., 2.1, -3.), vec3(2., 2., 2.))), None);
|
|
||||||
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(2., 3., 2.), vec3(1., 1., 1.))), None);
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(-2., 3., -2.), vec3(-1., 1., -1.))), None);
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(2., 3., 2.), vec3(-1., -1., -1.))), Some(0.));
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(2., -3., 2.), vec3(-1., 1., -1.))), Some(0.));
|
|
||||||
|
|
||||||
assert_eq!(r.trace_out_of(ray(vec3(0., 0., 0.), vec3(1., 1., 1.))), Some(2.));
|
|
||||||
assert_eq!(r.trace_out_of(ray(vec3(0., 0., 0.), vec3(0., 1., 0.))), Some(3.));
|
|
||||||
assert_eq!(r.trace_out_of(ray(vec3(0., 1., 0.), vec3(0., -1., 0.))), Some(4.));
|
|
||||||
assert_eq!(r.trace_out_of(ray(vec3(1., 1., 1.), vec3(0., -1., 0.))), Some(4.));
|
|
||||||
assert_eq!(r.trace_out_of(ray(vec3(2., 3., 2.), vec3(1., 1., 1.))), Some(0.));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_cylinder() {
|
|
||||||
assert_eq!(
|
|
||||||
YCylinder::flip_ray(ray(vec3(2., 3., 2.), vec3(4., 5., 4.))),
|
|
||||||
ray(vec3(2., 3., 2.), vec3(4., 5., 4.)),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
YCylinder::flip_ray(ray(vec3(2., 3., 2.), vec3(-4., 5., -4.))),
|
|
||||||
ray(vec3(-2., 3., -2.), vec3(4., 5., 4.)),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
YCylinder::flip_ray(ray(vec3(2., 3., 2.), vec3(4., -5., 4.))),
|
|
||||||
ray(vec3(2., -3., 2.), vec3(4., 5., 4.)),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
YCylinder::flip_ray(ray(vec3(2., 3., 2.), vec3(4., 0., 4.))),
|
|
||||||
ray(vec3(2., 3., 2.), vec3(4., 0., 4.)),
|
|
||||||
);
|
|
||||||
|
|
||||||
let r = YCylinder {
|
|
||||||
half_length: 3.,
|
|
||||||
radius: 2.,
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(3., 4., 3.), vec3(0., -1., 0.))), None);
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(1., 4., 1.), vec3(0., -1., 0.))), Some(1.));
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(3., 3., 3.), vec3(1., 1., 1.))), None);
|
|
||||||
assert_abs_diff_eq!(
|
|
||||||
r.trace_into(ray(vec3(-3., 2., -3.), vec3(1., 0., 1.))).unwrap(),
|
|
||||||
1.5857864
|
|
||||||
);
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(-3., 2., -3.), vec3(-1., 0., -1.))), None);
|
|
||||||
assert_abs_diff_eq!(
|
|
||||||
r.trace_into(ray(vec3(-3., 1., -3.), vec3(2., 2., 2.))).unwrap(),
|
|
||||||
0.7928932
|
|
||||||
);
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(-3., 2.1, -3.), vec3(2., 2., 2.))), None);
|
|
||||||
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(2., 3., 2.), vec3(1., 1., 1.))), None);
|
|
||||||
assert_eq!(r.trace_into(ray(vec3(-2., 3., -2.), vec3(-1., 1., -1.))), None);
|
|
||||||
assert_eq!(
|
|
||||||
r.trace_into(ray(vec3(1.4142135, 3., 1.4142135), vec3(-1., -1., -1.))),
|
|
||||||
Some(0.)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
r.trace_into(ray(vec3(1.4142135, -3., 1.4142135), vec3(-1., 1., -1.))),
|
|
||||||
Some(0.)
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_abs_diff_eq!(
|
|
||||||
r.trace_out_of(ray(vec3(0., 0., 0.), vec3(1., 1., 1.))).unwrap(),
|
|
||||||
1.4142135
|
|
||||||
);
|
|
||||||
assert_eq!(r.trace_out_of(ray(vec3(0., 0., 0.), vec3(0., 1., 0.))), Some(3.));
|
|
||||||
assert_eq!(r.trace_out_of(ray(vec3(0., 1., 0.), vec3(0., -1., 0.))), Some(4.));
|
|
||||||
assert_eq!(r.trace_out_of(ray(vec3(1., 1., 1.), vec3(0., -1., 0.))), Some(4.));
|
|
||||||
assert_abs_diff_eq!(
|
|
||||||
r.trace_out_of(ray(vec3(1.4142135, 3., 1.4142135), vec3(1., 1., 1.)))
|
|
||||||
.unwrap(),
|
|
||||||
0.
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user