Copy to Points node: add support for groups (#1541)

Copy to points by group
This commit is contained in:
0HyperCube 2024-01-03 12:21:10 +00:00 committed by GitHub
parent 202390e422
commit 4c64df038f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 21 deletions

View File

@ -1,7 +1,8 @@
use super::style::{Fill, FillType, Gradient, GradientType, Stroke}; use super::style::{Fill, FillType, Gradient, GradientType, Stroke};
use super::VectorData; use super::VectorData;
use crate::transform::Footprint; use crate::renderer::GraphicElementRendered;
use crate::{Color, Node}; use crate::transform::{Footprint, Transform, TransformMut};
use crate::{Color, GraphicGroup, Node};
use core::future::Future; use core::future::Future;
use bezier_rs::{Subpath, SubpathTValue}; use bezier_rs::{Subpath, SubpathTValue};
@ -145,6 +146,34 @@ fn generate_bounding_box(vector_data: VectorData) -> VectorData {
)]) )])
} }
pub trait ConcatElement {
fn concat(&mut self, other: &Self, transform: DAffine2);
}
impl ConcatElement for VectorData {
fn concat(&mut self, other: &Self, transform: DAffine2) {
for mut subpath in other.subpaths.iter().cloned() {
subpath.apply_transform(transform * other.transform);
self.subpaths.push(subpath);
}
// TODO: properly deal with fills such as gradients
self.style = other.style.clone();
self.mirror_angle.extend(other.mirror_angle.iter().copied());
self.alpha_blending = other.alpha_blending;
}
}
impl ConcatElement for GraphicGroup {
fn concat(&mut self, other: &Self, transform: DAffine2) {
// TODO: Decide if we want to keep this behaviour whereby the layers are flattened
for mut element in other.iter().cloned() {
*element.transform_mut() = transform * element.transform() * other.transform();
self.push(element);
}
self.alpha_blending = other.alpha_blending;
}
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct CopyToPoints<Points, Instance> { pub struct CopyToPoints<Points, Instance> {
points: Points, points: Points,
@ -152,37 +181,26 @@ pub struct CopyToPoints<Points, Instance> {
} }
#[node_macro::node_fn(CopyToPoints)] #[node_macro::node_fn(CopyToPoints)]
async fn copy_to_points<FP: Future<Output = VectorData>, FI: Future<Output = VectorData>>( async fn copy_to_points<I: GraphicElementRendered + Default + ConcatElement + TransformMut, FP: Future<Output = VectorData>, FI: Future<Output = I>>(
footprint: Footprint, footprint: Footprint,
points: impl Node<Footprint, Output = FP>, points: impl Node<Footprint, Output = FP>,
instance: impl Node<Footprint, Output = FI>, instance: impl Node<Footprint, Output = FI>,
) -> VectorData { ) -> I {
// TODO: https://github.com/GraphiteEditor/Graphite/pull/1536#discussion_r1436422419
let points = self.points.eval(footprint).await; let points = self.points.eval(footprint).await;
let instance = self.instance.eval(footprint).await; let instance = self.instance.eval(footprint).await;
let points_list = points.subpaths.iter().flat_map(|s| s.anchors()); let points_list = points.subpaths.iter().flat_map(|s| s.anchors());
let instance_bounding_box = instance.bounding_box_with_transform(instance.transform).unwrap_or_default(); let instance_bounding_box = instance.bounding_box(DAffine2::IDENTITY).unwrap_or_default();
let instance_center = DAffine2::from_translation(-0.5 * (instance_bounding_box[0] + instance_bounding_box[1])); let instance_center = -0.5 * (instance_bounding_box[0] + instance_bounding_box[1]);
let mut instanced_subpaths: Vec<Subpath<_>> = Vec::new(); let mut result = I::default();
for point in points_list { for point in points_list {
let transform = DAffine2::from_translation(points.transform.transform_point2(point)) * instance_center; let translation = points.transform.transform_point2(point) + instance_center;
result.concat(&instance, DAffine2::from_translation(translation));
for mut subpath in instance.subpaths.clone() {
subpath.apply_transform(transform * instance.transform);
instanced_subpaths.push(subpath);
}
} }
VectorData { result
subpaths: instanced_subpaths,
transform: DAffine2::IDENTITY,
style: instance.style,
alpha_blending: instance.alpha_blending,
mirror_angle: instance.mirror_angle,
}
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]

View File

@ -733,6 +733,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
register_node!(graphene_std::raster::SampleNode<_>, input: Footprint, params: [ImageFrame<Color>]), register_node!(graphene_std::raster::SampleNode<_>, input: Footprint, params: [ImageFrame<Color>]),
register_node!(graphene_std::raster::MandelbrotNode, input: Footprint, params: []), register_node!(graphene_std::raster::MandelbrotNode, input: Footprint, params: []),
async_node!(graphene_core::vector::CopyToPoints<_, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, Footprint => VectorData]), async_node!(graphene_core::vector::CopyToPoints<_, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, Footprint => VectorData]),
async_node!(graphene_core::vector::CopyToPoints<_, _>, input: Footprint, output: GraphicGroup, fn_params: [Footprint => VectorData, Footprint => GraphicGroup]),
register_node!(graphene_core::vector::ResamplePoints<_>, input: VectorData, params: [f64]), register_node!(graphene_core::vector::ResamplePoints<_>, input: VectorData, params: [f64]),
register_node!(graphene_core::vector::SplinesFromPointsNode, input: VectorData, params: []), register_node!(graphene_core::vector::SplinesFromPointsNode, input: VectorData, params: []),
register_node!(graphene_core::vector::generator_nodes::CircleGenerator<_>, input: (), params: [f32]), register_node!(graphene_core::vector::generator_nodes::CircleGenerator<_>, input: (), params: [f32]),