mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-04 02:55:54 +00:00
geom: a general fill's crown fills out to the side its neighbours' normals face
The crown moved the free points along the patch's own normal, whose sign is only the way the patch happens to be parameterised: the pentagonal window's crown 0.1 sank 1.56 mm into the cylinder (the middle 9.959 from the axis plain, 8.395 crowned) where the kernel documents it filling out to the side the G1/G2 neighbours' normals face. The crown now takes that side: the sum of the patch's normals against the neighbours' over the stations sets one sign for the fill. The pentagon's middle goes out to 11.526. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2117,7 +2117,8 @@ fn folds(patch: &Patch) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// The fill with its middle filled out by `crown` times the loop's `size` along the normals, on
|
||||
/// The fill with its middle filled out by `crown` times the loop's `size` along the normals (to
|
||||
/// the side the neighbours' normals face), on
|
||||
/// control points clear of the rows the conditions hold (n + 1 rows from a G^n edge), so the loop and the conditions across it do not move. One patch
|
||||
/// rises by `16·u(1−u)·v(1−v)`; patches about a centre by `u(2−u)·v(2−v)`, nought on the loop and
|
||||
/// one at the centre, the same on a spoke from either side.
|
||||
@@ -2126,6 +2127,15 @@ fn crowned(mut quilt: Quilt, stations: &[Station], crown: f64, size: f64) -> Spl
|
||||
return Ok(quilt);
|
||||
}
|
||||
let held = 1 + stations.iter().map(Station::order).max().unwrap_or(0);
|
||||
// Out to the side the neighbours' normals face (the patches all turn one way).
|
||||
let mut facing = 0.0;
|
||||
for s in stations {
|
||||
let (uv, _) = station_on(s.side, s.t);
|
||||
if let Some(n) = quilt.patches.get(s.patch).and_then(|p| p.normal(uv[0], uv[1])) {
|
||||
facing += n.dot(s.across.normal);
|
||||
}
|
||||
}
|
||||
let out = if facing < 0.0 { -1.0 } else { 1.0 };
|
||||
let about_centre = !quilt.spokes.is_empty();
|
||||
let bump = |x: f64, y: f64| if about_centre { x * (2.0 - x) * y * (2.0 - y) } else { 16.0 * x * (1.0 - x) * y * (1.0 - y) };
|
||||
let mut moved = std::collections::HashMap::new();
|
||||
@@ -2138,7 +2148,7 @@ fn crowned(mut quilt: Quilt, stations: &[Station], crown: f64, size: f64) -> Spl
|
||||
let Some(Some(id)) = quilt.slots.get(k).and_then(|s| s.get(patch.flat(i, j))) else { continue };
|
||||
let (x, y) = (gu.get(i).copied().unwrap_or(0.5), gv.get(j).copied().unwrap_or(0.5));
|
||||
let Some(n) = patch.normal(x, y) else { continue };
|
||||
moved.entry(*id).or_insert_with(|| patch.at(i, j) + n * (crown * size * bump(x, y)));
|
||||
moved.entry(*id).or_insert_with(|| patch.at(i, j) + n * (out * crown * size * bump(x, y)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,3 +370,24 @@ fn a_loop_whose_edges_run_straight_on_at_seams_is_one_patch_on_its_corners() {
|
||||
assert!(angle > 0.5 && angle < 179.5, "a flat corner at {c:?}: {angle}°");
|
||||
}
|
||||
}
|
||||
|
||||
/// A crown fills the middle out to the side the neighbours' normals face, whichever way the
|
||||
/// patch itself is parameterised: the sphere window, its neighbours' normals outward, rises away
|
||||
/// from the centre; given them inward, it sinks.
|
||||
#[test]
|
||||
fn a_crown_fills_out_to_the_side_the_neighbours_face() {
|
||||
let edges = window();
|
||||
let middle = |f: &IsoFill| f.patches[0].surface.eval(0.5, 0.5).unwrap().len();
|
||||
let plain = middle(&iso_fill(&edges, &mut sphere_beside(&edges, 1), &spec()).unwrap());
|
||||
let crowned = IsoSpec { crown: 0.1, ..spec() };
|
||||
let out = middle(&iso_fill(&edges, &mut sphere_beside(&edges, 1), &crowned).unwrap());
|
||||
let mut inward = {
|
||||
let mut beside = sphere_beside(&edges, 1);
|
||||
move |k: usize, ts: &[f64]| -> Result<Vec<Option<Across>>, String> {
|
||||
Ok(beside(k, ts)?.into_iter().map(|a| a.map(|a| Across { normal: a.normal * -1.0, ..a })).collect())
|
||||
}
|
||||
};
|
||||
let sunk = middle(&iso_fill(&edges, &mut inward, &crowned).unwrap());
|
||||
eprintln!("the window's middle {plain:.4} from the centre, crowned {out:.4}, crowned to inward neighbours {sunk:.4}");
|
||||
assert!(out > plain + 0.1 && sunk < plain - 0.1, "{plain} {out} {sunk}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user