Skip to content

Commit 97587f1

Browse files
Keavonoluseyi
authored andcommitted
Migrate 'Scatter Points' and 'Boolean Operation' from subgraphs to memoized proto nodes (GraphiteEditor#4066)
1 parent 249c54e commit 97587f1

6 files changed

Lines changed: 52 additions & 181 deletions

File tree

editor/src/messages/portfolio/document/document_message_handler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2144,7 +2144,7 @@ impl DocumentMessageHandler {
21442144
network_interface.upstream_flow_back_from_nodes(vec![selected_id.to_node()], &[], FlowType::HorizontalFlow).find(|id| {
21452145
network_interface
21462146
.reference(id, &[])
2147-
.is_some_and(|reference| reference == DefinitionIdentifier::Network("Boolean Operation".into()))
2147+
.is_some_and(|reference| reference == DefinitionIdentifier::ProtoNode(graphene_std::path_bool_nodes::boolean_operation::IDENTIFIER))
21482148
})
21492149
});
21502150

editor/src/messages/portfolio/document/graph_operation/utility_types.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,12 @@ impl<'a> ModifyInputsContext<'a> {
145145
}
146146

147147
pub fn insert_boolean_data(&mut self, operation: graphene_std::vector::misc::BooleanOperation, layer: LayerNodeIdentifier) {
148-
let boolean = resolve_network_node_type("Boolean Operation").expect("Boolean node does not exist").node_template_input_override([
149-
Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)),
150-
Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)),
151-
]);
148+
let boolean = resolve_proto_node_type(graphene_std::path_bool_nodes::boolean_operation::IDENTIFIER)
149+
.expect("Boolean node does not exist")
150+
.node_template_input_override([
151+
Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)),
152+
Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)),
153+
]);
152154

153155
let boolean_id = NodeId::new();
154156
self.network_interface.insert_node(boolean_id, boolean, &[]);

editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs

