mirror of
https://github.com/maplibre/maplibre-rs.git
synced 2025-12-08 19:05:57 +00:00
Add two ways of determining view bounding box: view_bounding_box2 and view_bounding_box
This commit is contained in:
parent
0ebbb80f90
commit
974f7eb2c9
@ -2,16 +2,13 @@
|
|||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use cgmath::Vector2;
|
use cgmath::{ElementWise, EuclideanSpace, InnerSpace, Point2, Point3, Vector2, Vector3, Vector4};
|
||||||
use winit::event::{
|
use winit::event::{DeviceEvent, ElementState, KeyboardInput, TouchPhase, WindowEvent};
|
||||||
DeviceEvent, ElementState, KeyboardInput, MouseButton, TouchPhase, WindowEvent,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::input::pan_handler::PanHandler;
|
use crate::input::pan_handler::PanHandler;
|
||||||
use crate::input::pinch_handler::PinchHandler;
|
use crate::input::pinch_handler::PinchHandler;
|
||||||
use crate::input::shift_handler::ShiftHandler;
|
use crate::input::shift_handler::ShiftHandler;
|
||||||
use crate::input::tilt_handler::TiltHandler;
|
use crate::input::tilt_handler::TiltHandler;
|
||||||
use crate::render::camera::Camera;
|
|
||||||
use crate::render::render_state::RenderState;
|
use crate::render::render_state::RenderState;
|
||||||
|
|
||||||
mod pan_handler;
|
mod pan_handler;
|
||||||
|
|||||||
@ -16,8 +16,6 @@ impl UpdateState for TiltHandler {
|
|||||||
|
|
||||||
let delta = self.delta_pitch * dt;
|
let delta = self.delta_pitch * dt;
|
||||||
state.camera.pitch += Rad::from(delta);
|
state.camera.pitch += Rad::from(delta);
|
||||||
let x: Deg<f64> = state.camera.pitch.into();
|
|
||||||
println!("{:?}", x);
|
|
||||||
self.delta_pitch -= delta;
|
self.delta_pitch -= delta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
use cgmath::prelude::*;
|
use cgmath::prelude::*;
|
||||||
use cgmath::{Matrix4, Vector2, Vector3, Vector4};
|
use cgmath::{Matrix4, Point2, Point3, Vector2, Vector3, Vector4};
|
||||||
|
|
||||||
use crate::render::shaders::ShaderCamera;
|
use crate::render::shaders::ShaderCamera;
|
||||||
|
use crate::util::math::{Aabb2, Aabb3, Plane};
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f64> = cgmath::Matrix4::new(
|
pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f64> = cgmath::Matrix4::new(
|
||||||
@ -124,8 +125,7 @@ impl Camera {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/dxtecharts/the-direct3d-transformation-pipeline
|
// https://docs.microsoft.com/en-us/windows/win32/dxtecharts/the-direct3d-transformation-pipeline
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/dxtecharts/the-direct3d-transformation-pipeline
|
fn clip_to_window_via_transform(&self, clip: &Vector4<f64>) -> Vector4<f64> {
|
||||||
fn clip_to_window_matrix(clip: &Vector4<f64>, width: f64, height: f64) -> Vector4<f64> {
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let ndc = Vector4::new(
|
let ndc = Vector4::new(
|
||||||
clip.x / clip.w,
|
clip.x / clip.w,
|
||||||
@ -134,16 +134,15 @@ impl Camera {
|
|||||||
clip.w / clip.w
|
clip.w / clip.w
|
||||||
);
|
);
|
||||||
|
|
||||||
let window = Self::clip_to_window_transform(width, height) * ndc;
|
let window = Self::clip_to_window_transform(self.width, self.height) * ndc;
|
||||||
window
|
window
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_to_world(
|
/// Order of transformations reversed: https://computergraphics.stackexchange.com/questions/6087/screen-space-coordinates-to-eye-space-conversion/6093
|
||||||
window: &Vector3<f64>,
|
/// `w` is lost.
|
||||||
view_proj: &Matrix4<f64>,
|
///
|
||||||
width: f64,
|
/// OpenGL explanation: https://www.khronos.org/opengl/wiki/Compute_eye_space_from_window_space#From_window_to_ndc
|
||||||
height: f64,
|
fn window_to_world(&self, window: &Vector3<f64>, view_proj: &Matrix4<f64>) -> Vector3<f64> {
|
||||||
) -> Vector3<f64> {
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let fixed_window = Vector4::new(
|
let fixed_window = Vector4::new(
|
||||||
window.x,
|
window.x,
|
||||||
@ -152,7 +151,7 @@ impl Camera {
|
|||||||
1.0
|
1.0
|
||||||
);
|
);
|
||||||
|
|
||||||
let ndc = Self::clip_to_window_transform(width, height)
|
let ndc = Self::clip_to_window_transform(self.width, self.height)
|
||||||
.invert()
|
.invert()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
* fixed_window;
|
* fixed_window;
|
||||||
@ -166,6 +165,8 @@ impl Camera {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Alternative implementation to `window_to_world`
|
/// Alternative implementation to `window_to_world`
|
||||||
|
///
|
||||||
|
/// https://docs.rs/nalgebra-glm/latest/src/nalgebra_glm/ext/matrix_projection.rs.html#164-181
|
||||||
fn window_to_world_nalgebra(
|
fn window_to_world_nalgebra(
|
||||||
window: &Vector3<f64>,
|
window: &Vector3<f64>,
|
||||||
view_proj: &Matrix4<f64>,
|
view_proj: &Matrix4<f64>,
|
||||||
@ -187,29 +188,110 @@ impl Camera {
|
|||||||
world
|
world
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Idea comes from: https://dondi.lmu.build/share/cg/unproject-explained.pdf
|
||||||
pub fn window_to_world_z0(
|
pub fn window_to_world_z0(
|
||||||
&self,
|
&self,
|
||||||
window: &Vector2<f64>,
|
window: &Vector2<f64>,
|
||||||
view_proj: &Matrix4<f64>,
|
view_proj: &Matrix4<f64>,
|
||||||
) -> Vector3<f64> {
|
) -> Vector3<f64> {
|
||||||
let near_world = Camera::window_to_world(
|
let near_world = self.window_to_world(&Vector3::new(window.x, window.y, 0.0), &view_proj);
|
||||||
&Vector3::new(window.x, window.y, 0.0),
|
|
||||||
&view_proj,
|
|
||||||
self.width,
|
|
||||||
self.height,
|
|
||||||
);
|
|
||||||
|
|
||||||
let far_world = Camera::window_to_world(
|
let far_world = self.window_to_world(&Vector3::new(window.x, window.y, 1.0), &view_proj);
|
||||||
&Vector3::new(window.x, window.y, 1.0),
|
|
||||||
&view_proj,
|
|
||||||
self.width,
|
|
||||||
self.height,
|
|
||||||
);
|
|
||||||
|
|
||||||
// for z = 0 in world coordinates
|
// for z = 0 in world coordinates
|
||||||
let u = -near_world.z / (far_world.z - near_world.z);
|
let u = -near_world.z / (far_world.z - near_world.z);
|
||||||
|
if u < 0.0 || u > 1.0 {
|
||||||
|
panic!("interpolation factor is out of bounds")
|
||||||
|
}
|
||||||
near_world + u * (far_world - near_world)
|
near_world + u * (far_world - near_world)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn view_bounding_box2(&self, perspective: &Perspective) -> Option<Aabb2<f64>> {
|
||||||
|
let view_proj = self.calc_view_proj(perspective);
|
||||||
|
|
||||||
|
let vec = vec![
|
||||||
|
Vector2::new(0.0, 0.0),
|
||||||
|
Vector2::new(self.width, 0.0),
|
||||||
|
Vector2::new(self.width, self.height),
|
||||||
|
Vector2::new(0.0, self.height),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.map(|point| self.window_to_world_z0(point, &view_proj))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let min_x = vec
|
||||||
|
.iter()
|
||||||
|
.map(|point| point.x)
|
||||||
|
.min_by(|a, b| a.partial_cmp(b).unwrap())?;
|
||||||
|
let min_y = vec
|
||||||
|
.iter()
|
||||||
|
.map(|point| point.y)
|
||||||
|
.min_by(|a, b| a.partial_cmp(b).unwrap())?;
|
||||||
|
let max_x = vec
|
||||||
|
.iter()
|
||||||
|
.map(|point| point.x)
|
||||||
|
.max_by(|a, b| a.partial_cmp(b).unwrap())?;
|
||||||
|
let max_y = vec
|
||||||
|
.iter()
|
||||||
|
.map(|point| point.y)
|
||||||
|
.max_by(|a, b| a.partial_cmp(b).unwrap())?;
|
||||||
|
Some(Aabb2::new(
|
||||||
|
Point2::new(min_x, min_y),
|
||||||
|
Point2::new(max_x, max_y),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn view_bounding_box(&self, perspective: &Perspective) -> Option<Aabb2<f64>> {
|
||||||
|
let view_proj = self.calc_view_proj(perspective);
|
||||||
|
let a = view_proj * Vector4::new(0.0, 0.0, 0.0, 1.0);
|
||||||
|
let b = view_proj * Vector4::new(1.0, 0.0, 0.0, 1.0);
|
||||||
|
let c = view_proj * Vector4::new(1.0, 1.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
let a = self.clip_to_window_via_transform(&a);
|
||||||
|
let a_ndc = a.truncate();
|
||||||
|
let b_ndc = self.clip_to_window_via_transform(&b).truncate();
|
||||||
|
let c_ndc = self.clip_to_window_via_transform(&c).truncate();
|
||||||
|
let to_ndc = Vector3::new(1.0 / self.width, 1.0 / self.height, 1.0);
|
||||||
|
let plane: Plane<f64> = Plane::from_points(
|
||||||
|
Point3::from_vec(a_ndc.mul_element_wise(to_ndc)),
|
||||||
|
Point3::from_vec(b_ndc.mul_element_wise(to_ndc)),
|
||||||
|
Point3::from_vec(c_ndc.mul_element_wise(to_ndc)),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
println!("{:?}", &plane);
|
||||||
|
|
||||||
|
let mut points = plane.intersection_points_aabb3(&Aabb3::new(
|
||||||
|
Point3::new(0.0, 0.0, 0.0).into(),
|
||||||
|
Point3::new(1.0, 1.0, 1.0).into(),
|
||||||
|
));
|
||||||
|
|
||||||
|
let from_ndc = Vector3::new(self.width, self.height, 1.0);
|
||||||
|
let vec = points
|
||||||
|
.iter()
|
||||||
|
.map(|point| self.window_to_world(&point.mul_element_wise(from_ndc), &view_proj))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let min_x = vec
|
||||||
|
.iter()
|
||||||
|
.map(|point| point.x)
|
||||||
|
.min_by(|a, b| a.partial_cmp(b).unwrap())?;
|
||||||
|
let min_y = vec
|
||||||
|
.iter()
|
||||||
|
.map(|point| point.y)
|
||||||
|
.min_by(|a, b| a.partial_cmp(b).unwrap())?;
|
||||||
|
let max_x = vec
|
||||||
|
.iter()
|
||||||
|
.map(|point| point.x)
|
||||||
|
.max_by(|a, b| a.partial_cmp(b).unwrap())?;
|
||||||
|
let max_y = vec
|
||||||
|
.iter()
|
||||||
|
.map(|point| point.y)
|
||||||
|
.max_by(|a, b| a.partial_cmp(b).unwrap())?;
|
||||||
|
Some(Aabb2::new(
|
||||||
|
Point2::new(min_x, min_y),
|
||||||
|
Point2::new(max_x, max_y),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Perspective {
|
pub struct Perspective {
|
||||||
@ -246,6 +328,7 @@ impl Perspective {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::render::camera;
|
||||||
use cgmath::{AbsDiffEq, ElementWise, Matrix4, SquareMatrix, Vector2, Vector3, Vector4};
|
use cgmath::{AbsDiffEq, ElementWise, Matrix4, SquareMatrix, Vector2, Vector3, Vector4};
|
||||||
|
|
||||||
use super::{Camera, Perspective};
|
use super::{Camera, Perspective};
|
||||||
@ -282,7 +365,7 @@ mod tests {
|
|||||||
println!("world_pos: {:?}", view_proj.invert().unwrap() * clip);
|
println!("world_pos: {:?}", view_proj.invert().unwrap() * clip);
|
||||||
|
|
||||||
println!("window: {:?}", Camera::clip_to_window(&clip, width, height));
|
println!("window: {:?}", Camera::clip_to_window(&clip, width, height));
|
||||||
let window = Camera::clip_to_window_matrix(&clip, width, height);
|
let window = camera.clip_to_window_via_transform(&clip);
|
||||||
println!("window (matrix): {:?}", window);
|
println!("window (matrix): {:?}", window);
|
||||||
|
|
||||||
// --------- nalgebra
|
// --------- nalgebra
|
||||||
@ -320,19 +403,9 @@ mod tests {
|
|||||||
let window = Vector2::new(960.0, 631.0); // 0, 4096: passt nicht
|
let window = Vector2::new(960.0, 631.0); // 0, 4096: passt nicht
|
||||||
//let window = Vector2::new(962.0, 1.0); // 0, 300: passt nicht
|
//let window = Vector2::new(962.0, 1.0); // 0, 300: passt nicht
|
||||||
//let window = Vector2::new(960.0, 540.0); // 0, 0 passt
|
//let window = Vector2::new(960.0, 540.0); // 0, 0 passt
|
||||||
let near_world = Camera::window_to_world(
|
let near_world = camera.window_to_world(&Vector3::new(window.x, window.y, 0.0), &view_proj);
|
||||||
&Vector3::new(window.x, window.y, 0.0),
|
|
||||||
&view_proj,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
);
|
|
||||||
|
|
||||||
let far_world = Camera::window_to_world(
|
let far_world = camera.window_to_world(&Vector3::new(window.x, window.y, 1.0), &view_proj);
|
||||||
&Vector3::new(window.x, window.y, 1.0),
|
|
||||||
&view_proj,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
);
|
|
||||||
|
|
||||||
// for z = 0 in world coordinates
|
// for z = 0 in world coordinates
|
||||||
let u = -near_world.z / (far_world.z - near_world.z);
|
let u = -near_world.z / (far_world.z - near_world.z);
|
||||||
|
|||||||
@ -350,6 +350,9 @@ impl RenderState {
|
|||||||
// TODO: Could we draw inspiration from StagingBelt (https://docs.rs/wgpu/latest/wgpu/util/struct.StagingBelt.html)?
|
// TODO: Could we draw inspiration from StagingBelt (https://docs.rs/wgpu/latest/wgpu/util/struct.StagingBelt.html)?
|
||||||
// TODO: What is StagingBelt for?
|
// TODO: What is StagingBelt for?
|
||||||
pub fn upload_tile_geometry(&mut self, worker_loop: &WorkerLoop) {
|
pub fn upload_tile_geometry(&mut self, worker_loop: &WorkerLoop) {
|
||||||
|
println!("1: {:?}", self.camera.view_bounding_box(&self.perspective));
|
||||||
|
println!("2: {:?}", self.camera.view_bounding_box2(&self.perspective));
|
||||||
|
|
||||||
let upload = worker_loop.pop_all();
|
let upload = worker_loop.pop_all();
|
||||||
|
|
||||||
for layer in upload.iter() {
|
for layer in upload.iter() {
|
||||||
|
|||||||
305
src/util/math.rs
Normal file
305
src/util/math.rs
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
use cgmath::{
|
||||||
|
ulps_eq, BaseFloat, BaseNum, EuclideanSpace, InnerSpace, Point2, Point3, Vector3, Vector4, Zero,
|
||||||
|
};
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// A 3-dimensional plane formed from the equation: `A*x + B*y + C*z - D = 0`.
|
||||||
|
///
|
||||||
|
/// # Fields
|
||||||
|
///
|
||||||
|
/// - `n`: a unit vector representing the normal of the plane where:
|
||||||
|
/// - `n.x`: corresponds to `A` in the plane equation
|
||||||
|
/// - `n.y`: corresponds to `B` in the plane equation
|
||||||
|
/// - `n.z`: corresponds to `C` in the plane equation
|
||||||
|
/// - `d`: the distance value, corresponding to `D` in the plane equation
|
||||||
|
///
|
||||||
|
/// # Notes
|
||||||
|
///
|
||||||
|
/// The `A*x + B*y + C*z - D = 0` form is preferred over the other common
|
||||||
|
/// alternative, `A*x + B*y + C*z + D = 0`, because it tends to avoid
|
||||||
|
/// superfluous negations (see _Real Time Collision Detection_, p. 55).
|
||||||
|
///
|
||||||
|
/// Copied from: https://github.com/rustgd/collision-rs
|
||||||
|
pub struct Plane<S> {
|
||||||
|
/// Plane normal
|
||||||
|
pub n: Vector3<S>,
|
||||||
|
/// Plane distance value
|
||||||
|
pub d: S,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: BaseFloat> Plane<S> {
|
||||||
|
/// Construct a plane from a normal vector and a scalar distance. The
|
||||||
|
/// plane will be perpendicular to `n`, and `d` units offset from the
|
||||||
|
/// origin.
|
||||||
|
pub fn new(n: Vector3<S>, d: S) -> Plane<S> {
|
||||||
|
Plane { n, d }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a plane that passes through the the three points `a`, `b` and `c`
|
||||||
|
pub fn from_points(a: Point3<S>, b: Point3<S>, c: Point3<S>) -> Option<Plane<S>> {
|
||||||
|
// create two vectors that run parallel to the plane
|
||||||
|
let v0 = b - a;
|
||||||
|
let v1 = c - a;
|
||||||
|
|
||||||
|
// find the normal vector that is perpendicular to v1 and v2
|
||||||
|
let n = v0.cross(v1);
|
||||||
|
if ulps_eq!(n, &Vector3::zero()) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// compute the normal and the distance to the plane
|
||||||
|
let n = n.normalize();
|
||||||
|
let d = -a.dot(n);
|
||||||
|
|
||||||
|
Some(Plane::new(n, d))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a plane from a point and a normal vector.
|
||||||
|
/// The plane will contain the point `p` and be perpendicular to `n`.
|
||||||
|
pub fn from_point_normal(p: Point3<S>, n: Vector3<S>) -> Plane<S> {
|
||||||
|
Plane { n, d: p.dot(n) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersection_distance_ray(
|
||||||
|
&self,
|
||||||
|
ray_origin: &Vector3<S>,
|
||||||
|
ray_direction: &Vector3<S>,
|
||||||
|
) -> Option<S> {
|
||||||
|
let vd: S =
|
||||||
|
self.n.x * ray_direction.x + self.n.y * ray_direction.y + self.n.z * ray_direction.z;
|
||||||
|
if vd == S::zero() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let t: S =
|
||||||
|
-(self.n.x * ray_origin.x + self.n.y * ray_origin.y + self.n.z * ray_origin.z + self.d)
|
||||||
|
/ vd;
|
||||||
|
|
||||||
|
return Some(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns unsorted intersection points with an Aabb3
|
||||||
|
/// Adopted from: https://www.asawicki.info/news_1428_finding_polygon_of_plane-aabb_intersection
|
||||||
|
/// Inspired by: https://godotengine.org/qa/54688/camera-frustum-intersection-with-plane
|
||||||
|
pub fn intersection_points_aabb3(&self, aabb: &Aabb3<S>) -> Vec<Vector3<S>> {
|
||||||
|
let mut out_points: Vec<Vector3<S>> = Vec::new();
|
||||||
|
let aabb_min: Vector3<S> = aabb.min.to_vec().into();
|
||||||
|
let aabb_max: Vector3<S> = aabb.max.to_vec().into();
|
||||||
|
|
||||||
|
// Test edges along X axis, pointing right.
|
||||||
|
let mut dir: Vector3<S> = Vector3::new(aabb_max.x - aabb_min.x, S::zero(), S::zero());
|
||||||
|
let mut orig = aabb_min;
|
||||||
|
if let Some(t) = self.intersection_distance_ray(&orig, &dir) {
|
||||||
|
if t >= S::zero() && t <= S::one() {
|
||||||
|
out_points.push(orig + dir * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orig = Vector3::new(aabb_min.x, aabb_max.y, aabb_min.z);
|
||||||
|
if let Some(t) = self.intersection_distance_ray(&orig, &dir) {
|
||||||
|
if t >= S::zero() && t <= S::one() {
|
||||||
|
out_points.push(orig + dir * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orig = Vector3::new(aabb_min.x, aabb_min.y, aabb_max.z);
|
||||||
|
if let Some(t) = self.intersection_distance_ray(&orig, &dir) {
|
||||||
|
if t >= S::zero() && t <= S::one() {
|
||||||
|
out_points.push(orig + dir * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orig = Vector3::new(aabb_min.x, aabb_max.y, aabb_max.z);
|
||||||
|
if let Some(t) = self.intersection_distance_ray(&orig, &dir) {
|
||||||
|
if t >= S::zero() && t <= S::one() {
|
||||||
|
out_points.push(orig + dir * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test edges along Y axis, pointing up.
|
||||||
|
dir = Vector3::new(S::zero(), aabb_max.y - aabb_min.y, S::zero());
|
||||||
|
orig = Vector3::new(aabb_min.x, aabb_min.y, aabb_min.z);
|
||||||
|
if let Some(t) = self.intersection_distance_ray(&orig, &dir) {
|
||||||
|
if t >= S::zero() && t <= S::one() {
|
||||||
|
out_points.push(orig + dir * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orig = Vector3::new(aabb_max.x, aabb_min.y, aabb_min.z);
|
||||||
|
if let Some(t) = self.intersection_distance_ray(&orig, &dir) {
|
||||||
|
if t >= S::zero() && t <= S::one() {
|
||||||
|
out_points.push(orig + dir * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orig = Vector3::new(aabb_min.x, aabb_min.y, aabb_max.z);
|
||||||
|
if let Some(t) = self.intersection_distance_ray(&orig, &dir) {
|
||||||
|
if t >= S::zero() && t <= S::one() {
|
||||||
|
out_points.push(orig + dir * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orig = Vector3::new(aabb_max.x, aabb_min.y, aabb_max.z);
|
||||||
|
if let Some(t) = self.intersection_distance_ray(&orig, &dir) {
|
||||||
|
if t >= S::zero() && t <= S::one() {
|
||||||
|
out_points.push(orig + dir * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test edges along Z axis, pointing forward.
|
||||||
|
dir = Vector3::new(S::zero(), S::zero(), aabb_max.z - aabb_min.z);
|
||||||
|
orig = Vector3::new(aabb_min.x, aabb_min.y, aabb_min.z);
|
||||||
|
if let Some(t) = self.intersection_distance_ray(&orig, &dir) {
|
||||||
|
if t >= S::zero() && t <= S::one() {
|
||||||
|
out_points.push(orig + dir * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orig = Vector3::new(aabb_max.x, aabb_min.y, aabb_min.z);
|
||||||
|
if let Some(t) = self.intersection_distance_ray(&orig, &dir) {
|
||||||
|
if t >= S::zero() && t <= S::one() {
|
||||||
|
out_points.push(orig + dir * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orig = Vector3::new(aabb_min.x, aabb_max.y, aabb_min.z);
|
||||||
|
if let Some(t) = self.intersection_distance_ray(&orig, &dir) {
|
||||||
|
if t >= S::zero() && t <= S::one() {
|
||||||
|
out_points.push(orig + dir * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orig = Vector3::new(aabb_max.x, aabb_max.y, aabb_min.z);
|
||||||
|
if let Some(t) = self.intersection_distance_ray(&orig, &dir) {
|
||||||
|
if t >= S::zero() && t <= S::one() {
|
||||||
|
out_points.push(orig + dir * t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out_points
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn intersection_polygon_aabb3(&self, aabb: &Aabb3<S>) -> Vec<Vector3<S>> {
|
||||||
|
let mut points = self.intersection_points_aabb3(aabb);
|
||||||
|
|
||||||
|
if points.is_empty() {
|
||||||
|
return points;
|
||||||
|
};
|
||||||
|
|
||||||
|
let plane_normal = Vector3::new(self.n.x, self.n.y, self.n.z);
|
||||||
|
let origin = points[0];
|
||||||
|
|
||||||
|
points.sort_by(|a, b| {
|
||||||
|
let cmp = (a - origin).cross(b - origin).dot(plane_normal);
|
||||||
|
if cmp < S::zero() {
|
||||||
|
Ordering::Less
|
||||||
|
} else if cmp == S::zero() {
|
||||||
|
Ordering::Equal
|
||||||
|
} else {
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
points
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: BaseFloat> fmt::Debug for Plane<S> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{:?}x + {:?}y + {:?}z - {:?} = 0",
|
||||||
|
self.n.x, self.n.y, self.n.z, self.d
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn min<S: PartialOrd + Copy>(lhs: S, rhs: S) -> S {
|
||||||
|
match lhs.partial_cmp(&rhs) {
|
||||||
|
Some(Ordering::Less) | Some(Ordering::Equal) | None => lhs,
|
||||||
|
_ => rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn max<S: PartialOrd + Copy>(lhs: S, rhs: S) -> S {
|
||||||
|
match lhs.partial_cmp(&rhs) {
|
||||||
|
Some(Ordering::Greater) | Some(Ordering::Equal) | None => lhs,
|
||||||
|
_ => rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A two-dimensional AABB, aka a rectangle.
|
||||||
|
pub struct Aabb2<S> {
|
||||||
|
/// Minimum point of the AABB
|
||||||
|
pub min: Point2<S>,
|
||||||
|
/// Maximum point of the AABB
|
||||||
|
pub max: Point2<S>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: BaseNum> Aabb2<S> {
|
||||||
|
/// Construct a new axis-aligned bounding box from two points.
|
||||||
|
#[inline]
|
||||||
|
pub fn new(p1: Point2<S>, p2: Point2<S>) -> Aabb2<S> {
|
||||||
|
Aabb2 {
|
||||||
|
min: Point2::new(min(p1.x, p2.x), min(p1.y, p2.y)),
|
||||||
|
max: Point2::new(max(p1.x, p2.x), max(p1.y, p2.y)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute corners.
|
||||||
|
#[inline]
|
||||||
|
pub fn to_corners(&self) -> [Point2<S>; 4] {
|
||||||
|
[
|
||||||
|
self.min,
|
||||||
|
Point2::new(self.max.x, self.min.y),
|
||||||
|
Point2::new(self.min.x, self.max.y),
|
||||||
|
self.max,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: BaseNum> fmt::Debug for Aabb2<S> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "[{:?} - {:?}]", self.min, self.max)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A three-dimensional AABB, aka a rectangular prism.
|
||||||
|
pub struct Aabb3<S> {
|
||||||
|
/// Minimum point of the AABB
|
||||||
|
pub min: Point3<S>,
|
||||||
|
/// Maximum point of the AABB
|
||||||
|
pub max: Point3<S>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: BaseNum> Aabb3<S> {
|
||||||
|
/// Construct a new axis-aligned bounding box from two points.
|
||||||
|
#[inline]
|
||||||
|
pub fn new(p1: Point3<S>, p2: Point3<S>) -> Aabb3<S> {
|
||||||
|
Aabb3 {
|
||||||
|
min: Point3::new(min(p1.x, p2.x), min(p1.y, p2.y), min(p1.z, p2.z)),
|
||||||
|
max: Point3::new(max(p1.x, p2.x), max(p1.y, p2.y), max(p1.z, p2.z)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute corners.
|
||||||
|
#[inline]
|
||||||
|
pub fn to_corners(&self) -> [Point3<S>; 8] {
|
||||||
|
[
|
||||||
|
self.min,
|
||||||
|
Point3::new(self.max.x, self.min.y, self.min.z),
|
||||||
|
Point3::new(self.min.x, self.max.y, self.min.z),
|
||||||
|
Point3::new(self.max.x, self.max.y, self.min.z),
|
||||||
|
Point3::new(self.min.x, self.min.y, self.max.z),
|
||||||
|
Point3::new(self.max.x, self.min.y, self.max.z),
|
||||||
|
Point3::new(self.min.x, self.max.y, self.max.z),
|
||||||
|
self.max,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: BaseNum> fmt::Debug for Aabb3<S> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "[{:?} - {:?}]", self.min, self.max)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
//! Utils which are used internally
|
//! Utils which are used internally
|
||||||
|
|
||||||
mod fps_meter;
|
mod fps_meter;
|
||||||
|
pub mod math;
|
||||||
mod measure;
|
mod measure;
|
||||||
|
|
||||||
pub use fps_meter::FPSMeter;
|
pub use fps_meter::FPSMeter;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user