1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! Speculative algorithms, off by default and exempt from semver.
//!
//! Ticket: X-003. Enable with `features = ["experimental"]`.
//!
//! # What this module is for
//!
//! Phases 11 through 15 are experiments: the same algorithm with one rule
//! swapped, measured against the rule it replaces. X-002 built the seam that
//! makes that possible without a second execution path; this is where the other
//! side of the seam lives, so a speculative rule does not have to enter the
//! stable public API to be measured.
//!
//! # Exempt from semver, and from nothing else
//!
//! Anything here may change or disappear in a patch release. It is **not**
//! exempt from correctness: T-001's validity suite, T-004's determinism check
//! and the property tests apply exactly as they do to the stable extractors, and
//! an experimental rule that cannot pass them is a wrong answer rather than an
//! early one.
//!
//! It is also not exempt from the dependency rule. The feature adds no
//! dependencies — `cargo tree -p isomesh -e normal` is `isomesh + libm` with the
//! feature on or off, which `the_experimental_feature_adds_no_dependencies`
//! checks rather than assumes.
use crateSdf;
use crate;
use crate;
use crateHermiteCell;
use crateReal;
/// Trettner & Kobbelt's probabilistic plane quadric, which for this crate's
/// formulation is the existing solve with a **crossing-count-scaled**
/// regularizer.
///
/// Ticket: X-004. Source: *Fast and Robust QEF Minimization using Probabilistic
/// Quadrics*, Trettner & Kobbelt, CGF 39(2) (`10.1111/cgf.13933`), §3.1.
///
/// # The paper's rule reduces to ours, and the derivation is the finding
///
/// X-004 was written expecting this to *supersede* the Tikhonov regularizer.
/// It does not — it **is** that regularizer, with one number changed, and the
/// reason is that this crate already solves in centroid-relative coordinates
/// (M-238).
///
/// Equations (6) and (7) give the probabilistic plane quadric under Gaussian
/// noise `Σₙ` on the normal:
///
/// ```text
/// A = Σ nᵢnᵢᵀ + N·Σₙ b = Σ nᵢnᵢᵀqᵢ + Σₙ·Σ qᵢ
/// ```
///
/// Write `x = c + Δ` and `qᵢ = c + rᵢ` for the crossings' centroid `c`, take
/// `Σₙ = σ²I`, and the system `Ax = b` becomes
///
/// ```text
/// (M + Nσ²I) Δ = Σ nᵢdᵢ + σ² Σ rᵢ
/// ```
///
/// where `dᵢ = nᵢ·(qᵢ − c)`. **`Σ rᵢ` is identically zero**, because `c` is
/// defined as the arithmetic mean of the `qᵢ` — so the extra term the paper adds
/// to `b` vanishes, and what remains is exactly
/// [`solve_with`](crate::dual_contouring::solve::solve_with) at `λ = Nσ²`.
///
/// `the_probabilistic_quadric_is_the_existing_solve` pins that as a numeric
/// identity rather than leaving it as algebra.
///
/// # So what is actually different
///
/// The **scaling**. [`Qef`](crate::dual_contouring::Qef) applies one fixed `λ`
/// to every cell; this applies `N·σ²`, so a cell with twelve crossings is
/// regularized four times as hard as one with three. That is the whole
/// experimental content of this rule, and it is measurable — which is why it
/// exists as a rule rather than as a paragraph.
///
/// # What is *not* implemented, and why that is the honest boundary
///
/// The paper's actual novelty is **anisotropic** `Σₙ`: a per-plane normal
/// covariance, which is what lets it distinguish noise from a sharp feature.
/// That needs a noise model, and this crate's fields are analytic with exact
/// gradients — there is no measurement error to model. Inventing a covariance so
/// the formula has somewhere to put one would be fitting the data to the method.
/// A consumer meshing scanned or quantised data has such a model and would be
/// the reason to add it.
/// The default per-crossing variance.
///
/// Chosen so that a cell with the **median** crossing count reproduces the
/// stable path's regularizer rather than by fitting anything: the reference
/// fields' dual cells carry four crossings far more often than any other count,
/// so `σ² = LAMBDA / 4` makes the common cell agree exactly and lets the tails
/// differ, which is the effect being measured.
pub const DEFAULT_SIGMA_SQUARED: f64 = LAMBDA / 4.0;