mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-05 03:25:58 +00:00
geom: a fill patch folds where its normal reverses between neighbours, not where it turns past the middle's
The fold check refused a patch whose normal, anywhere on a grid, was a right angle or more from the normal at its middle. A fill may turn its normal that far without folding: a dome that meets a tube's wall tangentially is vertical at its rim (90° from its top), a window round more than half a cylinder turns past 120°. A fold is the surface turning back over itself, which reverses the normal between neighbouring points of the grid (24 × 24, 3.75° steps on a half cylinder); that is what is refused now, and a normal that vanishes inside the patch. It may vanish at a corner where two sides run on straight (a closed loop's pieces) and on a three-sided patch's pole. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+29
-11
@@ -1648,19 +1648,37 @@ fn nearest(quilt: &Quilt, p: Vec3) -> (usize, [f64; 2]) {
|
||||
(k, [u, v])
|
||||
}
|
||||
|
||||
/// Whether a patch folds back on itself: its normal turns against the middle's somewhere on a
|
||||
/// grid (clear of a three-sided patch's pole at u = 0, where the normal is undefined).
|
||||
/// Whether a patch folds back on itself: on a grid of its parameters, its normal reverses between
|
||||
/// neighbouring points (the surface turns back over itself), or vanishes inside it. A patch may
|
||||
/// turn its normal through more than a right angle overall (a dome meeting a tube's wall, a
|
||||
/// window round more than half a cylinder): only a reversal between neighbours is a fold. The
|
||||
/// normal may vanish at a corner (where two sides run on straight, as on a closed loop's pieces)
|
||||
/// and on a three-sided patch's pole at u = 0.
|
||||
fn folds(patch: &Patch) -> bool {
|
||||
let Some(mid) = patch.normal(0.5, 0.5) else { return true };
|
||||
for i in 0..=FOLD_SAMPLES {
|
||||
if patch.pole && i == 0 {
|
||||
continue;
|
||||
let n = FOLD_SAMPLES;
|
||||
if patch.normal(0.5, 0.5).is_none() {
|
||||
return true;
|
||||
}
|
||||
let at = |i: usize, j: usize| patch.normal(i as f64 / n as f64, j as f64 / n as f64);
|
||||
let mut grid: Vec<Option<Vec3>> = Vec::with_capacity((n + 1) * (n + 1));
|
||||
for i in 0..=n {
|
||||
for j in 0..=n {
|
||||
let normal = at(i, j);
|
||||
let excused = (patch.pole && i == 0) || ((i == 0 || i == n) && (j == 0 || j == n));
|
||||
if normal.is_none() && !excused {
|
||||
return true;
|
||||
}
|
||||
grid.push(normal);
|
||||
}
|
||||
for j in 0..=FOLD_SAMPLES {
|
||||
let (u, v) = (i as f64 / FOLD_SAMPLES as f64, j as f64 / FOLD_SAMPLES as f64);
|
||||
match patch.normal(u, v) {
|
||||
Some(n) if n.dot(mid) > 0.0 => {}
|
||||
_ => return true,
|
||||
}
|
||||
let get = |i: usize, j: usize| grid.get(i * (n + 1) + j).copied().flatten();
|
||||
for i in 0..=n {
|
||||
for j in 0..=n {
|
||||
let Some(a) = get(i, j) else { continue };
|
||||
for (k, l) in [(i + 1, j), (i, j + 1)] {
|
||||
if k <= n && l <= n && get(k, l).is_some_and(|b| a.dot(b) <= 0.0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user