use crate::geo::ConvertTo;
use crate::meshanalyzer::SearchResult;
use crate::prelude::MaximumTracker;
use crate::probe::square_end_to_edge::square_end_to_edge_collision;
use crate::probe::{PlaneMetadata, QueryParameters, TriangleMetadata, xy_distance_to_line_squared};
use crate::{HronnError, is_inside_2d_triangle};
use vector_traits::{
approx,
prelude::{GenericVector3, HasXYZ},
};
pub(crate) fn shared_square_end_precompute_logic<T: GenericVector3, MESH>(
vertices: &[MESH],
triangles: &[u32],
probe_radius: T::Scalar,
) -> Result<Vec<TriangleMetadata<T, MESH>>, HronnError>
where
MESH: HasXYZ,
MESH: ConvertTo<T>,
{
triangles
.as_ref()
.chunks(3)
.map(|triangle| {
TriangleMetadata::new_for_square_end(
probe_radius,
vertices[triangle[0] as usize].to(),
vertices[triangle[1] as usize].to(),
vertices[triangle[2] as usize].to(),
)
})
.collect()
}
pub(crate) fn square_end_compute_collision<T: GenericVector3, MESH: HasXYZ + ConvertTo<T>>(
qp: &QueryParameters<'_, T, MESH>,
site_index: u32,
center: T::Vector2,
mt: &mut MaximumTracker<SearchResult<T>>,
) where
T::Scalar: approx::UlpsEq,
{
let triangle_index = site_index * 3;
if let Some(PlaneMetadata {
pft,
translated_triangle: [p0, p1, p2],
..
}) = &qp.meta_data[site_index as usize].plane
{
if is_inside_2d_triangle::<T::Vector2>(center, *p0, *p1, *p2) {
mt.insert(SearchResult::new(site_index, pft.compute_z(center)));
return;
}
}
let p0: T = qp.vertices[qp.indices[triangle_index as usize] as usize].to();
let p1: T = qp.vertices[qp.indices[(triangle_index + 1) as usize] as usize].to();
let p2: T = qp.vertices[qp.indices[(triangle_index + 2) as usize] as usize].to();
let closest_edge = xy_distance_to_line_squared(center, p0, p1).min_two(
xy_distance_to_line_squared(center, p1, p2),
xy_distance_to_line_squared(center, p2, p0),
);
square_end_to_edge_collision::<T>(closest_edge.0, qp.probe_radius, site_index, mt);
square_end_to_edge_collision::<T>(closest_edge.1, qp.probe_radius, site_index, mt);
}