Lines changed: 1 addition & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use super::utility_types::FrontendNodeType;
66
use crate::messages::layout::utility_types::widget_prelude::*;
77
use crate::messages::portfolio::document::utility_types::network_interface::{
88
DocumentNodeMetadata, DocumentNodePersistentMetadata, InputMetadata, NodeNetworkInterface, NodeNetworkMetadata, NodeNetworkPersistentMetadata, NodeTemplate, NodeTypePersistentMetadata,
9-
NumberInputSettings, Vec2InputSettings, WidgetOverride,
9+
Vec2InputSettings, WidgetOverride,
1010
};
1111
use crate::messages::portfolio::utility_types::CachedData;
1212
use crate::messages::prelude::Message;
@@ -1870,169 +1870,6 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
18701870
description: Cow::Borrowed("TODO"),
18711871
properties: None,
18721872
},
1873-
DocumentNodeDefinition {
1874-
identifier: "Boolean Operation",
1875-
category: "Vector: Modifier",
1876-
node_template: NodeTemplate {
1877-
document_node: DocumentNode {
1878-
implementation: DocumentNodeImplementation::Network(NodeNetwork {
1879-
exports: vec![NodeInput::node(NodeId(1), 0)],
1880-
nodes: vec![
1881-
DocumentNode {
1882-
inputs: vec![NodeInput::import(concrete!(Table<Vector>), 0), NodeInput::import(concrete!(vector::style::Fill), 1)],
1883-
implementation: DocumentNodeImplementation::ProtoNode(path_bool_nodes::boolean_operation::IDENTIFIER),
1884-
call_argument: generic!(T),
1885-
..Default::default()
1886-
},
1887-
DocumentNode {
1888-
inputs: vec![NodeInput::node(NodeId(0), 0)],
1889-
implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
1890-
call_argument: generic!(T),
1891-
..Default::default()
1892-
},
1893-
]
1894-
.into_iter()
1895-
.enumerate()
1896-
.map(|(id, node)| (NodeId(id as u64), node))
1897-
.collect(),
1898-
..Default::default()
1899-
}),
1900-
inputs: vec![
1901-
NodeInput::value(TaggedValue::Graphic(Default::default()), true),
1902-
NodeInput::value(TaggedValue::BooleanOperation(vector::misc::BooleanOperation::Union), false),
1903-
],
1904-
..Default::default()
1905-
},
1906-
persistent_node_metadata: DocumentNodePersistentMetadata {
1907-
network_metadata: Some(NodeNetworkMetadata {
1908-
persistent_metadata: NodeNetworkPersistentMetadata {
1909-
node_metadata: [
1910-
DocumentNodeMetadata {
1911-
persistent_metadata: DocumentNodePersistentMetadata {
1912-
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
1913-
..Default::default()
1914-
},
1915-
..Default::default()
1916-
},
1917-
DocumentNodeMetadata {
1918-
persistent_metadata: DocumentNodePersistentMetadata {
1919-
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
1920-
..Default::default()
1921-
},
1922-
..Default::default()
1923-
},
1924-
]
1925-
.into_iter()
1926-
.enumerate()
1927-
.map(|(id, node)| (NodeId(id as u64), node))
1928-
.collect(),
1929-
..Default::default()
1930-
},
1931-
..Default::default()
1932-
}),
1933-
input_metadata: vec![("Content", "TODO").into(), ("Operation", "TODO").into()],
1934-
output_names: vec!["Vector".to_string()],
1935-
..Default::default()
1936-
},
1937-
},
1938-
description: Cow::Borrowed("TODO"),
1939-
properties: None,
1940-
},
1941-
DocumentNodeDefinition {
1942-
identifier: "Scatter Points",
1943-
category: "Vector: Modifier",
1944-
node_template: NodeTemplate {
1945-
document_node: DocumentNode {
1946-
implementation: DocumentNodeImplementation::Network(NodeNetwork {
1947-
exports: vec![NodeInput::node(NodeId(1), 0)],
1948-
nodes: [
1949-
DocumentNode {
1950-
inputs: vec![
1951-
NodeInput::import(concrete!(Table<Vector>), 0),
1952-
NodeInput::import(concrete!(f64), 1),
1953-
NodeInput::import(concrete!(u32), 2),
1954-
],
1955-
call_argument: generic!(T),
1956-
implementation: DocumentNodeImplementation::ProtoNode(vector::poisson_disk_points::IDENTIFIER),
1957-
..Default::default()
1958-
},
1959-
DocumentNode {
1960-
inputs: vec![NodeInput::node(NodeId(0), 0)],
1961-
implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
1962-
call_argument: generic!(T),
1963-
..Default::default()
1964-
},
1965-
]
1966-
.into_iter()
1967-
.enumerate()
1968-
.map(|(id, node)| (NodeId(id as u64), node))
1969-
.collect(),
1970-
..Default::default()
1971-
}),
1972-
inputs: vec![
1973-
NodeInput::value(TaggedValue::Vector(Default::default()), true),
1974-
NodeInput::value(TaggedValue::F64(10.), false),
1975-
NodeInput::value(TaggedValue::U32(0), false),
1976-
],
1977-
..Default::default()
1978-
},
1979-
persistent_node_metadata: DocumentNodePersistentMetadata {
1980-
network_metadata: Some(NodeNetworkMetadata {
1981-
persistent_metadata: NodeNetworkPersistentMetadata {
1982-
node_metadata: [
1983-
DocumentNodeMetadata {
1984-
persistent_metadata: DocumentNodePersistentMetadata {
1985-
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
1986-
..Default::default()
1987-
},
1988-
..Default::default()
1989-
},
1990-
DocumentNodeMetadata {
1991-
persistent_metadata: DocumentNodePersistentMetadata {
1992-
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
1993-
..Default::default()
1994-
},
1995-
..Default::default()
1996-
},
1997-
]
1998-
.into_iter()
1999-
.enumerate()
2000-
.map(|(id, node)| (NodeId(id as u64), node))
2001-
.collect(),
2002-
..Default::default()
2003-
},
2004-
..Default::default()
2005-
}),
2006-
input_metadata: vec![
2007-
("Content", "TODO").into(),
2008-
InputMetadata::with_name_description_override(
2009-
"Separation",
2010-
"TODO",
2011-
WidgetOverride::Number(NumberInputSettings {
2012-
min: Some(0.01),
2013-
mode: NumberInputMode::Range,
2014-
range_min: Some(1.),
2015-
range_max: Some(100.),
2016-
..Default::default()
2017-
}),
2018-
),
2019-
InputMetadata::with_name_description_override(
2020-
"Seed",
2021-
"TODO",
2022-
WidgetOverride::Number(NumberInputSettings {
2023-
min: Some(0.),
2024-
is_integer: true,
2025-
..Default::default()
2026-
}),
2027-
),
2028-
],
2029-
output_names: vec!["Vector".to_string()],
2030-
..Default::default()
2031-
},
2032-
},
2033-
description: Cow::Borrowed("TODO"),
2034-
properties: None,
2035-
},
20361873
];
20371874

