diff --git a/src/scene/paper_canvas.rs b/src/scene/paper_canvas.rs index 9232d6ea8..fb529f90b 100644 --- a/src/scene/paper_canvas.rs +++ b/src/scene/paper_canvas.rs @@ -174,13 +174,32 @@ fn draw_hatch(frame: &mut canvas::Frame, hatch: &HatchModel, to_px: &impl Fn(f32 // Reconstruct offset-rel WCS from stored small offsets + f64 anchor. let ox = hatch.world_origin[0] as f32; let oy = hatch.world_origin[1] as f32; + // `boundary` may carry multiple disconnected sub-paths separated by + // NaN-NaN sentinels (multi-region hatches with islands / holes). + // Forwarding NaN to lyon's path builder panics + // (`IncorrectActiveEdgeOrder`) — start a fresh sub-path on each + // sentinel so each region is closed and filled independently. let path = canvas::Path::new(|builder| { - let first = to_px(hatch.boundary[0][0] + ox, hatch.boundary[0][1] + oy); - builder.move_to(first); - for &[x, y] in &hatch.boundary[1..] { - builder.line_to(to_px(x + ox, y + oy)); + let mut active = false; + for &[x, y] in hatch.boundary.iter() { + if x.is_nan() || y.is_nan() { + if active { + builder.close(); + active = false; + } + continue; + } + let p = to_px(x + ox, y + oy); + if !active { + builder.move_to(p); + active = true; + } else { + builder.line_to(p); + } + } + if active { + builder.close(); } - builder.close(); }); match &hatch.pattern {