use cartan_dec::Mesh;
use cartan_manifolds::euclidean::Euclidean;
use crate::config::RemeshConfig;
use crate::log::RemeshLog;
use crate::primitives::{collapse_edge, split_edge};
fn curvature_cfl_bound(h: f64, k: f64, curvature_scale: f64) -> f64 {
let k_max = h.abs() + (h * h - k).max(0.0).sqrt();
if k_max < 1e-30 {
return f64::MAX;
}
curvature_scale / k_max.sqrt()
}
pub fn needs_remesh(
mesh: &Mesh<Euclidean<2>, 3, 2>,
manifold: &Euclidean<2>,
mean_curvatures: &[f64],
gaussian_curvatures: &[f64],
config: &RemeshConfig,
) -> bool {
let nv = mesh.n_vertices();
assert_eq!(mean_curvatures.len(), nv, "mean_curvatures length mismatch");
assert_eq!(
gaussian_curvatures.len(),
nv,
"gaussian_curvatures length mismatch"
);
for e in 0..mesh.n_boundaries() {
let len_e = mesh.edge_length(manifold, e);
if len_e > config.max_edge_length {
return true;
}
if len_e < config.min_edge_length {
return true;
}
let [va, vb] = mesh.boundaries[e];
let cfl_a = curvature_cfl_bound(
mean_curvatures[va],
gaussian_curvatures[va],
config.curvature_scale,
);
let cfl_b = curvature_cfl_bound(
mean_curvatures[vb],
gaussian_curvatures[vb],
config.curvature_scale,
);
let cfl_bound = cfl_a.min(cfl_b);
if len_e > cfl_bound {
return true;
}
}
false
}
pub fn adaptive_remesh(
mesh: &mut Mesh<Euclidean<2>, 3, 2>,
manifold: &Euclidean<2>,
mean_curvatures: &[f64],
gaussian_curvatures: &[f64],
config: &RemeshConfig,
) -> RemeshLog {
let nv = mesh.n_vertices();
assert_eq!(mean_curvatures.len(), nv, "mean_curvatures length mismatch");
assert_eq!(
gaussian_curvatures.len(),
nv,
"gaussian_curvatures length mismatch"
);
let mut log = RemeshLog::new();
loop {
let mut to_split: Vec<(usize, f64)> = Vec::new();
for e in 0..mesh.n_boundaries() {
let len_e = mesh.edge_length(manifold, e);
if len_e > config.max_edge_length {
to_split.push((e, len_e));
continue;
}
let [va, vb] = mesh.boundaries[e];
if va < mean_curvatures.len() && vb < mean_curvatures.len() {
let cfl_a = curvature_cfl_bound(
mean_curvatures[va],
gaussian_curvatures[va],
config.curvature_scale,
);
let cfl_b = curvature_cfl_bound(
mean_curvatures[vb],
gaussian_curvatures[vb],
config.curvature_scale,
);
let cfl_bound = cfl_a.min(cfl_b);
if len_e > cfl_bound {
to_split.push((e, len_e));
}
}
}
if to_split.is_empty() {
break;
}
to_split.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
let (edge, _) = to_split[0];
let split_log = split_edge(mesh, manifold, edge);
log.merge(split_log);
}
loop {
let mut to_collapse: Vec<(usize, f64)> = Vec::new();
for e in 0..mesh.n_boundaries() {
let len_e = mesh.edge_length(manifold, e);
if len_e < config.min_edge_length {
to_collapse.push((e, len_e));
}
}
if to_collapse.is_empty() {
break;
}
to_collapse.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal));
let (edge, _) = to_collapse[0];
match collapse_edge(mesh, manifold, edge, config.foldover_threshold) {
Ok(collapse_log) => {
log.merge(collapse_log);
}
Err(_) => {
let remaining: Vec<(usize, f64)> = to_collapse.iter().skip(1).copied().collect();
let mut collapsed_any = false;
for (e, _) in remaining {
if e >= mesh.n_boundaries() {
continue;
}
if let Ok(cl) = collapse_edge(mesh, manifold, e, config.foldover_threshold) {
log.merge(cl);
collapsed_any = true;
break;
}
}
if !collapsed_any {
break;
}
}
}
}
log
}