From c3a3c4c907419e2ebb9a382546a1d7b66f57cdc0 Mon Sep 17 00:00:00 2001 From: James Lindsay <78500760+0HyperCube@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:06:53 +0100 Subject: [PATCH] Allow the Fill and Stroke nodes to work on groups (#2046) * Add the apply style trait for generalised application of styles * Fix Clippy warn * Use existing trait * Remove unnecessary lifetimes --------- Co-authored-by: Keavon Chambers --- node-graph/gcore/src/vector/vector_nodes.rs | 106 +++++++++++++++----- 1 file changed, 82 insertions(+), 24 deletions(-) diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 2509f2ce..e5b1188f 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -11,19 +11,27 @@ use bezier_rs::{Cap, Join, Subpath, SubpathTValue, TValue}; use glam::{DAffine2, DVec2}; use rand::{Rng, SeedableRng}; +/// Implemented for types that can be converted to an iterator of vector data. +/// Used for the fill and stroke node so they can be used on VectorData or GraphicGroup trait VectorIterMut { - fn vector_iter_mut(&mut self) -> impl ExactSizeIterator; + fn vector_iter_mut(&mut self) -> impl Iterator; } impl VectorIterMut for GraphicGroup { - fn vector_iter_mut(&mut self) -> impl ExactSizeIterator { - self.iter_mut().filter_map(|(element, _)| element.as_vector_data_mut()).collect::>().into_iter() + fn vector_iter_mut(&mut self) -> impl Iterator { + let parent_transform = self.transform; + // Grab only the direct children (perhaps unintuitive?) + self.iter_mut().filter_map(|(element, _)| element.as_vector_data_mut()).map(move |vector| { + let transform = parent_transform * vector.transform; + (vector, transform) + }) } } impl VectorIterMut for VectorData { - fn vector_iter_mut(&mut self) -> impl ExactSizeIterator { - std::iter::once(self) + fn vector_iter_mut(&mut self) -> impl Iterator { + let transform = self.transform; + std::iter::once((self, transform)) } } @@ -51,13 +59,12 @@ async fn assign_colors( repeat_every: u32, ) -> T { let mut input = vector_group.eval(footprint).await; - let vector_data = input.vector_iter_mut(); - let length = vector_data.len(); + let length = input.vector_iter_mut().count(); let gradient = if reverse { gradient.reversed() } else { gradient }; let mut rng = rand::rngs::StdRng::seed_from_u64(seed.into()); - for (i, vector_data) in vector_data.enumerate() { + for (i, (vector_data, _)) in input.vector_iter_mut().enumerate() { let factor = match randomize { true => rng.gen::(), false => match repeat_every { @@ -82,12 +89,23 @@ async fn assign_colors( } #[node_macro::node(category("Vector: Style"), path(graphene_core::vector))] -async fn fill + 'n + Send>( +async fn fill + 'n + Send, TargetTy: VectorIterMut + 'n + Send>( #[implementations( (), (), (), (), + (), + (), + (), + (), + Footprint, + Footprint, + Footprint, + Footprint, + Footprint, + Footprint, + Footprint, Footprint, )] footprint: F, @@ -96,9 +114,20 @@ async fn fill + 'n + Send>( () -> VectorData, () -> VectorData, () -> VectorData, + () -> GraphicGroup, + () -> GraphicGroup, + () -> GraphicGroup, + () -> GraphicGroup, Footprint -> VectorData, + Footprint -> VectorData, + Footprint -> VectorData, + Footprint -> VectorData, + Footprint -> GraphicGroup, + Footprint -> GraphicGroup, + Footprint -> GraphicGroup, + Footprint -> GraphicGroup, )] - vector_data: impl Node, + vector_data: impl Node, #[implementations( Fill, Option, @@ -108,49 +137,74 @@ async fn fill + 'n + Send>( Option, Color, Gradient, + Fill, + Option, + Color, + Gradient, + Fill, + Option, + Color, + Gradient, )] #[default(Color::BLACK)] - fill: T, + fill: FillTy, _backup_color: Option, _backup_gradient: Gradient, -) -> VectorData { - let mut vector_data = vector_data.eval(footprint).await; - vector_data.style.set_fill(fill.into()); +) -> TargetTy { + let mut target = vector_data.eval(footprint).await; + let fill: Fill = fill.into(); + for (target, _transform) in target.vector_iter_mut() { + target.style.set_fill(fill.clone()); + } - vector_data + target } #[node_macro::node(category("Vector: Style"), path(graphene_core::vector))] -async fn stroke> + 'n + Send>( +async fn stroke> + 'n + Send, TargetTy: VectorIterMut + 'n + Send>( #[implementations( (), (), + (), + (), + Footprint, + Footprint, + Footprint, Footprint, )] footprint: F, #[implementations( () -> VectorData, () -> VectorData, + () -> GraphicGroup, + () -> GraphicGroup, Footprint -> VectorData, + Footprint -> VectorData, + Footprint -> GraphicGroup, + Footprint -> GraphicGroup, )] - vector_data: impl Node, + vector_data: impl Node, #[implementations( Option, Color, Option, Color, + Option, + Color, + Option, + Color, )] #[default(Color::BLACK)] - color: T, + color: ColourTy, #[default(2.)] weight: f64, dash_lengths: Vec, dash_offset: f64, line_cap: crate::vector::style::LineCap, line_join: LineJoin, #[default(4.)] miter_limit: f64, -) -> VectorData { - let mut vector_data = vector_data.eval(footprint).await; - vector_data.style.set_stroke(Stroke { +) -> TargetTy { + let mut target = vector_data.eval(footprint).await; + let stroke = Stroke { color: color.into(), weight, dash_lengths, @@ -158,9 +212,13 @@ async fn stroke> + 'n + Send>( line_cap, line_join, line_join_miter_limit: miter_limit, - transform: vector_data.transform, - }); - vector_data + transform: DAffine2::IDENTITY, + }; + for (target, transform) in target.vector_iter_mut() { + target.style.set_stroke(Stroke { transform, ..stroke.clone() }); + } + + target } #[node_macro::node(category("Vector"), path(graphene_core::vector))]