use super::interner::{Interner, Vid};
use super::retriangulate::{
cmp_lex_v, edge_exists, lex_cmp, orient2d_v, tri_edges, Canonical, Mesh2d, SubTri,
};
use super::retriangulate_recover::{between, recover_via_traversal};
use super::{DropAxis, Sign};
use std::collections::BTreeSet;
fn chain_of(mesh: &Mesh2d, it: &Interner, axis: DropAxis, cs: Vid, ct: Vid) -> Vec<Vid> {
let mut on_seg: Vec<Vid> = mesh
.tris
.iter()
.flatten()
.copied()
.collect::<BTreeSet<Vid>>()
.into_iter()
.filter(|&v| {
v != cs
&& v != ct
&& orient2d_v(it, cs, ct, v, axis) == Sign::Zero
&& between(it, cs, ct, v)
})
.collect();
on_seg.sort_by(|&x, &y| lex_cmp(it, x, y));
if cmp_lex_v(it, cs, ct) == Sign::Positive {
on_seg.reverse();
}
let mut chain = vec![cs];
chain.extend(on_seg);
chain.push(ct);
chain
}
pub(crate) fn pocket_rebuild_valid(new_tris: &[SubTri]) -> bool {
let mut directed: Vec<(Vid, Vid)> = Vec::with_capacity(new_tris.len() * 3);
for &t in new_tris {
if t[0] == t[1] || t[1] == t[2] || t[0] == t[2] {
return false;
}
directed.extend(tri_edges(t));
}
let n = directed.len();
directed.sort_unstable();
directed.dedup();
directed.len() == n
}
pub(crate) fn audit_and_recover(mesh: &mut Mesh2d, it: &Interner, canon: &Canonical, axis: DropAxis) {
for &(cs, ct) in &canon.segments {
for w in chain_of(mesh, it, axis, cs, ct).windows(2) {
if !edge_exists(mesh, w[0], w[1]) {
recover_via_traversal(mesh, it, w[0], w[1]);
}
}
}
for &(cs, ct) in &canon.segments {
for w in chain_of(mesh, it, axis, cs, ct).windows(2) {
if !edge_exists(mesh, w[0], w[1]) {
mesh.unrecovered += 1;
}
}
}
}
#[cfg(test)]
#[path = "retriangulate_audit_tests.rs"]
mod retriangulate_audit_tests;