use super::*;
use crate::common::sealed::ScalarType;
use vector_traits::glam::Vec3;
fn make_triangle<S: ScalarType>(v0: S::Vec3, v1: S::Vec3, v2: S::Vec3) -> Triangle<S> {
let edge0 = v1 - v0;
let edge1 = v2 - v0;
let normal = edge0.cross(edge1).normalize();
Triangle { v0, v1, v2, normal }
}
#[test]
fn test_project_inside_triangle() {
let tri = make_triangle::<f32>(
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
);
let p = Vec3::new(0.25, 0.25, 1.0);
let result = project_point_to_triangle::<f32>(p, &tri);
println!("Point: {:?}, Projected: {:?}", p, result);
assert!(
(result.x - 0.25).abs() < 0.001,
"x should be 0.25, got {}",
result.x
);
assert!(
(result.y - 0.25).abs() < 0.001,
"y should be 0.25, got {}",
result.y
);
assert!(
(result.z).abs() < 0.001,
"z should be 0.0, got {}",
result.z
);
}
#[test]
fn test_project_below_triangle() {
let tri = make_triangle(
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
);
let p = Vec3::new(0.3, 0.3, -2.0);
let result = project_point_to_triangle::<f32>(p, &tri);
println!("Point: {:?}, Projected: {:?}", p, result);
assert!(
(result.x - 0.3).abs() < 0.001,
"x should be 0.3, got {}",
result.x
);
assert!(
(result.y - 0.3).abs() < 0.001,
"y should be 0.3, got {}",
result.y
);
assert!(
(result.z).abs() < 0.001,
"z should be 0.0, got {}",
result.z
);
}
#[test]
fn test_project_to_vertex_a() {
let tri = make_triangle::<f32>(
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
);
let p = Vec3::new(-1.0, -1.0, 0.0);
let result = project_point_to_triangle::<f32>(p, &tri);
println!("Point: {:?}, Projected: {:?}", p, result);
assert!(
result.distance(tri.v0) < 0.001,
"Should project to vertex A (0,0,0), got {:?}",
result
);
}
#[test]
fn test_project_to_vertex_b() {
let tri = make_triangle::<f32>(
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
);
let p = Vec3::new(2.0, -1.0, 0.0);
let result = project_point_to_triangle::<f32>(p, &tri);
println!("Point: {:?}, Projected: {:?}", p, result);
assert!(
result.distance(tri.v1) < 0.001,
"Should project to vertex B (1,0,0), got {:?}",
result
);
}
#[test]
fn test_project_to_vertex_c() {
let tri = make_triangle::<f32>(
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
);
let p = Vec3::new(-1.0, 2.0, 0.0);
let result = project_point_to_triangle::<f32>(p, &tri);
println!("Point: {:?}, Projected: {:?}", p, result);
assert!(
result.distance(tri.v2) < 0.001,
"Should project to vertex C (0,1,0), got {:?}",
result
);
}
#[test]
fn test_project_to_edge_ab() {
let tri = make_triangle::<f32>(
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
);
let p = Vec3::new(0.5, -1.0, 0.0);
let result = project_point_to_triangle::<f32>(p, &tri);
println!("Point: {:?}, Projected: {:?}", p, result);
assert!(
(result.x - 0.5).abs() < 0.001,
"x should be 0.5, got {}",
result.x
);
assert!(
(result.y).abs() < 0.001,
"y should be 0.0, got {}",
result.y
);
assert!(
(result.z).abs() < 0.001,
"z should be 0.0, got {}",
result.z
);
}
#[test]
fn test_project_to_edge_ac() {
let tri = make_triangle::<f32>(
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
);
let p = Vec3::new(-1.0, 0.5, 0.0);
let result = project_point_to_triangle::<f32>(p, &tri);
println!("Point: {:?}, Projected: {:?}", p, result);
assert!(
(result.x).abs() < 0.001,
"x should be 0.0, got {}",
result.x
);
assert!(
(result.y - 0.5).abs() < 0.001,
"y should be 0.5, got {}",
result.y
);
assert!(
(result.z).abs() < 0.001,
"z should be 0.0, got {}",
result.z
);
}
#[test]
fn test_project_to_edge_bc() {
let tri = make_triangle::<f32>(
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
);
let p = Vec3::new(1.0, 1.0, 0.0);
let result = project_point_to_triangle::<f32>(p, &tri);
println!("Point: {:?}, Projected: {:?}", p, result);
assert!(
(result.x - 0.5).abs() < 0.001,
"x should be ~0.5, got {}",
result.x
);
assert!(
(result.y - 0.5).abs() < 0.001,
"y should be ~0.5, got {}",
result.y
);
assert!(
(result.z).abs() < 0.001,
"z should be 0.0, got {}",
result.z
);
}
#[test]
fn test_project_on_triangle_plane() {
let tri = make_triangle::<f32>(
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
);
let p = Vec3::new(0.3, 0.3, 0.0);
let result = project_point_to_triangle::<f32>(p, &tri);
println!("Point: {:?}, Projected: {:?}", p, result);
assert!(
result.distance(p) < 0.001,
"Point on triangle should project to itself, got {:?}",
result
);
}
#[test]
fn test_project_tilted_triangle() {
let tri = make_triangle::<f32>(
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 1.0),
Vec3::new(0.0, 1.0, 1.0),
);
let p = Vec3::new(0.3, 0.3, 2.0);
let result = project_point_to_triangle::<f32>(p, &tri);
println!("Point: {:?}, Projected: {:?}", p, result);
let edge0 = tri.v1 - tri.v0;
let edge1 = tri.v2 - tri.v0;
let normal = edge0.cross(edge1).normalize();
let v0_to_result = result - tri.v0;
let dist_to_plane = v0_to_result.dot(normal).abs();
assert!(
dist_to_plane < 0.001,
"Result should be on triangle plane, distance: {}",
dist_to_plane
);
}
#[test]
fn test_project_large_triangle() {
let tri = make_triangle::<f32>(
Vec3::new(-100.0, -100.0, 0.0),
Vec3::new(100.0, -100.0, 0.0),
Vec3::new(0.0, 100.0, 0.0),
);
let p = Vec3::new(1.0, 1.0, 5.0);
let result = project_point_to_triangle::<f32>(p, &tri);
println!("Point: {:?}, Projected: {:?}", p, result);
assert!(
(result.x - 1.0).abs() < 0.001,
"x should be 1.0, got {}",
result.x
);
assert!(
(result.y - 1.0).abs() < 0.001,
"y should be 1.0, got {}",
result.y
);
assert!(
(result.z).abs() < 0.001,
"z should be 0.0, got {}",
result.z
);
}
#[test]
fn test_project_equilateral_triangle() {
let h = (3.0_f32).sqrt() / 2.0; let tri = make_triangle::<f32>(
Vec3::new(-0.5, -h / 3.0, 0.0),
Vec3::new(0.5, -h / 3.0, 0.0),
Vec3::new(0.0, 2.0 * h / 3.0, 0.0),
);
let p = Vec3::new(0.0, 0.0, 1.0);
let result = project_point_to_triangle::<f32>(p, &tri);
println!("Point: {:?}, Projected: {:?}", p, result);
assert!(
(result.x).abs() < 0.001,
"x should be ~0.0, got {}",
result.x
);
assert!(
(result.y).abs() < 0.001,
"y should be ~0.0, got {}",
result.y
);
assert!(
(result.z).abs() < 0.001,
"z should be 0.0, got {}",
result.z
);
}
#[should_panic]
#[test]
fn test_project_degenerate_triangle() {
let tri = make_triangle::<f32>(
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(2.0, 0.0, 0.0),
);
let p = Vec3::new(0.5, 1.0, 0.0);
let result = project_point_to_triangle::<f32>(p, &tri);
println!(
"Degenerate triangle - Point: {:?}, Projected: {:?}",
p, result
);
let dist_a = result.distance(tri.v0);
let dist_b = result.distance(tri.v1);
let dist_c = result.distance(tri.v2);
let on_vertex = dist_a < 0.001 || dist_b < 0.001 || dist_c < 0.001;
assert!(
on_vertex,
"Should project to a vertex for degenerate triangle, got {:?}",
result
);
}
#[test]
fn test_project_consistency() {
let tri = make_triangle::<f32>(
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
);
let p = Vec3::new(0.4, 0.4, 3.0);
let result1 = project_point_to_triangle::<f32>(p, &tri);
let result2 = project_point_to_triangle::<f32>(p, &tri);
let result3 = project_point_to_triangle::<f32>(p, &tri);
assert_eq!(result1, result2);
assert_eq!(result2, result3);
}