20381875
document_node_derive::post_process_nodes(custom)

editor/src/messages/portfolio/document_migration.rs

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
9494
"graphene_core::transform::FreezeRealTimeNode",
9595
"graphene_core::transform_nodes::BoundlessFootprintNode",
9696
"graphene_core::transform_nodes::FreezeRealTimeNode",
97-
// `subpath_segment_lengths` was inlined into the `sample_polyline` proto; old "Sample Polyline" subnetworks pass through unchanged.
9897
"graphene_core::vector::SubpathSegmentLengthsNode",
9998
"core_types::vector::SubpathSegmentLengthsNode",
10099
],
@@ -910,8 +909,8 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
910909
aliases: &["graphene_core::vector::PointsToPolylineNode"],
911910
},
912911
NodeReplacement {
913-
node: graphene_std::vector::poisson_disk_points::IDENTIFIER,
914-
aliases: &["graphene_core::vector::PoissonDiskPointsNode"],
912+
node: graphene_std::vector::scatter_points::IDENTIFIER,
913+
aliases: &["graphene_core::vector::PoissonDiskPointsNode", "core_types::vector::PoissonDiskPointsNode"],
915914
},
916915
NodeReplacement {
917916
node: graphene_std::vector::position_on_path::IDENTIFIER,
@@ -2036,10 +2035,10 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
20362035
/// definition by its old reference name, swaps it to a still-supported implementation, and preserves the user's inputs.
20372036
/// After this runs, the node's reference resolves cleanly so the rest of `migrate_node` proceeds normally.
20382037
fn migrate_removed_catalog_definitions(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], document: &mut DocumentMessageHandler) -> Option<()> {
2039-
// Collapse the legacy "Sample Polyline" wrapper network into the standalone `sample_polyline` proto.
2040-
// The proto now computes per-bezpath segment lengths inline, so the wrapper's separate `subpath_segment_lengths`
2038+
// Collapse the legacy "Sample Polyline" wrapper network into the standalone `sample_polyline` proto node.
2039+
// The proto node now computes per-bezpath segment lengths inline, so the wrapper's separate `subpath_segment_lengths`
20412040
// and `Memo` nodes are no longer needed. The 7 user-facing inputs are positionally identical between the
2042-
// old wrapper and the new proto.
2041+
// old wrapper and the new proto node.
20432042
if let Some(DefinitionIdentifier::Network(name)) = document.network_interface.reference(node_id, network_path)
20442043
&& name == "Sample Polyline"
20452044
&& node.inputs.len() == 7
@@ -2052,6 +2051,38 @@ fn migrate_removed_catalog_definitions(node_id: &NodeId, node: &DocumentNode, ne
20522051
}
20532052
}
20542053

