mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-12-23 10:11:54 +00:00
Instance tables refactor part 8: Make repeater nodes use pivot not bbox and output instance type not group; rename 'Flatten Vector Elements' to 'Flatten Path' and add 'Flatten Vector' (#2697)
Make repeater nodes use pivot not bbox and output instance type not group; rename 'Flatten Vector Elements' to 'Flatten Path' and add 'Flatten Vector'
This commit is contained in:
parent
523cc27523
commit
cea1a1c6a8
26 changed files with 252 additions and 125 deletions
|
|
@ -423,6 +423,49 @@ async fn flatten_group(_: impl Ctx, group: GraphicGroupTable, fully_flatten: boo
|
|||
output
|
||||
}
|
||||
|
||||
#[node_macro::node(category("General"))]
|
||||
async fn flatten_vector(_: impl Ctx, group: GraphicGroupTable) -> VectorDataTable {
|
||||
// TODO: Avoid mutable reference, instead return a new GraphicGroupTable?
|
||||
fn flatten_group(output_group_table: &mut VectorDataTable, current_group_table: GraphicGroupTable) {
|
||||
for current_instance in current_group_table.instance_ref_iter() {
|
||||
let current_element = current_instance.instance.clone();
|
||||
let reference = *current_instance.source_node_id;
|
||||
|
||||
match current_element {
|
||||
// If we're allowed to recurse, flatten any GraphicGroups we encounter
|
||||
GraphicElement::GraphicGroup(mut current_element) => {
|
||||
// Apply the parent group's transform to all child elements
|
||||
for graphic_element in current_element.instance_mut_iter() {
|
||||
*graphic_element.transform = *current_instance.transform * *graphic_element.transform;
|
||||
}
|
||||
|
||||
flatten_group(output_group_table, current_element);
|
||||
}
|
||||
// Handle any leaf elements we encounter, which can be either non-GraphicGroup elements or GraphicGroups that we don't want to flatten
|
||||
GraphicElement::VectorData(vector_instance) => {
|
||||
for current_element in vector_instance.instance_ref_iter() {
|
||||
output_group_table.push(Instance {
|
||||
instance: current_element.instance.clone(),
|
||||
transform: *current_instance.transform * *current_element.transform,
|
||||
alpha_blending: AlphaBlending {
|
||||
opacity: current_instance.alpha_blending.opacity * current_element.alpha_blending.opacity,
|
||||
blend_mode: current_element.alpha_blending.blend_mode,
|
||||
},
|
||||
source_node_id: reference,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut output = VectorDataTable::default();
|
||||
flatten_group(&mut output, group);
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""))]
|
||||
async fn to_artboard<Data: Into<GraphicGroupTable> + 'n>(
|
||||
ctx: impl ExtractAll + CloneVarArgs + Ctx,
|
||||
|
|
|
|||
|
|
@ -921,6 +921,10 @@ impl GraphicElementRendered for RasterDataTable<CPU> {
|
|||
let subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE);
|
||||
click_targets.push(ClickTarget::new(subpath, 0.));
|
||||
}
|
||||
|
||||
fn to_graphic_element(&self) -> GraphicElement {
|
||||
GraphicElement::RasterDataCPU(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl GraphicElementRendered for RasterDataTable<GPU> {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,13 @@ impl<T> Instances<T> {
|
|||
self.source_node_id.push(instance.source_node_id);
|
||||
}
|
||||
|
||||
pub fn extend(&mut self, instances: Instances<T>) {
|
||||
self.instance.extend(instances.instance);
|
||||
self.transform.extend(instances.transform);
|
||||
self.alpha_blending.extend(instances.alpha_blending);
|
||||
self.source_node_id.extend(instances.source_node_id);
|
||||
}
|
||||
|
||||
pub fn instance_iter(self) -> impl DoubleEndedIterator<Item = Instance<T>> {
|
||||
self.instance
|
||||
.into_iter()
|
||||
|
|
|
|||
|
|
@ -44,12 +44,26 @@ async fn switch<T, C: Send + 'n + Clone>(
|
|||
condition: bool,
|
||||
#[expose]
|
||||
#[implementations(
|
||||
Context -> String, Context -> bool, Context -> f64, Context -> u32, Context -> u64, Context -> DVec2, Context -> VectorDataTable, Context -> DAffine2,
|
||||
Context -> String,
|
||||
Context -> bool,
|
||||
Context -> f64,
|
||||
Context -> u32,
|
||||
Context -> u64,
|
||||
Context -> DVec2,
|
||||
Context -> VectorDataTable,
|
||||
Context -> DAffine2,
|
||||
)]
|
||||
if_true: impl Node<C, Output = T>,
|
||||
#[expose]
|
||||
#[implementations(
|
||||
Context -> String, Context -> bool, Context -> f64, Context -> u32, Context -> u64, Context -> DVec2, Context -> VectorDataTable, Context -> DAffine2,
|
||||
Context -> String,
|
||||
Context -> bool,
|
||||
Context -> f64,
|
||||
Context -> u32,
|
||||
Context -> u64,
|
||||
Context -> DVec2,
|
||||
Context -> VectorDataTable,
|
||||
Context -> DAffine2,
|
||||
)]
|
||||
if_false: impl Node<C, Output = T>,
|
||||
) -> T {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,22 @@
|
|||
use crate::instances::{InstanceRef, Instances};
|
||||
use crate::raster_types::{CPU, RasterDataTable};
|
||||
use crate::transform::TransformMut;
|
||||
use crate::vector::VectorDataTable;
|
||||
use crate::{CloneVarArgs, Context, Ctx, ExtractAll, ExtractIndex, ExtractVarArgs, GraphicElement, GraphicGroupTable, OwnedContextImpl};
|
||||
use glam::DVec2;
|
||||
|
||||
#[node_macro::node(name("Instance on Points"), category("Instancing"), path(graphene_core::vector))]
|
||||
async fn instance_on_points<T: Into<GraphicElement> + Default + Clone + 'static>(
|
||||
async fn instance_on_points<T: Into<GraphicElement> + Default + Send + Clone + 'static>(
|
||||
ctx: impl ExtractAll + CloneVarArgs + Sync + Ctx,
|
||||
points: VectorDataTable,
|
||||
#[implementations(Context -> GraphicGroupTable, Context -> VectorDataTable, Context -> RasterDataTable<CPU>)] instance: impl Node<'n, Context<'static>, Output = Instances<T>>,
|
||||
#[implementations(
|
||||
Context -> GraphicGroupTable,
|
||||
Context -> VectorDataTable,
|
||||
Context -> RasterDataTable<CPU>
|
||||
)]
|
||||
instance: impl Node<'n, Context<'static>, Output = Instances<T>>,
|
||||
reverse: bool,
|
||||
) -> GraphicGroupTable {
|
||||
let mut result_table = GraphicGroupTable::default();
|
||||
) -> Instances<T> {
|
||||
let mut result_table = Instances::<T>::default();
|
||||
|
||||
for InstanceRef { instance: points, transform, .. } in points.instance_ref_iter() {
|
||||
let mut iteration = async |index, point| {
|
||||
|
|
@ -22,8 +26,8 @@ async fn instance_on_points<T: Into<GraphicElement> + Default + Clone + 'static>
|
|||
let generated_instance = instance.eval(new_ctx.into_context()).await;
|
||||
|
||||
for mut instanced in generated_instance.instance_iter() {
|
||||
instanced.transform.translate(transformed_point);
|
||||
result_table.push(instanced.to_graphic_element());
|
||||
instanced.transform.translation = transformed_point;
|
||||
result_table.push(instanced);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -43,15 +47,20 @@ async fn instance_on_points<T: Into<GraphicElement> + Default + Clone + 'static>
|
|||
}
|
||||
|
||||
#[node_macro::node(category("Instancing"), path(graphene_core::vector))]
|
||||
async fn instance_repeat<T: Into<GraphicElement> + Default + Clone + 'static>(
|
||||
async fn instance_repeat<T: Into<GraphicElement> + Default + Send + Clone + 'static>(
|
||||
ctx: impl ExtractAll + CloneVarArgs + Ctx,
|
||||
#[implementations(Context -> GraphicGroupTable, Context -> VectorDataTable, Context -> RasterDataTable<CPU>)] instance: impl Node<'n, Context<'static>, Output = Instances<T>>,
|
||||
#[implementations(
|
||||
Context -> GraphicGroupTable,
|
||||
Context -> VectorDataTable,
|
||||
Context -> RasterDataTable<CPU>
|
||||
)]
|
||||
instance: impl Node<'n, Context<'static>, Output = Instances<T>>,
|
||||
#[default(1)] count: u64,
|
||||
reverse: bool,
|
||||
) -> GraphicGroupTable {
|
||||
) -> Instances<T> {
|
||||
let count = count.max(1) as usize;
|
||||
|
||||
let mut result_table = GraphicGroupTable::default();
|
||||
let mut result_table = Instances::<T>::default();
|
||||
|
||||
for index in 0..count {
|
||||
let index = if reverse { count - index - 1 } else { index };
|
||||
|
|
@ -60,7 +69,7 @@ async fn instance_repeat<T: Into<GraphicElement> + Default + Clone + 'static>(
|
|||
let generated_instance = instance.eval(new_ctx.into_context()).await;
|
||||
|
||||
for instanced in generated_instance.instance_iter() {
|
||||
result_table.push(instanced.to_graphic_element());
|
||||
result_table.push(instanced);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -124,16 +133,7 @@ mod test {
|
|||
let repeated = super::instance_on_points(owned, points, &rect, false).await;
|
||||
assert_eq!(repeated.len(), positions.len());
|
||||
for (position, instanced) in positions.into_iter().zip(repeated.instance_ref_iter()) {
|
||||
let bounds = instanced
|
||||
.instance
|
||||
.as_vector_data()
|
||||
.unwrap()
|
||||
.instance_ref_iter()
|
||||
.next()
|
||||
.unwrap()
|
||||
.instance
|
||||
.bounding_box_with_transform(*instanced.transform)
|
||||
.unwrap();
|
||||
let bounds = instanced.instance.bounding_box_with_transform(*instanced.transform).unwrap();
|
||||
assert!(position.abs_diff_eq((bounds[0] + bounds[1]) / 2., 1e-10));
|
||||
assert_eq!((bounds[1] - bounds[0]).x, position.y);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use glam::{DAffine2, DVec2};
|
|||
use kurbo::{Affine, BezPath, Shape};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::f64::consts::TAU;
|
||||
|
||||
/// 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
|
||||
|
|
@ -201,7 +202,7 @@ where
|
|||
}
|
||||
|
||||
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||
async fn repeat<I: 'n + Send>(
|
||||
async fn repeat<I: 'n + Send + Clone>(
|
||||
_: impl Ctx,
|
||||
// TODO: Implement other GraphicElementRendered types.
|
||||
#[implementations(GraphicGroupTable, VectorDataTable, RasterDataTable<CPU>)] instance: Instances<I>,
|
||||
|
|
@ -210,78 +211,72 @@ async fn repeat<I: 'n + Send>(
|
|||
direction: PixelSize,
|
||||
angle: Angle,
|
||||
#[default(4)] instances: IntegerCount,
|
||||
) -> GraphicGroupTable
|
||||
) -> Instances<I>
|
||||
where
|
||||
Instances<I>: GraphicElementRendered,
|
||||
{
|
||||
let angle = angle.to_radians();
|
||||
let instances = instances.max(1);
|
||||
let total = (instances - 1) as f64;
|
||||
let count = instances.max(1);
|
||||
let total = (count - 1) as f64;
|
||||
|
||||
let mut result_table = GraphicGroupTable::default();
|
||||
let mut result_table = Instances::<I>::default();
|
||||
|
||||
let Some(bounding_box) = instance.bounding_box(DAffine2::IDENTITY, false) else {
|
||||
return result_table;
|
||||
};
|
||||
|
||||
let center = (bounding_box[0] + bounding_box[1]) / 2.;
|
||||
|
||||
for index in 0..instances {
|
||||
for index in 0..count {
|
||||
let angle = index as f64 * angle / total;
|
||||
let translation = index as f64 * direction / total;
|
||||
let transform = DAffine2::from_translation(center) * DAffine2::from_angle(angle) * DAffine2::from_translation(translation) * DAffine2::from_translation(-center);
|
||||
let transform = DAffine2::from_angle(angle) * DAffine2::from_translation(translation);
|
||||
|
||||
result_table.push(Instance {
|
||||
instance: instance.to_graphic_element().clone(),
|
||||
transform,
|
||||
alpha_blending: Default::default(),
|
||||
source_node_id: None,
|
||||
});
|
||||
for instance in instance.instance_ref_iter() {
|
||||
let mut instance = instance.to_instance_cloned();
|
||||
|
||||
let local_translation = DAffine2::from_translation(instance.transform.translation);
|
||||
let local_matrix = DAffine2::from_mat2(instance.transform.matrix2);
|
||||
instance.transform = local_translation * transform * local_matrix;
|
||||
|
||||
result_table.push(instance);
|
||||
}
|
||||
}
|
||||
|
||||
result_table
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||
async fn circular_repeat<I: 'n + Send>(
|
||||
async fn circular_repeat<I: 'n + Send + Clone>(
|
||||
_: impl Ctx,
|
||||
// TODO: Implement other GraphicElementRendered types.
|
||||
#[implementations(GraphicGroupTable, VectorDataTable, RasterDataTable<CPU>)] instance: Instances<I>,
|
||||
angle_offset: Angle,
|
||||
#[default(5)] radius: f64,
|
||||
#[default(5)] instances: IntegerCount,
|
||||
) -> GraphicGroupTable
|
||||
) -> Instances<I>
|
||||
where
|
||||
Instances<I>: GraphicElementRendered,
|
||||
{
|
||||
let instances = instances.max(1);
|
||||
let count = instances.max(1);
|
||||
|
||||
let mut result_table = GraphicGroupTable::default();
|
||||
let mut result_table = Instances::<I>::default();
|
||||
|
||||
let Some(bounding_box) = instance.bounding_box(DAffine2::IDENTITY, false) else {
|
||||
return result_table;
|
||||
};
|
||||
for index in 0..count {
|
||||
let angle = DAffine2::from_angle((TAU / count as f64) * index as f64 + angle_offset.to_radians());
|
||||
let translation = DAffine2::from_translation(radius * DVec2::Y);
|
||||
let transform = angle * translation;
|
||||
|
||||
let center = (bounding_box[0] + bounding_box[1]) / 2.;
|
||||
let base_transform = DVec2::new(0., radius) - center;
|
||||
for instance in instance.instance_ref_iter() {
|
||||
let mut instance = instance.to_instance_cloned();
|
||||
|
||||
for index in 0..instances {
|
||||
let rotation = DAffine2::from_angle((std::f64::consts::TAU / instances as f64) * index as f64 + angle_offset.to_radians());
|
||||
let transform = DAffine2::from_translation(center) * rotation * DAffine2::from_translation(base_transform);
|
||||
let local_translation = DAffine2::from_translation(instance.transform.translation);
|
||||
let local_matrix = DAffine2::from_mat2(instance.transform.matrix2);
|
||||
instance.transform = local_translation * transform * local_matrix;
|
||||
|
||||
result_table.push(Instance {
|
||||
instance: instance.to_graphic_element().clone(),
|
||||
transform,
|
||||
alpha_blending: Default::default(),
|
||||
source_node_id: None,
|
||||
});
|
||||
result_table.push(instance);
|
||||
}
|
||||
}
|
||||
|
||||
result_table
|
||||
}
|
||||
|
||||
#[node_macro::node(name("Copy to Points"), category("Vector"), path(graphene_core::vector))]
|
||||
async fn copy_to_points<I: 'n + Send>(
|
||||
async fn copy_to_points<I: 'n + Send + Clone>(
|
||||
_: impl Ctx,
|
||||
points: VectorDataTable,
|
||||
#[expose]
|
||||
|
|
@ -308,17 +303,14 @@ async fn copy_to_points<I: 'n + Send>(
|
|||
random_rotation: Angle,
|
||||
/// Seed to determine unique variations on all the randomized instance angles.
|
||||
random_rotation_seed: SeedValue,
|
||||
) -> GraphicGroupTable
|
||||
) -> Instances<I>
|
||||
where
|
||||
Instances<I>: GraphicElementRendered,
|
||||
{
|
||||
let mut result_table = GraphicGroupTable::default();
|
||||
let mut result_table = Instances::<I>::default();
|
||||
|
||||
let random_scale_difference = random_scale_max - random_scale_min;
|
||||
|
||||
let instance_bounding_box = instance.bounding_box(DAffine2::IDENTITY, false).unwrap_or_default();
|
||||
let instance_center = -0.5 * (instance_bounding_box[0] + instance_bounding_box[1]);
|
||||
|
||||
for point_instance in points.instance_iter() {
|
||||
let mut scale_rng = rand::rngs::StdRng::seed_from_u64(random_scale_seed.into());
|
||||
let mut rotation_rng = rand::rngs::StdRng::seed_from_u64(random_rotation_seed.into());
|
||||
|
|
@ -328,13 +320,11 @@ where
|
|||
|
||||
let points_transform = point_instance.transform;
|
||||
for &point in point_instance.instance.point_domain.positions() {
|
||||
let center_transform = DAffine2::from_translation(instance_center);
|
||||
|
||||
let translation = points_transform.transform_point2(point);
|
||||
|
||||
let rotation = if do_rotation {
|
||||
let degrees = (rotation_rng.random::<f64>() - 0.5) * random_rotation;
|
||||
degrees / 360. * std::f64::consts::TAU
|
||||
degrees / 360. * TAU
|
||||
} else {
|
||||
0.
|
||||
};
|
||||
|
|
@ -353,22 +343,23 @@ where
|
|||
random_scale_min
|
||||
};
|
||||
|
||||
let transform = DAffine2::from_scale_angle_translation(DVec2::splat(scale), rotation, translation) * center_transform;
|
||||
let transform = DAffine2::from_scale_angle_translation(DVec2::splat(scale), rotation, translation);
|
||||
|
||||
result_table.push(Instance {
|
||||
instance: instance.to_graphic_element().clone(),
|
||||
transform,
|
||||
alpha_blending: Default::default(),
|
||||
source_node_id: None,
|
||||
});
|
||||
for mut instance in instance.instance_ref_iter().map(|instance| instance.to_instance_cloned()) {
|
||||
let local_matrix = DAffine2::from_mat2(instance.transform.matrix2);
|
||||
instance.transform = transform * local_matrix;
|
||||
|
||||
result_table.push(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result_table
|
||||
}
|
||||
|
||||
// TODO: Make this node return Instances<I> instead of GraphicGroupTable, while preserving the current transform behavior as the `reference_point` and `offset` parameters are varied
|
||||
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||
async fn mirror<I: 'n + Send>(
|
||||
async fn mirror<I: 'n + Send + Clone>(
|
||||
_: impl Ctx,
|
||||
#[implementations(GraphicGroupTable, VectorDataTable, RasterDataTable<CPU>)] instance: Instances<I>,
|
||||
#[default(ReferencePoint::Center)] reference_point: ReferencePoint,
|
||||
|
|
@ -388,10 +379,13 @@ where
|
|||
let Some(bounding_box) = instance.bounding_box(DAffine2::IDENTITY, false) else {
|
||||
return result_table;
|
||||
};
|
||||
let mirror_reference_point = reference_point
|
||||
.point_in_bounding_box((bounding_box[0], bounding_box[1]).into())
|
||||
.unwrap_or_else(|| (bounding_box[0] + bounding_box[1]) / 2.)
|
||||
+ normal * offset;
|
||||
|
||||
// TODO: If the reference point is not None, use the current behavior but make it work correctly with local pivot origins of each Instances<I> row
|
||||
let reference_point_location = reference_point.point_in_bounding_box((bounding_box[0], bounding_box[1]).into()).unwrap_or_else(|| {
|
||||
// TODO: In this None case, use the input's local pivot origin point instead of a point relative to its bounding box
|
||||
(bounding_box[0] + bounding_box[1]) / 2.
|
||||
});
|
||||
let mirror_reference_point = reference_point_location + normal * offset;
|
||||
|
||||
// Create the reflection matrix
|
||||
let reflection = DAffine2::from_mat2_translation(
|
||||
|
|
@ -1164,9 +1158,12 @@ async fn solidify_stroke(_: impl Ctx, vector_data: VectorDataTable) -> VectorDat
|
|||
}
|
||||
|
||||
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||
async fn flatten_vector_elements(_: impl Ctx, graphic_group_input: GraphicGroupTable) -> VectorDataTable {
|
||||
async fn flatten_path<I: 'n + Send>(_: impl Ctx, #[implementations(GraphicGroupTable, VectorDataTable)] graphic_group_input: Instances<I>) -> VectorDataTable
|
||||
where
|
||||
Instances<I>: GraphicElementRendered,
|
||||
{
|
||||
// A node based solution to support passing through vector data could be a network node with a cache node connected to
|
||||
// a flatten vector elements connected to an if else node, another connection from the cache directly
|
||||
// a Flatten Path connected to an if else node, another connection from the cache directly
|
||||
// To the if else node, and another connection from the cache to a matches type node connected to the if else node.
|
||||
fn flatten_group(graphic_group_table: &GraphicGroupTable, output: &mut InstanceMut<VectorData>) {
|
||||
for (group_index, current_element) in graphic_group_table.instance_ref_iter().enumerate() {
|
||||
|
|
@ -1208,7 +1205,8 @@ async fn flatten_vector_elements(_: impl Ctx, graphic_group_input: GraphicGroupT
|
|||
};
|
||||
|
||||
// Flatten the graphic group input into the output VectorData instance
|
||||
flatten_group(&graphic_group_input, &mut output);
|
||||
let base_graphic_group = GraphicGroupTable::new(graphic_group_input.to_graphic_element());
|
||||
flatten_group(&base_graphic_group, &mut output);
|
||||
|
||||
// Return the single-row VectorDataTable containing the flattened VectorData subpaths
|
||||
output_table
|
||||
|
|
@ -1485,7 +1483,7 @@ async fn jitter_points(_: impl Ctx, vector_data: VectorDataTable, #[default(5.)]
|
|||
|
||||
let deltas = (0..vector_data_instance.instance.point_domain.positions().len())
|
||||
.map(|_| {
|
||||
let angle = rng.random::<f64>() * std::f64::consts::TAU;
|
||||
let angle = rng.random::<f64>() * TAU;
|
||||
|
||||
inverse_transform.transform_vector2(DVec2::from_angle(angle) * rng.random::<f64>() * amount)
|
||||
})
|
||||
|
|
@ -1859,7 +1857,7 @@ mod test {
|
|||
let direction = DVec2::X * 1.5;
|
||||
let instances = 3;
|
||||
let repeated = super::repeat(Footprint::default(), vector_node(Subpath::new_rect(DVec2::ZERO, DVec2::ONE)), direction, 0., instances).await;
|
||||
let vector_data = super::flatten_vector_elements(Footprint::default(), repeated).await;
|
||||
let vector_data = super::flatten_path(Footprint::default(), repeated).await;
|
||||
let vector_data = vector_data.instance_ref_iter().next().unwrap().instance;
|
||||
assert_eq!(vector_data.region_bezier_paths().count(), 3);
|
||||
for (index, (_, subpath)) in vector_data.region_bezier_paths().enumerate() {
|
||||
|
|
@ -1871,7 +1869,7 @@ mod test {
|
|||
let direction = DVec2::new(12., 10.);
|
||||
let instances = 8;
|
||||
let repeated = super::repeat(Footprint::default(), vector_node(Subpath::new_rect(DVec2::ZERO, DVec2::ONE)), direction, 0., instances).await;
|
||||
let vector_data = super::flatten_vector_elements(Footprint::default(), repeated).await;
|
||||
let vector_data = super::flatten_path(Footprint::default(), repeated).await;
|
||||
let vector_data = vector_data.instance_ref_iter().next().unwrap().instance;
|
||||
assert_eq!(vector_data.region_bezier_paths().count(), 8);
|
||||
for (index, (_, subpath)) in vector_data.region_bezier_paths().enumerate() {
|
||||
|
|
@ -1881,7 +1879,7 @@ mod test {
|
|||
#[tokio::test]
|
||||
async fn circular_repeat() {
|
||||
let repeated = super::circular_repeat(Footprint::default(), vector_node(Subpath::new_rect(DVec2::NEG_ONE, DVec2::ONE)), 45., 4., 8).await;
|
||||
let vector_data = super::flatten_vector_elements(Footprint::default(), repeated).await;
|
||||
let vector_data = super::flatten_path(Footprint::default(), repeated).await;
|
||||
let vector_data = vector_data.instance_ref_iter().next().unwrap().instance;
|
||||
assert_eq!(vector_data.region_bezier_paths().count(), 8);
|
||||
|
||||
|
|
@ -1927,8 +1925,8 @@ mod test {
|
|||
let expected_points = VectorData::from_subpath(points.clone()).point_domain.positions().to_vec();
|
||||
|
||||
let copy_to_points = super::copy_to_points(Footprint::default(), vector_node(points), vector_node(instance), 1., 1., 0., 0, 0., 0).await;
|
||||
let flatten_vector_elements = super::flatten_vector_elements(Footprint::default(), copy_to_points).await;
|
||||
let flattened_copy_to_points = flatten_vector_elements.instance_ref_iter().next().unwrap().instance;
|
||||
let flatten_path = super::flatten_path(Footprint::default(), copy_to_points).await;
|
||||
let flattened_copy_to_points = flatten_path.instance_ref_iter().next().unwrap().instance;
|
||||
|
||||
assert_eq!(flattened_copy_to_points.region_bezier_paths().count(), expected_points.len());
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Vec<graphene_core::uuid::NodeId>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::Color]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Box<graphene_core::vector::VectorModification>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::CentroidType]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Image<Color>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => VectorDataTable]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => RasterDataTable<CPU>]),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue