use super::*;
use crate::marching_tetrahedra::table::TET_EDGES;
const CORNERS: [[f64; 3]; 4] = [
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
];
fn spaced(n: u32) -> Vec<f64> {
(0..n)
.map(|i| (f64::from(i) + 1.0) / (f64::from(n) + 1.0))
.collect()
}
fn crossings(count: [u32; TET_EDGE_COUNT]) -> Vec<Vec<f64>> {
count.iter().map(|n| spaced(*n)).collect()
}
fn tet<'a>(owned: &'a [Vec<f64>]) -> TetCrossings<'a, f64> {
let mut along: [&[f64]; TET_EDGE_COUNT] = [&[]; TET_EDGE_COUNT];
for (slot, v) in along.iter_mut().zip(owned.iter()) {
*slot = v.as_slice();
}
TetCrossings {
corners: CORNERS,
along,
}
}
fn pattern_coords(d1: u32, d2: u32) -> EdgeCoordinates {
let mut count = [0u32; TET_EDGE_COUNT];
count[0] = d1;
count[5] = d1;
count[1] = d2;
count[4] = d2;
count[2] = d1 + d2;
count[3] = d1 + d2;
EdgeCoordinates { count }
}
#[test]
fn edge_coordinates_come_from_the_crossing_lists_not_from_a_second_argument() {
let owned = crossings([2, 0, 3, 1, 0, 4]);
let t = tet(&owned);
assert_eq!(t.coordinates().count, [2, 0, 3, 1, 0, 4]);
}
#[test]
fn a_crossing_sits_where_its_parameter_puts_it_measured_from_the_lower_corner() {
let owned = crossings([1, 0, 0, 0, 0, 0]);
let t = tet(&owned);
let [lo, hi] = TET_EDGES[0];
assert_eq!([lo, hi], [0, 1]);
let p = t.position(FacePoint { edge: 0, index: 0 });
assert_eq!(p, Some([0.5, 0.0, 0.0]));
}
#[test]
fn unsorted_or_off_edge_crossings_are_rejected_rather_than_silently_repaired() {
let owned = [
alloc::vec![0.7, 0.3],
Vec::new(),
Vec::new(),
Vec::new(),
Vec::new(),
Vec::new(),
];
assert_eq!(
tet(&owned).check(),
Err(NotFillable::Unsorted { edge: 0, at: 1 })
);
let owned = [
alloc::vec![1.5],
Vec::new(),
Vec::new(),
Vec::new(),
Vec::new(),
Vec::new(),
];
assert_eq!(
tet(&owned).check(),
Err(NotFillable::OffEdge { edge: 0, at: 0 })
);
}
#[test]
fn a_classic_corner_cut_is_one_triangle() {
let coords = EdgeCoordinates::new([1, 1, 1, 0, 0, 0]);
let cycles = cycles(&coords);
assert_eq!(cycles.len(), 1);
assert_eq!(cycles[0].length(), 3);
assert!(cycles[0].is_corner_cut());
let owned = crossings(coords.count);
let mut patch = TetPatch::new();
assert_eq!(fill(&tet(&owned), &mut patch), Ok(Unfilled::None));
assert_eq!(patch.triangles.len(), 1);
assert_eq!(patch.positions.len(), 3);
}
#[test]
fn a_classic_diagonal_cut_is_a_quad_and_becomes_two_triangles() {
let coords = EdgeCoordinates::new([0, 1, 1, 1, 1, 0]);
let cycles = cycles(&coords);
assert_eq!(cycles.len(), 1);
assert_eq!(cycles[0].length(), 4);
assert!(!cycles[0].is_corner_cut());
let owned = crossings(coords.count);
let mut patch = TetPatch::new();
assert_eq!(fill(&tet(&owned), &mut patch), Ok(Unfilled::None));
assert_eq!(patch.triangles.len(), 2);
assert_eq!(patch.positions.len(), 4);
}
#[test]
fn every_classic_configuration_fills_completely() {
for signs in 0u8..16 {
let mut count = [0u32; TET_EDGE_COUNT];
for (e, slot) in count.iter_mut().enumerate() {
let [lo, hi] = TET_EDGES[e];
let inside = |c: u8| signs & (1 << c) != 0;
*slot = u32::from(inside(lo) != inside(hi));
}
let coords = EdgeCoordinates::new(count);
let owned = crossings(count);
let mut patch = TetPatch::new();
assert_eq!(
fill(&tet(&owned), &mut patch),
Ok(Unfilled::None),
"sign pattern {signs:04b} left something unfilled"
);
let expected = match coords.count.iter().sum::<u32>() {
0 => 0,
3 => 1,
4 => 2,
n => panic!("classic configuration with {n} crossings"),
};
assert_eq!(patch.triangles.len(), expected, "sign pattern {signs:04b}");
}
}
#[test]
fn the_appendix_formulas_predict_the_curves_section_3_1_actually_finds() {
let mut checked = 0;
for d1 in 1..=6u32 {
for d2 in 0..=d1 {
let coords = pattern_coords(d1, d2);
assert!(
coords.is_normal(),
"({d1}, {d2}) should satisfy both normality conditions"
);
let pattern = Pattern::of(&coords).expect("Property II holds by construction");
assert_eq!((pattern.d1, pattern.d2), (d1, d2));
let cycles = cycles(&coords);
assert!(
cycles.iter().all(|c| c.kind == CurveKind::Normal),
"({d1}, {d2}) produced a non-normal curve"
);
let predicted_count = pattern.loop_count();
let predicted_length = pattern
.loop_length()
.expect("a non-empty pattern has a length");
assert_eq!(
cycles.len() as u32,
predicted_count,
"({d1}, {d2}): Theorem B.4 predicted {predicted_count} loops"
);
for c in &cycles {
assert_eq!(
c.length() as u32,
predicted_length,
"({d1}, {d2}): Corollary B.6 predicted length {predicted_length}"
);
}
checked += 1;
}
}
assert_eq!(checked, 27);
}
#[test]
fn property_two_is_checked_and_not_assumed() {
assert_eq!(Pattern::of(&EdgeCoordinates::new([1, 0, 0, 0, 0, 2])), None);
assert_eq!(Pattern::of(&EdgeCoordinates::new([3, 1, 1, 1, 1, 3])), None);
assert_eq!(
Pattern::of(&EdgeCoordinates::new([0, 0, 0, 0, 0, 0])),
Some(Pattern { d1: 0, d2: 0 })
);
}
#[test]
fn removing_the_corner_cuts_is_what_makes_property_two_hold() {
let mut count = pattern_coords(1, 0).count;
for e in [0usize, 1, 2] {
count[e] += 1;
}
let coords = EdgeCoordinates::new(count);
assert_eq!(Pattern::of(&coords), None);
let cycles = cycles(&coords);
let residual = residual(&cycles);
assert_eq!(Pattern::of(&residual), Some(Pattern { d1: 1, d2: 0 }));
}
#[test]
fn parallel_quads_all_split_the_same_way() {
let coords = pattern_coords(3, 0);
let cycles = cycles(&coords);
assert_eq!(cycles.len(), 3, "gcd(3, 0) = 3 parallel quads");
let diagonal_edges: Vec<[u8; 2]> = cycles
.iter()
.map(|c| {
assert_eq!(c.length(), 4);
let mut e = [c.points[0].edge, c.points[2].edge];
e.sort_unstable();
e
})
.collect();
assert!(
diagonal_edges.windows(2).all(|w| w[0] == w[1]),
"quads split along different edge pairs: {diagonal_edges:?}"
);
}
#[test]
fn a_single_long_loop_fans_around_its_centre_of_mass() {
for (d1, d2, length) in [(3u32, 2u32, 20usize), (3, 1, 16), (5, 3, 32), (4, 3, 28)] {
let coords = pattern_coords(d1, d2);
let cycles = cycles(&coords);
assert_eq!(cycles.len(), 1, "({d1}, {d2}) should be a single loop");
assert_eq!(cycles[0].length(), length, "({d1}, {d2})");
let owned = crossings(coords.count);
let mut patch = TetPatch::new();
assert_eq!(
fill(&tet(&owned), &mut patch),
Ok(Unfilled::None),
"({d1}, {d2}) should be the single-loop case"
);
assert_eq!(patch.triangles.len(), length, "({d1}, {d2})");
assert_eq!(patch.positions.len(), length + 1, "({d1}, {d2})");
let steiner = patch.positions[length];
let mut sum = [0.0f64; 3];
for p in &patch.positions[..length] {
for (s, v) in sum.iter_mut().zip(p.iter()) {
*s += v;
}
}
for axis in 0..3 {
let mean = sum[axis] / length as f64;
assert!(
(steiner[axis] - mean).abs() < 1e-12,
"({d1}, {d2}): Steiner point is not the centre of mass"
);
}
}
}
fn two_tets(
shared: [Vec<f64>; 3],
apex_a: [Vec<f64>; 3],
apex_b: [Vec<f64>; 3],
) -> [Vec<Vec<f64>>; 2] {
let [s01, s02, s12] = shared;
let build = |apex: [Vec<f64>; 3]| {
let [a03, a13, a23] = apex;
alloc::vec![s01.clone(), s02.clone(), a03, s12.clone(), a13, a23,]
};
[build(apex_a), build(apex_b)]
}
#[expect(clippy::float_cmp, reason = "bit-identity is the property under test")]
#[test]
fn the_shared_face_of_two_tets_carries_no_crack() {
let corners_a = [
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
];
let corners_b = [
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, -1.0],
];
let cases: [([u32; 3], [u32; 3], [u32; 3]); 4] = [
([1, 1, 0], [1, 0, 0], [1, 0, 0]),
([1, 1, 2], [1, 2, 1], [2, 1, 2]),
([2, 2, 2], [2, 2, 2], [1, 1, 1]),
([3, 1, 2], [2, 1, 3], [1, 3, 2]),
];
let mut examined = 0;
let mut excused = 0;
for (shared, apex_a, apex_b) in cases {
let s = [spaced(shared[0]), spaced(shared[1]), spaced(shared[2])];
let a = [spaced(apex_a[0]), spaced(apex_a[1]), spaced(apex_a[2])];
let b = [spaced(apex_b[0]), spaced(apex_b[1]), spaced(apex_b[2])];
let [owned_a, owned_b] = two_tets(s, a, b);
let mut merged_positions: Vec<[f64; 3]> = Vec::new();
let mut merged_triangles: Vec<[u32; 3]> = Vec::new();
let mut any_unfilled = false;
for (owned, corners) in [(&owned_a, corners_a), (&owned_b, corners_b)] {
let mut along: [&[f64]; TET_EDGE_COUNT] = [&[]; TET_EDGE_COUNT];
for (slot, v) in along.iter_mut().zip(owned.iter()) {
*slot = v.as_slice();
}
let t = TetCrossings { corners, along };
let mut patch = TetPatch::new();
let outcome = fill(&t, &mut patch).expect("well-formed crossings");
if outcome != Unfilled::None {
any_unfilled = true;
}
for tri in &patch.triangles {
let mut welded = [0u32; 3];
for (slot, index) in welded.iter_mut().zip(tri.iter()) {
let p = patch.positions[*index as usize];
*slot = match merged_positions.iter().position(|q| *q == p) {
Some(existing) => existing as u32,
None => {
merged_positions.push(p);
merged_positions.len() as u32 - 1
}
};
}
merged_triangles.push(welded);
}
}
if any_unfilled || merged_triangles.is_empty() {
continue;
}
let mut edges: Vec<([u32; 2], u32)> = Vec::new();
for tri in &merged_triangles {
for k in 0..3 {
let (x, y) = (tri[k], tri[(k + 1) % 3]);
let key = if x < y { [x, y] } else { [y, x] };
match edges.iter_mut().find(|(e, _)| *e == key) {
Some((_, n)) => *n += 1,
None => edges.push((key, 1)),
}
}
}
let in_shared_face = |e: [u32; 2]| {
merged_positions[e[0] as usize][2] == 0.0 && merged_positions[e[1] as usize][2] == 0.0
};
let mut discarded: Vec<[[f64; 3]; 2]> = Vec::new();
for (owned, corners) in [(&owned_a, corners_a), (&owned_b, corners_b)] {
let mut along: [&[f64]; TET_EDGE_COUNT] = [&[]; TET_EDGE_COUNT];
for (slot, v) in along.iter_mut().zip(owned.iter()) {
*slot = v.as_slice();
}
let t = TetCrossings { corners, along };
for curve in crate::subgrid::curves::curves(&t.coordinates()) {
if curve.kind != CurveKind::Open {
continue;
}
for seg in &curve.segments {
if let (Some(p), Some(q)) = (t.position(seg.a), t.position(seg.b)) {
discarded.push([p, q]);
}
}
}
}
let was_discarded = |e: [u32; 2]| {
let (p, q) = (
merged_positions[e[0] as usize],
merged_positions[e[1] as usize],
);
discarded
.iter()
.any(|[a, b]| (*a == p && *b == q) || (*a == q && *b == p))
};
let cracks: Vec<[u32; 2]> = edges
.iter()
.filter(|(e, n)| *n == 1 && in_shared_face(*e) && !was_discarded(*e))
.map(|(e, _)| *e)
.collect();
assert!(
cracks.is_empty(),
"{shared:?}/{apex_a:?}/{apex_b:?}: {} boundary edges inside the shared face \
that no open curve accounts for: {cracks:?}",
cracks.len()
);
assert!(
edges.iter().all(|(e, n)| !in_shared_face(*e) || *n <= 2),
"{shared:?}: a shared-face edge is used by more than two triangles"
);
let shared_edges = edges.iter().filter(|(e, _)| in_shared_face(*e)).count();
assert!(
shared_edges > 0,
"{shared:?}: no triangle edge lies in the shared face at all"
);
excused += edges
.iter()
.filter(|(e, n)| *n == 1 && in_shared_face(*e) && was_discarded(*e))
.count();
examined += 1;
}
assert!(examined > 0, "no case filled completely enough to examine");
assert!(
excused > 0,
"no shared-face boundary edge was excused by a discarded open curve, \
so that clause is not being exercised"
);
}
#[test]
fn the_edge_labelling_closes_on_the_far_corner_it_was_not_told_about() {
let mut corner_loops = 0;
let mut contractible_loops = 0;
for raw in 0..4096u32 {
let mut count = [0u32; TET_EDGE_COUNT];
for (e, slot) in count.iter_mut().enumerate() {
*slot = (raw >> (2 * e)) & 0b11;
}
let coords = EdgeCoordinates::new(count);
for cycle in cycles(&coords) {
let Some(sides) = cycle.corner_sides() else {
continue;
};
match cycle.non_normal_kind() {
Some(NonNormalKind::Corner) => corner_loops += 1,
Some(NonNormalKind::Contractible) => contractible_loops += 1,
_ => panic!("only corner and contractible loops have sides"),
}
for edge in 0..TET_EDGE_COUNT as u8 {
let labels = cycle.edge_sides(edge).expect("this loop has sides");
let [lo, hi] = TET_EDGES[edge as usize];
let crossings = cycle.points.iter().filter(|p| p.edge == edge).count();
assert_eq!(labels.len(), crossings + 1, "{count:?} edge {edge}");
assert_eq!(labels[0], sides[lo as usize], "{count:?} edge {edge}");
assert_eq!(
*labels.last().expect("non-empty"),
sides[hi as usize],
"{count:?} edge {edge}: walking from corner {lo} across {crossings} \
crossings disagrees with corner {hi}'s own side"
);
}
if let Some(distinguished) = cycle.distinguished_corner() {
assert_eq!(sides[distinguished as usize], Side::Inside);
assert_eq!(
sides.iter().filter(|s| **s == Side::Inside).count(),
1,
"{count:?}: a corner loop has exactly one inside vertex"
);
}
}
}
assert!(
corner_loops > 0 && contractible_loops > 0,
"corner: {corner_loops}, contractible: {contractible_loops} -- both must be \
reached or one of the two labelling rules is untested"
);
}
#[test]
fn a_diagonal_loop_has_no_sides_and_that_is_the_papers_answer() {
let mut found = false;
for raw in 0..4096u32 {
let mut count = [0u32; TET_EDGE_COUNT];
for (e, slot) in count.iter_mut().enumerate() {
*slot = (raw >> (2 * e)) & 0b11;
}
for cycle in cycles(&EdgeCoordinates::new(count)) {
if cycle.non_normal_kind() == Some(NonNormalKind::Diagonal) {
assert_eq!(cycle.corner_sides(), None);
assert_eq!(cycle.edge_sides(0), None);
assert_eq!(cycle.distinguished_corner(), None);
found = true;
}
}
}
assert!(found, "no diagonal loop was reached");
}
#[test]
fn the_coverage_of_the_implemented_cases_is_pinned() {
let mut none = 0u32;
let mut single = 0u32;
let mut subdivision = 0u32;
let mut non_normal = 0u32;
let mut no_pattern = 0u32;
let mut inconsistent = 0u32;
for raw in 0..4096u32 {
let mut count = [0u32; TET_EDGE_COUNT];
for (e, slot) in count.iter_mut().enumerate() {
*slot = (raw >> (2 * e)) & 0b11;
}
let owned = crossings(count);
let mut patch = TetPatch::new();
let outcome = match fill(&tet(&owned), &mut patch) {
Ok(o) => o,
Err(e) => panic!("{count:?} was rejected as malformed: {e:?}"),
};
let n = patch.positions.len() as u32;
for t in &patch.triangles {
assert!(
t.iter().all(|i| *i < n),
"{count:?}: triangle {t:?} indexes past {n} vertices"
);
}
match outcome {
Unfilled::None => none += 1,
Unfilled::SingleLoop => single += 1,
Unfilled::Subdivision => subdivision += 1,
Unfilled::NonNormalLoop => non_normal += 1,
Unfilled::NoPattern => no_pattern += 1,
Unfilled::Inconsistent => inconsistent += 1,
}
}
assert_eq!(inconsistent, 0, "Inconsistent is a bug, not a case");
assert_eq!(
[none, single, subdivision, non_normal, no_pattern],
[4096, 0, 0, 0, 0],
"coverage moved: [None, SingleLoop, Subdivision, NonNormalLoop, NoPattern]"
);
assert_eq!(
none + single + subdivision + non_normal + no_pattern,
4096,
"the outcomes do not partition the sweep"
);
}
#[test]
fn non_normal_loops_are_classified_and_all_three_types_are_reachable() {
let mut seen = [0u32; 3];
let slot = |kind: NonNormalKind| match kind {
NonNormalKind::Contractible => 0usize,
NonNormalKind::Diagonal => 1,
NonNormalKind::Corner => 2,
};
for a in 0..4u32 {
for b in 0..4u32 {
for c in 0..4u32 {
for d in 0..4u32 {
for e in 0..4u32 {
for f in 0..4u32 {
let coords = EdgeCoordinates::new([a, b, c, d, e, f]);
for cycle in cycles(&coords) {
if let Some(kind) = cycle.non_normal_kind() {
seen[slot(kind)] += 1;
}
assert_eq!(
cycle.non_normal_kind().is_some(),
cycle.kind == CurveKind::NonNormal
);
}
}
}
}
}
}
}
for kind in [
NonNormalKind::Contractible,
NonNormalKind::Diagonal,
NonNormalKind::Corner,
] {
assert!(
seen[slot(kind)] > 0,
"{kind:?} was never produced, so its branch is untested"
);
}
}
#[test]
fn all_three_non_normal_types_now_have_a_spanning_disk() {
let mut seen = [0u32; 3];
let mut empty_disks = 0u32;
let slot = |kind: NonNormalKind| match kind {
NonNormalKind::Contractible => 0usize,
NonNormalKind::Diagonal => 1,
NonNormalKind::Corner => 2,
};
for raw in 0..4096u32 {
{
{
let mut count = [0u32; TET_EDGE_COUNT];
for (e, slot) in count.iter_mut().enumerate() {
*slot = (raw >> (2 * e)) & 0b11;
}
let coords = EdgeCoordinates::new(count);
let non_normal: Vec<_> = cycles(&coords)
.into_iter()
.filter(|x| x.kind == CurveKind::NonNormal)
.collect();
if non_normal.is_empty() {
continue;
}
for x in &non_normal {
if let Some(kind) = x.non_normal_kind() {
seen[slot(kind)] += 1;
}
}
let owned = crossings(coords.count);
let mut patch = TetPatch::new();
let outcome = fill(&tet(&owned), &mut patch).expect("well-formed");
assert_eq!(
outcome,
Unfilled::None,
"{:?}: every non-normal type has a disk now",
coords.count
);
if patch.triangles.is_empty() {
empty_disks += 1;
}
}
}
}
for kind in [
NonNormalKind::Contractible,
NonNormalKind::Diagonal,
NonNormalKind::Corner,
] {
assert!(
seen[slot(kind)] > 0,
"{kind:?} was never reached, so its disk is untested"
);
}
assert_eq!(empty_disks, 105, "degenerate bigon disks");
}
#[test]
fn the_subdivision_stencil_produces_four_normal_sub_tets() {
let mut checked = 0;
for d1 in 1..=6u32 {
for d2 in 0..=d1 {
let coords = pattern_coords(d1, d2);
let pattern = Pattern::of(&coords).expect("built as a pattern");
let Some(stencil) = Subdivision::label(&coords, pattern) else {
panic!("({d1}, {d2}): Property II holds but no labelling was found");
};
let [i, j, k, l] = stencil.corner;
let e = |a: u8, b: u8| coords.edge(crate::subgrid::coordinates::edge_between(a, b));
assert_eq!((e(i, j), e(k, l)), (d1, d1), "({d1}, {d2})");
assert_eq!((e(i, k), e(j, l)), (d2, d2), "({d1}, {d2})");
assert_eq!((e(i, l), e(j, k)), (d1 + d2, d1 + d2), "({d1}, {d2})");
assert_eq!(stencil.spoke(), [2 * d2, d1, d2, d1 - d2], "({d1}, {d2})");
for which in 0..4 {
let sub = stencil
.sub_tet(&coords, which)
.expect("four sub-tets exist");
assert!(
sub.is_normal(),
"({d1}, {d2}) sub-tet {which} is not a normal configuration: {:?}",
sub.count
);
}
checked += 1;
}
}
assert_eq!(checked, 27, "the sweep did not run");
}
#[test]
fn the_stencil_is_asymmetric_and_the_labelling_is_what_decides_it() {
let coords = pattern_coords(3, 1);
let pattern = Pattern::of(&coords).expect("built as a pattern");
let stencil = Subdivision::label(&coords, pattern).expect("a labelling exists");
let spoke = stencil.spoke();
assert_eq!(spoke, [2, 3, 1, 2]);
let mut seen: Vec<[u32; TET_EDGE_COUNT]> = (0..4)
.filter_map(|w| stencil.sub_tet(&coords, w))
.map(|c| c.count)
.collect();
assert_eq!(seen.len(), 4);
seen.sort_unstable();
seen.dedup();
assert_eq!(seen.len(), 4, "two sub-tets came out identical");
}
#[expect(
clippy::float_cmp,
reason = "bit-identity is what makes the weld sound"
)]
#[test]
fn every_implemented_case_emits_an_intersection_free_patch() {
let mut checked = 0;
for d1 in 1..=5u32 {
for d2 in 0..=d1 {
let coords = pattern_coords(d1, d2);
let owned = crossings(coords.count);
let mut patch = TetPatch::new();
let outcome = fill(&tet(&owned), &mut patch).expect("well-formed crossings");
if outcome != Unfilled::None {
continue;
}
let mut welded_positions: Vec<[f64; 3]> = Vec::new();
let mut remap: Vec<u32> = Vec::with_capacity(patch.positions.len());
for p in &patch.positions {
let at = match welded_positions.iter().position(|q| q == p) {
Some(existing) => existing,
None => {
welded_positions.push(*p);
welded_positions.len() - 1
}
};
remap.push(at as u32);
}
let indices: Vec<u32> = patch
.triangles
.iter()
.flatten()
.map(|i| remap[*i as usize])
.collect();
let report = crate::validate::self_intersections(&welded_positions, &indices, 1.0)
.expect("a unit tet is a valid spacing");
assert_eq!(
report.count(),
0,
"({d1}, {d2}): {} self-intersections in {} triangles",
report.count(),
patch.triangles.len()
);
checked += 1;
}
}
assert_eq!(checked, 20, "the sweep did not reach every case");
}
#[test]
fn the_single_loop_zero_is_vacuous_and_this_is_what_makes_that_visible() {
let coords = pattern_coords(3, 2);
let owned = crossings(coords.count);
let mut patch = TetPatch::new();
assert_eq!(fill(&tet(&owned), &mut patch), Ok(Unfilled::None));
let indices: Vec<u32> = patch.triangles.iter().flatten().copied().collect();
let report = crate::validate::self_intersections(&patch.positions, &indices, 1.0)
.expect("a unit tet is a valid spacing");
let n = patch.triangles.len() as u64;
let pairs = n * (n - 1) / 2;
assert_eq!(
report.adjacent_pairs_skipped, pairs,
"not every pair was skipped, so the counter can see *something* inside \
a fan and this test's premise needs revisiting"
);
assert_eq!(report.count(), 0);
}
#[test]
fn reversing_the_steiner_assignment_is_visibly_wrong() {
let m = 3u32;
let coords = pattern_coords(m, m);
let owned = crossings(coords.count);
let mut patch = TetPatch::new();
assert_eq!(fill(&tet(&owned), &mut patch), Ok(Unfilled::None));
let base = 8 * m;
let reversed: Vec<u32> = patch
.triangles
.iter()
.flatten()
.map(|i| {
if *i >= base {
base + (m - 1 - (*i - base))
} else {
*i
}
})
.collect();
let report = crate::validate::self_intersections(&patch.positions, &reversed, 1.0)
.expect("a unit tet is a valid spacing");
assert!(
report.count() > 0,
"reversing the Steiner assignment produced no intersections, so the \
intersection-free assertion is not measuring anything"
);
}
#[test]
fn a_cycle_visits_every_segment_once_and_returns_to_its_start() {
for d1 in 1..=4u32 {
for d2 in 0..=d1 {
let coords = pattern_coords(d1, d2);
for c in cycles(&coords) {
let mut seen = c.points.clone();
seen.sort_unstable();
seen.dedup();
assert_eq!(
seen.len(),
c.points.len(),
"({d1}, {d2}): a cycle repeated a point"
);
}
}
}
}
#[test]
fn the_subdivision_case_recurses_and_terminates() {
for (d1, d2, triangles) in [(4u32, 2u32, 52usize), (6, 3, 78), (6, 4, 116)] {
let coords = pattern_coords(d1, d2);
let owned = crossings(coords.count);
let mut patch = TetPatch::new();
assert_eq!(
fill(&tet(&owned), &mut patch),
Ok(Unfilled::None),
"({d1}, {d2}) should subdivide and fill"
);
assert_eq!(
patch.triangles.len(),
triangles,
"({d1}, {d2}) triangle count"
);
let n = patch.positions.len() as u32;
for t in &patch.triangles {
assert!(t.iter().all(|i| *i < n), "({d1}, {d2}): index past {n}");
}
}
}
#[test]
fn an_octagon_is_a_fan_around_its_steiner_point() {
let coords = pattern_coords(1, 1);
let cycles = cycles(&coords);
assert_eq!(cycles.len(), 1);
assert_eq!(cycles[0].length(), 8);
let owned = crossings(coords.count);
let mut patch = TetPatch::new();
assert_eq!(fill(&tet(&owned), &mut patch), Ok(Unfilled::None));
assert_eq!(patch.triangles.len(), 8);
assert_eq!(patch.positions.len(), 9);
let steiner = patch.positions.len() as u32 - 1;
for t in &patch.triangles {
assert_eq!(
t.iter().filter(|i| **i == steiner).count(),
1,
"triangle {t:?} does not fan around the Steiner point"
);
}
}
#[test]
fn m_octagons_get_m_steiner_points_ordered_along_the_axis() {
for m in 1..=4u32 {
let coords = pattern_coords(m, m);
let owned = crossings(coords.count);
let mut patch = TetPatch::new();
assert_eq!(
fill(&tet(&owned), &mut patch),
Ok(Unfilled::None),
"({m}, {m}) should be the octagon case"
);
let loops = m as usize;
assert_eq!(patch.triangles.len(), 8 * loops, "m = {m}");
assert_eq!(patch.positions.len(), 8 * loops + loops, "m = {m}");
let steiner = &patch.positions[8 * loops..];
assert_eq!(steiner.len(), loops);
let axis = [
steiner[loops - 1][0] - steiner[0][0],
steiner[loops - 1][1] - steiner[0][1],
steiner[loops - 1][2] - steiner[0][2],
];
if m > 1 {
let mut previous = f64::NEG_INFINITY;
for s in steiner {
let t = s[0] * axis[0] + s[1] * axis[1] + s[2] * axis[2];
assert!(t > previous, "m = {m}: Steiner points are not ordered");
previous = t;
}
}
}
}
#[test]
fn each_octagon_pairs_nested_crossings_on_the_long_edge() {
for m in 2..=4u32 {
let coords = pattern_coords(m, m);
let cycles = cycles(&coords);
assert_eq!(cycles.len(), m as usize);
let long = 2u8;
assert_eq!(coords.edge(long), 2 * m);
let mut ranks: Vec<[u32; 2]> = Vec::new();
for c in &cycles {
let mut on_long: Vec<u32> = c
.points
.iter()
.filter(|q| q.edge == long)
.map(|q| q.index)
.collect();
on_long.sort_unstable();
assert_eq!(on_long.len(), 2, "m = {m}: a loop did not cross e twice");
assert_eq!(
on_long[0] + on_long[1],
2 * m - 1,
"m = {m}: crossings {on_long:?} are not nested about the middle"
);
ranks.push([on_long[0], on_long[1]]);
}
ranks.sort_unstable();
for (i, r) in ranks.iter().enumerate() {
assert_eq!(r[0], i as u32, "m = {m}: nesting levels are not distinct");
}
}
}
#[test]
fn filling_is_deterministic_and_reset_keeps_capacity() {
let coords = pattern_coords(2, 0);
let owned = crossings(coords.count);
let t = tet(&owned);
let mut a = TetPatch::new();
let mut b = TetPatch::new();
assert_eq!(fill(&t, &mut a), Ok(Unfilled::None));
assert_eq!(fill(&t, &mut b), Ok(Unfilled::None));
assert_eq!(a.positions, b.positions);
assert_eq!(a.triangles, b.triangles);
let capacity = a.positions.capacity();
a.reset();
assert!(a.is_empty());
assert_eq!(a.positions.capacity(), capacity);
}
#[test]
fn no_triangle_indexes_a_vertex_that_does_not_exist_or_repeats_one() {
for d1 in 1..=4u32 {
for d2 in 0..=d1 {
let coords = pattern_coords(d1, d2);
let owned = crossings(coords.count);
let mut patch = TetPatch::new();
let outcome = fill(&tet(&owned), &mut patch).expect("well-formed crossings");
assert_ne!(outcome, Unfilled::Inconsistent);
assert_ne!(outcome, Unfilled::NoPattern);
let n = patch.positions.len() as u32;
for t in &patch.triangles {
assert!(t.iter().all(|i| *i < n), "({d1}, {d2}): index out of range");
assert!(
t[0] != t[1] && t[1] != t[2] && t[0] != t[2],
"({d1}, {d2}): degenerate triangle {t:?}"
);
}
}
}
}
#[test]
fn a_face_split_along_a_loop_partitions_into_regions() {
let mut faces_with_chords = 0;
let mut multi_chord_faces = 0;
for raw in 0..4096u32 {
let mut count = [0u32; TET_EDGE_COUNT];
for (e, slot) in count.iter_mut().enumerate() {
*slot = (raw >> (2 * e)) & 0b11;
}
for cycle in cycles(&EdgeCoordinates::new(count)) {
if cycle.corner_sides().is_none() {
continue;
}
for face in 0..4u8 {
let regions = face_regions(face, &EdgeCoordinates::new(count), &cycle)
.expect("this loop has sides");
assert!(!regions.is_empty(), "{count:?} face {face}: no regions");
let mut edge_arcs = 0usize;
let mut chords = 0usize;
for r in ®ions {
assert_eq!(
r.arc.len(),
r.node.len(),
"{count:?}: arcs and nodes differ"
);
assert!(r.arc.len() >= 2, "{count:?}: a region with under 2 arcs");
for a in &r.arc {
match a {
Arc::Edge { .. } => edge_arcs += 1,
Arc::Chord => chords += 1,
}
}
}
let expected_pieces: usize = (0..3)
.map(|k| {
let e = crate::subgrid::coordinates::TET_FACES[face as usize].edge[k];
cycle.points.iter().filter(|p| p.edge == e).count() + 1
})
.sum();
assert_eq!(
edge_arcs, expected_pieces,
"{count:?} face {face}: edge pieces not conserved"
);
let chord_count = chords;
assert_eq!(
chord_count % 2,
0,
"{count:?} face {face}: a chord bounds an odd number of regions"
);
assert_eq!(
regions.len(),
chord_count / 2 + 1,
"{count:?} face {face}: {} regions for {} chord sides",
regions.len(),
chord_count
);
let mut appearances: Vec<(Node, usize)> = Vec::new();
for r in ®ions {
for n in &r.node {
match appearances.iter_mut().find(|(m, _)| m == n) {
Some((_, c)) => *c += 1,
None => appearances.push((*n, 1)),
}
}
}
for (n, c) in &appearances {
let expected = match n {
Node::Corner(_) => 1,
Node::Crossing(_) => 2,
};
assert_eq!(
*c, expected,
"{count:?} face {face}: {n:?} appears in {c} regions, not {expected}"
);
}
if chord_count > 0 {
faces_with_chords += 1;
}
if chord_count / 2 >= 2 {
multi_chord_faces += 1;
}
}
}
}
assert!(faces_with_chords > 0, "no face was ever actually cut");
assert!(
multi_chord_faces > 0,
"no face carried two chords, so the innermost rule is untested"
);
}
#[test]
fn the_peel_refuses_crossing_chords_rather_than_dropping_them() {
let p = |index| Node::Crossing(FacePoint { edge: 0, index });
let node = alloc::vec![p(0), p(1), p(2), p(3)];
let side = Side::Inside;
let arc = alloc::vec![
Arc::Edge {
edge: 0,
piece: 0,
side
};
4
];
let partner = alloc::vec![Some(2), Some(3), Some(0), Some(1)];
assert_eq!(peel(node, arc, partner), None);
}
#[test]
fn the_subdivision_path_is_reached_and_its_orphaned_vertices_counted() {
let coords = pattern_coords(4, 2);
assert_eq!(coords.total(), 24, "the ticket's ≥24 intersections");
let pattern = Pattern::of(&coords).expect("Property II holds by construction");
assert_eq!(
pattern.loop_count(),
2,
"more than one loop, or it is case (4)"
);
assert_eq!(
pattern.loop_length(),
Some(12),
"loop length is not 4 or 8, or it is case (2)/(3)"
);
let owned = crossings(coords.count);
let mut patch = TetPatch::new();
let outcome = fill(&tet(&owned), &mut patch).expect("well-formed crossings");
assert_eq!(outcome, Unfilled::None, "case (5) did not fill");
let mut used = alloc::vec![false; patch.positions.len()];
for tri in &patch.triangles {
for i in tri {
let at = *i as usize;
assert!(at < used.len(), "an index past the end of the positions");
used[at] = true;
}
}
let orphaned = used.iter().filter(|u| !**u).count();
std::println!(
"(4, 2): {} positions, {} triangles, {orphaned} unreferenced",
patch.positions.len(),
patch.triangles.len(),
);
assert_eq!(
orphaned,
0,
"{orphaned} of {} positions are unreferenced",
patch.positions.len()
);
let named = patch.crossings.len();
let mut rediscovered = 0;
for at in 0..named {
let parent = patch.positions[at];
if patch.positions[named..].contains(&parent) {
rediscovered += 1;
}
}
std::println!("(4, 2): {rediscovered} of {named} parent crossings duplicated by a child");
assert_eq!(
rediscovered, 0,
"a child pushed its own copy of a parent crossing instead of inheriting \
the parent's index, which is what left the parent's block orphaned"
);
}