use super::ProbabilisticQuadric;
use crate::cube::corner_offset;
use crate::dual_contouring::{DualContouring, solve};
use crate::hermite::HermiteCell;
use crate::{MeshBuffer, RuntimeShape3, Sdf};
#[test]
fn the_probabilistic_quadric_is_the_existing_solve() {
fn paper_solve(cell: &HermiteCell<f64>, sigma_squared: f64) -> Option<[f64; 3]> {
let mut a = [[0.0f64; 3]; 3];
let mut b = [0.0f64; 3];
let mut planes = 0.0f64;
for edge in 0..12u8 {
let Some(crossing) = cell.get(edge) else {
continue;
};
planes += 1.0;
let (n, q) = (crossing.normal, crossing.position);
let nq = n[0] * q[0] + n[1] * q[1] + n[2] * q[2];
for i in 0..3 {
for j in 0..3 {
a[i][j] += n[i] * n[j];
}
b[i] += n[i] * nq + sigma_squared * q[i];
}
}
for (i, row) in a.iter_mut().enumerate() {
row[i] += planes * sigma_squared;
}
let det3 = |m: &[[f64; 3]; 3]| {
m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])
- m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])
+ m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0])
};
let det = det3(&a);
if det.abs() < 1e-30 {
return None;
}
let mut x = [0.0f64; 3];
for (k, slot) in x.iter_mut().enumerate() {
let mut m = a;
for i in 0..3 {
m[i][k] = b[i];
}
*slot = det3(&m) / det;
}
Some(x)
}
let field = crate::fields::BoxExact::<f64>::canonical();
let (h, origin) = (0.25f64, [-2.0f64; 3]);
let sigma_squared = 1e-3;
let mut worst = 0.0f64;
let mut compared = 0usize;
for z in 0..16u32 {
for y in 0..16u32 {
for x in 0..16u32 {
let mut corner = [0.0f64; 8];
for (i, slot) in corner.iter_mut().enumerate() {
let o = corner_offset(i as u8);
*slot = field.sample([
origin[0] + h * f64::from(x + o[0]),
origin[1] + h * f64::from(y + o[1]),
origin[2] + h * f64::from(z + o[2]),
]);
}
let cell_origin = [
origin[0] + h * f64::from(x),
origin[1] + h * f64::from(y),
origin[2] + h * f64::from(z),
];
let cell = HermiteCell::from_corners(&field, &corner, cell_origin, h);
if cell.len() < 3 {
continue;
}
let lambda = cell.len() as f64 * sigma_squared;
let (Some(ours), Some(theirs)) = (
solve::solve_with(&cell, lambda),
paper_solve(&cell, sigma_squared),
) else {
continue;
};
worst = worst.max(
(0..3)
.map(|i| (ours[i] - theirs[i]).abs())
.fold(0.0f64, f64::max),
);
compared += 1;
}
}
}
assert!(
compared > 100,
"only {compared} cells, too few to mean anything"
);
assert!(
worst < 1e-12,
"the paper's assembly and ours disagree by {worst:e} over {compared} cells, \
so the reduction in this module's docs is wrong"
);
std::println!("measured: {compared} cells, worst |ours - paper| = {worst:.3e}");
}
#[test]
fn the_scaled_regularizer_moves_vertices_without_moving_topology() {
let field = crate::fields::BoxExact::<f64>::canonical();
let shape = RuntimeShape3::new([25; 3]).expect("valid shape");
let mut fixed = MeshBuffer::<f64>::new();
DualContouring::<f64>::new()
.extract(&field, &shape, [-2.0; 3], 0.16, &mut fixed)
.expect("extraction");
let mut scaled = MeshBuffer::<f64>::new();
DualContouring::<f64, ProbabilisticQuadric>::with_rule(ProbabilisticQuadric::default())
.extract(&field, &shape, [-2.0; 3], 0.16, &mut scaled)
.expect("extraction");
assert_eq!(
fixed.indices, scaled.indices,
"a vertex rule changed the topology, which no vertex rule can do"
);
#[allow(clippy::float_cmp)]
let moved = fixed
.positions
.iter()
.zip(&scaled.positions)
.filter(|(a, b)| a != b)
.count();
assert!(
moved > 0,
"the scaled regularizer reproduced the fixed one exactly, so there is \
nothing here to measure"
);
std::println!(
"measured: {} vertices, {moved} moved by the crossing-count scaling",
fixed.positions.len()
);
}
#[test]
fn the_experimental_feature_adds_no_dependencies() {
let manifest = include_str!("../../Cargo.toml");
let (_, features) = manifest
.split_once("[features]")
.expect("the manifest has no [features] section");
let (features, _) = features
.split_once("\n[")
.expect("the [features] section is unterminated");
let declared: alloc::vec::Vec<&str> = features
.lines()
.map(str::trim)
.filter(|line| !line.is_empty() && !line.starts_with('#'))
.collect();
assert_eq!(
declared,
alloc::vec!["experimental = []"],
"a feature gained a dependency list, or a second feature appeared: {declared:?}"
);
}