use glam::{IVec2, Vec2, Vec3, vec2};
pub fn cross2d(a: Vec2, b: Vec2) -> f32 {
a.x * b.y - b.x * a.y
}
pub fn intersection(p1: Vec3, v1: Vec3, p2: Vec3, v2: Vec3) -> Option<Vec3> {
let cross = v1.cross(v2);
let denom = cross.length_squared();
if denom < f32::EPSILON {
return None;
}
let diff = p2 - p1;
let t = (diff).cross(v2).dot(cross) / denom;
let s = (diff).cross(v1).dot(cross) / denom;
let point1 = p1 + v1 * t;
let point2 = p2 + v2 * s;
if (point1 - point2).length_squared() < f32::EPSILON {
Some(point1)
} else {
None
}
}
#[derive(Debug, Clone, Copy)]
pub struct Rect {
min: Vec2,
max: Vec2,
}
impl Rect {
pub fn union(&self, other: &Self) -> Self {
let min = self.min.min(other.min);
let max = self.max.max(other.max);
Self { min, max }
}
pub fn intersection(&self, other: &Self) -> Self {
let min = self.min.max(other.min);
let max = self.max.min(other.max);
Self { min, max }
}
pub fn center(&self) -> Vec2 {
(self.min + self.max) / 2.0
}
pub fn point(&self, edge: IVec2) -> Vec2 {
let min = self.min;
let center = self.center();
let max = self.max;
let x = match edge.x {
-1 => min.y,
0 => center.y,
1 => max.y,
_ => unreachable!(),
};
let y = match edge.y {
-1 => min.y,
0 => center.y,
1 => max.y,
_ => unreachable!(),
};
vec2(x, y)
}
}
pub fn interpolate_usize(a: usize, b: usize, t: f32) -> (usize, f32) {
assert!(b >= a);
let t = t.clamp(0.0, 1.0);
let v = b - a;
let p = v as f32 * t;
(a + p.floor() as usize, p.fract())
}
#[cfg(test)]
mod test {
use core::f32;
use super::*;
#[test]
fn test_interpolate_usize() {
let test = |(x, t): (usize, f32), (expected_x, expected_t): (usize, f32)| {
assert_eq!(x, expected_x);
assert!((t - expected_t).abs() < f32::EPSILON);
};
test(interpolate_usize(0, 10, 0.0), (0, 0.0));
test(interpolate_usize(0, 10, 0.5), (5, 0.0));
test(interpolate_usize(0, 10, 1.0), (10, 0.0));
test(interpolate_usize(0, 1, 0.0), (0, 0.0));
test(interpolate_usize(0, 1, 0.5), (0, 0.5));
test(interpolate_usize(0, 1, 1.0), (1, 0.0));
test(interpolate_usize(0, 2, 0.0), (0, 0.0));
test(interpolate_usize(0, 2, 0.2), (0, 0.4));
test(interpolate_usize(0, 2, 0.4), (0, 0.8));
test(interpolate_usize(0, 2, 0.6), (1, 0.2));
test(interpolate_usize(0, 2, 0.8), (1, 0.6));
test(interpolate_usize(0, 2, 1.0), (2, 0.0));
}
#[test]
fn test_intersection() {
use glam::vec3;
let p1 = vec3(0.0, 0.0, 0.0);
let v1 = vec3(1.0, 0.0, 0.0);
let p2 = vec3(0.0, 1.0, 0.0);
let v2 = vec3(0.0, -1.0, 0.0);
assert_eq!(intersection(p1, v1, p2, v2), Some(vec3(0.0, 0.0, 0.0)));
let p1 = vec3(1.0, 1.0, 0.0);
let v1 = vec3(1.0, 2.0, 0.0);
let p2 = vec3(3.0, 1.0, 0.0);
let v2 = vec3(-1.0, 2.0, 0.0);
assert_eq!(intersection(p1, v1, p2, v2), Some(vec3(2.0, 3.0, 0.0)));
let p1 = vec3(0.0, 0.0, 0.0);
let v1 = vec3(1.0, 1.0, 1.0);
let p2 = vec3(1.0, 1.0, 1.0);
let v2 = vec3(2.0, 2.0, 2.0);
assert!(intersection(p1, v1, p2, v2).is_none());
let p1 = vec3(0.0, 0.0, 0.0);
let v1 = vec3(1.0, 1.0, 0.0);
let p2 = vec3(1.0, 0.0, 0.0);
let v2 = vec3(1.0, 1.0, 0.0);
assert!(intersection(p1, v1, p2, v2).is_none());
let p1 = vec3(0.0, 0.0, 0.0);
let v1 = vec3(1.0, 0.0, 1.0);
let p2 = vec3(0.0, 1.0, 0.0);
let v2 = vec3(1.0, 0.0, -1.0);
assert!(intersection(p1, v1, p2, v2).is_none());
}
}