Make Table<T> implement the IntoIterator trait

This commit is contained in:
Keavon Chambers
2025-08-04 15:20:48 -07:00
parent 7cb42b9523
commit 4b11dced48
23 changed files with 209 additions and 182 deletions
@@ -288,7 +288,7 @@ impl<T: TableRowLayout> TableRowLayout for Table<T> {
} }
let mut rows = self let mut rows = self
.iter_ref() .iter()
.enumerate() .enumerate()
.map(|(index, row)| { .map(|(index, row)| {
let (scale, angle, translation) = row.transform.to_scale_angle_translation(); let (scale, angle, translation) = row.transform.to_scale_angle_translation();
+1 -1
View File
@@ -316,7 +316,7 @@ impl NodeRuntime {
} else if let Some(record) = introspected_data.downcast_ref::<IORecord<Context, Table<Vector>>>() { } else if let Some(record) = introspected_data.downcast_ref::<IORecord<Context, Table<Vector>>>() {
let default = TableRow::default(); let default = TableRow::default();
self.vector_modify self.vector_modify
.insert(parent_network_node_id, record.output.iter_ref().next().unwrap_or_else(|| default.as_ref()).element.clone()); .insert(parent_network_node_id, record.output.iter().next().unwrap_or_else(|| default.as_ref()).element.clone());
} else { } else {
log::warn!("Failed to downcast monitor node output {parent_network_node_id:?}"); log::warn!("Failed to downcast monitor node output {parent_network_node_id:?}");
} }
+7 -7
View File
@@ -130,7 +130,7 @@ where
pub async fn create_brush_texture(brush_style: &BrushStyle) -> Raster<CPU> { pub async fn create_brush_texture(brush_style: &BrushStyle) -> Raster<CPU> {
let stamp = brush_stamp_generator(brush_style.diameter, brush_style.color, brush_style.hardness, brush_style.flow); let stamp = brush_stamp_generator(brush_style.diameter, brush_style.color, brush_style.hardness, brush_style.flow);
let transform = DAffine2::from_scale_angle_translation(DVec2::splat(brush_style.diameter), 0., -DVec2::splat(brush_style.diameter / 2.)); let transform = DAffine2::from_scale_angle_translation(DVec2::splat(brush_style.diameter), 0., -DVec2::splat(brush_style.diameter / 2.));
let blank_texture = empty_image((), transform, Color::TRANSPARENT).iter().next().unwrap_or_default(); let blank_texture = empty_image((), transform, Color::TRANSPARENT).into_iter().next().unwrap_or_default();
let image = blend_stamp_closure(stamp, blank_texture, |a, b| blend_colors(a, b, BlendMode::Normal, 1.)); let image = blend_stamp_closure(stamp, blank_texture, |a, b| blend_colors(a, b, BlendMode::Normal, 1.));
image.element image.element
@@ -184,7 +184,7 @@ async fn brush(_: impl Ctx, mut image_frame_table: Table<Raster<CPU>>, strokes:
image_frame_table.push(TableRow::default()); image_frame_table.push(TableRow::default());
} }
// TODO: Find a way to handle more than one row // TODO: Find a way to handle more than one row
let table_row = image_frame_table.iter_ref().next().expect("Expected the one row we just pushed").into_cloned(); let table_row = image_frame_table.iter().next().expect("Expected the one row we just pushed").into_cloned();
let [start, end] = Table::new_from_row(table_row.clone()).bounding_box(DAffine2::IDENTITY, false).unwrap_or([DVec2::ZERO, DVec2::ZERO]); let [start, end] = Table::new_from_row(table_row.clone()).bounding_box(DAffine2::IDENTITY, false).unwrap_or([DVec2::ZERO, DVec2::ZERO]);
let image_bbox = AxisAlignedBbox { start, end }; let image_bbox = AxisAlignedBbox { start, end };
@@ -198,7 +198,7 @@ async fn brush(_: impl Ctx, mut image_frame_table: Table<Raster<CPU>>, strokes:
let mut brush_plan = cache.compute_brush_plan(table_row, &draw_strokes); let mut brush_plan = cache.compute_brush_plan(table_row, &draw_strokes);
// TODO: Find a way to handle more than one row // TODO: Find a way to handle more than one row
let Some(mut actual_image) = extend_image_to_bounds((), Table::new_from_row(brush_plan.background), background_bounds).iter().next() else { let Some(mut actual_image) = extend_image_to_bounds((), Table::new_from_row(brush_plan.background), background_bounds).into_iter().next() else {
return Table::new(); return Table::new();
}; };
@@ -246,7 +246,7 @@ async fn brush(_: impl Ctx, mut image_frame_table: Table<Raster<CPU>>, strokes:
let table = blit_node.eval(blit_target).await; let table = blit_node.eval(blit_target).await;
assert_eq!(table.len(), 1); assert_eq!(table.len(), 1);
table.iter().next().unwrap_or_default() table.into_iter().next().unwrap_or_default()
}; };
// Cache image before doing final blend, and store final stroke texture. // Cache image before doing final blend, and store final stroke texture.
@@ -285,7 +285,7 @@ async fn brush(_: impl Ctx, mut image_frame_table: Table<Raster<CPU>>, strokes:
FutureWrapperNode::new(ClonedNode::new(positions)), FutureWrapperNode::new(ClonedNode::new(positions)),
FutureWrapperNode::new(ClonedNode::new(blend_params)), FutureWrapperNode::new(ClonedNode::new(blend_params)),
); );
erase_restore_mask = blit_node.eval(Table::new_from_row(erase_restore_mask)).await.iter().next().unwrap_or_default(); erase_restore_mask = blit_node.eval(Table::new_from_row(erase_restore_mask)).await.into_iter().next().unwrap_or_default();
} }
// Yes, this is essentially the same as the above, but we duplicate to inline the blend mode. // Yes, this is essentially the same as the above, but we duplicate to inline the blend mode.
BlendMode::Restore => { BlendMode::Restore => {
@@ -295,7 +295,7 @@ async fn brush(_: impl Ctx, mut image_frame_table: Table<Raster<CPU>>, strokes:
FutureWrapperNode::new(ClonedNode::new(positions)), FutureWrapperNode::new(ClonedNode::new(positions)),
FutureWrapperNode::new(ClonedNode::new(blend_params)), FutureWrapperNode::new(ClonedNode::new(blend_params)),
); );
erase_restore_mask = blit_node.eval(Table::new_from_row(erase_restore_mask)).await.iter().next().unwrap_or_default(); erase_restore_mask = blit_node.eval(Table::new_from_row(erase_restore_mask)).await.into_iter().next().unwrap_or_default();
} }
_ => unreachable!(), _ => unreachable!(),
} }
@@ -406,6 +406,6 @@ mod test {
BrushCache::default(), BrushCache::default(),
) )
.await; .await;
assert_eq!(image.iter_ref().next().unwrap().element.width, 20); assert_eq!(image.iter().next().unwrap().element.width, 20);
} }
} }
+1 -1
View File
@@ -90,7 +90,7 @@ pub fn migrate_artboard_group<'de, D: serde::Deserializer<'de>>(deserializer: D)
impl BoundingBox for Table<Artboard> { impl BoundingBox for Table<Artboard> {
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> { fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
self.iter_ref().filter_map(|row| row.element.bounding_box(transform, include_stroke)).reduce(Quad::combine_bounds) self.iter().filter_map(|row| row.element.bounding_box(transform, include_stroke)).reduce(Quad::combine_bounds)
} }
} }
+11 -11
View File
@@ -155,16 +155,16 @@ impl Graphic {
pub fn had_clip_enabled(&self) -> bool { pub fn had_clip_enabled(&self) -> bool {
match self { match self {
Graphic::Vector(vector) => vector.iter_ref().all(|row| row.alpha_blending.clip), Graphic::Vector(vector) => vector.iter().all(|row| row.alpha_blending.clip),
Graphic::Group(group) => group.iter_ref().all(|row| row.alpha_blending.clip), Graphic::Group(group) => group.iter().all(|row| row.alpha_blending.clip),
Graphic::RasterCPU(raster) => raster.iter_ref().all(|row| row.alpha_blending.clip), Graphic::RasterCPU(raster) => raster.iter().all(|row| row.alpha_blending.clip),
Graphic::RasterGPU(raster) => raster.iter_ref().all(|row| row.alpha_blending.clip), Graphic::RasterGPU(raster) => raster.iter().all(|row| row.alpha_blending.clip),
} }
} }
pub fn can_reduce_to_clip_path(&self) -> bool { pub fn can_reduce_to_clip_path(&self) -> bool {
match self { match self {
Graphic::Vector(vector) => vector.iter_ref().all(|row| { Graphic::Vector(vector) => vector.iter().all(|row| {
let style = &row.element.style; let style = &row.element.style;
let alpha_blending = &row.alpha_blending; let alpha_blending = &row.alpha_blending;
(alpha_blending.opacity > 1. - f32::EPSILON) && style.fill().is_opaque() && style.stroke().is_none_or(|stroke| !stroke.has_renderable_stroke()) (alpha_blending.opacity > 1. - f32::EPSILON) && style.fill().is_opaque() && style.stroke().is_none_or(|stroke| !stroke.has_renderable_stroke())
@@ -187,7 +187,7 @@ impl BoundingBox for Graphic {
impl BoundingBox for Table<Graphic> { impl BoundingBox for Table<Graphic> {
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> { fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
self.iter_ref() self.iter()
.filter_map(|element| element.element.bounding_box(transform * *element.transform, include_stroke)) .filter_map(|element| element.element.bounding_box(transform * *element.transform, include_stroke))
.reduce(Quad::combine_bounds) .reduce(Quad::combine_bounds)
} }
@@ -246,7 +246,7 @@ async fn to_group<Data: Into<Table<Graphic>> + 'n>(
async fn flatten_group(_: impl Ctx, group: Table<Graphic>, fully_flatten: bool) -> Table<Graphic> { async fn flatten_group(_: impl Ctx, group: Table<Graphic>, fully_flatten: bool) -> Table<Graphic> {
// TODO: Avoid mutable reference, instead return a new Table<Graphic>? // TODO: Avoid mutable reference, instead return a new Table<Graphic>?
fn flatten_group(output_group_table: &mut Table<Graphic>, current_group_table: Table<Graphic>, fully_flatten: bool, recursion_depth: usize) { fn flatten_group(output_group_table: &mut Table<Graphic>, current_group_table: Table<Graphic>, fully_flatten: bool, recursion_depth: usize) {
for current_row in current_group_table.iter_ref() { for current_row in current_group_table.iter() {
let current_element = current_row.element.clone(); let current_element = current_row.element.clone();
let reference = *current_row.source_node_id; let reference = *current_row.source_node_id;
@@ -285,7 +285,7 @@ async fn flatten_group(_: impl Ctx, group: Table<Graphic>, fully_flatten: bool)
async fn flatten_vector(_: impl Ctx, group: Table<Graphic>) -> Table<Vector> { async fn flatten_vector(_: impl Ctx, group: Table<Graphic>) -> Table<Vector> {
// TODO: Avoid mutable reference, instead return a new Table<Graphic>? // TODO: Avoid mutable reference, instead return a new Table<Graphic>?
fn flatten_group(output_group_table: &mut Table<Vector>, current_group_table: Table<Graphic>) { fn flatten_group(output_group_table: &mut Table<Vector>, current_group_table: Table<Graphic>) {
for current_graphic_row in current_group_table.iter_ref() { for current_graphic_row in current_group_table.iter() {
let current_graphic = current_graphic_row.element.clone(); let current_graphic = current_graphic_row.element.clone();
let source_node_id = *current_graphic_row.source_node_id; let source_node_id = *current_graphic_row.source_node_id;
@@ -301,7 +301,7 @@ async fn flatten_vector(_: impl Ctx, group: Table<Graphic>) -> Table<Vector> {
} }
// Handle any leaf elements we encounter, which can be either non-group elements or groups that we don't want to flatten // Handle any leaf elements we encounter, which can be either non-group elements or groups that we don't want to flatten
Graphic::Vector(vector_table) => { Graphic::Vector(vector_table) => {
for current_vector_row in vector_table.iter_ref() { for current_vector_row in vector_table.iter() {
output_group_table.push(TableRow { output_group_table.push(TableRow {
element: current_vector_row.element.clone(), element: current_vector_row.element.clone(),
transform: *current_graphic_row.transform * *current_vector_row.transform, transform: *current_graphic_row.transform * *current_vector_row.transform,
@@ -367,7 +367,7 @@ impl<T: Clone> AtIndex for Table<T> {
fn at_index(&self, index: usize) -> Option<Self::Output> { fn at_index(&self, index: usize) -> Option<Self::Output> {
let mut result_table = Self::default(); let mut result_table = Self::default();
if let Some(row) = self.iter_ref().nth(index) { if let Some(row) = self.iter().nth(index) {
result_table.push(row.into_cloned()); result_table.push(row.into_cloned());
Some(result_table) Some(result_table)
} else { } else {
@@ -415,7 +415,7 @@ pub fn migrate_group<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Resul
// Try to deserialize as either table format // Try to deserialize as either table format
if let Ok(old_table) = serde_json::from_value::<Table<GraphicGroup>>(value.clone()) { if let Ok(old_table) = serde_json::from_value::<Table<GraphicGroup>>(value.clone()) {
let mut group_table = Table::new(); let mut group_table = Table::new();
for row in old_table.iter_ref() { for row in old_table.iter() {
for (graphic, source_node_id) in &row.element.elements { for (graphic, source_node_id) in &row.element.elements {
group_table.push(TableRow { group_table.push(TableRow {
element: graphic.clone(), element: graphic.clone(),
+7 -7
View File
@@ -256,7 +256,7 @@ pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) ->
fn from(element: GraphicElement) -> Self { fn from(element: GraphicElement) -> Self {
match element { match element {
GraphicElement::RasterFrame(RasterFrame::ImageFrame(image)) => Self { GraphicElement::RasterFrame(RasterFrame::ImageFrame(image)) => Self {
image: image.iter_ref().next().unwrap().element.clone(), image: image.iter().next().unwrap().element.clone(),
}, },
_ => panic!("Expected Image, found {:?}", element), _ => panic!("Expected Image, found {:?}", element),
} }
@@ -298,14 +298,14 @@ pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) ->
} }
FormatVersions::ImageFrameTable(image_frame) => Table::new_from_element(Raster::new_cpu( FormatVersions::ImageFrameTable(image_frame) => Table::new_from_element(Raster::new_cpu(
image_frame image_frame
.iter_ref() .iter()
.next() .next()
.unwrap_or(Table::new_from_element(ImageFrame::default()).iter_ref().next().unwrap()) .unwrap_or(Table::new_from_element(ImageFrame::default()).iter().next().unwrap())
.element .element
.image .image
.clone(), .clone(),
)), )),
FormatVersions::ImageTable(table) => Table::new_from_element(Raster::new_cpu(table.iter_ref().next().unwrap().element.clone())), FormatVersions::ImageTable(table) => Table::new_from_element(Raster::new_cpu(table.iter().next().unwrap().element.clone())),
FormatVersions::RasterTable(table) => table, FormatVersions::RasterTable(table) => table,
}) })
} }
@@ -354,7 +354,7 @@ pub fn migrate_image_frame_row<'de, D: serde::Deserializer<'de>>(deserializer: D
fn from(element: GraphicElement) -> Self { fn from(element: GraphicElement) -> Self {
match element { match element {
GraphicElement::RasterFrame(RasterFrame::ImageFrame(image)) => Self { GraphicElement::RasterFrame(RasterFrame::ImageFrame(image)) => Self {
image: image.iter_ref().next().unwrap().element.clone(), image: image.iter().next().unwrap().element.clone(),
}, },
_ => panic!("Expected Image, found {:?}", element), _ => panic!("Expected Image, found {:?}", element),
} }
@@ -398,10 +398,10 @@ pub fn migrate_image_frame_row<'de, D: serde::Deserializer<'de>>(deserializer: D
source_node_id: None, source_node_id: None,
}, },
FormatVersions::ImageFrameTable(image_frame) => TableRow { FormatVersions::ImageFrameTable(image_frame) => TableRow {
element: Raster::new_cpu(image_frame.iter_ref().next().unwrap().element.image.clone()), element: Raster::new_cpu(image_frame.iter().next().unwrap().element.image.clone()),
..Default::default() ..Default::default()
}, },
FormatVersions::RasterTable(image_frame_table) => image_frame_table.iter().next().unwrap_or_default(), FormatVersions::RasterTable(image_frame_table) => image_frame_table.into_iter().next().unwrap_or_default(),
FormatVersions::RasterTableRow(image_table_row) => image_table_row, FormatVersions::RasterTableRow(image_table_row) => image_table_row,
}) })
} }
+1 -1
View File
@@ -204,7 +204,7 @@ where
Raster<T>: Storage, Raster<T>: Storage,
{ {
fn bounding_box(&self, transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> { fn bounding_box(&self, transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> {
self.iter_ref() self.iter()
.filter(|row| !row.element.is_empty()) // Eliminate empty images .filter(|row| !row.element.is_empty()) // Eliminate empty images
.flat_map(|row| { .flat_map(|row| {
let transform = transform * *row.transform; let transform = transform * *row.transform;
+1 -1
View File
@@ -12,7 +12,7 @@ pub trait RenderComplexity {
impl<T: RenderComplexity> RenderComplexity for Table<T> { impl<T: RenderComplexity> RenderComplexity for Table<T> {
fn render_complexity(&self) -> usize { fn render_complexity(&self) -> usize {
self.iter_ref().map(|row| row.element.render_complexity()).fold(0, usize::saturating_add) self.iter().map(|row| row.element.render_complexity()).fold(0, usize::saturating_add)
} }
} }
+69 -42
View File
@@ -60,48 +60,6 @@ impl<T> Table<T> {
self.source_node_id.extend(table.source_node_id); self.source_node_id.extend(table.source_node_id);
} }
pub fn iter(self) -> impl DoubleEndedIterator<Item = TableRow<T>> {
self.element
.into_iter()
.zip(self.transform)
.zip(self.alpha_blending)
.zip(self.source_node_id)
.map(|(((element, transform), alpha_blending), source_node_id)| TableRow {
element,
transform,
alpha_blending,
source_node_id,
})
}
pub fn iter_ref(&self) -> impl DoubleEndedIterator<Item = TableRowRef<'_, T>> + Clone {
self.element
.iter()
.zip(self.transform.iter())
.zip(self.alpha_blending.iter())
.zip(self.source_node_id.iter())
.map(|(((element, transform), alpha_blending), source_node_id)| TableRowRef {
element,
transform,
alpha_blending,
source_node_id,
})
}
pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = TableRowMut<'_, T>> {
self.element
.iter_mut()
.zip(self.transform.iter_mut())
.zip(self.alpha_blending.iter_mut())
.zip(self.source_node_id.iter_mut())
.map(|(((element, transform), alpha_blending), source_node_id)| TableRowMut {
element,
transform,
alpha_blending,
source_node_id,
})
}
pub fn get(&self, index: usize) -> Option<TableRowRef<'_, T>> { pub fn get(&self, index: usize) -> Option<TableRowRef<'_, T>> {
if index >= self.element.len() { if index >= self.element.len() {
return None; return None;
@@ -135,6 +93,75 @@ impl<T> Table<T> {
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.element.is_empty() self.element.is_empty()
} }
/// Borrows a [`Table`] and returns an iterator of [`TableRowRef`]s, each containing references to the data of the respective row from the table.
pub fn iter(&self) -> impl DoubleEndedIterator<Item = TableRowRef<'_, T>> + Clone {
self.element
.iter()
.zip(self.transform.iter())
.zip(self.alpha_blending.iter())
.zip(self.source_node_id.iter())
.map(|(((element, transform), alpha_blending), source_node_id)| TableRowRef {
element,
transform,
alpha_blending,
source_node_id,
})
}
/// Mutably borrows a [`Table`] and returns an iterator of [`TableRowMut`]s, each containing mutable references to the data of the respective row from the table.
pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = TableRowMut<'_, T>> {
self.element
.iter_mut()
.zip(self.transform.iter_mut())
.zip(self.alpha_blending.iter_mut())
.zip(self.source_node_id.iter_mut())
.map(|(((element, transform), alpha_blending), source_node_id)| TableRowMut {
element,
transform,
alpha_blending,
source_node_id,
})
}
}
impl<T> IntoIterator for Table<T> {
type Item = TableRow<T>;
type IntoIter = TableRowIter<T>;
/// Consumes a [`Table`] and returns an iterator of [`TableRow`]s, each containing the owned data of the respective row from the original table.
fn into_iter(self) -> Self::IntoIter {
TableRowIter {
element: self.element.into_iter(),
transform: self.transform.into_iter(),
alpha_blending: self.alpha_blending.into_iter(),
source_node_id: self.source_node_id.into_iter(),
}
}
}
pub struct TableRowIter<T> {
element: std::vec::IntoIter<T>,
transform: std::vec::IntoIter<DAffine2>,
alpha_blending: std::vec::IntoIter<AlphaBlending>,
source_node_id: std::vec::IntoIter<Option<NodeId>>,
}
impl<T> Iterator for TableRowIter<T> {
type Item = TableRow<T>;
fn next(&mut self) -> Option<Self::Item> {
let element = self.element.next()?;
let transform = self.transform.next()?;
let alpha_blending = self.alpha_blending.next()?;
let source_node_id = self.source_node_id.next()?;
Some(TableRow {
element,
transform,
alpha_blending,
source_node_id,
})
}
} }
impl<T> Default for Table<T> { impl<T> Default for Table<T> {
+1 -1
View File
@@ -63,7 +63,7 @@ async fn extract_transform<T>(
)] )]
vector: Table<T>, vector: Table<T>,
) -> DAffine2 { ) -> DAffine2 {
vector.iter_ref().next().map(|row| *row.transform).unwrap_or_default() vector.iter().next().map(|row| *row.transform).unwrap_or_default()
} }
#[node_macro::node(category("Math: Transform"))] #[node_macro::node(category("Math: Transform"))]
@@ -18,14 +18,14 @@ async fn instance_on_points<T: Into<Graphic> + Default + Send + Clone + 'static>
) -> Table<T> { ) -> Table<T> {
let mut result_table = Table::new(); let mut result_table = Table::new();
for TableRowRef { element: points, transform, .. } in points.iter_ref() { for TableRowRef { element: points, transform, .. } in points.iter() {
let mut iteration = async |index, point| { let mut iteration = async |index, point| {
let transformed_point = transform.transform_point2(point); let transformed_point = transform.transform_point2(point);
let new_ctx = OwnedContextImpl::from(ctx.clone()).with_index(index).with_vararg(Box::new(transformed_point)); let new_ctx = OwnedContextImpl::from(ctx.clone()).with_index(index).with_vararg(Box::new(transformed_point));
let generated_instance = instance.eval(new_ctx.into_context()).await; let generated_instance = instance.eval(new_ctx.into_context()).await;
for mut generated_row in generated_instance.iter() { for mut generated_row in generated_instance.into_iter() {
generated_row.transform.translation = transformed_point; generated_row.transform.translation = transformed_point;
result_table.push(generated_row); result_table.push(generated_row);
} }
@@ -68,7 +68,7 @@ async fn instance_repeat<T: Into<Graphic> + Default + Send + Clone + 'static>(
let new_ctx = OwnedContextImpl::from(ctx.clone()).with_index(index); let new_ctx = OwnedContextImpl::from(ctx.clone()).with_index(index);
let generated_instance = instance.eval(new_ctx.into_context()).await; let generated_instance = instance.eval(new_ctx.into_context()).await;
for generated_row in generated_instance.iter() { for generated_row in generated_instance.into_iter() {
result_table.push(generated_row); result_table.push(generated_row);
} }
} }
@@ -131,7 +131,7 @@ mod test {
let points = Table::new_from_element(Vector::from_subpath(Subpath::from_anchors_linear(positions, false))); let points = Table::new_from_element(Vector::from_subpath(Subpath::from_anchors_linear(positions, false)));
let generated = super::instance_on_points(owned, points, &rect, false).await; let generated = super::instance_on_points(owned, points, &rect, false).await;
assert_eq!(generated.len(), positions.len()); assert_eq!(generated.len(), positions.len());
for (position, generated_row) in positions.into_iter().zip(generated.iter_ref()) { for (position, generated_row) in positions.into_iter().zip(generated.iter()) {
let bounds = generated_row.element.bounding_box_with_transform(*generated_row.transform).unwrap(); let bounds = generated_row.element.bounding_box_with_transform(*generated_row.transform).unwrap();
assert!(position.abs_diff_eq((bounds[0] + bounds[1]) / 2., 1e-10)); assert!(position.abs_diff_eq((bounds[0] + bounds[1]) / 2., 1e-10));
assert_eq!((bounds[1] - bounds[0]).x, position.y); assert_eq!((bounds[1] - bounds[0]).x, position.y);
@@ -286,9 +286,9 @@ mod tests {
// Works properly // Works properly
let grid = grid((), (), GridType::Isometric, 10., 5, 5, (30., 30.).into()); let grid = grid((), (), GridType::Isometric, 10., 5, 5, (30., 30.).into());
assert_eq!(grid.iter_ref().next().unwrap().element.point_domain.ids().len(), 5 * 5); assert_eq!(grid.iter().next().unwrap().element.point_domain.ids().len(), 5 * 5);
assert_eq!(grid.iter_ref().next().unwrap().element.segment_bezier_iter().count(), 4 * 5 + 4 * 9); assert_eq!(grid.iter().next().unwrap().element.segment_bezier_iter().count(), 4 * 5 + 4 * 9);
for (_, bezier, _, _) in grid.iter_ref().next().unwrap().element.segment_bezier_iter() { for (_, bezier, _, _) in grid.iter().next().unwrap().element.segment_bezier_iter() {
assert_eq!(bezier.handles, bezier_rs::BezierHandles::Linear); assert_eq!(bezier.handles, bezier_rs::BezierHandles::Linear);
assert!( assert!(
((bezier.start - bezier.end).length() - 10.).abs() < 1e-5, ((bezier.start - bezier.end).length() - 10.).abs() < 1e-5,
@@ -301,9 +301,9 @@ mod tests {
#[test] #[test]
fn skew_isometric_grid_test() { fn skew_isometric_grid_test() {
let grid = grid((), (), GridType::Isometric, 10., 5, 5, (40., 30.).into()); let grid = grid((), (), GridType::Isometric, 10., 5, 5, (40., 30.).into());
assert_eq!(grid.iter_ref().next().unwrap().element.point_domain.ids().len(), 5 * 5); assert_eq!(grid.iter().next().unwrap().element.point_domain.ids().len(), 5 * 5);
assert_eq!(grid.iter_ref().next().unwrap().element.segment_bezier_iter().count(), 4 * 5 + 4 * 9); assert_eq!(grid.iter().next().unwrap().element.segment_bezier_iter().count(), 4 * 5 + 4 * 9);
for (_, bezier, _, _) in grid.iter_ref().next().unwrap().element.segment_bezier_iter() { for (_, bezier, _, _) in grid.iter().next().unwrap().element.segment_bezier_iter() {
assert_eq!(bezier.handles, bezier_rs::BezierHandles::Linear); assert_eq!(bezier.handles, bezier_rs::BezierHandles::Linear);
let vector = bezier.start - bezier.end; let vector = bezier.start - bezier.end;
let angle = (vector.angle_to(DVec2::X).to_degrees() + 180.) % 180.; let angle = (vector.angle_to(DVec2::X).to_degrees() + 180.) % 180.;
+50 -50
View File
@@ -237,7 +237,7 @@ async fn repeat<I: 'n + Send + Clone>(
let translation = index as f64 * direction / total; let translation = index as f64 * direction / total;
let transform = DAffine2::from_angle(angle) * DAffine2::from_translation(translation); let transform = DAffine2::from_angle(angle) * DAffine2::from_translation(translation);
for row in instance.iter_ref() { for row in instance.iter() {
let mut row = row.into_cloned(); let mut row = row.into_cloned();
let local_translation = DAffine2::from_translation(row.transform.translation); let local_translation = DAffine2::from_translation(row.transform.translation);
@@ -271,7 +271,7 @@ async fn circular_repeat<I: 'n + Send + Clone>(
let translation = DAffine2::from_translation(radius * DVec2::Y); let translation = DAffine2::from_translation(radius * DVec2::Y);
let transform = angle * translation; let transform = angle * translation;
for row in instance.iter_ref() { for row in instance.iter() {
let mut row = row.into_cloned(); let mut row = row.into_cloned();
let local_translation = DAffine2::from_translation(row.transform.translation); let local_translation = DAffine2::from_translation(row.transform.translation);
@@ -318,7 +318,7 @@ async fn copy_to_points<I: 'n + Send + Clone>(
let random_scale_difference = random_scale_max - random_scale_min; let random_scale_difference = random_scale_max - random_scale_min;
for row in points.iter() { for row in points.into_iter() {
let mut scale_rng = rand::rngs::StdRng::seed_from_u64(random_scale_seed.into()); 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()); let mut rotation_rng = rand::rngs::StdRng::seed_from_u64(random_rotation_seed.into());
@@ -352,7 +352,7 @@ async fn copy_to_points<I: 'n + Send + Clone>(
let transform = DAffine2::from_scale_angle_translation(DVec2::splat(scale), rotation, translation); let transform = DAffine2::from_scale_angle_translation(DVec2::splat(scale), rotation, translation);
for mut row in instance.iter_ref().map(|row| row.into_cloned()) { for mut row in instance.iter().map(|row| row.into_cloned()) {
row.transform = transform * row.transform; row.transform = transform * row.transform;
result_table.push(row); result_table.push(row);
@@ -406,13 +406,13 @@ where
// Add original instance depending on the keep_original flag // Add original instance depending on the keep_original flag
if keep_original { if keep_original {
for instance in instance.clone().iter() { for instance in instance.clone().into_iter() {
result_table.push(instance); result_table.push(instance);
} }
} }
// Create and add mirrored instance // Create and add mirrored instance
for mut row in instance.iter() { for mut row in instance.into_iter() {
row.transform = reflected_transform * row.transform; row.transform = reflected_transform * row.transform;
result_table.push(row); result_table.push(row);
} }
@@ -440,7 +440,7 @@ async fn round_corners(
min_angle_threshold: Angle, min_angle_threshold: Angle,
) -> Table<Vector> { ) -> Table<Vector> {
source source
.iter_ref() .iter()
.map(|source| { .map(|source| {
let source_transform = *source.transform; let source_transform = *source.transform;
let source_transform_inverse = source_transform.inverse(); let source_transform_inverse = source_transform.inverse();
@@ -555,14 +555,14 @@ pub fn merge_by_distance(
) -> Table<Vector> { ) -> Table<Vector> {
match algorithm { match algorithm {
MergeByDistanceAlgorithm::Spatial => content MergeByDistanceAlgorithm::Spatial => content
.iter() .into_iter()
.map(|mut row| { .map(|mut row| {
row.element.merge_by_distance_spatial(row.transform, distance); row.element.merge_by_distance_spatial(row.transform, distance);
row row
}) })
.collect(), .collect(),
MergeByDistanceAlgorithm::Topological => content MergeByDistanceAlgorithm::Topological => content
.iter() .into_iter()
.map(|mut row| { .map(|mut row| {
row.element.merge_by_distance_topological(distance); row.element.merge_by_distance_topological(distance);
row row
@@ -578,7 +578,7 @@ async fn box_warp(_: impl Ctx, content: Table<Vector>, #[expose] rectangle: Tabl
}; };
content content
.iter() .into_iter()
.map(|mut row| { .map(|mut row| {
let transform = row.transform; let transform = row.transform;
let vector = row.element; let vector = row.element;
@@ -672,7 +672,7 @@ async fn auto_tangents(
preserve_existing: bool, preserve_existing: bool,
) -> Table<Vector> { ) -> Table<Vector> {
source source
.iter_ref() .iter()
.map(|source| { .map(|source| {
let transform = *source.transform; let transform = *source.transform;
let alpha_blending = *source.alpha_blending; let alpha_blending = *source.alpha_blending;
@@ -784,7 +784,7 @@ async fn auto_tangents(
#[node_macro::node(category("Vector: Modifier"), path(graphene_core::vector))] #[node_macro::node(category("Vector: Modifier"), path(graphene_core::vector))]
async fn bounding_box(_: impl Ctx, content: Table<Vector>) -> Table<Vector> { async fn bounding_box(_: impl Ctx, content: Table<Vector>) -> Table<Vector> {
content content
.iter() .into_iter()
.map(|mut row| { .map(|mut row| {
let vector = row.element; let vector = row.element;
@@ -809,7 +809,7 @@ async fn bounding_box(_: impl Ctx, content: Table<Vector>) -> Table<Vector> {
#[node_macro::node(category("Vector: Measure"), path(graphene_core::vector))] #[node_macro::node(category("Vector: Measure"), path(graphene_core::vector))]
async fn dimensions(_: impl Ctx, content: Table<Vector>) -> DVec2 { async fn dimensions(_: impl Ctx, content: Table<Vector>) -> DVec2 {
content content
.iter_ref() .iter()
.filter_map(|vector| vector.element.bounding_box_with_transform(*vector.transform)) .filter_map(|vector| vector.element.bounding_box_with_transform(*vector.transform))
.reduce(|[acc_top_left, acc_bottom_right], [top_left, bottom_right]| [acc_top_left.min(top_left), acc_bottom_right.max(bottom_right)]) .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) .map(|[top_left, bottom_right]| bottom_right - top_left)
@@ -861,7 +861,7 @@ async fn points_to_polyline(_: impl Ctx, mut points: Table<Vector>, #[default(tr
#[node_macro::node(category("Vector: Modifier"), path(graphene_core::vector), properties("offset_path_properties"))] #[node_macro::node(category("Vector: Modifier"), path(graphene_core::vector), properties("offset_path_properties"))]
async fn offset_path(_: impl Ctx, content: Table<Vector>, distance: f64, join: StrokeJoin, #[default(4.)] miter_limit: f64) -> Table<Vector> { async fn offset_path(_: impl Ctx, content: Table<Vector>, distance: f64, join: StrokeJoin, #[default(4.)] miter_limit: f64) -> Table<Vector> {
content content
.iter() .into_iter()
.map(|mut row| { .map(|mut row| {
let transform = Affine::new(row.transform.to_cols_array()); let transform = Affine::new(row.transform.to_cols_array());
let vector = row.element; let vector = row.element;
@@ -904,7 +904,7 @@ async fn offset_path(_: impl Ctx, content: Table<Vector>, distance: f64, join: S
#[node_macro::node(category("Vector: Modifier"), path(graphene_core::vector))] #[node_macro::node(category("Vector: Modifier"), path(graphene_core::vector))]
async fn solidify_stroke(_: impl Ctx, content: Table<Vector>) -> Table<Vector> { async fn solidify_stroke(_: impl Ctx, content: Table<Vector>) -> Table<Vector> {
content content
.iter() .into_iter()
.map(|mut row| { .map(|mut row| {
let vector = row.element; let vector = row.element;
@@ -966,11 +966,11 @@ where
// the if else node, and another connection from the cache to a matches type node connected to the if else node. // the if else node, and another connection from the cache to a matches type node connected to the if else node.
fn flatten_group(group: &Table<Graphic>, output: &mut TableRowMut<Vector>) { fn flatten_group(group: &Table<Graphic>, output: &mut TableRowMut<Vector>) {
for (group_index, current_element) in group.iter_ref().enumerate() { for (group_index, current_element) in group.iter().enumerate() {
match current_element.element { match current_element.element {
Graphic::Vector(vector) => { Graphic::Vector(vector) => {
// Loop through every row of the `Table<Vector>` and concatenate each element's subpath into the output `Vector` element. // Loop through every row of the `Table<Vector>` and concatenate each element's subpath into the output `Vector` element.
for (vector_index, row) in vector.iter_ref().enumerate() { for (vector_index, row) in vector.iter().enumerate() {
let other = row.element; let other = row.element;
let transform = *current_element.transform * *row.transform; let transform = *current_element.transform * *row.transform;
let node_id = current_element.source_node_id.map(|node_id| node_id.0).unwrap_or_default(); let node_id = current_element.source_node_id.map(|node_id| node_id.0).unwrap_or_default();
@@ -1026,7 +1026,7 @@ async fn sample_polyline(
subpath_segment_lengths: Vec<f64>, subpath_segment_lengths: Vec<f64>,
) -> Table<Vector> { ) -> Table<Vector> {
content content
.iter() .into_iter()
.map(|mut row| { .map(|mut row| {
let mut result = Vector { let mut result = Vector {
point_domain: Default::default(), point_domain: Default::default(),
@@ -1088,7 +1088,7 @@ async fn split_path(_: impl Ctx, mut content: Table<Vector>, progress: Fraction,
let euclidian = !parameterized_distance; let euclidian = !parameterized_distance;
let bezpaths = content let bezpaths = content
.iter_ref() .iter()
.enumerate() .enumerate()
.flat_map(|(row_index, vector)| vector.element.stroke_bezpath_iter().map(|bezpath| (row_index, bezpath)).collect::<Vec<_>>()) .flat_map(|(row_index, vector)| vector.element.stroke_bezpath_iter().map(|bezpath| (row_index, bezpath)).collect::<Vec<_>>())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@@ -1198,7 +1198,7 @@ async fn position_on_path(
let euclidian = !parameterized_distance; let euclidian = !parameterized_distance;
let mut bezpaths = content let mut bezpaths = content
.iter() .into_iter()
.flat_map(|vector| { .flat_map(|vector| {
let transform = vector.transform; let transform = vector.transform;
vector.element.stroke_bezpath_iter().map(|bezpath| (bezpath, transform)).collect::<Vec<_>>() vector.element.stroke_bezpath_iter().map(|bezpath| (bezpath, transform)).collect::<Vec<_>>()
@@ -1237,7 +1237,7 @@ async fn tangent_on_path(
let euclidian = !parameterized_distance; let euclidian = !parameterized_distance;
let mut bezpaths = content let mut bezpaths = content
.iter() .into_iter()
.flat_map(|vector| { .flat_map(|vector| {
let transform = vector.transform; let transform = vector.transform;
vector.element.stroke_bezpath_iter().map(|bezpath| (bezpath, transform)).collect::<Vec<_>>() vector.element.stroke_bezpath_iter().map(|bezpath| (bezpath, transform)).collect::<Vec<_>>()
@@ -1280,7 +1280,7 @@ async fn poisson_disk_points(
let mut rng = rand::rngs::StdRng::seed_from_u64(seed.into()); let mut rng = rand::rngs::StdRng::seed_from_u64(seed.into());
content content
.iter() .into_iter()
.map(|mut row| { .map(|mut row| {
let mut result = Vector::default(); let mut result = Vector::default();
@@ -1318,7 +1318,7 @@ async fn poisson_disk_points(
#[node_macro::node(category(""), path(graphene_core::vector))] #[node_macro::node(category(""), path(graphene_core::vector))]
async fn subpath_segment_lengths(_: impl Ctx, content: Table<Vector>) -> Vec<f64> { async fn subpath_segment_lengths(_: impl Ctx, content: Table<Vector>) -> Vec<f64> {
content content
.iter() .into_iter()
.flat_map(|vector| { .flat_map(|vector| {
let transform = vector.transform; let transform = vector.transform;
vector vector
@@ -1336,7 +1336,7 @@ async fn subpath_segment_lengths(_: impl Ctx, content: Table<Vector>) -> Vec<f64
#[node_macro::node(name("Spline"), category("Vector: Modifier"), path(graphene_core::vector))] #[node_macro::node(name("Spline"), category("Vector: Modifier"), path(graphene_core::vector))]
async fn spline(_: impl Ctx, content: Table<Vector>) -> Table<Vector> { async fn spline(_: impl Ctx, content: Table<Vector>) -> Table<Vector> {
content content
.iter() .into_iter()
.filter_map(|mut row| { .filter_map(|mut row| {
// Exit early if there are no points to generate splines from. // Exit early if there are no points to generate splines from.
if row.element.point_domain.positions().is_empty() { if row.element.point_domain.positions().is_empty() {
@@ -1388,7 +1388,7 @@ async fn jitter_points(
seed: SeedValue, seed: SeedValue,
) -> Table<Vector> { ) -> Table<Vector> {
content content
.iter() .into_iter()
.map(|mut row| { .map(|mut row| {
let mut rng = rand::rngs::StdRng::seed_from_u64(seed.into()); let mut rng = rand::rngs::StdRng::seed_from_u64(seed.into());
@@ -1485,8 +1485,8 @@ async fn morph(_: impl Ctx, source: Table<Vector>, #[expose] target: Table<Vecto
let time = time.clamp(0., 1.); let time = time.clamp(0., 1.);
source source
.iter() .into_iter()
.zip(target.iter()) .zip(target.into_iter())
.map(|(source_row, target_row)| { .map(|(source_row, target_row)| {
let mut vector = Vector::default(); let mut vector = Vector::default();
@@ -1878,7 +1878,7 @@ fn bevel_algorithm(mut vector: Vector, transform: DAffine2, distance: f64) -> Ve
#[node_macro::node(category("Vector: Modifier"), path(graphene_core::vector))] #[node_macro::node(category("Vector: Modifier"), path(graphene_core::vector))]
fn bevel(_: impl Ctx, source: Table<Vector>, #[default(10.)] distance: Length) -> Table<Vector> { fn bevel(_: impl Ctx, source: Table<Vector>, #[default(10.)] distance: Length) -> Table<Vector> {
source source
.iter() .into_iter()
.map(|row| TableRow { .map(|row| TableRow {
element: bevel_algorithm(row.element, row.transform, distance), element: bevel_algorithm(row.element, row.transform, distance),
..row ..row
@@ -1889,7 +1889,7 @@ fn bevel(_: impl Ctx, source: Table<Vector>, #[default(10.)] distance: Length) -
#[node_macro::node(category("Vector: Modifier"), path(graphene_core::vector))] #[node_macro::node(category("Vector: Modifier"), path(graphene_core::vector))]
fn close_path(_: impl Ctx, source: Table<Vector>) -> Table<Vector> { fn close_path(_: impl Ctx, source: Table<Vector>) -> Table<Vector> {
source source
.iter() .into_iter()
.map(|mut row| { .map(|mut row| {
row.element.close_subpaths(); row.element.close_subpaths();
row row
@@ -1899,7 +1899,7 @@ fn close_path(_: impl Ctx, source: Table<Vector>) -> Table<Vector> {
#[node_macro::node(category("Vector: Measure"), path(graphene_core::vector))] #[node_macro::node(category("Vector: Measure"), path(graphene_core::vector))]
fn point_inside(_: impl Ctx, source: Table<Vector>, point: DVec2) -> bool { fn point_inside(_: impl Ctx, source: Table<Vector>, point: DVec2) -> bool {
source.iter().any(|row| row.element.check_point_inside_shape(row.transform, point)) source.into_iter().any(|row| row.element.check_point_inside_shape(row.transform, point))
} }
#[node_macro::node(category("General"), path(graphene_core::vector))] #[node_macro::node(category("General"), path(graphene_core::vector))]
@@ -1910,7 +1910,7 @@ async fn count_elements<I>(_: impl Ctx, #[implementations(Table<Graphic>, Table<
#[node_macro::node(category("Vector: Measure"), path(graphene_core::vector))] #[node_macro::node(category("Vector: Measure"), path(graphene_core::vector))]
async fn path_length(_: impl Ctx, source: Table<Vector>) -> f64 { async fn path_length(_: impl Ctx, source: Table<Vector>) -> f64 {
source source
.iter() .into_iter()
.map(|row| { .map(|row| {
let transform = row.transform; let transform = row.transform;
row.element row.element
@@ -1930,7 +1930,7 @@ async fn area(ctx: impl Ctx + CloneVarArgs + ExtractAll, content: impl Node<Cont
let vector = content.eval(new_ctx).await; let vector = content.eval(new_ctx).await;
vector vector
.iter_ref() .iter()
.map(|row| { .map(|row| {
let scale = row.transform.decompose_scale(); let scale = row.transform.decompose_scale();
row.element.stroke_bezpath_iter().map(|subpath| subpath.area() * scale.x * scale.y).sum::<f64>() row.element.stroke_bezpath_iter().map(|subpath| subpath.area() * scale.x * scale.y).sum::<f64>()
@@ -1952,7 +1952,7 @@ async fn centroid(ctx: impl Ctx + CloneVarArgs + ExtractAll, content: impl Node<
// Cumulative area or length of all subpaths // Cumulative area or length of all subpaths
let mut sum = 0.; let mut sum = 0.;
for row in vector.iter_ref() { for row in vector.iter() {
for subpath in row.element.stroke_bezier_paths() { for subpath in row.element.stroke_bezier_paths() {
let partial = match centroid_type { let partial = match centroid_type {
CentroidType::Area => subpath.area_centroid_and_area(Some(1e-3), Some(1e-3)).filter(|(_, area)| *area > 0.), CentroidType::Area => subpath.area_centroid_and_area(Some(1e-3), Some(1e-3)).filter(|(_, area)| *area > 0.),
@@ -1975,7 +1975,7 @@ async fn centroid(ctx: impl Ctx + CloneVarArgs + ExtractAll, content: impl Node<
let mut count: usize = 0; let mut count: usize = 0;
let summed_positions = vector let summed_positions = vector
.iter_ref() .iter()
.flat_map(|row| row.element.point_domain.positions().iter().map(|&p| row.transform.transform_point2(p))) .flat_map(|row| row.element.point_domain.positions().iter().map(|&p| row.transform.transform_point2(p)))
.inspect(|_| count += 1) .inspect(|_| count += 1)
.sum::<DVec2>(); .sum::<DVec2>();
@@ -2031,7 +2031,7 @@ mod test {
) )
.await; .await;
let vector_table = super::flatten_path(Footprint::default(), repeated).await; let vector_table = super::flatten_path(Footprint::default(), repeated).await;
let vector = vector_table.iter_ref().next().unwrap().element; let vector = vector_table.iter().next().unwrap().element;
assert_eq!(vector.region_manipulator_groups().count(), 3); assert_eq!(vector.region_manipulator_groups().count(), 3);
for (index, (_, manipulator_groups)) in vector.region_manipulator_groups().enumerate() { 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); assert!((manipulator_groups[0].anchor - direction * index as f64 / (count - 1) as f64).length() < 1e-5);
@@ -2050,7 +2050,7 @@ mod test {
) )
.await; .await;
let vector_table = super::flatten_path(Footprint::default(), repeated).await; let vector_table = super::flatten_path(Footprint::default(), repeated).await;
let vector = vector_table.iter_ref().next().unwrap().element; let vector = vector_table.iter().next().unwrap().element;
assert_eq!(vector.region_manipulator_groups().count(), 8); assert_eq!(vector.region_manipulator_groups().count(), 8);
for (index, (_, manipulator_groups)) in vector.region_manipulator_groups().enumerate() { 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); assert!((manipulator_groups[0].anchor - direction * index as f64 / (count - 1) as f64).length() < 1e-5);
@@ -2060,7 +2060,7 @@ mod test {
async fn circular_repeat() { async fn circular_repeat() {
let repeated = super::circular_repeat(Footprint::default(), vector_node_from_bezpath(Rect::new(-1., -1., 1., 1.).to_path(DEFAULT_ACCURACY)), 45., 4., 8).await; let repeated = super::circular_repeat(Footprint::default(), vector_node_from_bezpath(Rect::new(-1., -1., 1., 1.).to_path(DEFAULT_ACCURACY)), 45., 4., 8).await;
let vector_table = super::flatten_path(Footprint::default(), repeated).await; let vector_table = super::flatten_path(Footprint::default(), repeated).await;
let vector = vector_table.iter_ref().next().unwrap().element; let vector = vector_table.iter().next().unwrap().element;
assert_eq!(vector.region_manipulator_groups().count(), 8); assert_eq!(vector.region_manipulator_groups().count(), 8);
for (index, (_, manipulator_groups)) in vector.region_manipulator_groups().enumerate() { for (index, (_, manipulator_groups)) in vector.region_manipulator_groups().enumerate() {
@@ -2075,7 +2075,7 @@ mod test {
#[tokio::test] #[tokio::test]
async fn bounding_box() { async fn bounding_box() {
let bounding_box = super::bounding_box((), vector_node_from_bezpath(Rect::new(-1., -1., 1., 1.).to_path(DEFAULT_ACCURACY))).await; let bounding_box = super::bounding_box((), vector_node_from_bezpath(Rect::new(-1., -1., 1., 1.).to_path(DEFAULT_ACCURACY))).await;
let bounding_box = bounding_box.iter_ref().next().unwrap().element; let bounding_box = bounding_box.iter().next().unwrap().element;
assert_eq!(bounding_box.region_manipulator_groups().count(), 1); assert_eq!(bounding_box.region_manipulator_groups().count(), 1);
let manipulator_groups_anchors = bounding_box.region_manipulator_groups().next().unwrap().1.iter().map(|group| group.anchor).collect::<Vec<DVec2>>(); let manipulator_groups_anchors = bounding_box.region_manipulator_groups().next().unwrap().1.iter().map(|group| group.anchor).collect::<Vec<DVec2>>();
@@ -2086,7 +2086,7 @@ mod test {
let mut square = Table::new_from_element(square); let mut square = Table::new_from_element(square);
*square.get_mut(0).unwrap().transform *= DAffine2::from_angle(std::f64::consts::FRAC_PI_4); *square.get_mut(0).unwrap().transform *= DAffine2::from_angle(std::f64::consts::FRAC_PI_4);
let bounding_box = BoundingBoxNode { content: FutureWrapperNode(square) }.eval(Footprint::default()).await; let bounding_box = BoundingBoxNode { content: FutureWrapperNode(square) }.eval(Footprint::default()).await;
let bounding_box = bounding_box.iter_ref().next().unwrap().element; let bounding_box = bounding_box.iter().next().unwrap().element;
assert_eq!(bounding_box.region_manipulator_groups().count(), 1); assert_eq!(bounding_box.region_manipulator_groups().count(), 1);
let manipulator_groups_anchors = bounding_box.region_manipulator_groups().next().unwrap().1.iter().map(|group| group.anchor).collect::<Vec<DVec2>>(); let manipulator_groups_anchors = bounding_box.region_manipulator_groups().next().unwrap().1.iter().map(|group| group.anchor).collect::<Vec<DVec2>>();
@@ -2104,7 +2104,7 @@ mod test {
let copy_to_points = super::copy_to_points(Footprint::default(), vector_node_from_bezpath(points), vector_node_from_bezpath(element), 1., 1., 0., 0, 0., 0).await; let copy_to_points = super::copy_to_points(Footprint::default(), vector_node_from_bezpath(points), vector_node_from_bezpath(element), 1., 1., 0., 0, 0., 0).await;
let flatten_path = super::flatten_path(Footprint::default(), copy_to_points).await; let flatten_path = super::flatten_path(Footprint::default(), copy_to_points).await;
let flattened_copy_to_points = flatten_path.iter_ref().next().unwrap().element; let flattened_copy_to_points = flatten_path.iter().next().unwrap().element;
assert_eq!(flattened_copy_to_points.region_manipulator_groups().count(), expected_points.len()); assert_eq!(flattened_copy_to_points.region_manipulator_groups().count(), expected_points.len());
@@ -2122,7 +2122,7 @@ mod test {
async fn sample_polyline() { async fn sample_polyline() {
let path = BezPath::from_vec(vec![PathEl::MoveTo(Point::ZERO), PathEl::CurveTo(Point::ZERO, Point::new(100., 0.), Point::new(100., 0.))]); let path = BezPath::from_vec(vec![PathEl::MoveTo(Point::ZERO), PathEl::CurveTo(Point::ZERO, Point::new(100., 0.), Point::new(100., 0.))]);
let sample_polyline = super::sample_polyline(Footprint::default(), vector_node_from_bezpath(path), PointSpacingType::Separation, 30., 0, 0., 0., false, vec![100.]).await; let sample_polyline = super::sample_polyline(Footprint::default(), vector_node_from_bezpath(path), PointSpacingType::Separation, 30., 0, 0., 0., false, vec![100.]).await;
let sample_polyline = sample_polyline.iter_ref().next().unwrap().element; let sample_polyline = sample_polyline.iter().next().unwrap().element;
assert_eq!(sample_polyline.point_domain.positions().len(), 4); assert_eq!(sample_polyline.point_domain.positions().len(), 4);
for (pos, expected) in sample_polyline.point_domain.positions().iter().zip([DVec2::X * 0., DVec2::X * 30., DVec2::X * 60., DVec2::X * 90.]) { for (pos, expected) in sample_polyline.point_domain.positions().iter().zip([DVec2::X * 0., DVec2::X * 30., DVec2::X * 60., DVec2::X * 90.]) {
assert!(pos.distance(expected) < 1e-3, "Expected {expected} found {pos}"); assert!(pos.distance(expected) < 1e-3, "Expected {expected} found {pos}");
@@ -2132,7 +2132,7 @@ mod test {
async fn sample_polyline_adaptive_spacing() { async fn sample_polyline_adaptive_spacing() {
let path = BezPath::from_vec(vec![PathEl::MoveTo(Point::ZERO), PathEl::CurveTo(Point::ZERO, Point::new(100., 0.), Point::new(100., 0.))]); let path = BezPath::from_vec(vec![PathEl::MoveTo(Point::ZERO), PathEl::CurveTo(Point::ZERO, Point::new(100., 0.), Point::new(100., 0.))]);
let sample_polyline = super::sample_polyline(Footprint::default(), vector_node_from_bezpath(path), PointSpacingType::Separation, 18., 0, 45., 10., true, vec![100.]).await; let sample_polyline = super::sample_polyline(Footprint::default(), vector_node_from_bezpath(path), PointSpacingType::Separation, 18., 0, 45., 10., true, vec![100.]).await;
let sample_polyline = sample_polyline.iter_ref().next().unwrap().element; let sample_polyline = sample_polyline.iter().next().unwrap().element;
assert_eq!(sample_polyline.point_domain.positions().len(), 4); assert_eq!(sample_polyline.point_domain.positions().len(), 4);
for (pos, expected) in sample_polyline.point_domain.positions().iter().zip([DVec2::X * 45., DVec2::X * 60., DVec2::X * 75., DVec2::X * 90.]) { for (pos, expected) in sample_polyline.point_domain.positions().iter().zip([DVec2::X * 45., DVec2::X * 60., DVec2::X * 75., DVec2::X * 90.]) {
assert!(pos.distance(expected) < 1e-3, "Expected {expected} found {pos}"); assert!(pos.distance(expected) < 1e-3, "Expected {expected} found {pos}");
@@ -2147,7 +2147,7 @@ mod test {
0, 0,
) )
.await; .await;
let poisson_points = poisson_points.iter_ref().next().unwrap().element; let poisson_points = poisson_points.iter().next().unwrap().element;
assert!( assert!(
(20..=40).contains(&poisson_points.point_domain.positions().len()), (20..=40).contains(&poisson_points.point_domain.positions().len()),
"actual len {}", "actual len {}",
@@ -2178,7 +2178,7 @@ mod test {
#[tokio::test] #[tokio::test]
async fn spline() { async fn spline() {
let spline = super::spline(Footprint::default(), vector_node_from_bezpath(Rect::new(0., 0., 100., 100.).to_path(DEFAULT_ACCURACY))).await; let spline = super::spline(Footprint::default(), vector_node_from_bezpath(Rect::new(0., 0., 100., 100.).to_path(DEFAULT_ACCURACY))).await;
let spline = spline.iter_ref().next().unwrap().element; let spline = spline.iter().next().unwrap().element;
assert_eq!(spline.stroke_bezpath_iter().count(), 1); assert_eq!(spline.stroke_bezpath_iter().count(), 1);
assert_eq!(spline.point_domain.positions(), &[DVec2::ZERO, DVec2::new(100., 0.), DVec2::new(100., 100.), DVec2::new(0., 100.)]); assert_eq!(spline.point_domain.positions(), &[DVec2::ZERO, DVec2::new(100., 0.), DVec2::new(100., 100.), DVec2::new(0., 100.)]);
} }
@@ -2187,7 +2187,7 @@ mod test {
let source = Rect::new(0., 0., 100., 100.).to_path(DEFAULT_ACCURACY); let source = Rect::new(0., 0., 100., 100.).to_path(DEFAULT_ACCURACY);
let target = Rect::new(-100., -100., 0., 0.).to_path(DEFAULT_ACCURACY); let target = Rect::new(-100., -100., 0., 0.).to_path(DEFAULT_ACCURACY);
let morphed = super::morph(Footprint::default(), vector_node_from_bezpath(source), vector_node_from_bezpath(target), 0.5).await; let morphed = super::morph(Footprint::default(), vector_node_from_bezpath(source), vector_node_from_bezpath(target), 0.5).await;
let morphed = morphed.iter_ref().next().unwrap().element; let morphed = morphed.iter().next().unwrap().element;
assert_eq!( assert_eq!(
&morphed.point_domain.positions()[..4], &morphed.point_domain.positions()[..4],
vec![DVec2::new(-50., -50.), DVec2::new(50., -50.), DVec2::new(50., 50.), DVec2::new(-50., 50.)] vec![DVec2::new(-50., -50.), DVec2::new(50., -50.), DVec2::new(50., 50.), DVec2::new(-50., 50.)]
@@ -2213,7 +2213,7 @@ mod test {
async fn bevel_rect() { async fn bevel_rect() {
let source = Rect::new(0., 0., 100., 100.).to_path(DEFAULT_ACCURACY); let source = Rect::new(0., 0., 100., 100.).to_path(DEFAULT_ACCURACY);
let beveled = super::bevel(Footprint::default(), vector_node_from_bezpath(source), 2_f64.sqrt() * 10.); let beveled = super::bevel(Footprint::default(), vector_node_from_bezpath(source), 2_f64.sqrt() * 10.);
let beveled = beveled.iter_ref().next().unwrap().element; let beveled = beveled.iter().next().unwrap().element;
assert_eq!(beveled.point_domain.positions().len(), 8); assert_eq!(beveled.point_domain.positions().len(), 8);
assert_eq!(beveled.segment_domain.ids().len(), 8); assert_eq!(beveled.segment_domain.ids().len(), 8);
@@ -2241,7 +2241,7 @@ mod test {
source.push(curve.as_path_el()); source.push(curve.as_path_el());
let beveled = super::bevel((), vector_node_from_bezpath(source), 2_f64.sqrt() * 10.); let beveled = super::bevel((), vector_node_from_bezpath(source), 2_f64.sqrt() * 10.);
let beveled = beveled.iter_ref().next().unwrap().element; let beveled = beveled.iter().next().unwrap().element;
assert_eq!(beveled.point_domain.positions().len(), 4); assert_eq!(beveled.point_domain.positions().len(), 4);
assert_eq!(beveled.segment_domain.ids().len(), 3); assert_eq!(beveled.segment_domain.ids().len(), 3);
@@ -2270,7 +2270,7 @@ mod test {
*vector_table.get_mut(0).unwrap().transform = DAffine2::from_scale_angle_translation(DVec2::splat(10.), 1., DVec2::new(99., 77.)); *vector_table.get_mut(0).unwrap().transform = DAffine2::from_scale_angle_translation(DVec2::splat(10.), 1., DVec2::new(99., 77.));
let beveled = super::bevel((), Table::new_from_element(vector), 2_f64.sqrt() * 10.); let beveled = super::bevel((), Table::new_from_element(vector), 2_f64.sqrt() * 10.);
let beveled = beveled.iter_ref().next().unwrap().element; let beveled = beveled.iter().next().unwrap().element;
assert_eq!(beveled.point_domain.positions().len(), 4); assert_eq!(beveled.point_domain.positions().len(), 4);
assert_eq!(beveled.segment_domain.ids().len(), 3); assert_eq!(beveled.segment_domain.ids().len(), 3);
@@ -2293,7 +2293,7 @@ mod test {
source.line_to(Point::new(0., 100.)); source.line_to(Point::new(0., 100.));
let beveled = super::bevel(Footprint::default(), vector_node_from_bezpath(source), 999.); let beveled = super::bevel(Footprint::default(), vector_node_from_bezpath(source), 999.);
let beveled = beveled.iter_ref().next().unwrap().element; let beveled = beveled.iter().next().unwrap().element;
assert_eq!(beveled.point_domain.positions().len(), 6); assert_eq!(beveled.point_domain.positions().len(), 6);
assert_eq!(beveled.segment_domain.ids().len(), 5); assert_eq!(beveled.segment_domain.ids().len(), 5);
@@ -2317,7 +2317,7 @@ mod test {
let subpath = BezPath::from_path_segments([line, point, curve].into_iter()); let subpath = BezPath::from_path_segments([line, point, curve].into_iter());
let beveled_table = super::bevel(Footprint::default(), vector_node_from_bezpath(subpath), 5.); let beveled_table = super::bevel(Footprint::default(), vector_node_from_bezpath(subpath), 5.);
let beveled = beveled_table.iter_ref().next().unwrap().element; let beveled = beveled_table.iter().next().unwrap().element;
assert_eq!(beveled.point_domain.positions().len(), 6); assert_eq!(beveled.point_domain.positions().len(), 6);
assert_eq!(beveled.segment_domain.ids().len(), 5); assert_eq!(beveled.segment_domain.ids().len(), 5);
+1 -1
View File
@@ -436,7 +436,7 @@ impl Vector {
impl BoundingBox for Table<Vector> { impl BoundingBox for Table<Vector> {
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> { fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> {
self.iter_ref() self.iter()
.flat_map(|row| { .flat_map(|row| {
if !include_stroke { if !include_stroke {
return row.element.bounding_box_with_transform(transform * *row.transform); return row.element.bounding_box_with_transform(transform * *row.transform);
+9 -9
View File
@@ -48,7 +48,7 @@ async fn boolean_operation<I: Into<Table<Graphic>> + 'n + Send + Clone>(
let group_of_paths = group_of_paths.into(); let group_of_paths = group_of_paths.into();
// The first index is the bottom of the stack // The first index is the bottom of the stack
let mut result_vector_table = boolean_operation_on_vector_table(flatten_vector(&group_of_paths).iter_ref(), operation); let mut result_vector_table = boolean_operation_on_vector_table(flatten_vector(&group_of_paths).iter(), operation);
// Replace the transformation matrix with a mutation of the vector points themselves // Replace the transformation matrix with a mutation of the vector points themselves
if let Some(result_vector) = result_vector_table.iter_mut().next() { if let Some(result_vector) = result_vector_table.iter_mut().next() {
@@ -182,7 +182,7 @@ fn difference<'a>(vector: impl DoubleEndedIterator<Item = TableRowRef<'a, Vector
while let Some(lower_vector) = second_vector { while let Some(lower_vector) = second_vector {
let filtered_vector = vector.clone().filter(|v| *v != lower_vector).collect::<Vec<_>>().into_iter(); let filtered_vector = vector.clone().filter(|v| *v != lower_vector).collect::<Vec<_>>().into_iter();
let unioned = boolean_operation_on_vector_table(filtered_vector, BooleanOperation::Union); let unioned = boolean_operation_on_vector_table(filtered_vector, BooleanOperation::Union);
let first_row = unioned.iter_ref().next().expect("Expected at least one row after the boolean union"); let first_row = unioned.iter().next().expect("Expected at least one row after the boolean union");
let transform_of_lower_into_space_of_upper = first_row.transform.inverse() * *lower_vector.transform; let transform_of_lower_into_space_of_upper = first_row.transform.inverse() * *lower_vector.transform;
@@ -218,18 +218,18 @@ fn difference<'a>(vector: impl DoubleEndedIterator<Item = TableRowRef<'a, Vector
// Subtract the area where they intersect at least once from the union of all vector paths // Subtract the area where they intersect at least once from the union of all vector paths
let union = boolean_operation_on_vector_table(vector, BooleanOperation::Union); let union = boolean_operation_on_vector_table(vector, BooleanOperation::Union);
boolean_operation_on_vector_table(union.iter_ref().chain(std::iter::once(any_intersection.as_ref())), BooleanOperation::SubtractFront) boolean_operation_on_vector_table(union.iter().chain(std::iter::once(any_intersection.as_ref())), BooleanOperation::SubtractFront)
} }
fn flatten_vector(group_table: &Table<Graphic>) -> Table<Vector> { fn flatten_vector(group_table: &Table<Graphic>) -> Table<Vector> {
group_table group_table
.iter_ref() .iter()
.flat_map(|element| { .flat_map(|element| {
match element.element.clone() { match element.element.clone() {
Graphic::Vector(vector) => { Graphic::Vector(vector) => {
// Apply the parent group's transform to each element of the vector table // Apply the parent group's transform to each element of the vector table
vector vector
.iter() .into_iter()
.map(|mut sub_vector| { .map(|mut sub_vector| {
sub_vector.transform = *element.transform * sub_vector.transform; sub_vector.transform = *element.transform * sub_vector.transform;
@@ -251,7 +251,7 @@ fn flatten_vector(group_table: &Table<Graphic>) -> Table<Vector> {
}; };
// Apply the parent group's transform to each raster element // Apply the parent group's transform to each raster element
image.iter_ref().map(|row| make_row(*element.transform * *row.transform)).collect::<Vec<_>>() image.iter().map(|row| make_row(*element.transform * *row.transform)).collect::<Vec<_>>()
} }
Graphic::RasterGPU(image) => { Graphic::RasterGPU(image) => {
let make_row = |transform| { let make_row = |transform| {
@@ -267,7 +267,7 @@ fn flatten_vector(group_table: &Table<Graphic>) -> Table<Vector> {
}; };
// Apply the parent group's transform to each raster element // Apply the parent group's transform to each raster element
image.iter_ref().map(|row| make_row(*element.transform * *row.transform)).collect::<Vec<_>>() image.iter().map(|row| make_row(*element.transform * *row.transform)).collect::<Vec<_>>()
} }
Graphic::Group(mut group) => { Graphic::Group(mut group) => {
// Apply the parent group's transform to each element of inner group // Apply the parent group's transform to each element of inner group
@@ -276,9 +276,9 @@ fn flatten_vector(group_table: &Table<Graphic>) -> Table<Vector> {
} }
// Recursively flatten the inner group into the vector table // Recursively flatten the inner group into the vector table
let unioned = boolean_operation_on_vector_table(flatten_vector(&group).iter_ref(), BooleanOperation::Union); let unioned = boolean_operation_on_vector_table(flatten_vector(&group).iter(), BooleanOperation::Union);
unioned.iter().collect::<Vec<_>>() unioned.into_iter().collect::<Vec<_>>()
} }
} }
}) })
@@ -38,7 +38,7 @@ mod blend_std {
impl Blend<Color> for Table<Raster<CPU>> { impl Blend<Color> for Table<Raster<CPU>> {
fn blend(&self, under: &Self, blend_fn: impl Fn(Color, Color) -> Color) -> Self { fn blend(&self, under: &Self, blend_fn: impl Fn(Color, Color) -> Color) -> Self {
let mut result_table = self.clone(); let mut result_table = self.clone();
for (over, under) in result_table.iter_mut().zip(under.iter_ref()) { for (over, under) in result_table.iter_mut().zip(under.iter()) {
let data = over.element.data.iter().zip(under.element.data.iter()).map(|(a, b)| blend_fn(*a, *b)).collect(); let data = over.element.data.iter().zip(under.element.data.iter()).map(|(a, b)| blend_fn(*a, *b)).collect();
*over.element = Raster::new_cpu(Image { *over.element = Raster::new_cpu(Image {
@@ -203,7 +203,7 @@ mod test {
let opacity = 100_f64; let opacity = 100_f64;
let result = super::color_overlay((), Table::new_from_element(Raster::new_cpu(image.clone())), overlay_color, BlendMode::Multiply, opacity); let result = super::color_overlay((), Table::new_from_element(Raster::new_cpu(image.clone())), overlay_color, BlendMode::Multiply, opacity);
let result = result.iter_ref().next().unwrap().element; let result = result.iter().next().unwrap().element;
// The output should just be the original green and alpha channels (as we multiply them by 1 and other channels by 0) // The output should just be the original green and alpha channels (as we multiply them by 1 and other channels by 0)
assert_eq!(result.data[0], Color::from_rgbaf32_unchecked(0., image_color.g(), 0., image_color.a())); assert_eq!(result.data[0], Color::from_rgbaf32_unchecked(0., image_color.g(), 0., image_color.a()));
+1 -1
View File
@@ -10,7 +10,7 @@ use std::cmp::{max, min};
#[node_macro::node(category("Raster: Filter"))] #[node_macro::node(category("Raster: Filter"))]
async fn dehaze(_: impl Ctx, image_frame: Table<Raster<CPU>>, strength: Percentage) -> Table<Raster<CPU>> { async fn dehaze(_: impl Ctx, image_frame: Table<Raster<CPU>>, strength: Percentage) -> Table<Raster<CPU>> {
image_frame image_frame
.iter() .into_iter()
.map(|mut row| { .map(|mut row| {
let image = row.element; let image = row.element;
// Prepare the image data for processing // Prepare the image data for processing
+1 -1
View File
@@ -22,7 +22,7 @@ async fn blur(
gamma: bool, gamma: bool,
) -> Table<Raster<CPU>> { ) -> Table<Raster<CPU>> {
image_frame image_frame
.iter() .into_iter()
.map(|mut row| { .map(|mut row| {
let image = row.element.clone(); let image = row.element.clone();
@@ -18,7 +18,7 @@ async fn image_color_palette(
let mut histogram: Vec<usize> = vec![0; (bins + 1.) as usize]; let mut histogram: Vec<usize> = vec![0; (bins + 1.) as usize];
let mut colors: Vec<Vec<Color>> = vec![vec![]; (bins + 1.) as usize]; let mut colors: Vec<Vec<Color>> = vec![vec![]; (bins + 1.) as usize];
for row in image.iter_ref() { for row in image.iter() {
for pixel in row.element.data.iter() { for pixel in row.element.data.iter() {
let r = pixel.r() * GRID; let r = pixel.r() * GRID;
let g = pixel.g() * GRID; let g = pixel.g() * GRID;
+9 -9
View File
@@ -32,7 +32,7 @@ impl From<std::io::Error> for Error {
#[node_macro::node(category("Debug: Raster"))] #[node_macro::node(category("Debug: Raster"))]
pub fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: Table<Raster<CPU>>) -> Table<Raster<CPU>> { pub fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: Table<Raster<CPU>>) -> Table<Raster<CPU>> {
image_frame image_frame
.iter() .into_iter()
.filter_map(|mut row| { .filter_map(|mut row| {
let image_frame_transform = row.transform; let image_frame_transform = row.transform;
let image = row.element; let image = row.element;
@@ -104,10 +104,10 @@ pub fn combine_channels(
#[expose] alpha: Table<Raster<CPU>>, #[expose] alpha: Table<Raster<CPU>>,
) -> Table<Raster<CPU>> { ) -> Table<Raster<CPU>> {
let max_len = red.len().max(green.len()).max(blue.len()).max(alpha.len()); let max_len = red.len().max(green.len()).max(blue.len()).max(alpha.len());
let red = red.iter().map(Some).chain(std::iter::repeat(None)).take(max_len); let red = red.into_iter().map(Some).chain(std::iter::repeat(None)).take(max_len);
let green = green.iter().map(Some).chain(std::iter::repeat(None)).take(max_len); let green = green.into_iter().map(Some).chain(std::iter::repeat(None)).take(max_len);
let blue = blue.iter().map(Some).chain(std::iter::repeat(None)).take(max_len); let blue = blue.into_iter().map(Some).chain(std::iter::repeat(None)).take(max_len);
let alpha = alpha.iter().map(Some).chain(std::iter::repeat(None)).take(max_len); let alpha = alpha.into_iter().map(Some).chain(std::iter::repeat(None)).take(max_len);
red.zip(green) red.zip(green)
.zip(blue) .zip(blue)
@@ -193,14 +193,14 @@ pub fn mask(
stencil: Table<Raster<CPU>>, stencil: Table<Raster<CPU>>,
) -> Table<Raster<CPU>> { ) -> Table<Raster<CPU>> {
// TODO: Figure out what it means to support multiple stencil rows? // TODO: Figure out what it means to support multiple stencil rows?
let Some(stencil) = stencil.iter().next() else { let Some(stencil) = stencil.into_iter().next() else {
// No stencil provided so we return the original image // No stencil provided so we return the original image
return image; return image;
}; };
let stencil_size = DVec2::new(stencil.element.width as f64, stencil.element.height as f64); let stencil_size = DVec2::new(stencil.element.width as f64, stencil.element.height as f64);
image image
.iter() .into_iter()
.filter_map(|mut row| { .filter_map(|mut row| {
let image_size = DVec2::new(row.element.width as f64, row.element.height as f64); let image_size = DVec2::new(row.element.width as f64, row.element.height as f64);
let mask_size = stencil.transform.decompose_scale(); let mask_size = stencil.transform.decompose_scale();
@@ -235,7 +235,7 @@ pub fn mask(
#[node_macro::node(category(""))] #[node_macro::node(category(""))]
pub fn extend_image_to_bounds(_: impl Ctx, image: Table<Raster<CPU>>, bounds: DAffine2) -> Table<Raster<CPU>> { pub fn extend_image_to_bounds(_: impl Ctx, image: Table<Raster<CPU>>, bounds: DAffine2) -> Table<Raster<CPU>> {
image image
.iter() .into_iter()
.map(|mut row| { .map(|mut row| {
let image_aabb = Bbox::unit().affine_transform(row.transform).to_axis_aligned_bbox(); let image_aabb = Bbox::unit().affine_transform(row.transform).to_axis_aligned_bbox();
let bounds_aabb = Bbox::unit().affine_transform(bounds.transform()).to_axis_aligned_bbox(); let bounds_aabb = Bbox::unit().affine_transform(bounds.transform()).to_axis_aligned_bbox();
@@ -246,7 +246,7 @@ pub fn extend_image_to_bounds(_: impl Ctx, image: Table<Raster<CPU>>, bounds: DA
let image_data = &row.element.data; let image_data = &row.element.data;
let (image_width, image_height) = (row.element.width, row.element.height); let (image_width, image_height) = (row.element.width, row.element.height);
if image_width == 0 || image_height == 0 { if image_width == 0 || image_height == 0 {
return empty_image((), bounds, Color::TRANSPARENT).iter().next().unwrap(); return empty_image((), bounds, Color::TRANSPARENT).into_iter().next().unwrap();
} }
let orig_image_scale = DVec2::new(image_width as f64, image_height as f64); let orig_image_scale = DVec2::new(image_width as f64, image_height as f64);
+1 -1
View File
@@ -101,7 +101,7 @@ fn string_to_bytes(_: impl Ctx, string: String) -> Vec<u8> {
#[node_macro::node(category("Web Request"), name("Image to Bytes"))] #[node_macro::node(category("Web Request"), name("Image to Bytes"))]
fn image_to_bytes(_: impl Ctx, image: Table<Raster<CPU>>) -> Vec<u8> { fn image_to_bytes(_: impl Ctx, image: Table<Raster<CPU>>) -> Vec<u8> {
let Some(image) = image.iter_ref().next() else { return vec![] }; let Some(image) = image.iter().next() else { return vec![] };
image.element.data.iter().flat_map(|color| color.to_rgb8_srgb().into_iter()).collect::<Vec<u8>>() image.element.data.iter().flat_map(|color| color.to_rgb8_srgb().into_iter()).collect::<Vec<u8>>()
} }
+23 -23
View File
@@ -236,7 +236,7 @@ pub trait Render: BoundingBox + RenderComplexity {
impl Render for Table<Graphic> { impl Render for Table<Graphic> {
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) { fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
let mut iter = self.iter_ref().peekable(); let mut iter = self.iter().peekable();
let mut mask_state = None; let mut mask_state = None;
while let Some(row) = iter.next() { while let Some(row) = iter.next() {
@@ -288,7 +288,7 @@ impl Render for Table<Graphic> {
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) { fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
let mut iter = self.iter_ref().peekable(); let mut iter = self.iter().peekable();
let mut mask_element_and_transform = None; let mut mask_element_and_transform = None;
while let Some(row) = iter.next() { while let Some(row) = iter.next() {
@@ -356,7 +356,7 @@ impl Render for Table<Graphic> {
} }
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, element_id: Option<NodeId>) { fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, element_id: Option<NodeId>) {
for row in self.iter_ref() { for row in self.iter() {
if let Some(element_id) = row.source_node_id { if let Some(element_id) = row.source_node_id {
let mut footprint = footprint; let mut footprint = footprint;
footprint.transform *= *row.transform; footprint.transform *= *row.transform;
@@ -368,7 +368,7 @@ impl Render for Table<Graphic> {
if let Some(group_id) = element_id { if let Some(group_id) = element_id {
let mut all_upstream_click_targets = Vec::new(); let mut all_upstream_click_targets = Vec::new();
for row in self.iter_ref() { for row in self.iter() {
let mut new_click_targets = Vec::new(); let mut new_click_targets = Vec::new();
row.element.add_upstream_click_targets(&mut new_click_targets); row.element.add_upstream_click_targets(&mut new_click_targets);
@@ -384,7 +384,7 @@ impl Render for Table<Graphic> {
} }
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) { fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
for row in self.iter_ref() { for row in self.iter() {
let mut new_click_targets = Vec::new(); let mut new_click_targets = Vec::new();
row.element.add_upstream_click_targets(&mut new_click_targets); row.element.add_upstream_click_targets(&mut new_click_targets);
@@ -398,7 +398,7 @@ impl Render for Table<Graphic> {
} }
fn contains_artboard(&self) -> bool { fn contains_artboard(&self) -> bool {
self.iter_ref().any(|row| row.element.contains_artboard()) self.iter().any(|row| row.element.contains_artboard())
} }
fn new_ids_from_hash(&mut self, _reference: Option<NodeId>) { fn new_ids_from_hash(&mut self, _reference: Option<NodeId>) {
@@ -410,7 +410,7 @@ impl Render for Table<Graphic> {
impl Render for Table<Vector> { impl Render for Table<Vector> {
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) { fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
for row in self.iter_ref() { for row in self.iter() {
let multiplied_transform = *row.transform; let multiplied_transform = *row.transform;
let vector = &row.element; let vector = &row.element;
// Only consider strokes with non-zero weight, since default strokes with zero weight would prevent assigning the correct stroke transform // Only consider strokes with non-zero weight, since default strokes with zero weight would prevent assigning the correct stroke transform
@@ -519,7 +519,7 @@ impl Render for Table<Vector> {
use vello::kurbo::{Cap, Join}; use vello::kurbo::{Cap, Join};
use vello::peniko; use vello::peniko;
for row in self.iter_ref() { for row in self.iter() {
let multiplied_transform = parent_transform * *row.transform; let multiplied_transform = parent_transform * *row.transform;
let has_real_stroke = row.element.style.stroke().filter(|stroke| stroke.weight() > 0.); let has_real_stroke = row.element.style.stroke().filter(|stroke| stroke.weight() > 0.);
let set_stroke_transform = has_real_stroke.map(|stroke| stroke.transform).filter(|transform| transform.matrix2.determinant() != 0.); let set_stroke_transform = has_real_stroke.map(|stroke| stroke.transform).filter(|transform| transform.matrix2.determinant() != 0.);
@@ -728,7 +728,7 @@ impl Render for Table<Vector> {
} }
fn collect_metadata(&self, metadata: &mut RenderMetadata, mut footprint: Footprint, element_id: Option<NodeId>) { fn collect_metadata(&self, metadata: &mut RenderMetadata, mut footprint: Footprint, element_id: Option<NodeId>) {
for row in self.iter_ref() { for row in self.iter() {
let transform = *row.transform; let transform = *row.transform;
let vector = row.element; let vector = row.element;
@@ -772,7 +772,7 @@ impl Render for Table<Vector> {
} }
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) { fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
for row in self.iter_ref() { for row in self.iter() {
let stroke_width = row.element.style.stroke().as_ref().map_or(0., Stroke::weight); let stroke_width = row.element.style.stroke().as_ref().map_or(0., Stroke::weight);
let filled = row.element.style.fill() != &Fill::None; let filled = row.element.style.fill() != &Fill::None;
let fill = |mut subpath: Subpath<_>| { let fill = |mut subpath: Subpath<_>| {
@@ -909,38 +909,38 @@ impl Render for Artboard {
impl Render for Table<Artboard> { impl Render for Table<Artboard> {
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) { fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
for artboard in self.iter_ref() { for artboard in self.iter() {
artboard.element.render_svg(render, render_params); artboard.element.render_svg(render, render_params);
} }
} }
#[cfg(feature = "vello")] #[cfg(feature = "vello")]
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) { fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) {
for row in self.iter_ref() { for row in self.iter() {
row.element.render_to_vello(scene, transform, context, render_params); row.element.render_to_vello(scene, transform, context, render_params);
} }
} }
fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, _element_id: Option<NodeId>) { fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, _element_id: Option<NodeId>) {
for row in self.iter_ref() { for row in self.iter() {
row.element.collect_metadata(metadata, footprint, *row.source_node_id); row.element.collect_metadata(metadata, footprint, *row.source_node_id);
} }
} }
fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) { fn add_upstream_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
for row in self.iter_ref() { for row in self.iter() {
row.element.add_upstream_click_targets(click_targets); row.element.add_upstream_click_targets(click_targets);
} }
} }
fn contains_artboard(&self) -> bool { fn contains_artboard(&self) -> bool {
self.iter_ref().count() > 0 self.iter().count() > 0
} }
} }
impl Render for Table<Raster<CPU>> { impl Render for Table<Raster<CPU>> {
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) { fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
for row in self.iter_ref() { for row in self.iter() {
let image = row.element; let image = row.element;
let transform = *row.transform; let transform = *row.transform;
@@ -1029,7 +1029,7 @@ impl Render for Table<Raster<CPU>> {
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, _: &mut RenderContext, render_params: &RenderParams) { fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, _: &mut RenderContext, render_params: &RenderParams) {
use vello::peniko; use vello::peniko;
for row in self.iter_ref() { for row in self.iter() {
let image = &row.element; let image = &row.element;
if image.data.is_empty() { if image.data.is_empty() {
continue; continue;
@@ -1068,7 +1068,7 @@ impl Render for Table<Raster<CPU>> {
metadata.click_targets.insert(element_id, vec![ClickTarget::new_with_subpath(subpath, 0.)]); metadata.click_targets.insert(element_id, vec![ClickTarget::new_with_subpath(subpath, 0.)]);
metadata.upstream_footprints.insert(element_id, footprint); metadata.upstream_footprints.insert(element_id, footprint);
// TODO: Find a way to handle more than one row of the graphical data table // TODO: Find a way to handle more than one row of the graphical data table
if let Some(image) = self.iter_ref().next() { if let Some(image) = self.iter().next() {
metadata.local_transforms.insert(element_id, *image.transform); metadata.local_transforms.insert(element_id, *image.transform);
} }
} }
@@ -1090,7 +1090,7 @@ impl Render for Table<Raster<GPU>> {
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, _render_params: &RenderParams) { fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, _render_params: &RenderParams) {
use vello::peniko; use vello::peniko;
for row in self.iter_ref() { for row in self.iter() {
let blend_mode = *row.alpha_blending; let blend_mode = *row.alpha_blending;
let mut layer = false; let mut layer = false;
if blend_mode != Default::default() { if blend_mode != Default::default() {
@@ -1126,7 +1126,7 @@ impl Render for Table<Raster<GPU>> {
metadata.click_targets.insert(element_id, vec![ClickTarget::new_with_subpath(subpath, 0.)]); metadata.click_targets.insert(element_id, vec![ClickTarget::new_with_subpath(subpath, 0.)]);
metadata.upstream_footprints.insert(element_id, footprint); metadata.upstream_footprints.insert(element_id, footprint);
// TODO: Find a way to handle more than one row of the graphical data table // TODO: Find a way to handle more than one row of the graphical data table
if let Some(image) = self.iter_ref().next() { if let Some(image) = self.iter().next() {
metadata.local_transforms.insert(element_id, *image.transform); metadata.local_transforms.insert(element_id, *image.transform);
} }
} }
@@ -1166,7 +1166,7 @@ impl Render for Graphic {
Graphic::Vector(vector) => { Graphic::Vector(vector) => {
metadata.upstream_footprints.insert(element_id, footprint); metadata.upstream_footprints.insert(element_id, footprint);
// TODO: Find a way to handle more than one row of the graphical data table // TODO: Find a way to handle more than one row of the graphical data table
if let Some(vector) = vector.iter_ref().next() { if let Some(vector) = vector.iter().next() {
metadata.first_element_source_id.insert(element_id, *vector.source_node_id); metadata.first_element_source_id.insert(element_id, *vector.source_node_id);
metadata.local_transforms.insert(element_id, *vector.transform); metadata.local_transforms.insert(element_id, *vector.transform);
} }
@@ -1175,7 +1175,7 @@ impl Render for Graphic {
metadata.upstream_footprints.insert(element_id, footprint); metadata.upstream_footprints.insert(element_id, footprint);
// TODO: Find a way to handle more than one row of images // TODO: Find a way to handle more than one row of images
if let Some(image) = raster_frame.iter_ref().next() { if let Some(image) = raster_frame.iter().next() {
metadata.local_transforms.insert(element_id, *image.transform); metadata.local_transforms.insert(element_id, *image.transform);
} }
} }
@@ -1183,7 +1183,7 @@ impl Render for Graphic {
metadata.upstream_footprints.insert(element_id, footprint); metadata.upstream_footprints.insert(element_id, footprint);
// TODO: Find a way to handle more than one row of images // TODO: Find a way to handle more than one row of images
if let Some(image) = raster_frame.iter_ref().next() { if let Some(image) = raster_frame.iter().next() {
metadata.local_transforms.insert(element_id, *image.transform); metadata.local_transforms.insert(element_id, *image.transform);
} }
} }
@@ -11,7 +11,7 @@ pub async fn upload_texture<'a: 'n>(_: impl ExtractFootprint + Ctx, input: Table
let device = &executor.context.device; let device = &executor.context.device;
let queue = &executor.context.queue; let queue = &executor.context.queue;
let table = input let table = input
.iter_ref() .iter()
.map(|row| { .map(|row| {
let image = row.element; let image = row.element;
let rgba8_data: Vec<SRGBA8> = image.data.iter().map(|x| (*x).into()).collect(); let rgba8_data: Vec<SRGBA8> = image.data.iter().map(|x| (*x).into()).collect();