diff --git a/Cargo.lock b/Cargo.lock index 94fdbf12a9..b1ac0ce1de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -208,6 +208,9 @@ name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "serde", +] [[package]] name = "as-raw-xcb-connection" @@ -2204,6 +2207,8 @@ dependencies = [ "dyn-any", "glam", "graphene-core", + "kurbo 0.12.0", + "linesweeper", "log", "node-macro", "path-bool", @@ -3251,12 +3256,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets 0.53.3", + "windows-link 0.2.1", ] [[package]] @@ -3282,6 +3287,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" +[[package]] +name = "linesweeper" +version = "0.1.0" +source = "git+https://github.com/jneem/linesweeper#3025966b31c05a61ad57c5da008f538202c70af4" +dependencies = [ + "arrayvec", + "kurbo 0.12.0", + "polycool", +] + [[package]] name = "linux-raw-sys" version = "0.9.4" diff --git a/node-graph/gpath-bool/Cargo.toml b/node-graph/gpath-bool/Cargo.toml index 9882a75c6e..b1a20b9be2 100644 --- a/node-graph/gpath-bool/Cargo.toml +++ b/node-graph/gpath-bool/Cargo.toml @@ -16,3 +16,6 @@ specta = { workspace = true } log = { workspace = true } path-bool = { workspace = true } serde = { workspace = true } + +linesweeper = { git = "https://github.com/jneem/linesweeper", features = ["slow-asserts"] } +kurbo.workspace = true diff --git a/node-graph/gpath-bool/src/lib.rs b/node-graph/gpath-bool/src/lib.rs index df3a089414..5d5a9b8f54 100644 --- a/node-graph/gpath-bool/src/lib.rs +++ b/node-graph/gpath-bool/src/lib.rs @@ -7,7 +7,7 @@ use graphene_core::vector::style::Fill; use graphene_core::vector::{PointId, Vector}; use graphene_core::{Color, Ctx, Graphic}; pub use path_bool as path_bool_lib; -use path_bool::{FillRule, PathBooleanOperation}; +use path_bool::PathBooleanOperation; use std::ops::Mul; // TODO: Fix boolean ops to work by removing .transform() and .one_instnace_*() calls, @@ -331,6 +331,26 @@ fn to_path(vector: &Vector, transform: DAffine2) -> Vec path } +fn path_to_bezpath(path: Path) -> kurbo::BezPath { + let p = |p: DVec2| -> kurbo::Point { kurbo::Point::new(p.x, p.y) }; + let mut ret = kurbo::BezPath::new(); + let mut last_point = None; + for s in path { + let p0 = p(s.start()); + if last_point != Some(p0) { + ret.move_to(p0); + } + match s { + path_bool::PathSegment::Line(_, p1) => ret.line_to(p(p1)), + path_bool::PathSegment::Cubic(_, p1, p2, p3) => ret.curve_to(p(p1), p(p2), p(p3)), + path_bool::PathSegment::Quadratic(_, p1, p2) => ret.quad_to(p(p1), p(p2)), + path_bool::PathSegment::Arc(..) => unimplemented!(), + } + last_point = Some(p(s.end())); + } + ret +} + fn to_path_segments(path: &mut Vec, subpath: &Subpath, transform: DAffine2) { use path_bool::PathSegment; let mut global_start = None; @@ -419,15 +439,33 @@ fn boolean_union(a: Path, b: Path) -> Vec { } fn path_bool(a: Path, b: Path, op: PathBooleanOperation) -> Vec { - match path_bool::path_boolean(&a, FillRule::NonZero, &b, FillRule::NonZero, op) { - Ok(results) => results, - Err(e) => { - let a_path = path_bool::path_to_path_data(&a, 0.001); - let b_path = path_bool::path_to_path_data(&b, 0.001); - log::error!("Boolean error {e:?} encountered while processing {a_path}\n {op:?}\n {b_path}"); - Vec::new() - } - } + let op = match op { + PathBooleanOperation::Union => linesweeper::BinaryOp::Union, + PathBooleanOperation::Difference => linesweeper::BinaryOp::Difference, + PathBooleanOperation::Intersection => linesweeper::BinaryOp::Intersection, + PathBooleanOperation::Exclusion => linesweeper::BinaryOp::Xor, + PathBooleanOperation::Division => unimplemented!(), + PathBooleanOperation::Fracture => unimplemented!(), + }; + let a = path_to_bezpath(a); + let b = path_to_bezpath(b); + log::warn!("first path: {:?}", a.to_svg()); + log::warn!("second path: {:?}", b.to_svg()); + let p = |q: kurbo::Point| -> DVec2 { DVec2::new(q.x, q.y) }; + linesweeper::binary_op(&a, &b, linesweeper::FillRule::NonZero, op) + .unwrap() + .contours() + .map(|c| { + c.path + .segments() + .map(|s| match s { + kurbo::PathSeg::Line(ln) => path_bool::PathSegment::Line(p(ln.p0), p(ln.p1)), + kurbo::PathSeg::Quad(q) => path_bool::PathSegment::Quadratic(p(q.p0), p(q.p1), p(q.p2)), + kurbo::PathSeg::Cubic(c) => path_bool::PathSegment::Cubic(p(c.p0), p(c.p1), p(c.p2), p(c.p3)), + }) + .collect() + }) + .collect() } fn boolean_subtract(a: Path, b: Path) -> Vec { diff --git a/node-graph/interpreted-executor/benches/benchmark_util.rs b/node-graph/interpreted-executor/benches/benchmark_util.rs index 71ab004f09..0b078e87c9 100644 --- a/node-graph/interpreted-executor/benches/benchmark_util.rs +++ b/node-graph/interpreted-executor/benches/benchmark_util.rs @@ -10,9 +10,7 @@ use interpreted_executor::util::wrap_network_in_scope; pub fn setup_network(name: &str) -> (DynamicExecutor, ProtoNetwork) { let mut network = load_from_name(name); let editor_api = std::sync::Arc::new(EditorApi::default()); - println!("generating substitutions"); let substitutions = preprocessor::generate_node_substitutions(); - println!("expanding network"); preprocessor::expand_network(&mut network, &substitutions); let network = wrap_network_in_scope(network, editor_api); let proto_network = compile(network);