mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-08 00:05:00 +00:00
Extract gpath_bool
from mod gstd::ops
path_bool-related nodes (#2762)
* cargo shear * Extract `gpath_bool` from `mod gstd::ops` path_bool-related nodes
This commit is contained in:
parent
9cf8d2cd05
commit
ffc6c5532b
25 changed files with 128 additions and 107 deletions
30
Cargo.lock
generated
30
Cargo.lock
generated
|
@ -2132,6 +2132,7 @@ dependencies = [
|
||||||
"graph-craft",
|
"graph-craft",
|
||||||
"graphene-application-io",
|
"graphene-application-io",
|
||||||
"graphene-core",
|
"graphene-core",
|
||||||
|
"graphene-path-bool",
|
||||||
"iai-callgrind",
|
"iai-callgrind",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
|
@ -2214,12 +2215,26 @@ dependencies = [
|
||||||
"wgpu",
|
"wgpu",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "graphene-path-bool"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bezier-rs",
|
||||||
|
"dyn-any",
|
||||||
|
"glam",
|
||||||
|
"graphene-core",
|
||||||
|
"log",
|
||||||
|
"node-macro",
|
||||||
|
"path-bool",
|
||||||
|
"serde",
|
||||||
|
"specta",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "graphene-std"
|
name = "graphene-std"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bezier-rs",
|
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
"fastnoise-lite",
|
"fastnoise-lite",
|
||||||
|
@ -2228,16 +2243,15 @@ dependencies = [
|
||||||
"graph-craft",
|
"graph-craft",
|
||||||
"graphene-application-io",
|
"graphene-application-io",
|
||||||
"graphene-core",
|
"graphene-core",
|
||||||
|
"graphene-path-bool",
|
||||||
"image",
|
"image",
|
||||||
"log",
|
"log",
|
||||||
"ndarray",
|
"ndarray",
|
||||||
"node-macro",
|
"node-macro",
|
||||||
"path-bool",
|
|
||||||
"rand 0.9.0",
|
"rand 0.9.0",
|
||||||
"rand_chacha 0.9.0",
|
"rand_chacha 0.9.0",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"tokio",
|
"tokio",
|
||||||
"usvg",
|
|
||||||
"vello",
|
"vello",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
|
@ -2313,7 +2327,6 @@ dependencies = [
|
||||||
name = "graphite-wasm"
|
name = "graphite-wasm"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glam",
|
|
||||||
"graph-craft",
|
"graph-craft",
|
||||||
"graphene-std",
|
"graphene-std",
|
||||||
"graphite-editor",
|
"graphite-editor",
|
||||||
|
@ -2948,6 +2961,7 @@ dependencies = [
|
||||||
"glam",
|
"glam",
|
||||||
"graph-craft",
|
"graph-craft",
|
||||||
"graphene-core",
|
"graphene-core",
|
||||||
|
"graphene-path-bool",
|
||||||
"graphene-std",
|
"graphene-std",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
@ -4481,17 +4495,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||||
name = "preprocessor"
|
name = "preprocessor"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
|
||||||
"dyn-any",
|
|
||||||
"futures",
|
|
||||||
"glam",
|
|
||||||
"graph-craft",
|
"graph-craft",
|
||||||
"graphene-std",
|
"graphene-std",
|
||||||
"interpreted-executor",
|
"interpreted-executor",
|
||||||
"log",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tokio",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -7,6 +7,7 @@ members = [
|
||||||
"node-graph/gapplication-io",
|
"node-graph/gapplication-io",
|
||||||
"node-graph/gcore",
|
"node-graph/gcore",
|
||||||
"node-graph/gstd",
|
"node-graph/gstd",
|
||||||
|
"node-graph/gpath-bool",
|
||||||
"node-graph/graph-craft",
|
"node-graph/graph-craft",
|
||||||
"node-graph/graphene-cli",
|
"node-graph/graphene-cli",
|
||||||
"node-graph/interpreted-executor",
|
"node-graph/interpreted-executor",
|
||||||
|
@ -23,6 +24,7 @@ default-members = [
|
||||||
"frontend/wasm",
|
"frontend/wasm",
|
||||||
"node-graph/gcore",
|
"node-graph/gcore",
|
||||||
"node-graph/gstd",
|
"node-graph/gstd",
|
||||||
|
"node-graph/gpath-bool",
|
||||||
"node-graph/graph-craft",
|
"node-graph/graph-craft",
|
||||||
"node-graph/graphene-cli",
|
"node-graph/graphene-cli",
|
||||||
"node-graph/interpreted-executor",
|
"node-graph/interpreted-executor",
|
||||||
|
@ -39,6 +41,7 @@ math-parser = { path = "libraries/math-parser" }
|
||||||
path-bool = { path = "libraries/path-bool" }
|
path-bool = { path = "libraries/path-bool" }
|
||||||
graphene-application-io = { path = "node-graph/gapplication-io" }
|
graphene-application-io = { path = "node-graph/gapplication-io" }
|
||||||
graphene-core = { path = "node-graph/gcore" }
|
graphene-core = { path = "node-graph/gcore" }
|
||||||
|
graphene-path-bool = { path = "node-graph/gpath-bool" }
|
||||||
graph-craft = { path = "node-graph/graph-craft" }
|
graph-craft = { path = "node-graph/graph-craft" }
|
||||||
graphene-std = { path = "node-graph/gstd" }
|
graphene-std = { path = "node-graph/gstd" }
|
||||||
interpreted-executor = { path = "node-graph/interpreted-executor" }
|
interpreted-executor = { path = "node-graph/interpreted-executor" }
|
||||||
|
|
|
@ -30,11 +30,12 @@ use glam::{DAffine2, DVec2, IVec2};
|
||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
|
use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
|
||||||
use graphene_std::math::quad::Quad;
|
use graphene_std::math::quad::Quad;
|
||||||
|
use graphene_std::path_bool::{boolean_intersect, path_bool_lib};
|
||||||
use graphene_std::raster::BlendMode;
|
use graphene_std::raster::BlendMode;
|
||||||
use graphene_std::raster_types::{Raster, RasterDataTable};
|
use graphene_std::raster_types::{Raster, RasterDataTable};
|
||||||
|
use graphene_std::vector::PointId;
|
||||||
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
|
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
|
||||||
use graphene_std::vector::style::ViewMode;
|
use graphene_std::vector::style::ViewMode;
|
||||||
use graphene_std::vector::{PointId, path_bool_lib};
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub struct DocumentMessageData<'a> {
|
pub struct DocumentMessageData<'a> {
|
||||||
|
@ -2962,7 +2963,7 @@ impl<'a> ClickXRayIter<'a> {
|
||||||
// We do this on this using the target area to reduce computation (as the target area is usually very simple).
|
// We do this on this using the target area to reduce computation (as the target area is usually very simple).
|
||||||
if clip && intersects {
|
if clip && intersects {
|
||||||
let clip_path = click_targets_to_path_lib_segments(click_targets.iter().flat_map(|x| x.iter()), transform);
|
let clip_path = click_targets_to_path_lib_segments(click_targets.iter().flat_map(|x| x.iter()), transform);
|
||||||
let subtracted = graphene_std::vector::boolean_intersect(path, clip_path).into_iter().flatten().collect::<Vec<_>>();
|
let subtracted = boolean_intersect(path, clip_path).into_iter().flatten().collect::<Vec<_>>();
|
||||||
if subtracted.is_empty() {
|
if subtracted.is_empty() {
|
||||||
use_children = false;
|
use_children = false;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -79,7 +79,7 @@ pub enum GraphOperationMessage {
|
||||||
},
|
},
|
||||||
NewBooleanOperationLayer {
|
NewBooleanOperationLayer {
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
operation: graphene_std::vector::misc::BooleanOperation,
|
operation: graphene_std::path_bool::BooleanOperation,
|
||||||
parent: LayerNodeIdentifier,
|
parent: LayerNodeIdentifier,
|
||||||
insert_index: usize,
|
insert_index: usize,
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,8 +10,8 @@ use glam::{DAffine2, DVec2, IVec2};
|
||||||
use graph_craft::document::{NodeId, NodeInput};
|
use graph_craft::document::{NodeId, NodeInput};
|
||||||
use graphene_std::Color;
|
use graphene_std::Color;
|
||||||
use graphene_std::renderer::Quad;
|
use graphene_std::renderer::Quad;
|
||||||
|
use graphene_std::renderer::convert_usvg_path::convert_usvg_path;
|
||||||
use graphene_std::text::{Font, TypesettingConfig};
|
use graphene_std::text::{Font, TypesettingConfig};
|
||||||
use graphene_std::vector::convert_usvg_path;
|
|
||||||
use graphene_std::vector::style::{Fill, Gradient, GradientStops, GradientType, PaintOrder, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
|
use graphene_std::vector::style::{Fill, Gradient, GradientStops, GradientType, PaintOrder, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
@ -134,7 +134,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||||
LayerNodeIdentifier::new(new_id, self.network_interface, &[])
|
LayerNodeIdentifier::new(new_id, self.network_interface, &[])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_boolean_data(&mut self, operation: graphene_std::vector::misc::BooleanOperation, layer: LayerNodeIdentifier) {
|
pub fn insert_boolean_data(&mut self, operation: graphene_std::path_bool::BooleanOperation, layer: LayerNodeIdentifier) {
|
||||||
let boolean = resolve_document_node_type("Boolean Operation").expect("Boolean node does not exist").node_template_input_override([
|
let boolean = resolve_document_node_type("Boolean Operation").expect("Boolean node does not exist").node_template_input_override([
|
||||||
Some(NodeInput::value(TaggedValue::GraphicGroup(graphene_std::GraphicGroupTable::default()), true)),
|
Some(NodeInput::value(TaggedValue::GraphicGroup(graphene_std::GraphicGroupTable::default()), true)),
|
||||||
Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)),
|
Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)),
|
||||||
|
|
|
@ -1734,7 +1734,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
nodes: vec![
|
nodes: vec![
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0), NodeInput::network(concrete!(vector::style::Fill), 1)],
|
inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0), NodeInput::network(concrete!(vector::style::Fill), 1)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::vector::BooleanOperationNode")),
|
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_path_bool::BooleanOperationNode")),
|
||||||
manual_composition: Some(generic!(T)),
|
manual_composition: Some(generic!(T)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -1765,7 +1765,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
}),
|
}),
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroupTable::default()), true),
|
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroupTable::default()), true),
|
||||||
NodeInput::value(TaggedValue::BooleanOperation(vector::misc::BooleanOperation::Union), false),
|
NodeInput::value(TaggedValue::BooleanOperation(path_bool::BooleanOperation::Union), false),
|
||||||
],
|
],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
|
@ -13,6 +13,7 @@ use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput};
|
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput};
|
||||||
use graphene_std::animation::RealTimeMode;
|
use graphene_std::animation::RealTimeMode;
|
||||||
use graphene_std::ops::XY;
|
use graphene_std::ops::XY;
|
||||||
|
use graphene_std::path_bool::BooleanOperation;
|
||||||
use graphene_std::raster::curve::Curve;
|
use graphene_std::raster::curve::Curve;
|
||||||
use graphene_std::raster::{
|
use graphene_std::raster::{
|
||||||
BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute,
|
BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute,
|
||||||
|
@ -22,8 +23,8 @@ use graphene_std::raster_types::{CPU, GPU, RasterDataTable};
|
||||||
use graphene_std::text::Font;
|
use graphene_std::text::Font;
|
||||||
use graphene_std::transform::{Footprint, ReferencePoint};
|
use graphene_std::transform::{Footprint, ReferencePoint};
|
||||||
use graphene_std::vector::VectorDataTable;
|
use graphene_std::vector::VectorDataTable;
|
||||||
|
use graphene_std::vector::misc::GridType;
|
||||||
use graphene_std::vector::misc::{ArcType, MergeByDistanceAlgorithm};
|
use graphene_std::vector::misc::{ArcType, MergeByDistanceAlgorithm};
|
||||||
use graphene_std::vector::misc::{BooleanOperation, GridType};
|
|
||||||
use graphene_std::vector::misc::{CentroidType, PointSpacingType};
|
use graphene_std::vector::misc::{CentroidType, PointSpacingType};
|
||||||
use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientStops};
|
use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientStops};
|
||||||
use graphene_std::vector::style::{GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin};
|
use graphene_std::vector::style::{GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin};
|
||||||
|
|
|
@ -693,5 +693,5 @@ impl PTZ {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum GroupFolderType {
|
pub enum GroupFolderType {
|
||||||
Layer,
|
Layer,
|
||||||
BooleanOperation(graphene_std::vector::misc::BooleanOperation),
|
BooleanOperation(graphene_std::path_bool::BooleanOperation),
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ const REPLACEMENTS: &[(&str, &str)] = &[
|
||||||
("graphene_core::transform::CullNode", "graphene_core::ops::IdentityNode"),
|
("graphene_core::transform::CullNode", "graphene_core::ops::IdentityNode"),
|
||||||
("graphene_std::raster::MaskImageNode", "graphene_std::raster::MaskNode"),
|
("graphene_std::raster::MaskImageNode", "graphene_std::raster::MaskNode"),
|
||||||
("graphene_core::vector::FlattenVectorElementsNode", "graphene_core::vector::FlattenPathNode"),
|
("graphene_core::vector::FlattenVectorElementsNode", "graphene_core::vector::FlattenPathNode"),
|
||||||
|
("graphene_std::vector::BooleanOperationNode", "graphene_path_bool::BooleanOperationNode"),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn document_migration_string_preprocessing(document_serialized_content: String) -> String {
|
pub fn document_migration_string_preprocessing(document_serialized_content: String) -> String {
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
||||||
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis, GroupFolderType};
|
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis, GroupFolderType};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use graphene_std::vector::misc::BooleanOperation;
|
use graphene_std::path_bool::BooleanOperation;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct MenuBarMessageHandler {
|
pub struct MenuBarMessageHandler {
|
||||||
|
|
|
@ -22,10 +22,10 @@ use crate::messages::tool::common_functionality::utility_functions::{resize_boun
|
||||||
use bezier_rs::Subpath;
|
use bezier_rs::Subpath;
|
||||||
use glam::DMat2;
|
use glam::DMat2;
|
||||||
use graph_craft::document::NodeId;
|
use graph_craft::document::NodeId;
|
||||||
|
use graphene_std::path_bool::BooleanOperation;
|
||||||
use graphene_std::renderer::Quad;
|
use graphene_std::renderer::Quad;
|
||||||
use graphene_std::renderer::Rect;
|
use graphene_std::renderer::Rect;
|
||||||
use graphene_std::transform::ReferencePoint;
|
use graphene_std::transform::ReferencePoint;
|
||||||
use graphene_std::vector::misc::BooleanOperation;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
|
@ -35,7 +35,6 @@ wasm-bindgen = { workspace = true }
|
||||||
serde-wasm-bindgen = { workspace = true }
|
serde-wasm-bindgen = { workspace = true }
|
||||||
js-sys = { workspace = true }
|
js-sys = { workspace = true }
|
||||||
wasm-bindgen-futures = { workspace = true }
|
wasm-bindgen-futures = { workspace = true }
|
||||||
glam = { workspace = true }
|
|
||||||
math-parser = { workspace = true }
|
math-parser = { workspace = true }
|
||||||
wgpu = { workspace = true }
|
wgpu = { workspace = true }
|
||||||
web-sys = { workspace = true }
|
web-sys = { workspace = true }
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
pub mod convert_usvg_path;
|
||||||
|
|
||||||
use crate::instances::Instance;
|
use crate::instances::Instance;
|
||||||
pub use crate::math::quad::Quad;
|
pub use crate::math::quad::Quad;
|
||||||
pub use crate::math::rect::Rect;
|
pub use crate::math::rect::Rect;
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
use crate::vector::PointId;
|
||||||
|
use bezier_rs::{ManipulatorGroup, Subpath};
|
||||||
|
use glam::DVec2;
|
||||||
|
|
||||||
|
pub fn convert_usvg_path(path: &usvg::Path) -> Vec<Subpath<PointId>> {
|
||||||
|
let mut subpaths = Vec::new();
|
||||||
|
let mut groups = Vec::new();
|
||||||
|
|
||||||
|
let mut points = path.data().points().iter();
|
||||||
|
let to_vec = |p: &usvg::tiny_skia_path::Point| DVec2::new(p.x as f64, p.y as f64);
|
||||||
|
|
||||||
|
for verb in path.data().verbs() {
|
||||||
|
match verb {
|
||||||
|
usvg::tiny_skia_path::PathVerb::Move => {
|
||||||
|
subpaths.push(Subpath::new(std::mem::take(&mut groups), false));
|
||||||
|
let Some(start) = points.next().map(to_vec) else { continue };
|
||||||
|
groups.push(ManipulatorGroup::new(start, Some(start), Some(start)));
|
||||||
|
}
|
||||||
|
usvg::tiny_skia_path::PathVerb::Line => {
|
||||||
|
let Some(end) = points.next().map(to_vec) else { continue };
|
||||||
|
groups.push(ManipulatorGroup::new(end, Some(end), Some(end)));
|
||||||
|
}
|
||||||
|
usvg::tiny_skia_path::PathVerb::Quad => {
|
||||||
|
let Some(handle) = points.next().map(to_vec) else { continue };
|
||||||
|
let Some(end) = points.next().map(to_vec) else { continue };
|
||||||
|
if let Some(last) = groups.last_mut() {
|
||||||
|
last.out_handle = Some(last.anchor + (2. / 3.) * (handle - last.anchor));
|
||||||
|
}
|
||||||
|
groups.push(ManipulatorGroup::new(end, Some(end + (2. / 3.) * (handle - end)), Some(end)));
|
||||||
|
}
|
||||||
|
usvg::tiny_skia_path::PathVerb::Cubic => {
|
||||||
|
let Some(first_handle) = points.next().map(to_vec) else { continue };
|
||||||
|
let Some(second_handle) = points.next().map(to_vec) else { continue };
|
||||||
|
let Some(end) = points.next().map(to_vec) else { continue };
|
||||||
|
if let Some(last) = groups.last_mut() {
|
||||||
|
last.out_handle = Some(first_handle);
|
||||||
|
}
|
||||||
|
groups.push(ManipulatorGroup::new(end, Some(second_handle), Some(end)));
|
||||||
|
}
|
||||||
|
usvg::tiny_skia_path::PathVerb::Close => {
|
||||||
|
subpaths.push(Subpath::new(std::mem::take(&mut groups), true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subpaths.push(Subpath::new(groups, false));
|
||||||
|
subpaths
|
||||||
|
}
|
|
@ -13,22 +13,6 @@ pub enum CentroidType {
|
||||||
Length,
|
Length,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash, DynAny, specta::Type, node_macro::ChoiceType)]
|
|
||||||
#[widget(Radio)]
|
|
||||||
pub enum BooleanOperation {
|
|
||||||
#[default]
|
|
||||||
#[icon("BooleanUnion")]
|
|
||||||
Union,
|
|
||||||
#[icon("BooleanSubtractFront")]
|
|
||||||
SubtractFront,
|
|
||||||
#[icon("BooleanSubtractBack")]
|
|
||||||
SubtractBack,
|
|
||||||
#[icon("BooleanIntersect")]
|
|
||||||
Intersect,
|
|
||||||
#[icon("BooleanDifference")]
|
|
||||||
Difference,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait AsU64 {
|
pub trait AsU64 {
|
||||||
fn as_u64(&self) -> u64;
|
fn as_u64(&self) -> u64;
|
||||||
}
|
}
|
||||||
|
|
19
node-graph/gpath-bool/Cargo.toml
Normal file
19
node-graph/gpath-bool/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "graphene-path-bool"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
description = "graphene path bool nodes"
|
||||||
|
authors = ["Graphite Authors <contact@graphite.rs>"]
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# Local dependencies
|
||||||
|
dyn-any = { workspace = true }
|
||||||
|
bezier-rs = { workspace = true }
|
||||||
|
graphene-core = { workspace = true }
|
||||||
|
node-macro = { workspace = true }
|
||||||
|
glam = { workspace = true }
|
||||||
|
specta = { workspace = true }
|
||||||
|
log = { workspace = true }
|
||||||
|
path-bool = { workspace = true }
|
||||||
|
serde = { workspace = true }
|
|
@ -1,10 +1,10 @@
|
||||||
use bezier_rs::{ManipulatorGroup, Subpath};
|
use bezier_rs::{ManipulatorGroup, Subpath};
|
||||||
|
use dyn_any::DynAny;
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use graphene_core::instances::{Instance, InstanceRef};
|
use graphene_core::instances::{Instance, InstanceRef};
|
||||||
use graphene_core::vector::algorithms::merge_by_distance::MergeByDistanceExt;
|
use graphene_core::vector::algorithms::merge_by_distance::MergeByDistanceExt;
|
||||||
use graphene_core::vector::misc::BooleanOperation;
|
|
||||||
use graphene_core::vector::style::Fill;
|
use graphene_core::vector::style::Fill;
|
||||||
pub use graphene_core::vector::*;
|
use graphene_core::vector::{PointId, VectorData, VectorDataTable};
|
||||||
use graphene_core::{Color, Ctx, GraphicElement, GraphicGroupTable};
|
use graphene_core::{Color, Ctx, GraphicElement, GraphicGroupTable};
|
||||||
pub use path_bool as path_bool_lib;
|
pub use path_bool as path_bool_lib;
|
||||||
use path_bool::{FillRule, PathBooleanOperation};
|
use path_bool::{FillRule, PathBooleanOperation};
|
||||||
|
@ -14,6 +14,22 @@ use std::ops::Mul;
|
||||||
// TODO: since before we used a Vec of single-row tables and now we use a single table
|
// TODO: since before we used a Vec of single-row tables and now we use a single table
|
||||||
// TODO: with multiple rows while still assuming a single row for the boolean operations.
|
// TODO: with multiple rows while still assuming a single row for the boolean operations.
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash, DynAny, specta::Type, node_macro::ChoiceType)]
|
||||||
|
#[widget(Radio)]
|
||||||
|
pub enum BooleanOperation {
|
||||||
|
#[default]
|
||||||
|
#[icon("BooleanUnion")]
|
||||||
|
Union,
|
||||||
|
#[icon("BooleanSubtractFront")]
|
||||||
|
SubtractFront,
|
||||||
|
#[icon("BooleanSubtractBack")]
|
||||||
|
SubtractBack,
|
||||||
|
#[icon("BooleanIntersect")]
|
||||||
|
Intersect,
|
||||||
|
#[icon("BooleanDifference")]
|
||||||
|
Difference,
|
||||||
|
}
|
||||||
|
|
||||||
/// Combines the geometric forms of one or more closed paths into a new vector path that results from cutting or joining the paths by the chosen method.
|
/// Combines the geometric forms of one or more closed paths into a new vector path that results from cutting or joining the paths by the chosen method.
|
||||||
#[node_macro::node(category(""))]
|
#[node_macro::node(category(""))]
|
||||||
async fn boolean_operation<I: Into<GraphicGroupTable> + 'n + Send + Clone>(
|
async fn boolean_operation<I: Into<GraphicGroupTable> + 'n + Send + Clone>(
|
||||||
|
@ -356,50 +372,6 @@ fn from_path(path_data: &[Path]) -> VectorData {
|
||||||
VectorData::from_subpaths(all_subpaths, false)
|
VectorData::from_subpaths(all_subpaths, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_usvg_path(path: &usvg::Path) -> Vec<Subpath<PointId>> {
|
|
||||||
let mut subpaths = Vec::new();
|
|
||||||
let mut groups = Vec::new();
|
|
||||||
|
|
||||||
let mut points = path.data().points().iter();
|
|
||||||
let to_vec = |p: &usvg::tiny_skia_path::Point| DVec2::new(p.x as f64, p.y as f64);
|
|
||||||
|
|
||||||
for verb in path.data().verbs() {
|
|
||||||
match verb {
|
|
||||||
usvg::tiny_skia_path::PathVerb::Move => {
|
|
||||||
subpaths.push(Subpath::new(std::mem::take(&mut groups), false));
|
|
||||||
let Some(start) = points.next().map(to_vec) else { continue };
|
|
||||||
groups.push(ManipulatorGroup::new(start, Some(start), Some(start)));
|
|
||||||
}
|
|
||||||
usvg::tiny_skia_path::PathVerb::Line => {
|
|
||||||
let Some(end) = points.next().map(to_vec) else { continue };
|
|
||||||
groups.push(ManipulatorGroup::new(end, Some(end), Some(end)));
|
|
||||||
}
|
|
||||||
usvg::tiny_skia_path::PathVerb::Quad => {
|
|
||||||
let Some(handle) = points.next().map(to_vec) else { continue };
|
|
||||||
let Some(end) = points.next().map(to_vec) else { continue };
|
|
||||||
if let Some(last) = groups.last_mut() {
|
|
||||||
last.out_handle = Some(last.anchor + (2. / 3.) * (handle - last.anchor));
|
|
||||||
}
|
|
||||||
groups.push(ManipulatorGroup::new(end, Some(end + (2. / 3.) * (handle - end)), Some(end)));
|
|
||||||
}
|
|
||||||
usvg::tiny_skia_path::PathVerb::Cubic => {
|
|
||||||
let Some(first_handle) = points.next().map(to_vec) else { continue };
|
|
||||||
let Some(second_handle) = points.next().map(to_vec) else { continue };
|
|
||||||
let Some(end) = points.next().map(to_vec) else { continue };
|
|
||||||
if let Some(last) = groups.last_mut() {
|
|
||||||
last.out_handle = Some(first_handle);
|
|
||||||
}
|
|
||||||
groups.push(ManipulatorGroup::new(end, Some(second_handle), Some(end)));
|
|
||||||
}
|
|
||||||
usvg::tiny_skia_path::PathVerb::Close => {
|
|
||||||
subpaths.push(Subpath::new(std::mem::take(&mut groups), true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
subpaths.push(Subpath::new(groups, false));
|
|
||||||
subpaths
|
|
||||||
}
|
|
||||||
|
|
||||||
type Path = Vec<path_bool::PathSegment>;
|
type Path = Vec<path_bool::PathSegment>;
|
||||||
|
|
||||||
fn boolean_union(a: Path, b: Path) -> Vec<Path> {
|
fn boolean_union(a: Path, b: Path) -> Vec<Path> {
|
|
@ -16,6 +16,7 @@ loading = ["serde_json"]
|
||||||
# Local dependencies
|
# Local dependencies
|
||||||
dyn-any = { workspace = true }
|
dyn-any = { workspace = true }
|
||||||
graphene-core = { workspace = true }
|
graphene-core = { workspace = true }
|
||||||
|
graphene-path-bool = { workspace = true }
|
||||||
graphene-application-io = { workspace = true }
|
graphene-application-io = { workspace = true }
|
||||||
|
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
|
|
|
@ -247,7 +247,7 @@ tagged_value! {
|
||||||
GradientType(graphene_core::vector::style::GradientType),
|
GradientType(graphene_core::vector::style::GradientType),
|
||||||
ReferencePoint(graphene_core::transform::ReferencePoint),
|
ReferencePoint(graphene_core::transform::ReferencePoint),
|
||||||
CentroidType(graphene_core::vector::misc::CentroidType),
|
CentroidType(graphene_core::vector::misc::CentroidType),
|
||||||
BooleanOperation(graphene_core::vector::misc::BooleanOperation),
|
BooleanOperation(graphene_path_bool::BooleanOperation),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaggedValue {
|
impl TaggedValue {
|
||||||
|
|
|
@ -28,18 +28,16 @@ dyn-any = { workspace = true }
|
||||||
graph-craft = { workspace = true }
|
graph-craft = { workspace = true }
|
||||||
wgpu-executor = { workspace = true }
|
wgpu-executor = { workspace = true }
|
||||||
graphene-core = { workspace = true }
|
graphene-core = { workspace = true }
|
||||||
|
graphene-path-bool = { workspace = true }
|
||||||
graphene-application-io = { workspace = true }
|
graphene-application-io = { workspace = true }
|
||||||
|
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
fastnoise-lite = { workspace = true }
|
fastnoise-lite = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
bezier-rs = { workspace = true }
|
|
||||||
path-bool = { workspace = true }
|
|
||||||
glam = { workspace = true }
|
glam = { workspace = true }
|
||||||
node-macro = { workspace = true }
|
node-macro = { workspace = true }
|
||||||
reqwest = { workspace = true }
|
reqwest = { workspace = true }
|
||||||
futures = { workspace = true }
|
futures = { workspace = true }
|
||||||
usvg = { workspace = true }
|
|
||||||
rand_chacha = { workspace = true }
|
rand_chacha = { workspace = true }
|
||||||
rand = { workspace = true }
|
rand = { workspace = true }
|
||||||
bytemuck = { workspace = true }
|
bytemuck = { workspace = true }
|
||||||
|
|
|
@ -6,9 +6,10 @@ pub mod http;
|
||||||
pub mod image_color_palette;
|
pub mod image_color_palette;
|
||||||
pub mod raster;
|
pub mod raster;
|
||||||
pub mod text;
|
pub mod text;
|
||||||
pub mod vector;
|
|
||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
pub mod wasm_application_io;
|
pub mod wasm_application_io;
|
||||||
|
|
||||||
pub use graphene_application_io as application_io;
|
pub use graphene_application_io as application_io;
|
||||||
|
pub use graphene_core::vector;
|
||||||
pub use graphene_core::*;
|
pub use graphene_core::*;
|
||||||
|
pub use graphene_path_bool as path_bool;
|
||||||
|
|
|
@ -14,6 +14,7 @@ graphene-std = { workspace = true }
|
||||||
graph-craft = { workspace = true }
|
graph-craft = { workspace = true }
|
||||||
wgpu-executor = { workspace = true }
|
wgpu-executor = { workspace = true }
|
||||||
graphene-core = { workspace = true }
|
graphene-core = { workspace = true }
|
||||||
|
graphene-path-bool = { workspace = true }
|
||||||
dyn-any = { workspace = true }
|
dyn-any = { workspace = true }
|
||||||
|
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
|
|
|
@ -60,7 +60,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Vec<f64>]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Vec<f64>]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => BlendMode]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => BlendMode]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::transform::ReferencePoint]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::transform::ReferencePoint]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::misc::BooleanOperation]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_path_bool::BooleanOperation]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Option<Color>]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Option<Color>]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::Fill]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::Fill]),
|
||||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::StrokeCap]),
|
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::StrokeCap]),
|
||||||
|
|
|
@ -7,23 +7,8 @@ license = "MIT OR Apache-2.0"
|
||||||
[features]
|
[features]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Local dependencies
|
|
||||||
dyn-any = { path = "../../libraries/dyn-any", features = [
|
|
||||||
"log-bad-types",
|
|
||||||
"rc",
|
|
||||||
"glam",
|
|
||||||
] }
|
|
||||||
|
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
graphene-std = { workspace = true, features = ["gpu"] }
|
graphene-std = { workspace = true, features = ["gpu"] }
|
||||||
graph-craft = { workspace = true }
|
graph-craft = { workspace = true }
|
||||||
interpreted-executor = { workspace = true }
|
interpreted-executor = { workspace = true }
|
||||||
log = { workspace = true }
|
|
||||||
futures = { workspace = true }
|
|
||||||
glam = { workspace = true }
|
|
||||||
base64 = { workspace = true }
|
|
||||||
|
|
||||||
# Optional workspace dependencies
|
|
||||||
serde = { workspace = true, optional = true }
|
|
||||||
tokio = { workspace = true, optional = true }
|
|
||||||
serde_json = { workspace = true, optional = true }
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue