Add shapes
This commit is contained in:
parent
664077b46e
commit
44efe70348
153
src/bin/flat.rs
153
src/bin/flat.rs
|
|
@ -222,11 +222,164 @@ impl Metric for Coil {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Ray {
|
||||
pos: Vec2,
|
||||
dir: Vec2,
|
||||
}
|
||||
|
||||
mod basic_shapes {
|
||||
use glam::{Vec2, vec2};
|
||||
use crate::{Ray, shape};
|
||||
|
||||
pub struct Rect {
|
||||
pub size: Vec2,
|
||||
}
|
||||
|
||||
impl Rect {
|
||||
/// Отражает луч, чтобы все координаты направления были положительны (допустимо благодаря симметрии Rect).
|
||||
fn flip_ray(ray: Ray) -> Ray {
|
||||
Ray { pos: ray.pos * ray.dir.signum(), dir: ray.dir.abs() }
|
||||
}
|
||||
}
|
||||
|
||||
impl shape::Shape for Rect {
|
||||
fn is_inside(&self, pt: Vec2) -> 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 visualise(&self) -> Vec<Vec2> {
|
||||
vec![vec2(-self.size.x, -self.size.y), vec2(self.size.x, -self.size.y), vec2(self.size.x, self.size.y), vec2(-self.size.x, self.size.y)]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::shape::Shape;
|
||||
|
||||
#[test]
|
||||
fn test_rect() {
|
||||
assert_eq!(Rect::flip_ray(Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, 5.0) }), Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, 5.0) });
|
||||
assert_eq!(Rect::flip_ray(Ray { pos: vec2(2.0, 3.0), dir: vec2(-4.0, 5.0) }), Ray { pos: vec2(-2.0, 3.0), dir: vec2(4.0, 5.0) });
|
||||
assert_eq!(Rect::flip_ray(Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, -5.0) }), Ray { pos: vec2(2.0, -3.0), dir: vec2(4.0, 5.0) });
|
||||
assert_eq!(Rect::flip_ray(Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, 0.0) }), Ray { pos: vec2(2.0, 3.0), dir: vec2(4.0, 0.0) });
|
||||
|
||||
let r = Rect { size: vec2(2.0, 3.0) };
|
||||
|
||||
assert_eq!(r.trace_into(Ray { pos: vec2(3.0, 3.0), dir: vec2(1.0, 1.0) }), None);
|
||||
assert_eq!(r.trace_into(Ray { pos: vec2(-3.0, 2.0), dir: vec2(1.0, 0.0) }), Some(1.0));
|
||||
assert_eq!(r.trace_into(Ray { pos: vec2(-3.0, 2.0), dir: vec2(-1.0, 0.0) }), None);
|
||||
assert_eq!(r.trace_into(Ray { pos: vec2(-3.0, 1.0), dir: vec2(2.0, 2.0) }), Some(0.5));
|
||||
assert_eq!(r.trace_into(Ray { pos: vec2(-3.0, 2.1), dir: vec2(2.0, 2.0) }), None);
|
||||
|
||||
assert_eq!(r.trace_into(Ray { pos: vec2(2.0, 3.0), dir: vec2(1.0, 1.0) }), None);
|
||||
assert_eq!(r.trace_into(Ray { pos: vec2(-2.0, 3.0), dir: vec2(-1.0, 1.0) }), None);
|
||||
assert_eq!(r.trace_into(Ray { pos: vec2(2.0, 3.0), dir: vec2(-1.0, -1.0) }), Some(0.0));
|
||||
assert_eq!(r.trace_into(Ray { pos: vec2(2.0, -3.0), dir: vec2(-1.0, 1.0) }), Some(0.0));
|
||||
|
||||
assert_eq!(r.trace_out_of(Ray { pos: vec2(0.0, 0.0), dir: vec2(1.0, 1.0) }), Some(2.0));
|
||||
assert_eq!(r.trace_out_of(Ray { pos: vec2(0.0, 0.0), dir: vec2(0.0, 1.0) }), Some(3.0));
|
||||
assert_eq!(r.trace_out_of(Ray { pos: vec2(0.0, 1.0), dir: vec2(0.0, -1.0) }), Some(4.0));
|
||||
assert_eq!(r.trace_out_of(Ray { pos: vec2(1.0, 1.0), dir: vec2(0.0, -1.0) }), Some(4.0));
|
||||
assert_eq!(r.trace_out_of(Ray { pos: vec2(2.0, 3.0), dir: vec2(1.0, 1.0) }), Some(0.0));
|
||||
}
|
||||
}
|
||||
|
||||
mod shape {
|
||||
use glam::{Affine2, Vec2};
|
||||
use crate::Ray;
|
||||
|
||||
pub trait Shape {
|
||||
fn is_inside(&self, pt: Vec2) -> bool;
|
||||
|
||||
/// Ищет ближайшее пересечение луча с границей в направлении внутрь контура. Возвращает расстояние (в ray.dir).
|
||||
fn trace_into(&self, ray: Ray) -> Option<f32>;
|
||||
/// Ищет ближайшее пересечение луча с границей в направлении вовне контура. Возвращает расстояние (в ray.dir).
|
||||
fn trace_out_of(&self, ray: Ray) -> Option<f32>;
|
||||
|
||||
/// Возвращает визуальное представление контура, для отладки.
|
||||
fn visualise(&self) -> Vec<Vec2>;
|
||||
}
|
||||
|
||||
pub struct MovedShape<S: Shape> {
|
||||
pub shape: S,
|
||||
pub transform: Affine2, // transform(координаты контура) = 0
|
||||
}
|
||||
|
||||
impl<S: Shape> MovedShape<S> {
|
||||
fn pt_to_inner(&self, pt: Vec2) -> Vec2 {
|
||||
self.transform.transform_point2(pt)
|
||||
}
|
||||
fn pt_to_outer(&self, pt: Vec2) -> Vec2 {
|
||||
self.transform.inverse().transform_point2(pt)
|
||||
}
|
||||
fn vec_to_inner(&self, vec: Vec2) -> Vec2 {
|
||||
self.transform.transform_vector2(vec)
|
||||
}
|
||||
fn vec_to_outer(&self, vec: Vec2) -> Vec2 {
|
||||
self.transform.inverse().transform_vector2(vec)
|
||||
}
|
||||
fn ray_to_inner(&self, ray: Ray) -> Ray {
|
||||
Ray { pos: self.pt_to_inner(ray.pos), dir: self.vec_to_inner(ray.dir) }
|
||||
}
|
||||
fn ray_to_outer(&self, ray: Ray) -> Ray {
|
||||
Ray { pos: self.pt_to_outer(ray.pos), dir: self.vec_to_outer(ray.dir) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Shape> Shape for MovedShape<S> {
|
||||
fn is_inside(&self, pt: Vec2) -> bool {
|
||||
self.shape.is_inside(self.pt_to_inner(pt))
|
||||
}
|
||||
fn trace_into(&self, ray: Ray) -> Option<f32> {
|
||||
self.shape.trace_into(self.ray_to_inner(ray))
|
||||
}
|
||||
fn trace_out_of(&self, ray: Ray) -> Option<f32> {
|
||||
self.shape.trace_out_of(self.ray_to_inner(ray))
|
||||
}
|
||||
fn visualise(&self) -> Vec<Vec2> {
|
||||
self.shape.visualise().iter().map(|pt| self.pt_to_outer(*pt)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InvertedShape<S: Shape> {
|
||||
pub shape: S,
|
||||
}
|
||||
|
||||
impl<S: Shape> Shape for InvertedShape<S> {
|
||||
fn is_inside(&self, pt: Vec2) -> bool {
|
||||
!self.shape.is_inside(pt)
|
||||
}
|
||||
fn trace_into(&self, ray: Ray) -> Option<f32> {
|
||||
self.shape.trace_out_of(ray)
|
||||
}
|
||||
fn trace_out_of(&self, ray: Ray) -> Option<f32> {
|
||||
self.shape.trace_into(ray)
|
||||
}
|
||||
fn visualise(&self) -> Vec<Vec2> {
|
||||
self.shape.visualise()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Grid {
|
||||
hlines: Vec<f32>,
|
||||
vlines: Vec<f32>,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user