use crate::geo::ConvertTo;
use crate::meshanalyzer::SearchResult;
use crate::prelude::MaximumTracker;
use crate::probe::{
PlaneMetadata, QueryParameters, TriangleMetadata, ball_end_to_edge::ball_end_to_edge_collision,
xy_distance_to_line_squared,
};
use crate::{HronnError, is_inside_2d_triangle};
use vector_traits::prelude::{GenericVector3, HasXYZ};
pub(crate) fn shared_ball_nose_precompute_logic<T: GenericVector3, MESH: HasXYZ + ConvertTo<T>>(
vertices: &[MESH],
indices: &[u32],
probe_radius: T::Scalar,
) -> Result<Vec<TriangleMetadata<T, MESH>>, HronnError> {
indices
.as_ref()
.chunks(3)
.map(|triangle| {
TriangleMetadata::<T, MESH>::new_for_ball_nose(
probe_radius,
vertices[triangle[0] as usize],
vertices[triangle[1] as usize],
vertices[triangle[2] as usize],
)
})
.collect::<Result<Vec<_>, HronnError>>()
}
pub(crate) fn ball_nose_compute_collision<T: GenericVector3, MESH: HasXYZ + ConvertTo<T>>(
qp: &QueryParameters<'_, T, MESH>,
site_index: u32,
center: T::Vector2,
mt: &mut MaximumTracker<SearchResult<T>>,
) {
let triangle_index = site_index * 3;
let TriangleMetadata {
scalar: delta_z,
plane,
..
} = &qp.meta_data[site_index as usize];
if let Some(PlaneMetadata {
pft,
translated_triangle: [p0, p1, p2],
..
}) = plane
{
if is_inside_2d_triangle(center, *p0, *p1, *p2) {
mt.insert(SearchResult::new(
site_index,
pft.compute_z(center) + *delta_z,
));
return;
}
}
let p0 = qp.vertices[qp.indices[triangle_index as usize] as usize].to();
let p1 = qp.vertices[qp.indices[(triangle_index + 1) as usize] as usize].to();
let p2 = 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),
);
ball_end_to_edge_collision::<T>(
closest_edge.0,
BallEndProperties::new(qp.probe_radius),
site_index,
mt,
);
ball_end_to_edge_collision::<T>(
closest_edge.1,
BallEndProperties::new(qp.probe_radius),
site_index,
mt,
);
}
pub(crate) struct BallEndProperties<T: GenericVector3> {
pub r: T::Scalar,
pub r_sq: T::Scalar,
}
impl<T: GenericVector3> BallEndProperties<T> {
pub fn new(radius: T::Scalar) -> Self {
Self {
r: radius,
r_sq: radius * radius,
}
}
}