mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-04 13:30:48 +00:00
Separate the Merge node from the Boolean Operation node (#1933)
* Rework boolean operation node * Set Boolean Operation name for layer * Remove memoize * Update both demo artworks that use booleans * Delete dead code, rename input connectors * Remove more dead code --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
fa981a0897
commit
33739b9ad4
13 changed files with 60 additions and 273 deletions
2
demo-artwork/isometric-fountain.graphite
generated
2
demo-artwork/isometric-fountain.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/painted-dreams.graphite
generated
2
demo-artwork/painted-dreams.graphite
generated
File diff suppressed because one or more lines are too long
|
@ -24,7 +24,7 @@ use crate::messages::tool::utility_types::ToolType;
|
|||
use crate::node_graph_executor::NodeGraphExecutor;
|
||||
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
|
||||
use graph_craft::document::{NodeId, NodeNetwork, OldNodeNetwork};
|
||||
use graphene_core::raster::BlendMode;
|
||||
use graphene_core::raster::ImageFrame;
|
||||
use graphene_core::vector::style::ViewMode;
|
||||
|
@ -329,28 +329,19 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
|
|||
let insert_index = DocumentMessageHandler::get_calculated_insert_index(self.metadata(), self.network_interface.selected_nodes(&[]).unwrap(), parent);
|
||||
|
||||
let folder_id = NodeId(generate_uuid());
|
||||
let new_group_node = super::node_graph::document_node_types::resolve_document_node_type("Boolean Operation")
|
||||
.expect("Failed to create merge node")
|
||||
.node_template_input_override([
|
||||
Some(NodeInput::value(TaggedValue::VectorData(graphene_std::vector::VectorData::empty()), true)),
|
||||
Some(NodeInput::value(TaggedValue::VectorData(graphene_std::vector::VectorData::empty()), true)),
|
||||
Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)),
|
||||
]);
|
||||
responses.add(NodeGraphMessage::InsertNode {
|
||||
node_id: folder_id,
|
||||
node_template: new_group_node,
|
||||
});
|
||||
let new_group_folder = LayerNodeIdentifier::new_unchecked(folder_id);
|
||||
|
||||
// Move the boolean operation to the correct position
|
||||
responses.add(NodeGraphMessage::MoveLayerToStack {
|
||||
layer: new_group_folder,
|
||||
let boolean_operation_layer = LayerNodeIdentifier::new_unchecked(folder_id);
|
||||
responses.add(GraphOperationMessage::NewBooleanOperationLayer {
|
||||
id: folder_id,
|
||||
operation,
|
||||
parent,
|
||||
insert_index,
|
||||
});
|
||||
|
||||
responses.add(NodeGraphMessage::SetDisplayNameImpl {
|
||||
node_id: folder_id,
|
||||
alias: "Boolean Operation".to_string(),
|
||||
});
|
||||
// Move all shallowest selected layers as children
|
||||
responses.add(DocumentMessage::MoveSelectedLayersToGroup { parent: new_group_folder });
|
||||
responses.add(DocumentMessage::MoveSelectedLayersToGroup { parent: boolean_operation_layer });
|
||||
}
|
||||
DocumentMessage::CreateEmptyFolder => {
|
||||
let id = NodeId(generate_uuid());
|
||||
|
@ -651,10 +642,11 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
|
|||
if self.graph_view_overlay_open {
|
||||
responses.add(NodeGraphMessage::ShiftNodes {
|
||||
node_ids: self.network_interface.selected_nodes(&[]).unwrap().selected_nodes().cloned().collect(),
|
||||
displacement_x: delta_x.signum() as i32,
|
||||
displacement_y: delta_y.signum() as i32,
|
||||
displacement_x: if delta_x == 0.0 { 0 } else { delta_x.signum() as i32 },
|
||||
displacement_y: if delta_y == 0.0 { 0 } else { delta_y.signum() as i32 },
|
||||
move_upstream: ipp.keyboard.get(Key::Shift as usize),
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,12 @@ pub enum GraphOperationMessage {
|
|||
parent: LayerNodeIdentifier,
|
||||
insert_index: usize,
|
||||
},
|
||||
NewBooleanOperationLayer {
|
||||
id: NodeId,
|
||||
operation: graphene_std::vector::misc::BooleanOperation,
|
||||
parent: LayerNodeIdentifier,
|
||||
insert_index: usize,
|
||||
},
|
||||
NewCustomLayer {
|
||||
id: NodeId,
|
||||
nodes: Vec<(NodeId, NodeTemplate)>,
|
||||
|
|
|
@ -145,6 +145,13 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageData<'_>> for Gr
|
|||
network_interface.move_layer_to_stack(layer, parent, insert_index, &[]);
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
GraphOperationMessage::NewBooleanOperationLayer { id, operation, parent, insert_index } => {
|
||||
let mut modify_inputs = ModifyInputsContext::new(network_interface, responses);
|
||||
let layer = modify_inputs.create_layer(id);
|
||||
modify_inputs.insert_boolean_data(operation, layer);
|
||||
network_interface.move_layer_to_stack(layer, parent, insert_index, &[]);
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
GraphOperationMessage::NewCustomLayer { id, nodes, parent, insert_index } => {
|
||||
let mut modify_inputs = ModifyInputsContext::new(network_interface, responses);
|
||||
let layer = modify_inputs.create_layer(id);
|
||||
|
|
|
@ -132,6 +132,18 @@ impl<'a> ModifyInputsContext<'a> {
|
|||
self.network_interface.insert_node(new_id, artboard_node_template, &[]);
|
||||
LayerNodeIdentifier::new(new_id, self.network_interface)
|
||||
}
|
||||
|
||||
pub fn insert_boolean_data(&mut self, operation: graphene_std::vector::misc::BooleanOperation, layer: LayerNodeIdentifier) {
|
||||
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::GraphicGroup::EMPTY), true)),
|
||||
Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)),
|
||||
]);
|
||||
|
||||
let boolean_id = NodeId(generate_uuid());
|
||||
self.network_interface.insert_node(boolean_id, boolean, &[]);
|
||||
self.network_interface.move_node_to_chain_start(&boolean_id, layer, &[]);
|
||||
}
|
||||
|
||||
pub fn insert_vector_data(&mut self, subpaths: Vec<Subpath<PointId>>, layer: LayerNodeIdentifier) {
|
||||
let shape = resolve_document_node_type("Shape")
|
||||
.expect("Shape node does not exist")
|
||||
|
|
|
@ -3719,201 +3719,20 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
category: "Vector",
|
||||
properties: node_properties::circular_repeat_properties,
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Binary Boolean Operation",
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(1), 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
inputs: vec![
|
||||
NodeInput::network(concrete!(graphene_core::vector::VectorData), 0),
|
||||
NodeInput::network(concrete!(graphene_core::vector::VectorData), 1),
|
||||
NodeInput::network(concrete!(vector::misc::BooleanOperation), 2),
|
||||
],
|
||||
implementation: DocumentNodeImplementation::proto("graphene_std::vector::BinaryBooleanOperationNode<_, _>"),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode<_, _, _>")),
|
||||
manual_composition: Some(concrete!(Footprint)),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (NodeId(id as u64), node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
|
||||
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
|
||||
NodeInput::value(TaggedValue::BooleanOperation(vector::misc::BooleanOperation::Union), false),
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
network_metadata: Some(NodeNetworkMetadata {
|
||||
persistent_metadata: NodeNetworkPersistentMetadata {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "BinaryBooleanOperation".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-17, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "MemoizeImpure".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-10, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (NodeId(id as u64), node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
input_names: vec!["Upper Vector Data".to_string(), "Lower Vector Data".to_string(), "Operation".to_string()],
|
||||
output_names: vec!["Vector".to_string()],
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
category: "Vector",
|
||||
properties: node_properties::binary_boolean_operation_properties,
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Boolean Operation",
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroup::EMPTY), true),
|
||||
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroup::EMPTY), true),
|
||||
NodeInput::value(TaggedValue::BooleanOperation(vector::misc::BooleanOperation::Union), false),
|
||||
],
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(5), 0)],
|
||||
nodes: [
|
||||
// Primary (bottom) input type coercion
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(generic!(T), 0)],
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::ToGraphicGroupNode"),
|
||||
..Default::default()
|
||||
},
|
||||
// Secondary (left) input type coercion
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(generic!(T), 1), NodeInput::network(concrete!(vector::misc::BooleanOperation), 2)],
|
||||
implementation: DocumentNodeImplementation::proto("graphene_std::vector::BooleanOperationNode<_>"),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::ToGraphicElementNode"),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(2), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode<_, _, _>")),
|
||||
manual_composition: Some(concrete!(Footprint)),
|
||||
..Default::default()
|
||||
},
|
||||
// The monitor node is used to display a thumbnail in the UI
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(3), 0)],
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode<_, _, _>"),
|
||||
manual_composition: Some(generic!(T)),
|
||||
skip_deduplication: true,
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
manual_composition: Some(concrete!(Footprint)),
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(4), 0)],
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::ConstructLayerNode<_, _>"),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (NodeId(id as u64), node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::vector::BooleanOperationNode<_>")),
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
network_metadata: Some(NodeNetworkMetadata {
|
||||
persistent_metadata: NodeNetworkPersistentMetadata {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "ToGraphicGroup".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-9, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "BooleanOperation".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-16, -1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "ToGraphicElement".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-9, -1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "MemoizeImpure".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-2, -1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Monitor".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(5, -1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "ConstructLayer".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(12, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (NodeId(id as u64), node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
input_names: vec!["Graphical Data".to_string(), "Vector Data".to_string(), "Operation".to_string()],
|
||||
input_names: vec!["Group of Paths".to_string(), "Operation".to_string()],
|
||||
output_names: vec!["Vector".to_string()],
|
||||
node_type_metadata: NodeTypePersistentMetadata::layer(IVec2::new(0, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1043,7 +1043,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||
responses.add(NodeGraphMessage::SendGraph);
|
||||
}
|
||||
NodeGraphMessage::SetDisplayNameImpl { node_id, alias } => {
|
||||
network_interface.set_display_name(&node_id, selection_network_path, alias);
|
||||
network_interface.set_display_name(&node_id, alias, selection_network_path);
|
||||
}
|
||||
NodeGraphMessage::TogglePreview { node_id } => {
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
|
|
|
@ -2398,18 +2398,18 @@ pub fn circular_repeat_properties(document_node: &DocumentNode, node_id: NodeId,
|
|||
]
|
||||
}
|
||||
|
||||
pub fn binary_boolean_operation_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
let lower_vector_data = vector_widget(document_node, node_id, 1, "Lower Vector Data", true);
|
||||
let operation = boolean_operation_radio_buttons(document_node, node_id, 2, "Operation", true);
|
||||
|
||||
vec![LayoutGroup::Row { widgets: lower_vector_data }, operation]
|
||||
}
|
||||
|
||||
pub fn boolean_operation_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
let vector_data = vector_widget(document_node, node_id, 1, "Vector Data", true);
|
||||
let operation = boolean_operation_radio_buttons(document_node, node_id, 2, "Operation", true);
|
||||
let group_of_paths_index = 0;
|
||||
let operation_index = 1;
|
||||
|
||||
vec![LayoutGroup::Row { widgets: vector_data }, operation]
|
||||
let mut widgets = start_widgets(document_node, node_id, group_of_paths_index, "Group of Paths", FrontendGraphDataType::Graphic, true);
|
||||
|
||||
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||
widgets.push(TextLabel::new("The output of a layer stack, which contains all elements to operate on").widget_holder());
|
||||
|
||||
let operation = boolean_operation_radio_buttons(document_node, node_id, operation_index, "Operation", true);
|
||||
|
||||
vec![LayoutGroup::Row { widgets }, operation]
|
||||
}
|
||||
|
||||
pub fn copy_to_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
|
|
|
@ -3027,7 +3027,7 @@ impl NodeNetworkInterface {
|
|||
// }
|
||||
// }
|
||||
|
||||
pub fn set_display_name(&mut self, node_id: &NodeId, network_path: &[NodeId], display_name: String) {
|
||||
pub fn set_display_name(&mut self, node_id: &NodeId, display_name: String, network_path: &[NodeId]) {
|
||||
let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else {
|
||||
log::error!("Could not get node {node_id} in set_visibility");
|
||||
return;
|
||||
|
|
|
@ -16,11 +16,7 @@ export function booleanIntersect(path1: string, path2: string): string {
|
|||
return booleanOperation(path1, path2, "intersect");
|
||||
}
|
||||
|
||||
export function booleanDifference(path1: string, path2: string): string {
|
||||
return booleanOperation(path1, path2, "exclude");
|
||||
}
|
||||
|
||||
function booleanOperation(path1: string, path2: string, operation: "unite" | "subtract" | "intersect" | "exclude"): string {
|
||||
function booleanOperation(path1: string, path2: string, operation: "unite" | "subtract" | "intersect"): string {
|
||||
const paperPath1 = new paper.CompoundPath(path1);
|
||||
const paperPath2 = new paper.CompoundPath(path2);
|
||||
const result = paperPath1[operation](paperPath2);
|
||||
|
|
|
@ -2,58 +2,20 @@ use crate::Node;
|
|||
|
||||
use bezier_rs::{ManipulatorGroup, Subpath};
|
||||
use graphene_core::transform::Transform;
|
||||
use graphene_core::vector::misc::BooleanOperation;
|
||||
pub use graphene_core::vector::*;
|
||||
use graphene_core::Color;
|
||||
use graphene_core::{transform::Footprint, GraphicGroup};
|
||||
use graphene_core::{vector::misc::BooleanOperation, GraphicElement};
|
||||
use graphene_core::{Color, GraphicElement, GraphicGroup};
|
||||
|
||||
use glam::{DAffine2, DVec2};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub struct BinaryBooleanOperationNode<LowerVectorData, BooleanOp> {
|
||||
lower_vector_data: LowerVectorData,
|
||||
boolean_operation: BooleanOp,
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(BinaryBooleanOperationNode)]
|
||||
async fn binary_boolean_operation_node(upper_vector_data: VectorData, lower_vector_data: impl Node<Footprint, Output = VectorData>, boolean_operation: BooleanOperation) -> VectorData {
|
||||
let lower_vector_data = self.lower_vector_data.eval(Footprint::default()).await;
|
||||
let transform_of_lower_into_space_of_upper = upper_vector_data.transform.inverse() * lower_vector_data.transform;
|
||||
|
||||
let upper_path_string = to_svg_string(&upper_vector_data, DAffine2::IDENTITY);
|
||||
let lower_path_string = to_svg_string(&lower_vector_data, transform_of_lower_into_space_of_upper);
|
||||
|
||||
let mut use_lower_style = false;
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
let result = unsafe {
|
||||
match boolean_operation {
|
||||
BooleanOperation::Union => boolean_union(upper_path_string, lower_path_string),
|
||||
BooleanOperation::SubtractFront => {
|
||||
use_lower_style = true;
|
||||
boolean_subtract(lower_path_string, upper_path_string)
|
||||
}
|
||||
BooleanOperation::SubtractBack => boolean_subtract(upper_path_string, lower_path_string),
|
||||
BooleanOperation::Intersect => boolean_intersect(upper_path_string, lower_path_string),
|
||||
BooleanOperation::Difference => boolean_difference(upper_path_string, lower_path_string),
|
||||
}
|
||||
};
|
||||
|
||||
let mut result = from_svg_string(&result);
|
||||
result.transform = upper_vector_data.transform;
|
||||
result.style = if use_lower_style { lower_vector_data.style } else { upper_vector_data.style };
|
||||
result.alpha_blending = if use_lower_style { lower_vector_data.alpha_blending } else { upper_vector_data.alpha_blending };
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub struct BooleanOperationNode<BooleanOp> {
|
||||
boolean_operation: BooleanOp,
|
||||
operation: BooleanOp,
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(BooleanOperationNode)]
|
||||
fn boolean_operation_node(graphic_group: GraphicGroup, boolean_operation: BooleanOperation) -> VectorData {
|
||||
fn boolean_operation_node(group_of_paths: GraphicGroup, operation: BooleanOperation) -> VectorData {
|
||||
fn vector_from_image<T: Transform>(image_frame: T) -> VectorData {
|
||||
let corner1 = DVec2::ZERO;
|
||||
let corner2 = DVec2::new(1., 1.);
|
||||
|
@ -212,7 +174,7 @@ fn boolean_operation_node(graphic_group: GraphicGroup, boolean_operation: Boolea
|
|||
}
|
||||
|
||||
// The first index is the bottom of the stack
|
||||
boolean_operation_on_vector_data(&collect_vector_data(&graphic_group), boolean_operation)
|
||||
boolean_operation_on_vector_data(&collect_vector_data(&group_of_paths), operation)
|
||||
}
|
||||
|
||||
fn to_svg_string(vector: &VectorData, transform: DAffine2) -> String {
|
||||
|
@ -288,8 +250,6 @@ extern "C" {
|
|||
fn boolean_subtract(path1: String, path2: String) -> String;
|
||||
#[wasm_bindgen(js_name = booleanIntersect)]
|
||||
fn boolean_intersect(path1: String, path2: String) -> String;
|
||||
#[wasm_bindgen(js_name = booleanDifference)]
|
||||
fn boolean_difference(path1: String, path2: String) -> String;
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn boolean_union(_path1: String, _path2: String) -> String {
|
||||
|
@ -303,7 +263,3 @@ fn boolean_subtract(_path1: String, _path2: String) -> String {
|
|||
fn boolean_intersect(_path1: String, _path2: String) -> String {
|
||||
String::from("M0,0 L1,0 L1,1 L0,1 Z")
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn boolean_difference(_path1: String, _path2: String) -> String {
|
||||
String::from("M0,0 L1,0 L1,1 L0,1 Z")
|
||||
}
|
||||
|
|
|
@ -686,7 +686,6 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||
register_node!(graphene_core::vector::BoundingBoxNode, input: VectorData, params: []),
|
||||
register_node!(graphene_core::vector::SolidifyStrokeNode, input: VectorData, params: []),
|
||||
register_node!(graphene_core::vector::CircularRepeatNode<_, _, _>, input: VectorData, params: [f64, f64, u32]),
|
||||
async_node!(graphene_std::vector::BinaryBooleanOperationNode<_, _>, input: VectorData, output: VectorData, fn_params: [Footprint => VectorData, () => graphene_core::vector::misc::BooleanOperation]),
|
||||
register_node!(graphene_std::vector::BooleanOperationNode<_>, input: GraphicGroup, fn_params: [() => graphene_core::vector::misc::BooleanOperation]),
|
||||
vec![(
|
||||
ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>"),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue