use alloc::vec::Vec;
use crate::math::Vector;
use crate::utils::point_in_triangle::{corner_direction, Orientation};
fn find_edge_index_in_polygon(p1: u32, p2: u32, indices: &[u32]) -> Option<(usize, usize)> {
for i1 in 0..indices.len() {
let i2 = (i1 + 1) % indices.len();
if p1 == indices[i1] && p2 == indices[i2] {
return Some((i1, i2));
}
}
None
}
pub fn hertel_mehlhorn(vertices: &[Vector], indices: &[[u32; 3]]) -> Vec<Vec<Vector>> {
hertel_mehlhorn_idx(vertices, indices)
.into_iter()
.map(|poly_indices| {
poly_indices
.into_iter()
.map(|idx| vertices[idx as usize])
.collect()
})
.collect()
}
pub fn hertel_mehlhorn_idx(vertices: &[Vector], indices: &[[u32; 3]]) -> Vec<Vec<u32>> {
let mut indices: Vec<Vec<u32>> = indices.iter().map(|indices| indices.to_vec()).collect();
let mut i_poly1 = 0;
while i_poly1 < indices.len() {
let mut i11 = 0;
while i11 < indices[i_poly1].len() {
let polygon1 = &indices[i_poly1];
let i12 = (i11 + 1) % polygon1.len();
let edge_start = polygon1[i11];
let edge_end = polygon1[i12];
let (i_poly2, edge_indices) = match indices
.iter()
.enumerate()
.skip(i_poly1 + 1)
.find_map(|(i, poly_indices)| {
find_edge_index_in_polygon(edge_end, edge_start, poly_indices)
.map(|edge_indices| (i, edge_indices))
}) {
Some(found) => found,
None => {
i11 += 1;
continue;
}
};
let (i21, i22) = edge_indices;
let polygon2 = &indices[i_poly2];
let i13 = (polygon1.len() + i11 - 1) % polygon1.len();
let i23 = (i22 + 1) % polygon2.len();
let p1 = vertices[polygon2[i23] as usize];
let p2 = vertices[polygon1[i13] as usize];
let p3 = vertices[polygon1[i11] as usize];
if corner_direction(p1, p2, p3) == Orientation::Cw {
i11 += 1;
continue;
}
let i13 = (i12 + 1) % polygon1.len();
let i23 = (polygon2.len() + i21 - 1) % polygon2.len();
let p1 = vertices[polygon1[i13] as usize];
let p2 = vertices[polygon2[i23] as usize];
let p3 = vertices[polygon1[i12] as usize];
if corner_direction(p1, p2, p3) == Orientation::Cw {
i11 += 1;
continue;
}
let mut new_polygon = Vec::with_capacity(polygon1.len() + polygon2.len() - 2);
new_polygon.extend(polygon1.iter().cycle().skip(i12).take(polygon1.len() - 1));
new_polygon.extend(polygon2.iter().cycle().skip(i22).take(polygon2.len() - 1));
let _ = indices.remove(i_poly2);
indices[i_poly1] = new_polygon;
i11 = 0;
}
i_poly1 += 1;
}
indices
}
#[cfg(test)]
mod tests {
use super::hertel_mehlhorn_idx;
use crate::math::Vector;
#[test]
fn origin_outside_shape() {
let vertices = vec![
Vector::new(2.0, 2.0), Vector::new(2.0, -2.0), Vector::new(4.0, -2.0), Vector::new(4.0, 4.0), Vector::new(-4.0, 4.0), Vector::new(-4.0, -2.0), Vector::new(-2.0, -2.0), Vector::new(-2.0, 2.0), ];
let triangles = [
[5, 6, 7],
[4, 5, 7],
[3, 4, 7],
[3, 7, 0],
[2, 3, 0],
[2, 0, 1],
];
let indices = hertel_mehlhorn_idx(&vertices, &triangles);
let expected_indices = vec![
vec![5, 6, 7, 4],
vec![3, 4, 7, 0],
vec![2, 3, 0, 1],
];
assert_eq!(indices, expected_indices);
}
}