mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-27 19:27:21 -06:00
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:
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user