2054+
// Collapse the legacy "Scatter Points" wrapper network into the standalone `scatter_points` proto node.
2055+
// The wrapper's trailing `Memo` node is now produced automatically by the `memoize` attribute on the
2056+
// proto node, so the wrapper itself is redundant. The 3 user-facing inputs are positionally identical
2057+
// between the old wrapper and the new proto node.
2058+
if let Some(DefinitionIdentifier::Network(name)) = document.network_interface.reference(node_id, network_path)
2059+
&& name == "Scatter Points"
2060+
&& node.inputs.len() == 3
2061+
{
2062+
let mut node_template = resolve_proto_node_type(graphene_std::vector::scatter_points::IDENTIFIER)?.default_node_template();
2063+
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
2064+
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
2065+
for (index, input) in old_inputs.iter().take(3).enumerate() {
2066+
document.network_interface.set_input(&InputConnector::node(*node_id, index), input.clone(), network_path);
2067+
}
2068+
}
2069+
2070+
// Collapse the legacy "Boolean Operation" wrapper network into the standalone `boolean_operation` proto node.
2071+
// The wrapper's trailing `Memo` node is now produced automatically by the `memoize` attribute on the
2072+
// proto node, so the wrapper itself is redundant. The 2 user-facing inputs are positionally identical
2073+
// between the old wrapper and the new proto node.
2074+
if let Some(DefinitionIdentifier::Network(name)) = document.network_interface.reference(node_id, network_path)
2075+
&& name == "Boolean Operation"
2076+
&& node.inputs.len() == 2
2077+
{
2078+
let mut node_template = resolve_proto_node_type(graphene_std::path_bool_nodes::boolean_operation::IDENTIFIER)?.default_node_template();
2079+
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
2080+
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
2081+
for (index, input) in old_inputs.iter().take(2).enumerate() {
2082+
document.network_interface.set_input(&InputConnector::node(*node_id, index), input.clone(), network_path);
2083+
}
2084+
}
2085+
20552086
Some(())
20562087
}
20572088

node-graph/nodes/path-bool/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub use vector_types::vector::misc::BooleanOperation;
1818
// TODO: with multiple rows while still assuming a single row for the boolean operations.
1919

2020
/// 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.
21-
#[node_macro::node(category(""))]
21+
#[node_macro::node(category("Vector: Modifier"), memoize)]
2222
async fn boolean_operation<I: graphic_types::IntoGraphicTable + 'n + Send + Clone>(
2323
_: impl Ctx,
2424
/// The table of vector paths to perform the boolean operation on. Nested tables are automatically flattened.

node-graph/nodes/vector/src/vector_nodes.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1780,14 +1780,15 @@ async fn tangent_on_path(
17801780
if radians { angle } else { angle.to_degrees() }
17811781
}
17821782

1783-
#[node_macro::node(category(""), path(core_types::vector))]
1784-
async fn poisson_disk_points(
1783+
#[node_macro::node(category("Vector: Modifier"), path(core_types::vector), memoize)]
1784+
async fn scatter_points(
17851785
_: impl Ctx,
17861786
content: Table<Vector>,
17871787
#[unit(" px")]
17881788
#[default(10.)]
17891789
#[hard_min(0.01)]
1790-
separation_disk_diameter: f64,
1790+
#[range((1., 100.))]
1791+
separation: f64,
17911792
seed: SeedValue,
17921793
) -> Table<Vector> {
17931794
let mut rng = rand::rngs::StdRng::seed_from_u64(seed.into());
@@ -1813,7 +1814,7 @@ async fn poisson_disk_points(
18131814
continue;
18141815
}
18151816

1816-
for point in bezpath_algorithms::poisson_disk_points(i, &path_with_bounding_boxes, separation_disk_diameter, || rng.random::<f64>()) {
1817+
for point in bezpath_algorithms::poisson_disk_points(i, &path_with_bounding_boxes, separation, || rng.random::<f64>()) {
18171818
result.point_domain.push(PointId::generate(), point);
18181819
}
18191820
}
@@ -3120,7 +3121,7 @@ mod test {
31203121
}
31213122
#[tokio::test]
31223123
async fn poisson() {
3123-
let poisson_points = super::poisson_disk_points(
3124+
let poisson_points = super::scatter_points(
31243125
Footprint::default(),
31253126
vector_node_from_bezpath(Ellipse::from_rect(Rect::new(-50., -50., 50., 50.)).to_path(DEFAULT_ACCURACY)),
31263127
10. * std::f64::consts::SQRT_2,

0 commit comments

Comments
 (0)