From 40b5661162c263fcc9be971bb2842ec110d7fd3a Mon Sep 17 00:00:00 2001 From: Chase Date: Sat, 20 May 2023 09:27:08 +0800 Subject: [PATCH 01/28] Create node (no implementation) --- .../document_node_types.rs | 11 +++++++++++ .../node_graph_message_handler/node_properties.rs | 6 ++++++ node-graph/gcore/src/vector/vector_nodes.rs | 12 ++++++++++++ node-graph/interpreted-executor/src/node_registry.rs | 1 + 4 files changed, 30 insertions(+) diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index 280c9d03bdf..f4daa1f40e9 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -2046,6 +2046,17 @@ fn static_nodes() -> Vec { properties: node_properties::circular_repeat_properties, ..Default::default() }, + DocumentNodeType { + name: "Resample Curve", + category: "Vector", + identifier: NodeImplementation::proto("graphene_core::vector::SetResampleCurveNode<_>"), + inputs: vec![ + DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), + DocumentInputType::value("Density", TaggedValue::U32(2), false), + ], + outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], + properties: node_properties::resample_curve_properties, + }, DocumentNodeType { name: "Image Segmentation", category: "Image Adjustments", diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs index 0c94a7470a6..3bcc9d6775e 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs @@ -1796,6 +1796,12 @@ pub fn circular_repeat_properties(document_node: &DocumentNode, node_id: NodeId, vec![LayoutGroup::Row { widgets: angle_offset }, LayoutGroup::Row { widgets: radius }, LayoutGroup::Row { widgets: count }] } +pub fn resample_curve_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { + let density = number_widget(document_node, node_id, 1, "Density", NumberInput::default().unit(" points").min(2.), true); + + vec![LayoutGroup::Row { widgets: density }] +} + /// Fill Node Widgets LayoutGroup pub fn fill_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { let fill_type_index = 1; diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 87f653e2c8f..c57c9bc791c 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -147,3 +147,15 @@ fn generate_bounding_box(vector_data: VectorData) -> VectorData { vector_data.transform.transform_point2(bounding_box[1]), )]) } + +#[derive(Debug, Clone, Copy)] +pub struct SetResampleCurveNode { + density: Density, +} + +#[node_macro::node_fn(SetResampleCurveNode)] +fn set_vector_data_resample_curve(vector_data: VectorData, density: u32) -> VectorData { + warn!("Density: {:?}", density); + // TODO: Implement sampling. + vector_data +} diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index cb0e0f958a4..1a04f2cef7a 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -630,6 +630,7 @@ fn node_registry() -> HashMap, input: VectorData, params: [DVec2, u32]), register_node!(graphene_core::vector::BoundingBoxNode, input: VectorData, params: []), register_node!(graphene_core::vector::CircularRepeatNode<_, _, _>, input: VectorData, params: [f32, f32, u32]), + register_node!(graphene_core::vector::SetResampleCurveNode<_>, input: VectorData, params: [u32]), register_node!(graphene_core::vector::generator_nodes::UnitCircleGenerator, input: (), params: []), register_node!( graphene_core::vector::generator_nodes::PathGenerator<_>, From cc4fce2616a4ab3123543d4a939e4a4a0219d2dc Mon Sep 17 00:00:00 2001 From: Chase Date: Sun, 21 May 2023 09:12:32 +0800 Subject: [PATCH 02/28] Resampling - WIP --- .../document_node_types.rs | 2 +- .../node_properties.rs | 2 +- node-graph/gcore/src/vector/vector_nodes.rs | 38 ++++++++++++++++--- .../interpreted-executor/src/node_registry.rs | 1 + 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index f4daa1f40e9..701b0c44281 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -2052,7 +2052,7 @@ fn static_nodes() -> Vec { identifier: NodeImplementation::proto("graphene_core::vector::SetResampleCurveNode<_>"), inputs: vec![ DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), - DocumentInputType::value("Density", TaggedValue::U32(2), false), + DocumentInputType::value("Density", TaggedValue::F64(100.), false), ], outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], properties: node_properties::resample_curve_properties, diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs index 3bcc9d6775e..34403e33437 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs @@ -1797,7 +1797,7 @@ pub fn circular_repeat_properties(document_node: &DocumentNode, node_id: NodeId, } pub fn resample_curve_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { - let density = number_widget(document_node, node_id, 1, "Density", NumberInput::default().unit(" points").min(2.), true); + let density = number_widget(document_node, node_id, density_index, "Density", NumberInput::default().min(0.01), true); vec![LayoutGroup::Row { widgets: density }] } diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index c57c9bc791c..f07949b4bce 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -1,9 +1,9 @@ use super::style::{Fill, FillType, Gradient, GradientType, Stroke}; -use super::VectorData; +use super::{ManipulatorPointId, VectorData}; +use crate::uuid::ManipulatorGroupId; use crate::{Color, Node}; -use bezier_rs::Subpath; - +use bezier_rs::{Subpath, SubpathTValue}; use glam::{DAffine2, DVec2}; #[derive(Debug, Clone, Copy)] @@ -154,8 +154,34 @@ pub struct SetResampleCurveNode { } #[node_macro::node_fn(SetResampleCurveNode)] -fn set_vector_data_resample_curve(vector_data: VectorData, density: u32) -> VectorData { - warn!("Density: {:?}", density); - // TODO: Implement sampling. +fn set_vector_data_resample_curve(mut vector_data: VectorData, density: f64) -> VectorData { + vector_data.subpaths = vector_data + .subpaths + .iter() + //.map(|subpath| Subpath::new_cubic_spline(subpath.compute_lookup_table(Some((subpath.length(None) / density).round() as usize), Some(TValueType::Euclidean)))) + .map(|subpath| { + let mut travel = 0.; + let length = subpath.length(None); + let mut path: Vec = Vec::new(); + + while travel < length { + path.push(subpath.evaluate(SubpathTValue::GlobalEuclidean(travel / length))); + travel += density; + } + + //Subpath::new_cubic_spline(path) + + let mut curve: Subpath = Subpath::new_line(path[0], path[1]); + let mut last = path[1]; + + for anchor in path.iter().skip(2) { + curve.append_bezier(&Subpath::::new_line(last, *anchor).get_segment(0).unwrap(), bezier_rs::AppendType::SmoothJoin(0.001)); + last = *anchor; + } + + //lines + curve + }) + .collect(); vector_data } diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index 1a04f2cef7a..c214f3938f0 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -631,6 +631,7 @@ fn node_registry() -> HashMap, input: VectorData, params: [f32, f32, u32]), register_node!(graphene_core::vector::SetResampleCurveNode<_>, input: VectorData, params: [u32]), + register_node!(graphene_core::vector::SetResampleCurveNode<_>, input: VectorData, params: [f64]), register_node!(graphene_core::vector::generator_nodes::UnitCircleGenerator, input: (), params: []), register_node!( graphene_core::vector::generator_nodes::PathGenerator<_>, From 2086b2835b992c2aa67e5a95ea5fa070c75c5d59 Mon Sep 17 00:00:00 2001 From: Chase Date: Sun, 21 May 2023 09:26:22 +0800 Subject: [PATCH 03/28] use bezier::from_linear_dvec2 --- node-graph/gcore/src/vector/vector_nodes.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index f07949b4bce..ad8fbe830f1 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -3,7 +3,7 @@ use super::{ManipulatorPointId, VectorData}; use crate::uuid::ManipulatorGroupId; use crate::{Color, Node}; -use bezier_rs::{Subpath, SubpathTValue}; +use bezier_rs::{AppendType, Bezier, Subpath, SubpathTValue}; use glam::{DAffine2, DVec2}; #[derive(Debug, Clone, Copy)] @@ -158,6 +158,7 @@ fn set_vector_data_resample_curve(mut vector_data: VectorData, density: f64) -> vector_data.subpaths = vector_data .subpaths .iter() + // Rounded less accurate approach //.map(|subpath| Subpath::new_cubic_spline(subpath.compute_lookup_table(Some((subpath.length(None) / density).round() as usize), Some(TValueType::Euclidean)))) .map(|subpath| { let mut travel = 0.; @@ -169,17 +170,14 @@ fn set_vector_data_resample_curve(mut vector_data: VectorData, density: f64) -> travel += density; } - //Subpath::new_cubic_spline(path) - let mut curve: Subpath = Subpath::new_line(path[0], path[1]); let mut last = path[1]; for anchor in path.iter().skip(2) { - curve.append_bezier(&Subpath::::new_line(last, *anchor).get_segment(0).unwrap(), bezier_rs::AppendType::SmoothJoin(0.001)); + curve.append_bezier(&Bezier::from_linear_dvec2(last, *anchor), AppendType::SmoothJoin(0.001)); last = *anchor; } - //lines curve }) .collect(); From 13a97cd3a69838122699648deec8b77df88ad52c Mon Sep 17 00:00:00 2001 From: Chase Date: Sun, 21 May 2023 09:47:14 +0800 Subject: [PATCH 04/28] Use from anchors instead of Bezier --- node-graph/gcore/src/vector/vector_nodes.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index ad8fbe830f1..5d8ca2ccb57 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -1,9 +1,8 @@ use super::style::{Fill, FillType, Gradient, GradientType, Stroke}; use super::{ManipulatorPointId, VectorData}; -use crate::uuid::ManipulatorGroupId; use crate::{Color, Node}; -use bezier_rs::{AppendType, Bezier, Subpath, SubpathTValue}; +use bezier_rs::{Subpath, SubpathTValue}; use glam::{DAffine2, DVec2}; #[derive(Debug, Clone, Copy)] @@ -170,15 +169,7 @@ fn set_vector_data_resample_curve(mut vector_data: VectorData, density: f64) -> travel += density; } - let mut curve: Subpath = Subpath::new_line(path[0], path[1]); - let mut last = path[1]; - - for anchor in path.iter().skip(2) { - curve.append_bezier(&Bezier::from_linear_dvec2(last, *anchor), AppendType::SmoothJoin(0.001)); - last = *anchor; - } - - curve + Subpath::from_anchors(path, false) }) .collect(); vector_data From 85579a37b9befc0472763689b4166855f47b2714 Mon Sep 17 00:00:00 2001 From: Chase Date: Sun, 21 May 2023 10:26:30 +0800 Subject: [PATCH 05/28] Tidy up anchor collection & subpath creation --- node-graph/gcore/src/vector/vector_nodes.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 5d8ca2ccb57..a9557a37bae 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -1,5 +1,5 @@ use super::style::{Fill, FillType, Gradient, GradientType, Stroke}; -use super::{ManipulatorPointId, VectorData}; +use super::VectorData; use crate::{Color, Node}; use bezier_rs::{Subpath, SubpathTValue}; @@ -157,19 +157,10 @@ fn set_vector_data_resample_curve(mut vector_data: VectorData, density: f64) -> vector_data.subpaths = vector_data .subpaths .iter() - // Rounded less accurate approach //.map(|subpath| Subpath::new_cubic_spline(subpath.compute_lookup_table(Some((subpath.length(None) / density).round() as usize), Some(TValueType::Euclidean)))) .map(|subpath| { - let mut travel = 0.; - let length = subpath.length(None); - let mut path: Vec = Vec::new(); - - while travel < length { - path.push(subpath.evaluate(SubpathTValue::GlobalEuclidean(travel / length))); - travel += density; - } - - Subpath::from_anchors(path, false) + let step = subpath.length(None) / density; + Subpath::from_anchors((0..=step as usize).map(|t| subpath.evaluate(SubpathTValue::GlobalEuclidean(t as f64 / step))).collect::>(), false) }) .collect(); vector_data From d40f084b23ab0071b34baaa92e5139019e27b92b Mon Sep 17 00:00:00 2001 From: Chase Date: Mon, 22 May 2023 15:47:17 +0800 Subject: [PATCH 06/28] Add Spline from Points node (not implemented) --- .../node_graph_message_handler/document_node_types.rs | 8 ++++++++ node-graph/gcore/src/vector/vector_nodes.rs | 8 ++++++++ node-graph/interpreted-executor/src/node_registry.rs | 1 + 3 files changed, 17 insertions(+) diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index 701b0c44281..84b405ba9cc 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -2057,6 +2057,14 @@ fn static_nodes() -> Vec { outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], properties: node_properties::resample_curve_properties, }, + DocumentNodeType { + name: "Spline from Points", + category: "Vector", + identifier: NodeImplementation::proto("graphene_core::vector::SetSplineFromPointsNode"), + inputs: vec![DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true)], + outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], + properties: node_properties::no_properties, + }, DocumentNodeType { name: "Image Segmentation", category: "Image Adjustments", diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index a9557a37bae..daa9de7b128 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -165,3 +165,11 @@ fn set_vector_data_resample_curve(mut vector_data: VectorData, density: f64) -> .collect(); vector_data } + +#[derive(Debug, Clone, Copy)] +pub struct SetSplineFromPointsNode {} + +#[node_macro::node_fn(SetSplineFromPointsNode)] +fn set_vector_data_spline_from_points(mut vector_data: VectorData) -> VectorData { + vector_data +} diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index c214f3938f0..b5c85dd6be2 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -632,6 +632,7 @@ fn node_registry() -> HashMap, input: VectorData, params: [f32, f32, u32]), register_node!(graphene_core::vector::SetResampleCurveNode<_>, input: VectorData, params: [u32]), register_node!(graphene_core::vector::SetResampleCurveNode<_>, input: VectorData, params: [f64]), + register_node!(graphene_core::vector::SetSplineFromPointsNode, input: VectorData, params: []), register_node!(graphene_core::vector::generator_nodes::UnitCircleGenerator, input: (), params: []), register_node!( graphene_core::vector::generator_nodes::PathGenerator<_>, From a551552d96bf1122c865d6d16163960ebf7806a7 Mon Sep 17 00:00:00 2001 From: Chase Date: Mon, 22 May 2023 16:22:22 +0800 Subject: [PATCH 07/28] Add spline from points node implementation --- node-graph/gcore/src/vector/vector_nodes.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index daa9de7b128..6f01eefe7d5 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -171,5 +171,8 @@ pub struct SetSplineFromPointsNode {} #[node_macro::node_fn(SetSplineFromPointsNode)] fn set_vector_data_spline_from_points(mut vector_data: VectorData) -> VectorData { + let points = vector_data.subpaths.iter().flat_map(|subpath| subpath.manipulator_groups().iter().map(|group| group.anchor)).collect(); + + vector_data.subpaths = vec![Subpath::new_cubic_spline(points)]; vector_data } From 6a3ab8725c9db564b91cf2c596d34eeccc6b518b Mon Sep 17 00:00:00 2001 From: Chase Date: Thu, 25 May 2023 19:16:05 +0800 Subject: [PATCH 08/28] Update resampling --- node-graph/gcore/src/vector/vector_nodes.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 6f01eefe7d5..212a7cc9641 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -157,10 +157,16 @@ fn set_vector_data_resample_curve(mut vector_data: VectorData, density: f64) -> vector_data.subpaths = vector_data .subpaths .iter() - //.map(|subpath| Subpath::new_cubic_spline(subpath.compute_lookup_table(Some((subpath.length(None) / density).round() as usize), Some(TValueType::Euclidean)))) .map(|subpath| { - let step = subpath.length(None) / density; - Subpath::from_anchors((0..=step as usize).map(|t| subpath.evaluate(SubpathTValue::GlobalEuclidean(t as f64 / step))).collect::>(), false) + let length = subpath.length(None); + let rounded_count = (length / density).round(); + let difference = length - rounded_count * density; + let adjusted_density = density + difference / rounded_count; + + Subpath::from_anchors( + (0..=rounded_count as usize).map(|c| subpath.evaluate(SubpathTValue::GlobalEuclidean((c as f64 * adjusted_density / length).clamp(0.0, 0.99999)))), + false, + ) }) .collect(); vector_data From 9f6d0bd3056d60b967d0e8f26bb055fa8cecfe15 Mon Sep 17 00:00:00 2001 From: Chase Date: Thu, 25 May 2023 19:28:35 +0800 Subject: [PATCH 09/28] Update minimum density 0.01 -> 1.0 --- .../node_graph/node_graph_message_handler/node_properties.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs index 34403e33437..83fcd8cc17b 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs @@ -1797,7 +1797,7 @@ pub fn circular_repeat_properties(document_node: &DocumentNode, node_id: NodeId, } pub fn resample_curve_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { - let density = number_widget(document_node, node_id, density_index, "Density", NumberInput::default().min(0.01), true); + let density = number_widget(document_node, node_id, density_index, "Density", NumberInput::default().min(1.), true); vec![LayoutGroup::Row { widgets: density }] } From 069473a85ccc194d6f89d2591827c9a5e7b200fb Mon Sep 17 00:00:00 2001 From: Chase Date: Mon, 29 May 2023 16:41:16 +0800 Subject: [PATCH 10/28] Add a way to create a custom vector network --- .../document_node_types.rs | 27 +++++++++++++++++++ .../graph_modification_utils.rs | 5 ++++ 2 files changed, 32 insertions(+) diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index 84b405ba9cc..6add76140fb 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -2337,6 +2337,33 @@ pub fn new_vector_network(subpaths: Vec, subpaths: Vec>) -> NodeNetwork { + let mut network = NodeNetwork { + inputs: vec![0], + ..Default::default() + }; + + let path_generator = resolve_document_node_type("Path Generator").expect("Path Generator node does not exist"); + network.push_node( + path_generator.to_document_node_default_inputs([Some(NodeInput::value(TaggedValue::Subpaths(subpaths), false))], DocumentNodeMetadata::position((0, 4))), + false, + ); + + for name in node_names { + let node = resolve_document_node_type(&name).expect(&format!("{} node does not exist", name)); + network.push_node(node.to_document_node_default_inputs([None], Default::default()), true); + } + + let output = resolve_document_node_type("Output").expect("Output node does not exist"); + network.push_node(output.to_document_node_default_inputs([None], Default::default()), true); + + network +} + pub fn new_text_network(text: String, font: Font, size: f64) -> NodeNetwork { let text_generator = resolve_document_node_type("Text").expect("Text node does not exist"); let transform = resolve_document_node_type("Transform").expect("Transform node does not exist"); diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index 7bef3c6225c..775499d5cc4 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -16,6 +16,11 @@ pub fn new_vector_layer(subpaths: Vec>, layer_path: new_custom_layer(network, layer_path, responses); } +pub fn new_custom_vector_layer(node_names: Vec, subpaths: Vec>, layer_path: Vec, responses: &mut VecDeque) { + let network = node_graph::new_custom_vector_network(node_names, subpaths); + new_custom_layer(network, layer_path, responses); +} + pub fn new_custom_layer(network: NodeNetwork, layer_path: Vec, responses: &mut VecDeque) { responses.add(DocumentMessage::DeselectAllLayers); responses.add(Operation::AddFrame { From ecd0baed4bd7e6cdf86c8895abd6c01dd3df265f Mon Sep 17 00:00:00 2001 From: Chase Date: Mon, 29 May 2023 16:43:20 +0800 Subject: [PATCH 11/28] Add spline from points node to spline tool --- editor/src/messages/tool/tool_messages/spline_tool.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/spline_tool.rs b/editor/src/messages/tool/tool_messages/spline_tool.rs index 3eff6875e7a..943bfff8ca1 100644 --- a/editor/src/messages/tool/tool_messages/spline_tool.rs +++ b/editor/src/messages/tool/tool_messages/spline_tool.rs @@ -332,11 +332,16 @@ fn add_spline(tool_data: &SplineToolData, show_preview: bool, fill_color: Option points.push(tool_data.next_point) } - let subpath = bezier_rs::Subpath::new_cubic_spline(points); + let subpath = bezier_rs::Subpath::from_anchors(points, false); let layer_path = tool_data.path.clone().unwrap(); let manipulator_groups = subpath.manipulator_groups().to_vec(); - graph_modification_utils::new_vector_layer(vec![subpath], layer_path.clone(), responses); + graph_modification_utils::new_custom_vector_layer( + vec!["Spline from Points".into(), "Transform".into(), "Fill".into(), "Stroke".into()], + vec![subpath], + layer_path.clone(), + responses, + ); graph_modification_utils::set_manipulator_mirror_angle(&manipulator_groups, &layer_path, true, responses); responses.add(GraphOperationMessage::FillSet { From e57197d652d105ebacd95c35f465a71a86f638a0 Mon Sep 17 00:00:00 2001 From: Chase Date: Mon, 29 May 2023 18:22:48 +0800 Subject: [PATCH 12/28] Fix crash when no points --- .../tool/common_functionality/graph_modification_utils.rs | 4 ++++ node-graph/gcore/src/vector/vector_nodes.rs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index 775499d5cc4..80385ddf5c5 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -16,6 +16,10 @@ pub fn new_vector_layer(subpaths: Vec>, layer_path: new_custom_layer(network, layer_path, responses); } +/// Creates a new custom vector network by resolving node names. +/// +/// * `node_names`: The names of the nodes to be resolved and inserted between the path_generator and output nodes. +/// * `subpaths`: The subpath that contains the vector data. pub fn new_custom_vector_layer(node_names: Vec, subpaths: Vec>, layer_path: Vec, responses: &mut VecDeque) { let network = node_graph::new_custom_vector_network(node_names, subpaths); new_custom_layer(network, layer_path, responses); diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 212a7cc9641..fadc6d9c24f 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -177,8 +177,8 @@ pub struct SetSplineFromPointsNode {} #[node_macro::node_fn(SetSplineFromPointsNode)] fn set_vector_data_spline_from_points(mut vector_data: VectorData) -> VectorData { - let points = vector_data.subpaths.iter().flat_map(|subpath| subpath.manipulator_groups().iter().map(|group| group.anchor)).collect(); + let points: Vec = vector_data.subpaths.iter().flat_map(|subpath| subpath.manipulator_groups().iter().map(|group| group.anchor)).collect(); - vector_data.subpaths = vec![Subpath::new_cubic_spline(points)]; + vector_data.subpaths = if points.is_empty() { vec![] } else { vec![Subpath::new_cubic_spline(points)] }; vector_data } From c9dd501ae965667f12a9facef6576382699b02c9 Mon Sep 17 00:00:00 2001 From: Chase Date: Tue, 30 May 2023 15:24:59 +0800 Subject: [PATCH 13/28] Add anchor method to subpath --- libraries/bezier-rs/src/subpath/core.rs | 5 +++++ node-graph/gcore/src/vector/vector_nodes.rs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/bezier-rs/src/subpath/core.rs b/libraries/bezier-rs/src/subpath/core.rs index 288e1cf7699..e677e4027ad 100644 --- a/libraries/bezier-rs/src/subpath/core.rs +++ b/libraries/bezier-rs/src/subpath/core.rs @@ -112,6 +112,11 @@ impl Subpath { &self.manipulator_groups } + /// Returns a vector of all the anchors (DVec2) for this `Subpath`. + pub fn anchors(&self) -> Vec { + self.manipulator_groups().iter().map(|group| group.anchor).collect() + } + /// Returns if the Subpath is equivalent to a single point. pub fn is_point(&self) -> bool { if self.is_empty() { diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index fadc6d9c24f..091e834ae56 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -177,7 +177,7 @@ pub struct SetSplineFromPointsNode {} #[node_macro::node_fn(SetSplineFromPointsNode)] fn set_vector_data_spline_from_points(mut vector_data: VectorData) -> VectorData { - let points: Vec = vector_data.subpaths.iter().flat_map(|subpath| subpath.manipulator_groups().iter().map(|group| group.anchor)).collect(); + let points: Vec = vector_data.subpaths.iter().flat_map(|subpath| subpath.anchors()).collect(); vector_data.subpaths = if points.is_empty() { vec![] } else { vec![Subpath::new_cubic_spline(points)] }; vector_data From 492d186d5bd20163652188cf87dcb2498cc422ea Mon Sep 17 00:00:00 2001 From: hypercube <0hypercube@gmail.com> Date: Sun, 20 Aug 2023 09:12:30 +0100 Subject: [PATCH 14/28] Exact start and end point --- libraries/bezier-rs/src/bezier/lookup.rs | 7 +++++++ libraries/bezier-rs/src/subpath/lookup.rs | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/libraries/bezier-rs/src/bezier/lookup.rs b/libraries/bezier-rs/src/bezier/lookup.rs index 68c45754555..5706514ae12 100644 --- a/libraries/bezier-rs/src/bezier/lookup.rs +++ b/libraries/bezier-rs/src/bezier/lookup.rs @@ -6,6 +6,13 @@ use super::*; impl Bezier { /// Convert a euclidean distance ratio along the `Bezier` curve to a parametric `t`-value. pub fn euclidean_to_parametric(&self, ratio: f64, error: f64) -> f64 { + if ratio < error { + return 0.; + } + if 1. - ratio < error { + return 1.; + } + let mut low = 0.; let mut mid = 0.; let mut high = 1.; diff --git a/libraries/bezier-rs/src/subpath/lookup.rs b/libraries/bezier-rs/src/subpath/lookup.rs index 81b89e3f266..acc0e306558 100644 --- a/libraries/bezier-rs/src/subpath/lookup.rs +++ b/libraries/bezier-rs/src/subpath/lookup.rs @@ -252,4 +252,16 @@ mod tests { assert_eq!(closed_subpath.t_value_to_parametric(SubpathTValue::GlobalParametric(0.)), (0, 0.)); assert_eq!(closed_subpath.t_value_to_parametric(SubpathTValue::GlobalParametric(1.)), (4, 1.)); } + + #[test] + fn exact_start_end() { + let start = DVec2::new(20., 30.); + let end = DVec2::new(60., 45.); + let handle = DVec2::new(75., 85.); + + let subpath: Subpath = Subpath::from_bezier(&Bezier::from_quadratic_dvec2(start, handle, end)); + + assert_eq!(subpath.evaluate(SubpathTValue::GlobalEuclidean(0.0)), start); + assert_eq!(subpath.evaluate(SubpathTValue::GlobalEuclidean(1.0)), end); + } } From 4666e8315e485cfeada39509b61fcbdba74c9e49 Mon Sep 17 00:00:00 2001 From: hypercube <0hypercube@gmail.com> Date: Sun, 20 Aug 2023 09:23:05 +0100 Subject: [PATCH 15/28] Fix compile errors from rebase --- .../node_graph_message_handler/document_node_types.rs | 2 ++ .../node_graph/node_graph_message_handler/node_properties.rs | 2 +- node-graph/interpreted-executor/src/node_registry.rs | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index 6add76140fb..9fa7bf9619a 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -2056,6 +2056,7 @@ fn static_nodes() -> Vec { ], outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], properties: node_properties::resample_curve_properties, + ..Default::default() }, DocumentNodeType { name: "Spline from Points", @@ -2064,6 +2065,7 @@ fn static_nodes() -> Vec { inputs: vec![DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true)], outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], properties: node_properties::no_properties, + ..Default::default() }, DocumentNodeType { name: "Image Segmentation", diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs index 83fcd8cc17b..01c77f1f079 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs @@ -1797,7 +1797,7 @@ pub fn circular_repeat_properties(document_node: &DocumentNode, node_id: NodeId, } pub fn resample_curve_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { - let density = number_widget(document_node, node_id, density_index, "Density", NumberInput::default().min(1.), true); + let density = number_widget(document_node, node_id, 1, "Density", NumberInput::default().min(1.), true); vec![LayoutGroup::Row { widgets: density }] } diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index b5c85dd6be2..304dc97cbc4 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -630,7 +630,6 @@ fn node_registry() -> HashMap, input: VectorData, params: [DVec2, u32]), register_node!(graphene_core::vector::BoundingBoxNode, input: VectorData, params: []), register_node!(graphene_core::vector::CircularRepeatNode<_, _, _>, input: VectorData, params: [f32, f32, u32]), - register_node!(graphene_core::vector::SetResampleCurveNode<_>, input: VectorData, params: [u32]), register_node!(graphene_core::vector::SetResampleCurveNode<_>, input: VectorData, params: [f64]), register_node!(graphene_core::vector::SetSplineFromPointsNode, input: VectorData, params: []), register_node!(graphene_core::vector::generator_nodes::UnitCircleGenerator, input: (), params: []), From d8cdd817aa82a3d7012c7e7eb5db8297923c545c Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Fri, 25 Aug 2023 09:36:26 +0100 Subject: [PATCH 16/28] Fix spline tool --- .../document_node_types.rs | 27 ------------------- .../graph_modification_utils.rs | 9 ------- .../tool/tool_messages/spline_tool.rs | 9 ++----- 3 files changed, 2 insertions(+), 43 deletions(-) diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index 9fa7bf9619a..8ea96a323c9 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -2339,33 +2339,6 @@ pub fn new_vector_network(subpaths: Vec, subpaths: Vec>) -> NodeNetwork { - let mut network = NodeNetwork { - inputs: vec![0], - ..Default::default() - }; - - let path_generator = resolve_document_node_type("Path Generator").expect("Path Generator node does not exist"); - network.push_node( - path_generator.to_document_node_default_inputs([Some(NodeInput::value(TaggedValue::Subpaths(subpaths), false))], DocumentNodeMetadata::position((0, 4))), - false, - ); - - for name in node_names { - let node = resolve_document_node_type(&name).expect(&format!("{} node does not exist", name)); - network.push_node(node.to_document_node_default_inputs([None], Default::default()), true); - } - - let output = resolve_document_node_type("Output").expect("Output node does not exist"); - network.push_node(output.to_document_node_default_inputs([None], Default::default()), true); - - network -} - pub fn new_text_network(text: String, font: Font, size: f64) -> NodeNetwork { let text_generator = resolve_document_node_type("Text").expect("Text node does not exist"); let transform = resolve_document_node_type("Transform").expect("Transform node does not exist"); diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index 80385ddf5c5..7bef3c6225c 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -16,15 +16,6 @@ pub fn new_vector_layer(subpaths: Vec>, layer_path: new_custom_layer(network, layer_path, responses); } -/// Creates a new custom vector network by resolving node names. -/// -/// * `node_names`: The names of the nodes to be resolved and inserted between the path_generator and output nodes. -/// * `subpaths`: The subpath that contains the vector data. -pub fn new_custom_vector_layer(node_names: Vec, subpaths: Vec>, layer_path: Vec, responses: &mut VecDeque) { - let network = node_graph::new_custom_vector_network(node_names, subpaths); - new_custom_layer(network, layer_path, responses); -} - pub fn new_custom_layer(network: NodeNetwork, layer_path: Vec, responses: &mut VecDeque) { responses.add(DocumentMessage::DeselectAllLayers); responses.add(Operation::AddFrame { diff --git a/editor/src/messages/tool/tool_messages/spline_tool.rs b/editor/src/messages/tool/tool_messages/spline_tool.rs index 943bfff8ca1..3eff6875e7a 100644 --- a/editor/src/messages/tool/tool_messages/spline_tool.rs +++ b/editor/src/messages/tool/tool_messages/spline_tool.rs @@ -332,16 +332,11 @@ fn add_spline(tool_data: &SplineToolData, show_preview: bool, fill_color: Option points.push(tool_data.next_point) } - let subpath = bezier_rs::Subpath::from_anchors(points, false); + let subpath = bezier_rs::Subpath::new_cubic_spline(points); let layer_path = tool_data.path.clone().unwrap(); let manipulator_groups = subpath.manipulator_groups().to_vec(); - graph_modification_utils::new_custom_vector_layer( - vec!["Spline from Points".into(), "Transform".into(), "Fill".into(), "Stroke".into()], - vec![subpath], - layer_path.clone(), - responses, - ); + graph_modification_utils::new_vector_layer(vec![subpath], layer_path.clone(), responses); graph_modification_utils::set_manipulator_mirror_angle(&manipulator_groups, &layer_path, true, responses); responses.add(GraphOperationMessage::FillSet { From dcb248d7c3e056ce7e32a0b433c850188238a79d Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sun, 27 Aug 2023 00:20:38 -0700 Subject: [PATCH 17/28] Rename 'Density' to 'Spacing' --- .../document_node_types.rs | 2 +- .../node_graph_message_handler/node_properties.rs | 4 ++-- node-graph/gcore/src/vector/vector_nodes.rs | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index 8ea96a323c9..818e360adb3 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -2052,7 +2052,7 @@ fn static_nodes() -> Vec { identifier: NodeImplementation::proto("graphene_core::vector::SetResampleCurveNode<_>"), inputs: vec![ DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), - DocumentInputType::value("Density", TaggedValue::F64(100.), false), + DocumentInputType::value("Spacing", TaggedValue::F64(100.), false), ], outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], properties: node_properties::resample_curve_properties, diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs index 01c77f1f079..29d30cd1c3b 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs @@ -1797,9 +1797,9 @@ pub fn circular_repeat_properties(document_node: &DocumentNode, node_id: NodeId, } pub fn resample_curve_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { - let density = number_widget(document_node, node_id, 1, "Density", NumberInput::default().min(1.), true); + let spacing = number_widget(document_node, node_id, 1, "Spacing", NumberInput::default().min(1.), true); - vec![LayoutGroup::Row { widgets: density }] + vec![LayoutGroup::Row { widgets: spacing }] } /// Fill Node Widgets LayoutGroup diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 091e834ae56..d23224de594 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -148,23 +148,23 @@ fn generate_bounding_box(vector_data: VectorData) -> VectorData { } #[derive(Debug, Clone, Copy)] -pub struct SetResampleCurveNode { - density: Density, +pub struct SetResampleCurveNode { + spacing: Spacing, } #[node_macro::node_fn(SetResampleCurveNode)] -fn set_vector_data_resample_curve(mut vector_data: VectorData, density: f64) -> VectorData { +fn set_vector_data_resample_curve(mut vector_data: VectorData, spacing: f64) -> VectorData { vector_data.subpaths = vector_data .subpaths .iter() .map(|subpath| { let length = subpath.length(None); - let rounded_count = (length / density).round(); - let difference = length - rounded_count * density; - let adjusted_density = density + difference / rounded_count; + let rounded_count = (length / spacing).round(); + let difference = length - rounded_count * spacing; + let adjusted_spacing = spacing + difference / rounded_count; Subpath::from_anchors( - (0..=rounded_count as usize).map(|c| subpath.evaluate(SubpathTValue::GlobalEuclidean((c as f64 * adjusted_density / length).clamp(0.0, 0.99999)))), + (0..=rounded_count as usize).map(|c| subpath.evaluate(SubpathTValue::GlobalEuclidean((c as f64 * adjusted_spacing / length).clamp(0.0, 0.99999)))), false, ) }) From c9cfc00ee48b2933809613ac8c263a711021e091 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Wed, 30 Aug 2023 10:13:41 +0100 Subject: [PATCH 18/28] Fix transforms --- node-graph/gcore/src/vector/vector_nodes.rs | 25 +++++++++------------ 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index d23224de594..195b7f40425 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -154,21 +154,16 @@ pub struct SetResampleCurveNode { #[node_macro::node_fn(SetResampleCurveNode)] fn set_vector_data_resample_curve(mut vector_data: VectorData, spacing: f64) -> VectorData { - vector_data.subpaths = vector_data - .subpaths - .iter() - .map(|subpath| { - let length = subpath.length(None); - let rounded_count = (length / spacing).round(); - let difference = length - rounded_count * spacing; - let adjusted_spacing = spacing + difference / rounded_count; - - Subpath::from_anchors( - (0..=rounded_count as usize).map(|c| subpath.evaluate(SubpathTValue::GlobalEuclidean((c as f64 * adjusted_spacing / length).clamp(0.0, 0.99999)))), - false, - ) - }) - .collect(); + for subpath in &mut vector_data.subpaths { + subpath.apply_transform(vector_data.transform); + let length = subpath.length(None); + let rounded_count = (length / spacing).round(); + + let new_anchors = (0..=rounded_count as usize).map(|c| subpath.evaluate(SubpathTValue::GlobalEuclidean(c as f64 / rounded_count))); + *subpath = Subpath::from_anchors(new_anchors, subpath.closed()); + + subpath.apply_transform(vector_data.transform.inverse()); + } vector_data } From d0448f35cd906b3dcd86f22428dece9690dee6c8 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Wed, 30 Aug 2023 11:25:42 +0100 Subject: [PATCH 19/28] Only close subpaths with >1 anchor --- node-graph/gcore/src/vector/vector_nodes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 195b7f40425..d44945f69b0 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -160,7 +160,7 @@ fn set_vector_data_resample_curve(mut vector_data: VectorData, spacing: f64) -> let rounded_count = (length / spacing).round(); let new_anchors = (0..=rounded_count as usize).map(|c| subpath.evaluate(SubpathTValue::GlobalEuclidean(c as f64 / rounded_count))); - *subpath = Subpath::from_anchors(new_anchors, subpath.closed()); + *subpath = Subpath::from_anchors(new_anchors, subpath.closed() && new_anchors.len() > 1); subpath.apply_transform(vector_data.transform.inverse()); } From d920452a0d8c4768f0d6d6fbedf61b15ec3764f7 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Wed, 30 Aug 2023 11:37:43 +0100 Subject: [PATCH 20/28] Fix compile --- node-graph/gcore/src/vector/vector_nodes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index d44945f69b0..9d7b0bb57e5 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -160,7 +160,7 @@ fn set_vector_data_resample_curve(mut vector_data: VectorData, spacing: f64) -> let rounded_count = (length / spacing).round(); let new_anchors = (0..=rounded_count as usize).map(|c| subpath.evaluate(SubpathTValue::GlobalEuclidean(c as f64 / rounded_count))); - *subpath = Subpath::from_anchors(new_anchors, subpath.closed() && new_anchors.len() > 1); + *subpath = Subpath::from_anchors(new_anchors, subpath.closed() && rounded_count > 1); subpath.apply_transform(vector_data.transform.inverse()); } From 8be2681932d1f4b79085ef2d02dd9affd49a4045 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Wed, 30 Aug 2023 11:39:05 +0100 Subject: [PATCH 21/28] Fix compile error --- node-graph/gcore/src/vector/vector_nodes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 9d7b0bb57e5..e2d020fbdf5 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -160,7 +160,7 @@ fn set_vector_data_resample_curve(mut vector_data: VectorData, spacing: f64) -> let rounded_count = (length / spacing).round(); let new_anchors = (0..=rounded_count as usize).map(|c| subpath.evaluate(SubpathTValue::GlobalEuclidean(c as f64 / rounded_count))); - *subpath = Subpath::from_anchors(new_anchors, subpath.closed() && rounded_count > 1); + *subpath = Subpath::from_anchors(new_anchors, subpath.closed() && rounded_count as usize > 1); subpath.apply_transform(vector_data.transform.inverse()); } From b2fb370787dc92fe947c8201743568fa216aa9bd Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Wed, 30 Aug 2023 12:20:11 +0100 Subject: [PATCH 22/28] Fix from points with many subpaths --- node-graph/gcore/src/vector/vector_nodes.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index e2d020fbdf5..1f0aa2c3db8 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -172,8 +172,9 @@ pub struct SetSplineFromPointsNode {} #[node_macro::node_fn(SetSplineFromPointsNode)] fn set_vector_data_spline_from_points(mut vector_data: VectorData) -> VectorData { - let points: Vec = vector_data.subpaths.iter().flat_map(|subpath| subpath.anchors()).collect(); + for subpath in &mut vector_data.subpaths { + *subpath = Subpath::new_cubic_spline(subpath.anchors()); + } - vector_data.subpaths = if points.is_empty() { vec![] } else { vec![Subpath::new_cubic_spline(points)] }; vector_data } From 6ef8abd12c5febcdbcd41ba4a79a037a99cb3009 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Wed, 30 Aug 2023 12:30:55 +0100 Subject: [PATCH 23/28] Fix new_cubic_spline crash with one point --- libraries/bezier-rs/src/subpath/core.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/bezier-rs/src/subpath/core.rs b/libraries/bezier-rs/src/subpath/core.rs index 25d68a43c4a..6798bf8b790 100644 --- a/libraries/bezier-rs/src/subpath/core.rs +++ b/libraries/bezier-rs/src/subpath/core.rs @@ -259,7 +259,7 @@ impl Subpath { /// Construct a cubic spline from a list of points. /// Based on . pub fn new_cubic_spline(points: Vec) -> Self { - if points.is_empty() { + if points.len() < 2 { return Self::new(Vec::new(), false); } From 14325c265aa97e756d17419381c62488aeb32560 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Wed, 30 Aug 2023 12:37:37 +0100 Subject: [PATCH 24/28] Rename to resample as polyline --- .../node_graph_message_handler/document_node_types.rs | 6 +++--- node-graph/gcore/src/vector/vector_nodes.rs | 8 ++++---- node-graph/interpreted-executor/src/node_registry.rs | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index 0da91d5c4e7..b17fbb8122f 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -2171,9 +2171,9 @@ fn static_nodes() -> Vec { ..Default::default() }, DocumentNodeType { - name: "Resample Curve", + name: "Resample as Polyline", category: "Vector", - identifier: NodeImplementation::proto("graphene_core::vector::SetResampleCurveNode<_>"), + identifier: NodeImplementation::proto("graphene_core::vector::ResampleAsPolyline<_>"), inputs: vec![ DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), DocumentInputType::value("Spacing", TaggedValue::F64(100.), false), @@ -2185,7 +2185,7 @@ fn static_nodes() -> Vec { DocumentNodeType { name: "Spline from Points", category: "Vector", - identifier: NodeImplementation::proto("graphene_core::vector::SetSplineFromPointsNode"), + identifier: NodeImplementation::proto("graphene_core::vector::SplineFromPointsNode"), inputs: vec![DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true)], outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], properties: node_properties::no_properties, diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 1f0aa2c3db8..4870ad45da1 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -148,11 +148,11 @@ fn generate_bounding_box(vector_data: VectorData) -> VectorData { } #[derive(Debug, Clone, Copy)] -pub struct SetResampleCurveNode { +pub struct ResampleAsPolyline { spacing: Spacing, } -#[node_macro::node_fn(SetResampleCurveNode)] +#[node_macro::node_fn(ResampleAsPolyline)] fn set_vector_data_resample_curve(mut vector_data: VectorData, spacing: f64) -> VectorData { for subpath in &mut vector_data.subpaths { subpath.apply_transform(vector_data.transform); @@ -168,9 +168,9 @@ fn set_vector_data_resample_curve(mut vector_data: VectorData, spacing: f64) -> } #[derive(Debug, Clone, Copy)] -pub struct SetSplineFromPointsNode {} +pub struct SplineFromPointsNode {} -#[node_macro::node_fn(SetSplineFromPointsNode)] +#[node_macro::node_fn(SplineFromPointsNode)] fn set_vector_data_spline_from_points(mut vector_data: VectorData) -> VectorData { for subpath in &mut vector_data.subpaths { *subpath = Subpath::new_cubic_spline(subpath.anchors()); diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index 6b01a3d6cbe..ca6c5d3645d 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -634,8 +634,8 @@ fn node_registry() -> HashMap, input: VectorData, params: [DVec2, u32]), register_node!(graphene_core::vector::BoundingBoxNode, input: VectorData, params: []), register_node!(graphene_core::vector::CircularRepeatNode<_, _, _>, input: VectorData, params: [f32, f32, u32]), - register_node!(graphene_core::vector::SetResampleCurveNode<_>, input: VectorData, params: [f64]), - register_node!(graphene_core::vector::SetSplineFromPointsNode, input: VectorData, params: []), + register_node!(graphene_core::vector::ResampleAsPolyline<_>, input: VectorData, params: [f64]), + register_node!(graphene_core::vector::SplineFromPointsNode, input: VectorData, params: []), register_node!(graphene_core::vector::generator_nodes::CircleGenerator<_>, input: (), params: [f32]), register_node!(graphene_core::vector::generator_nodes::EllipseGenerator<_, _>, input: (), params: [f32, f32]), register_node!(graphene_core::vector::generator_nodes::RectangleGenerator<_, _>, input: (), params: [f32, f32]), From 2049783366ec40452647fe7012a5c46fded690c7 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Wed, 30 Aug 2023 12:43:22 +0100 Subject: [PATCH 25/28] Fix div zero --- node-graph/gcore/src/vector/vector_nodes.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 4870ad45da1..830dc430887 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -148,16 +148,22 @@ fn generate_bounding_box(vector_data: VectorData) -> VectorData { } #[derive(Debug, Clone, Copy)] -pub struct ResampleAsPolyline { +pub struct SetResampleCurveNode { spacing: Spacing, } -#[node_macro::node_fn(ResampleAsPolyline)] +#[node_macro::node_fn(SetResampleCurveNode)] fn set_vector_data_resample_curve(mut vector_data: VectorData, spacing: f64) -> VectorData { for subpath in &mut vector_data.subpaths { + if subpath.is_empty() { + continue; + } subpath.apply_transform(vector_data.transform); let length = subpath.length(None); let rounded_count = (length / spacing).round(); + if rounded_count < 1. { + continue; + } let new_anchors = (0..=rounded_count as usize).map(|c| subpath.evaluate(SubpathTValue::GlobalEuclidean(c as f64 / rounded_count))); *subpath = Subpath::from_anchors(new_anchors, subpath.closed() && rounded_count as usize > 1); From 12ec0d013ff2ab488cb11b1c788938aa1b6b4cc4 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Wed, 30 Aug 2023 12:51:20 +0100 Subject: [PATCH 26/28] Fix missing file --- node-graph/gcore/src/vector/vector_nodes.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 830dc430887..f41511fbe2e 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -148,12 +148,12 @@ fn generate_bounding_box(vector_data: VectorData) -> VectorData { } #[derive(Debug, Clone, Copy)] -pub struct SetResampleCurveNode { +pub struct ResampleAsPolyline { spacing: Spacing, } -#[node_macro::node_fn(SetResampleCurveNode)] -fn set_vector_data_resample_curve(mut vector_data: VectorData, spacing: f64) -> VectorData { +#[node_macro::node_fn(ResampleAsPolyline)] +fn resample_as_polyline(mut vector_data: VectorData, spacing: f64) -> VectorData { for subpath in &mut vector_data.subpaths { if subpath.is_empty() { continue; @@ -177,7 +177,7 @@ fn set_vector_data_resample_curve(mut vector_data: VectorData, spacing: f64) -> pub struct SplineFromPointsNode {} #[node_macro::node_fn(SplineFromPointsNode)] -fn set_vector_data_spline_from_points(mut vector_data: VectorData) -> VectorData { +fn spline_from_points(mut vector_data: VectorData) -> VectorData { for subpath in &mut vector_data.subpaths { *subpath = Subpath::new_cubic_spline(subpath.anchors()); } From 4354b892be92e5a309dddbe64f4dd22972d980f2 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Wed, 30 Aug 2023 13:00:10 +0100 Subject: [PATCH 27/28] Fix resample --- node-graph/gcore/src/vector/vector_nodes.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index f41511fbe2e..5629d2c0021 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -4,6 +4,7 @@ use crate::{Color, Node}; use bezier_rs::{Subpath, SubpathTValue}; use glam::{DAffine2, DVec2}; +use num_traits::Zero; #[derive(Debug, Clone, Copy)] pub struct SetFillNode { @@ -155,18 +156,18 @@ pub struct ResampleAsPolyline { #[node_macro::node_fn(ResampleAsPolyline)] fn resample_as_polyline(mut vector_data: VectorData, spacing: f64) -> VectorData { for subpath in &mut vector_data.subpaths { - if subpath.is_empty() { + if subpath.is_empty() || spacing.is_zero() || !spacing.is_finite() { continue; } + subpath.apply_transform(vector_data.transform); let length = subpath.length(None); let rounded_count = (length / spacing).round(); - if rounded_count < 1. { - continue; - } - let new_anchors = (0..=rounded_count as usize).map(|c| subpath.evaluate(SubpathTValue::GlobalEuclidean(c as f64 / rounded_count))); - *subpath = Subpath::from_anchors(new_anchors, subpath.closed() && rounded_count as usize > 1); + if rounded_count >= 1. { + let new_anchors = (0..=rounded_count as usize).map(|c| subpath.evaluate(SubpathTValue::GlobalEuclidean(c as f64 / rounded_count))); + *subpath = Subpath::from_anchors(new_anchors, subpath.closed() && rounded_count as usize > 1); + } subpath.apply_transform(vector_data.transform.inverse()); } From 0eb363aba02e30440196b2175a2c94d40c330ff6 Mon Sep 17 00:00:00 2001 From: 0hypercube <0hypercube@gmail.com> Date: Wed, 30 Aug 2023 13:12:41 +0100 Subject: [PATCH 28/28] Rename to resample points --- .../node_graph_message_handler/document_node_types.rs | 6 +++--- .../node_graph_message_handler/node_properties.rs | 2 +- node-graph/gcore/src/vector/vector_nodes.rs | 6 +++--- node-graph/interpreted-executor/src/node_registry.rs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index b17fbb8122f..66487425374 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -2171,15 +2171,15 @@ fn static_nodes() -> Vec { ..Default::default() }, DocumentNodeType { - name: "Resample as Polyline", + name: "Resample Points", category: "Vector", - identifier: NodeImplementation::proto("graphene_core::vector::ResampleAsPolyline<_>"), + identifier: NodeImplementation::proto("graphene_core::vector::ResamplePoints<_>"), inputs: vec![ DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), DocumentInputType::value("Spacing", TaggedValue::F64(100.), false), ], outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], - properties: node_properties::resample_curve_properties, + properties: node_properties::resample_points_properties, ..Default::default() }, DocumentNodeType { diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs index e9ba4fd4102..ed30ca2d389 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs @@ -1868,7 +1868,7 @@ pub fn circular_repeat_properties(document_node: &DocumentNode, node_id: NodeId, vec![LayoutGroup::Row { widgets: angle_offset }, LayoutGroup::Row { widgets: radius }, LayoutGroup::Row { widgets: count }] } -pub fn resample_curve_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { +pub fn resample_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { let spacing = number_widget(document_node, node_id, 1, "Spacing", NumberInput::default().min(1.), true); vec![LayoutGroup::Row { widgets: spacing }] diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 5629d2c0021..50e7a5801a9 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -149,12 +149,12 @@ fn generate_bounding_box(vector_data: VectorData) -> VectorData { } #[derive(Debug, Clone, Copy)] -pub struct ResampleAsPolyline { +pub struct ResamplePoints { spacing: Spacing, } -#[node_macro::node_fn(ResampleAsPolyline)] -fn resample_as_polyline(mut vector_data: VectorData, spacing: f64) -> VectorData { +#[node_macro::node_fn(ResamplePoints)] +fn resample_points(mut vector_data: VectorData, spacing: f64) -> VectorData { for subpath in &mut vector_data.subpaths { if subpath.is_empty() || spacing.is_zero() || !spacing.is_finite() { continue; diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index ca6c5d3645d..484568c6cd1 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -634,7 +634,7 @@ fn node_registry() -> HashMap, input: VectorData, params: [DVec2, u32]), register_node!(graphene_core::vector::BoundingBoxNode, input: VectorData, params: []), register_node!(graphene_core::vector::CircularRepeatNode<_, _, _>, input: VectorData, params: [f32, f32, u32]), - register_node!(graphene_core::vector::ResampleAsPolyline<_>, input: VectorData, params: [f64]), + register_node!(graphene_core::vector::ResamplePoints<_>, input: VectorData, params: [f64]), register_node!(graphene_core::vector::SplineFromPointsNode, input: VectorData, params: []), register_node!(graphene_core::vector::generator_nodes::CircleGenerator<_>, input: (), params: [f32]), register_node!(graphene_core::vector::generator_nodes::EllipseGenerator<_, _>, input: (), params: [f32, f32]),