Merge pull request #2155 from dotCooCoo/fix/inflate-one-edge-index

3D and Materials: Inflate builds its edge index once
This commit is contained in:
BFlat
2026-10-16 03:19:34 +07:00
committed by GitHub
2 changed files with 7 additions and 5 deletions
+3 -3
View File
@@ -886,8 +886,8 @@ struct Membrane {
}
impl Membrane {
fn solve(rings: &[Vec<Point>], origin: Point, step: f64, nx: usize, ny: usize) -> Self {
let edges = Edges::new(rings);
/// `edges` is the index of `rings`' edges (`Edges::new(rings)`).
fn solve(rings: &[Vec<Point>], edges: &Edges, origin: Point, step: f64, nx: usize, ny: usize) -> Self {
let node = |i: usize, j: usize| Point::new(origin.x + i as f64 * step, origin.y + j as f64 * step);
let idx = |i: usize, j: usize| j * nx + i;
// A node on the outline itself is held at zero with the outside.
@@ -1035,8 +1035,8 @@ pub fn inflate(path: &PathData, rule: FillRule, bounds: Rect, options: Inflate,
const CELLS: usize = 48;
let cell = size / CELLS as f64;
let (nx, ny) = (((bounds.width() / cell).ceil() as usize).max(1), ((bounds.height() / cell).ceil() as usize).max(1));
let m = Membrane::solve(&rings, bounds.origin(), cell, nx + 1, ny + 1);
let edges = Edges::new(&rings);
let m = Membrane::solve(&rings, &edges, bounds.origin(), cell, nx + 1, ny + 1);
let outline = PathData::new(rings.iter().map(|r| vectorcraft_geom::SubPath::polyline(r, true)).collect());
// A circle of radius r puffs into a half sphere of radius r at 50 % (its membrane peaks at r²/4).
let height = 2.0 * m.peak.sqrt() * o.volume / 50.0;
+4 -2
View File
@@ -284,10 +284,12 @@ fn the_inflate_membrane_matches_known_solutions() {
let mut c = BezPath::new();
c.extend(vectorcraft_geom::kurbo::Shape::path_elements(&vectorcraft_geom::kurbo::Circle::new((100.0, 100.0), 50.0), 0.01));
let (p, b) = shape(&c);
let disc = Membrane::solve(&rings(&p, FillRule::EvenOdd, 100.0, MAX_SOLID_POINTS).unwrap(), b.origin(), b.width() / 48.0, 49, 49);
let r = rings(&p, FillRule::EvenOdd, 100.0, MAX_SOLID_POINTS).unwrap();
let disc = Membrane::solve(&r, &Edges::new(&r), b.origin(), b.width() / 48.0, 49, 49);
assert!(close(disc.peak, 50.0 * 50.0 / 4.0, 625.0 * 0.02), "{}", disc.peak);
let (p, b) = shape(&square(0.0, 0.0, 100.0));
let sq = Membrane::solve(&rings(&p, FillRule::EvenOdd, 100.0, MAX_SOLID_POINTS).unwrap(), b.origin(), 100.0 / 48.0, 49, 49);
let r = rings(&p, FillRule::EvenOdd, 100.0, MAX_SOLID_POINTS).unwrap();
let sq = Membrane::solve(&r, &Edges::new(&r), b.origin(), 100.0 / 48.0, 49, 49);
assert!(close(sq.peak, 0.07367 * 100.0 * 100.0, 736.7 * 0.02), "{}", sq.peak);
// Smooth across the middle: no crease where a distance-to-the-edge height would have one
// (the diagonals). The second difference along a diagonal stays small and even.