Refactor some vector nodes to use loops instead of one_instance, as a start to #1834 part 6
This commit is contained in:
parent
a6ff221c1e
commit
db34ac3f53
|
|
@ -760,7 +760,15 @@ async fn gradient_map<T: Adjust<Color>>(
|
|||
//
|
||||
// Algorithm based on:
|
||||
// https://stackoverflow.com/questions/33966121/what-is-the-algorithm-for-vibrance-filters
|
||||
// The results of this implementation are very close to correct, but not quite perfect
|
||||
// The results of this implementation are very close to correct, but not quite perfect.
|
||||
//
|
||||
// A bit of additional analysis can be found at here:
|
||||
// https://www.photo-mark.com/notes/analyzing-photoshop-vibrance-and-saturation/
|
||||
//
|
||||
// This algorithm is currently lacking a "Saturation" parameter which is needed for interoperability.
|
||||
// It's not the same as the saturation component of Hue/Saturation/Value. Vibrance and Saturation are both separable.
|
||||
// When both parameters are set, it is equivalent to running this adjustment twice, with only vibrance set and then only saturation set.
|
||||
// (Except for some noise probably due to rounding error.)
|
||||
#[node_macro::node(category("Raster: Adjustment"))]
|
||||
async fn vibrance<T: Adjust<Color>>(
|
||||
_: impl Ctx,
|
||||
|
|
|
|||
|
|
@ -446,8 +446,13 @@ async fn round_corners(
|
|||
) -> VectorDataTable {
|
||||
let source_transform = source.transform();
|
||||
let source_transform_inverse = source_transform.inverse();
|
||||
let source = source.one_instance_ref().instance;
|
||||
let upstream_graphics_group = source.upstream_graphic_group.clone();
|
||||
|
||||
let mut result_table = VectorDataTable::empty();
|
||||
|
||||
for source in source.instance_ref_iter() {
|
||||
let source = source.instance;
|
||||
|
||||
let upstream_graphic_group = source.upstream_graphic_group.clone();
|
||||
|
||||
// Flip the roundness to help with user intuition
|
||||
let roundness = 1. - roundness;
|
||||
|
|
@ -531,9 +536,16 @@ async fn round_corners(
|
|||
result.append_subpath(rounded_subpath, false);
|
||||
}
|
||||
|
||||
result.upstream_graphic_group = upstream_graphics_group;
|
||||
let mut result_table = VectorDataTable::new(result);
|
||||
*result_table.transform_mut() = source_transform;
|
||||
result.upstream_graphic_group = upstream_graphic_group;
|
||||
|
||||
result_table.push(Instance {
|
||||
instance: result,
|
||||
transform: source_transform,
|
||||
alpha_blending: Default::default(),
|
||||
source_node_id: None,
|
||||
});
|
||||
}
|
||||
|
||||
result_table
|
||||
}
|
||||
|
||||
|
|
@ -545,8 +557,12 @@ async fn spatial_merge_by_distance(
|
|||
#[hard_min(0.0001)]
|
||||
distance: f64,
|
||||
) -> VectorDataTable {
|
||||
let vector_data_transform = vector_data.transform();
|
||||
let vector_data = vector_data.one_instance_ref().instance;
|
||||
let mut result_table = VectorDataTable::empty();
|
||||
|
||||
for vector_data in vector_data.instance_ref_iter() {
|
||||
let vector_data_transform = *vector_data.transform;
|
||||
let vector_data = vector_data.instance;
|
||||
|
||||
let point_count = vector_data.point_domain.positions().len();
|
||||
|
||||
// Find min x and y for grid cell normalization
|
||||
|
|
@ -659,18 +675,28 @@ async fn spatial_merge_by_distance(
|
|||
result.segment_domain = new_segment_domain;
|
||||
|
||||
// Create and return the result
|
||||
let mut result_table = VectorDataTable::new(result);
|
||||
*result_table.transform_mut() = vector_data_transform;
|
||||
result_table.push(Instance {
|
||||
instance: result,
|
||||
transform: vector_data_transform,
|
||||
alpha_blending: Default::default(),
|
||||
source_node_id: None,
|
||||
});
|
||||
}
|
||||
|
||||
result_table
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Debug"), path(graphene_core::vector))]
|
||||
async fn box_warp(_: impl Ctx, vector_data: VectorDataTable, #[expose] rectangle: VectorDataTable) -> VectorDataTable {
|
||||
let vector_data_transform = vector_data.transform();
|
||||
let vector_data = vector_data.one_instance_ref().instance.clone();
|
||||
let Some((target, target_transform)) = rectangle.get(0).map(|rect| (rect.instance, rect.transform)) else {
|
||||
return vector_data;
|
||||
};
|
||||
|
||||
let target_transform = rectangle.transform();
|
||||
let target = rectangle.one_instance_ref().instance;
|
||||
let mut result_table = VectorDataTable::empty();
|
||||
|
||||
for vector_data in vector_data.instance_ref_iter() {
|
||||
let vector_data_transform = *vector_data.transform;
|
||||
let vector_data = vector_data.instance;
|
||||
|
||||
// Get the bounding box of the source vector data
|
||||
let source_bbox = vector_data.bounding_box_with_transform(vector_data_transform).unwrap_or([DVec2::ZERO, DVec2::ONE]);
|
||||
|
|
@ -727,11 +753,14 @@ async fn box_warp(_: impl Ctx, vector_data: VectorDataTable, #[expose] rectangle
|
|||
|
||||
result.style.set_stroke_transform(DAffine2::IDENTITY);
|
||||
|
||||
// Create a new VectorDataTable with the result
|
||||
let mut result_table = VectorDataTable::new(result);
|
||||
|
||||
// Reset the transform since we've applied it directly to the points
|
||||
*result_table.transform_mut() = DAffine2::IDENTITY;
|
||||
// Add this to the table and reset the transform since we've applied it directly to the points
|
||||
result_table.push(Instance {
|
||||
instance: result,
|
||||
transform: DAffine2::IDENTITY,
|
||||
alpha_blending: Default::default(),
|
||||
source_node_id: None,
|
||||
});
|
||||
}
|
||||
|
||||
result_table
|
||||
}
|
||||
|
|
@ -755,8 +784,11 @@ async fn remove_handles(
|
|||
#[soft_min(0.)]
|
||||
max_handle_distance: f64,
|
||||
) -> VectorDataTable {
|
||||
let vector_data_transform = vector_data.transform();
|
||||
let mut vector_data = vector_data.one_instance_ref().instance.clone();
|
||||
let mut result_table = VectorDataTable::empty();
|
||||
|
||||
for vector_data in vector_data.instance_iter() {
|
||||
let vector_data_transform = vector_data.transform;
|
||||
let mut vector_data = vector_data.instance;
|
||||
|
||||
for (_, handles, start, end) in vector_data.segment_domain.handles_mut() {
|
||||
// Only convert to linear if handles are within the threshold distance
|
||||
|
|
@ -788,9 +820,15 @@ async fn remove_handles(
|
|||
}
|
||||
}
|
||||
|
||||
let mut result = VectorDataTable::new(vector_data);
|
||||
*result.transform_mut() = vector_data_transform;
|
||||
result
|
||||
result_table.push(Instance {
|
||||
instance: vector_data,
|
||||
transform: vector_data_transform,
|
||||
alpha_blending: Default::default(),
|
||||
source_node_id: None,
|
||||
});
|
||||
}
|
||||
|
||||
result_table
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||
|
|
@ -801,8 +839,11 @@ async fn generate_handles(
|
|||
#[range((0., 1.))]
|
||||
curvature: f64,
|
||||
) -> VectorDataTable {
|
||||
let source_transform = source.transform();
|
||||
let source = source.one_instance_ref().instance;
|
||||
let mut result_table = VectorDataTable::empty();
|
||||
|
||||
for source in source.instance_ref_iter() {
|
||||
let source_transform = *source.transform;
|
||||
let source = source.instance;
|
||||
|
||||
let mut result = VectorData::empty();
|
||||
result.style = source.style.clone();
|
||||
|
|
@ -872,8 +913,14 @@ async fn generate_handles(
|
|||
result.append_subpath(softened_subpath, true);
|
||||
}
|
||||
|
||||
let mut result_table = VectorDataTable::new(result);
|
||||
*result_table.transform_mut() = source_transform;
|
||||
result_table.push(Instance {
|
||||
instance: result,
|
||||
transform: source_transform,
|
||||
alpha_blending: Default::default(),
|
||||
source_node_id: None,
|
||||
});
|
||||
}
|
||||
|
||||
result_table
|
||||
}
|
||||
|
||||
|
|
@ -887,37 +934,6 @@ async fn generate_handles(
|
|||
// #[soft_max(8.)]
|
||||
// subdivisions: f64,
|
||||
// ) -> VectorDataTable {
|
||||
// let source_transform = source.transform();
|
||||
// let source_vector_data = source.one_instance().instance;
|
||||
// let subdivisions = subdivisions as usize;
|
||||
|
||||
// let mut result = VectorData::empty();
|
||||
// result.style = source_vector_data.style.clone();
|
||||
|
||||
// for mut subpath in source_vector_data.stroke_bezier_paths() {
|
||||
// subpath.apply_transform(source_transform);
|
||||
|
||||
// if subpath.manipulator_groups().len() < 2 {
|
||||
// // Not enough points to subdivide
|
||||
// result.append_subpath(subpath, true);
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// // Apply subdivisions recursively
|
||||
// let mut current_subpath = subpath;
|
||||
// for _ in 0..subdivisions {
|
||||
// current_subpath = subdivide_once(¤t_subpath);
|
||||
// }
|
||||
|
||||
// current_subpath.apply_transform(source_transform.inverse());
|
||||
// result.append_subpath(current_subpath, true);
|
||||
// }
|
||||
|
||||
// let mut result_table = VectorDataTable::new(result);
|
||||
// *result_table.transform_mut() = source_transform;
|
||||
// result_table
|
||||
// }
|
||||
|
||||
// fn subdivide_once(subpath: &Subpath<PointId>) -> Subpath<PointId> {
|
||||
// let original_groups = subpath.manipulator_groups();
|
||||
// let mut new_groups = Vec::new();
|
||||
|
|
@ -936,7 +952,7 @@ async fn generate_handles(
|
|||
// let current_bezier = original_groups[start_idx].to_bezier(&original_groups[end_idx]);
|
||||
|
||||
// // Create modified start point with original ID, but updated in_handle & out_handle
|
||||
// let mut start_point = original_groups[start_idx].clone();
|
||||
// let mut start_point = original_groups[start_idx];
|
||||
// let [first, _] = current_bezier.split(TValue::Euclidean(0.5));
|
||||
// start_point.out_handle = first.handle_start();
|
||||
// start_point.in_handle = last_in_handle;
|
||||
|
|
@ -966,7 +982,7 @@ async fn generate_handles(
|
|||
|
||||
// // Handle the final point for open paths
|
||||
// if !is_closed && !original_groups.is_empty() {
|
||||
// let mut last_point = original_groups.last().unwrap().clone();
|
||||
// let mut last_point = *original_groups.last().unwrap();
|
||||
// last_point.in_handle = last_in_handle;
|
||||
// if new_groups.contains(&last_point) {
|
||||
// debug!("last_point already in");
|
||||
|
|
@ -981,10 +997,50 @@ async fn generate_handles(
|
|||
// Subpath::new(new_groups, is_closed)
|
||||
// }
|
||||
|
||||
// let mut result_table = VectorDataTable::empty();
|
||||
|
||||
// for source_vector_data in source.instances() {
|
||||
// let source_transform = *source_vector_data.transform;
|
||||
// let source_vector_data = source_vector_data.instance;
|
||||
|
||||
// let subdivisions = subdivisions as usize;
|
||||
|
||||
// let mut result = VectorData::empty();
|
||||
// result.style = source_vector_data.style.clone();
|
||||
|
||||
// for mut subpath in source_vector_data.stroke_bezier_paths() {
|
||||
// subpath.apply_transform(source_transform);
|
||||
|
||||
// if subpath.manipulator_groups().len() < 2 {
|
||||
// // Not enough points to subdivide
|
||||
// result.append_subpath(subpath, true);
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// // Apply subdivisions recursively
|
||||
// let mut current_subpath = subpath;
|
||||
// for _ in 0..subdivisions {
|
||||
// current_subpath = subdivide_once(¤t_subpath);
|
||||
// }
|
||||
|
||||
// current_subpath.apply_transform(source_transform.inverse());
|
||||
// result.append_subpath(current_subpath, true);
|
||||
// }
|
||||
|
||||
// let pushed = result_table.push(result);
|
||||
// *pushed.transform = source_transform;
|
||||
// }
|
||||
|
||||
// result_table
|
||||
// }
|
||||
|
||||
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||
async fn bounding_box(_: impl Ctx, vector_data: VectorDataTable) -> VectorDataTable {
|
||||
let vector_data_transform = vector_data.transform();
|
||||
let vector_data = vector_data.one_instance_ref().instance;
|
||||
let mut result_table = VectorDataTable::empty();
|
||||
|
||||
for vector_data in vector_data.instance_ref_iter() {
|
||||
let vector_data_transform = *vector_data.transform;
|
||||
let vector_data = vector_data.instance;
|
||||
|
||||
let mut result = vector_data
|
||||
.bounding_box()
|
||||
|
|
@ -993,25 +1049,34 @@ async fn bounding_box(_: impl Ctx, vector_data: VectorDataTable) -> VectorDataTa
|
|||
result.style = vector_data.style.clone();
|
||||
result.style.set_stroke_transform(DAffine2::IDENTITY);
|
||||
|
||||
let mut result = VectorDataTable::new(result);
|
||||
*result.transform_mut() = vector_data_transform;
|
||||
result
|
||||
result_table.push(Instance {
|
||||
instance: result,
|
||||
transform: vector_data_transform,
|
||||
alpha_blending: Default::default(),
|
||||
source_node_id: None,
|
||||
});
|
||||
}
|
||||
|
||||
result_table
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||
async fn dimensions(_: impl Ctx, vector_data: VectorDataTable) -> DVec2 {
|
||||
let vector_data_transform = vector_data.transform();
|
||||
let vector_data = vector_data.one_instance_ref().instance;
|
||||
vector_data
|
||||
.bounding_box_with_transform(vector_data_transform)
|
||||
.instance_ref_iter()
|
||||
.filter_map(|vector_data| vector_data.instance.bounding_box_with_transform(*vector_data.transform))
|
||||
.reduce(|[acc_top_left, acc_bottom_right], [top_left, bottom_right]| [acc_top_left.min(top_left), acc_bottom_right.max(bottom_right)])
|
||||
.map(|[top_left, bottom_right]| bottom_right - top_left)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Vector"), path(graphene_core::vector), properties("offset_path_properties"))]
|
||||
async fn offset_path(_: impl Ctx, vector_data: VectorDataTable, distance: f64, line_join: LineJoin, #[default(4.)] miter_limit: f64) -> VectorDataTable {
|
||||
let vector_data_transform = vector_data.transform();
|
||||
let vector_data = vector_data.one_instance_ref().instance;
|
||||
let mut result_table = VectorDataTable::empty();
|
||||
|
||||
for vector_data in vector_data.instance_ref_iter() {
|
||||
let vector_data_transform = *vector_data.transform;
|
||||
let vector_data = vector_data.instance;
|
||||
|
||||
let subpaths = vector_data.stroke_bezier_paths();
|
||||
let mut result = VectorData::empty();
|
||||
|
|
@ -1039,15 +1104,24 @@ async fn offset_path(_: impl Ctx, vector_data: VectorDataTable, distance: f64, l
|
|||
result.append_subpath(subpath_out, false);
|
||||
}
|
||||
|
||||
let mut result = VectorDataTable::new(result);
|
||||
*result.transform_mut() = vector_data_transform;
|
||||
result
|
||||
result_table.push(Instance {
|
||||
instance: result,
|
||||
transform: vector_data_transform,
|
||||
alpha_blending: Default::default(),
|
||||
source_node_id: None,
|
||||
});
|
||||
}
|
||||
|
||||
result_table
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||
async fn solidify_stroke(_: impl Ctx, vector_data: VectorDataTable) -> VectorDataTable {
|
||||
let vector_data_transform = vector_data.transform();
|
||||
let vector_data = vector_data.one_instance_ref().instance;
|
||||
let mut result_table = VectorDataTable::empty();
|
||||
|
||||
for vector_data in vector_data.instance_ref_iter() {
|
||||
let vector_data_transform = *vector_data.transform;
|
||||
let vector_data = vector_data.instance;
|
||||
|
||||
let stroke = vector_data.style.stroke().clone().unwrap_or_default();
|
||||
let bezpaths = vector_data.stroke_bezpath_iter();
|
||||
|
|
@ -1090,9 +1164,15 @@ async fn solidify_stroke(_: impl Ctx, vector_data: VectorDataTable) -> VectorDat
|
|||
result.style.set_stroke(Stroke::default());
|
||||
}
|
||||
|
||||
let mut result = VectorDataTable::new(result);
|
||||
*result.transform_mut() = vector_data_transform;
|
||||
result
|
||||
result_table.push(Instance {
|
||||
instance: result,
|
||||
transform: vector_data_transform,
|
||||
alpha_blending: Default::default(),
|
||||
source_node_id: None,
|
||||
});
|
||||
}
|
||||
|
||||
result_table
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||
|
|
|
|||
Loading…
Reference in New Issue