mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 14:18:04 +08:00
Implement dynamic table attributes to generalize the graphic-specific Table type (#4050)
* Feature-gate serde derives behind cfg_attr in all runtime node graph type crates * Refactor Table to move its hard-coded fields into an attributes field * Encapsulate TableRow/TableRowRef/TableRowMut attribute fields behind accessor methods * Remove TaggedValue::GraphicUnused * Refactor Table<T> to use dynamic attributes instead fixed names * Fix code review soundness concerns * Add todo work * Replace row-oriented Table<T> API with column-oriented access * Fix attribute propagation bugs ---------
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use crate::gcore::Context;
|
||||
use core::f64::consts::TAU;
|
||||
use core_types::registry::types::{Angle, PixelSize};
|
||||
use core_types::table::{Table, TableRowRef};
|
||||
use core_types::table::Table;
|
||||
use core_types::{CloneVarArgs, Color, Ctx, ExtractAll, InjectVarArgs, OwnedContextImpl};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphic_types::{Graphic, Vector};
|
||||
@@ -77,12 +77,13 @@ pub async fn repeat_array<T: Into<Graphic> + Default + Send + Clone + 'static>(
|
||||
let new_ctx = OwnedContextImpl::from(ctx.clone()).with_index(index as usize);
|
||||
let generated_instance = instance.eval(new_ctx.into_context()).await;
|
||||
|
||||
for row in generated_instance.iter() {
|
||||
let mut row = row.into_cloned();
|
||||
for row_index in 0..generated_instance.len() {
|
||||
let Some(mut row) = generated_instance.clone_row(row_index) else { continue };
|
||||
|
||||
let local_translation = DAffine2::from_translation(row.transform.translation);
|
||||
let local_matrix = DAffine2::from_mat2(row.transform.matrix2);
|
||||
row.transform = local_translation * transform * local_matrix;
|
||||
let local_transform: DAffine2 = row.attribute_cloned_or_default("transform");
|
||||
let local_translation = DAffine2::from_translation(local_transform.translation);
|
||||
let local_matrix = DAffine2::from_mat2(local_transform.matrix2);
|
||||
*row.attribute_mut_or_insert_default("transform") = local_translation * transform * local_matrix;
|
||||
|
||||
result_table.push(row);
|
||||
}
|
||||
@@ -122,12 +123,13 @@ async fn repeat_radial<T: Into<Graphic> + Default + Send + Clone + 'static>(
|
||||
let new_ctx = OwnedContextImpl::from(ctx.clone()).with_index(index as usize);
|
||||
let generated_instance = instance.eval(new_ctx.into_context()).await;
|
||||
|
||||
for row in generated_instance.iter() {
|
||||
let mut row = row.into_cloned();
|
||||
for row_index in 0..generated_instance.len() {
|
||||
let Some(mut row) = generated_instance.clone_row(row_index) else { continue };
|
||||
|
||||
let local_translation = DAffine2::from_translation(row.transform.translation);
|
||||
let local_matrix = DAffine2::from_mat2(row.transform.matrix2);
|
||||
row.transform = local_translation * transform * local_matrix;
|
||||
let local_transform: DAffine2 = row.attribute_cloned_or_default("transform");
|
||||
let local_translation = DAffine2::from_translation(local_transform.translation);
|
||||
let local_matrix = DAffine2::from_mat2(local_transform.matrix2);
|
||||
*row.attribute_mut_or_insert_default("transform") = local_translation * transform * local_matrix;
|
||||
|
||||
result_table.push(row);
|
||||
}
|
||||
@@ -152,7 +154,10 @@ async fn repeat_on_points<T: Into<Graphic> + Default + Send + Clone + 'static>(
|
||||
) -> Table<T> {
|
||||
let mut result_table = Table::new();
|
||||
|
||||
for TableRowRef { element: points, transform, .. } in points.iter() {
|
||||
for points_index in 0..points.len() {
|
||||
let Some(points_element) = points.element(points_index) else { continue };
|
||||
let transform: DAffine2 = points.attribute_cloned_or_default("transform", points_index);
|
||||
|
||||
let mut iteration = async |index, point| {
|
||||
let transformed_point = transform.transform_point2(point);
|
||||
|
||||
@@ -160,12 +165,12 @@ async fn repeat_on_points<T: Into<Graphic> + Default + Send + Clone + 'static>(
|
||||
let generated_instance = instance.eval(new_ctx.into_context()).await;
|
||||
|
||||
for mut generated_row in generated_instance.into_iter() {
|
||||
generated_row.transform.translation = transformed_point;
|
||||
generated_row.attribute_mut_or_insert_default::<DAffine2>("transform").translation = transformed_point;
|
||||
result_table.push(generated_row);
|
||||
}
|
||||
};
|
||||
|
||||
let range = points.point_domain.positions().iter().enumerate();
|
||||
let range = points_element.point_domain.positions().iter().enumerate();
|
||||
if reverse {
|
||||
for (index, &point) in range.rev() {
|
||||
iteration(index, point).await;
|
||||
@@ -228,8 +233,12 @@ mod test {
|
||||
let points = Table::new_from_element(Vector::from_subpath(Subpath::from_anchors(positions, false)));
|
||||
let generated = super::repeat_on_points(context, points, &rect, false).await;
|
||||
assert_eq!(generated.len(), positions.len());
|
||||
for (position, generated_row) in positions.into_iter().zip(generated.iter()) {
|
||||
let bounds = generated_row.element.bounding_box_with_transform(*generated_row.transform).unwrap();
|
||||
for (position, index) in positions.into_iter().zip(0..generated.len()) {
|
||||
let bounds = generated
|
||||
.element(index)
|
||||
.unwrap()
|
||||
.bounding_box_with_transform(generated.attribute_cloned_or_default("transform", index))
|
||||
.unwrap();
|
||||
assert!(position.abs_diff_eq((bounds[0] + bounds[1]) / 2., 1e-10));
|
||||
assert_eq!((bounds[1] - bounds[0]).x, position.y);
|
||||
}
|
||||
@@ -249,7 +258,7 @@ mod test {
|
||||
)
|
||||
.await;
|
||||
let vector_table = vector_nodes::flatten_path(Footprint::default(), repeated).await;
|
||||
let vector = vector_table.iter().next().unwrap().element;
|
||||
let vector = vector_table.element(0).unwrap();
|
||||
assert_eq!(vector.region_manipulator_groups().count(), 3);
|
||||
for (index, (_, manipulator_groups)) in vector.region_manipulator_groups().enumerate() {
|
||||
assert!((manipulator_groups[0].anchor - direction * index as f64 / (count - 1) as f64).length() < 1e-5);
|
||||
@@ -270,7 +279,7 @@ mod test {
|
||||
)
|
||||
.await;
|
||||
let vector_table = vector_nodes::flatten_path(Footprint::default(), repeated).await;
|
||||
let vector = vector_table.iter().next().unwrap().element;
|
||||
let vector = vector_table.element(0).unwrap();
|
||||
assert_eq!(vector.region_manipulator_groups().count(), 8);
|
||||
for (index, (_, manipulator_groups)) in vector.region_manipulator_groups().enumerate() {
|
||||
assert!((manipulator_groups[0].anchor - direction * index as f64 / (count - 1) as f64).length() < 1e-5);
|
||||
@@ -282,7 +291,7 @@ mod test {
|
||||
let context = OwnedContextImpl::default().into_context();
|
||||
let repeated = super::repeat_radial(context, &FutureWrapperNode(vector_node_from_bezpath(Rect::new(-1., -1., 1., 1.).to_path(DEFAULT_ACCURACY))), 45., 4., 8).await;
|
||||
let vector_table = vector_nodes::flatten_path(Footprint::default(), repeated).await;
|
||||
let vector = vector_table.iter().next().unwrap().element;
|
||||
let vector = vector_table.element(0).unwrap();
|
||||
assert_eq!(vector.region_manipulator_groups().count(), 8);
|
||||
|
||||
for (index, (_, manipulator_groups)) in vector.region_manipulator_groups().enumerate() {
|
||||
|
||||
Reference in New Issue
Block a user