Merge pull request #1572 from switch87/fix/1570-pathfinder-strokes

Pathfinder: Trim, Merge and Crop remove strokes
This commit is contained in:
BFlat 2026-10-13 11:26:39 +07:00 committed by GitHub
commit 3126e82ebd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 32 additions and 1 deletions

View File

@ -383,10 +383,15 @@ fn run_pf(s: &mut Session, op: PathfinderOp) -> Result<Value> {
let mut styles: Vec<Style> = vec![];
let mut shapes: Vec<po::Shape> = vec![];
let mut names: Vec<Option<String>> = vec![];
let mut push = |mut path: PathData, rule: FillRule, st: Style, name: Option<String>| {
let mut push = |mut path: PathData, rule: FillRule, mut st: Style, name: Option<String>| {
if path.is_empty() {
return;
}
// Trim, Merge and Crop remove any strokes (and Merge then merges by fill alone), as the
// public Pathfinder documentation describes.
if matches!(op, PathfinderOp::Trim | PathfinderOp::Merge | PathfinderOp::Crop) {
st.appearance.items.retain(|i| !matches!(i, AppearanceItem::Stroke(_)));
}
if op == PathfinderOp::Divide && st.appearance.items.iter().any(|i| matches!(i, AppearanceItem::Fill(f) if !f.paint.is_none())) {
// Filled open contours keep their implicit closing edge. A zero-area line
// stays a cutter; normalised area also catches zero-signed-area self crossings.

View File

@ -893,3 +893,29 @@ fn divide_keeps_implicitly_closed_filled_paths_including_zero_signed_area() {
assert!(pieces.iter().all(|n| n.appearance == source.appearance));
}
}
/// #1570: Trim, Merge and Crop remove the objects' strokes; Merge then merges same-coloured
/// fills whatever their strokes were.
#[test]
fn trim_merge_and_crop_remove_strokes() {
for op in ["trim", "merge", "crop"] {
let mut s = session();
let (a, b) = two_rects(&mut s);
for (id, c) in [(a, Color::rgb(0.0, 0.0, 0.0)), (b, Color::rgb(1.0, 0.0, 0.0))] {
s.edit("t", |d, _| {
d.node_mut(id).unwrap().appearance = Appearance::basic(Paint::solid(Color::rgb(0.0, 0.0, 1.0)), Paint::solid(c), 3.0).into();
Ok(())
})
.unwrap();
}
s.execute("select.set", &json!({"ids": [a.0, b.0]})).unwrap();
let r = ids(&s.execute(&format!("object.pathfinder.{op}"), &json!({})).unwrap());
let g = node(&s, r[0]);
let pieces = g.children().unwrap();
assert!(!pieces.is_empty(), "{op}");
assert!(pieces.iter().all(|c| c.appearance.stroke_width() == 0.0 && c.appearance.fill().is_some()), "{op} keeps a stroke");
if op == "merge" {
assert_eq!(pieces.len(), 1, "same fill, different strokes: merged");
}
}
}