mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-26 10:47:11 -06:00
#1197: Make Compound Path cuts holes where paths overlap
Make Compound Path kept each path's direction under the non-zero fill rule, so a shape drawn inside or across another, running the same way, left the overlap filled instead of making a hole. The paths in front of the backmost one now run against it, so where they overlap it they cut holes, as users expect from a compound path.
This commit is contained in:
+1
-1
File diff suppressed because one or more lines are too long
@@ -652,11 +652,19 @@ fn compound_make(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
d.remove(*id)?;
|
||||
}
|
||||
let ch = d.node_mut(cid).and_then(|n| n.children_mut()).ok_or(EngineError::NoNode(cid))?;
|
||||
for mut p in paths {
|
||||
// The paths in front run against the backmost one, so where they overlap it they cut holes
|
||||
// under the non-zero fill rule (#1197).
|
||||
let direction = |n: &Node| n.path_data().and_then(|pd| pd.subpaths.first()).map_or(0.0, |sp| sp.signed_area().signum());
|
||||
let back = paths.first().map_or(0.0, |p| direction(p));
|
||||
for (i, mut p) in paths.into_iter().enumerate() {
|
||||
let pn = Arc::make_mut(&mut p);
|
||||
pn.appearance = Appearance::default();
|
||||
if let NodeKind::Path { live, .. } = &mut pn.kind {
|
||||
let flip = i > 0 && back != 0.0 && direction(pn) == back;
|
||||
if let NodeKind::Path { path, live, .. } = &mut pn.kind {
|
||||
*live = None;
|
||||
if flip {
|
||||
path.reverse();
|
||||
}
|
||||
}
|
||||
ch.push(p);
|
||||
}
|
||||
|
||||
@@ -1699,3 +1699,19 @@ fn file_list_lists_a_folder_within_the_read_root() {
|
||||
assert!(s.execute("file.list", &json!({})).is_err());
|
||||
let _ = std::fs::remove_dir_all(base);
|
||||
}
|
||||
|
||||
/// #1197: Make Compound Path cuts holes where the paths in front overlap the backmost one, also
|
||||
/// when they were drawn running the same way.
|
||||
#[test]
|
||||
fn a_compound_path_has_holes_where_its_paths_overlap() {
|
||||
let mut s = session();
|
||||
let square = rect(&mut s, 0.0, 0.0, 100.0, 100.0);
|
||||
let diamond = NodeId(s.execute("path.create", &json!({"d": "M50 -20 L120 50 L50 120 L-20 50 Z"})).unwrap()["id"].as_u64().unwrap());
|
||||
s.execute("select.set", &json!({"ids": [square.0, diamond.0]})).unwrap();
|
||||
let c = NodeId(s.execute("object.compoundPath.make", &json!({})).unwrap()["id"].as_u64().unwrap());
|
||||
let hit =
|
||||
|x: f64, y: f64| vectorcraft_doc::hit::hit_test(&s.doc().unwrap().doc, Point::new(x, y), Default::default()).map(|h| h.top_object(None));
|
||||
assert_eq!(hit(50.0, 50.0), None, "the overlap is a hole");
|
||||
assert_eq!(hit(3.0, 3.0), Some(c), "the square's corner is filled");
|
||||
assert_eq!(hit(110.0, 50.0), Some(c), "the diamond's point outside the square is filled");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user