mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 23:08:05 +08:00
Rename the Group type to Graphic everywhere (#3009)
This commit is contained in:
@@ -14,7 +14,7 @@ use std::hash::Hash;
|
||||
/// Some [`ArtboardData`] with some optional clipping bounds that can be exported.
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Artboard {
|
||||
pub group: Table<Graphic>,
|
||||
pub content: Table<Graphic>,
|
||||
pub label: String,
|
||||
pub location: IVec2,
|
||||
pub dimensions: IVec2,
|
||||
@@ -31,7 +31,7 @@ impl Default for Artboard {
|
||||
impl Artboard {
|
||||
pub fn new(location: IVec2, dimensions: IVec2) -> Self {
|
||||
Self {
|
||||
group: Table::new(),
|
||||
content: Table::new(),
|
||||
label: "Artboard".to_string(),
|
||||
location: location.min(location + dimensions),
|
||||
dimensions: dimensions.abs(),
|
||||
@@ -47,7 +47,7 @@ impl BoundingBox for Artboard {
|
||||
if self.clip {
|
||||
Some(artboard_bounds)
|
||||
} else {
|
||||
[self.group.bounding_box(transform, include_stroke), Some(artboard_bounds)]
|
||||
[self.content.bounding_box(transform, include_stroke), Some(artboard_bounds)]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.reduce(Quad::combine_bounds)
|
||||
@@ -56,7 +56,7 @@ impl BoundingBox for Artboard {
|
||||
}
|
||||
|
||||
// TODO: Eventually remove this migration document upgrade code
|
||||
pub fn migrate_artboard_group<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Table<Artboard>, D::Error> {
|
||||
pub fn migrate_artboard<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Table<Artboard>, D::Error> {
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, Default, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
||||
@@ -84,7 +84,7 @@ pub fn migrate_artboard_group<'de, D: serde::Deserializer<'de>>(deserializer: D)
|
||||
}
|
||||
table
|
||||
}
|
||||
EitherFormat::ArtboardTable(artboard_group_table) => artboard_group_table,
|
||||
EitherFormat::ArtboardTable(artboard_table) => artboard_table,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ async fn create_artboard<T: Into<Table<Graphic>> + 'n>(
|
||||
footprint.translate(location.as_dvec2());
|
||||
new_ctx = new_ctx.with_footprint(footprint);
|
||||
}
|
||||
let group = content.eval(new_ctx.into_context()).await.into();
|
||||
let content = content.eval(new_ctx.into_context()).await.into();
|
||||
|
||||
let dimensions = dimensions.as_ivec2().max(IVec2::ONE);
|
||||
|
||||
@@ -128,7 +128,7 @@ async fn create_artboard<T: Into<Table<Graphic>> + 'n>(
|
||||
let dimensions = dimensions.abs();
|
||||
|
||||
Table::new_from_element(Artboard {
|
||||
group,
|
||||
content,
|
||||
label,
|
||||
location,
|
||||
dimensions,
|
||||
|
||||
@@ -13,7 +13,7 @@ use std::hash::Hash;
|
||||
/// The possible forms of graphical content that can be rendered by the Render node into either an image or SVG syntax.
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny, serde::Serialize, serde::Deserialize)]
|
||||
pub enum Graphic {
|
||||
Group(Table<Graphic>),
|
||||
Graphic(Table<Graphic>),
|
||||
Vector(Table<Vector>),
|
||||
RasterCPU(Table<Raster<CPU>>),
|
||||
RasterGPU(Table<Raster<GPU>>),
|
||||
@@ -21,14 +21,14 @@ pub enum Graphic {
|
||||
|
||||
impl Default for Graphic {
|
||||
fn default() -> Self {
|
||||
Self::Group(Default::default())
|
||||
Self::Graphic(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
// Group
|
||||
// Graphic
|
||||
impl From<Table<Graphic>> for Graphic {
|
||||
fn from(group: Table<Graphic>) -> Self {
|
||||
Graphic::Group(group)
|
||||
fn from(graphic: Table<Graphic>) -> Self {
|
||||
Graphic::Graphic(graphic)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,16 +111,16 @@ impl From<DAffine2> for Table<Graphic> {
|
||||
}
|
||||
|
||||
impl Graphic {
|
||||
pub fn as_group(&self) -> Option<&Table<Graphic>> {
|
||||
pub fn as_graphic(&self) -> Option<&Table<Graphic>> {
|
||||
match self {
|
||||
Graphic::Group(group) => Some(group),
|
||||
Graphic::Graphic(graphic) => Some(graphic),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_group_mut(&mut self) -> Option<&mut Table<Graphic>> {
|
||||
pub fn as_graphic_mut(&mut self) -> Option<&mut Table<Graphic>> {
|
||||
match self {
|
||||
Graphic::Group(group) => Some(group),
|
||||
Graphic::Graphic(graphic) => Some(graphic),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ impl Graphic {
|
||||
pub fn had_clip_enabled(&self) -> bool {
|
||||
match self {
|
||||
Graphic::Vector(vector) => vector.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::Group(group) => group.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::Graphic(graphic) => graphic.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::RasterCPU(raster) => raster.iter().all(|row| row.alpha_blending.clip),
|
||||
Graphic::RasterGPU(raster) => raster.iter().all(|row| row.alpha_blending.clip),
|
||||
}
|
||||
@@ -180,7 +180,7 @@ impl BoundingBox for Graphic {
|
||||
Graphic::Vector(vector) => vector.bounding_box(transform, include_stroke),
|
||||
Graphic::RasterCPU(raster) => raster.bounding_box(transform, include_stroke),
|
||||
Graphic::RasterGPU(raster) => raster.bounding_box(transform, include_stroke),
|
||||
Graphic::Group(group) => group.bounding_box(transform, include_stroke),
|
||||
Graphic::Graphic(graphic) => graphic.bounding_box(transform, include_stroke),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -295,7 +295,7 @@ async fn flatten_graphic(_: impl Ctx, content: Table<Graphic>, fully_flatten: bo
|
||||
|
||||
match current_element {
|
||||
// If we're allowed to recurse, flatten any graphics we encounter
|
||||
Graphic::Group(mut current_element) if recurse => {
|
||||
Graphic::Graphic(mut current_element) if recurse => {
|
||||
// Apply the parent graphic's transform to all child elements
|
||||
for graphic in current_element.iter_mut() {
|
||||
*graphic.transform = *current_row.transform * *graphic.transform;
|
||||
@@ -332,7 +332,7 @@ async fn flatten_vector(_: impl Ctx, content: Table<Graphic>) -> Table<Vector> {
|
||||
|
||||
match current_graphic {
|
||||
// If we're allowed to recurse, flatten any tables we encounter
|
||||
Graphic::Group(mut current_graphic_table) => {
|
||||
Graphic::Graphic(mut current_graphic_table) => {
|
||||
// Apply the parent graphic's transform to all child elements
|
||||
for graphic in current_graphic_table.iter_mut() {
|
||||
*graphic.transform = *current_graphic_row.transform * *graphic.transform;
|
||||
@@ -418,7 +418,7 @@ impl<T: Clone> AtIndex for Table<T> {
|
||||
}
|
||||
|
||||
// TODO: Eventually remove this migration document upgrade code
|
||||
pub fn migrate_group<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Table<Graphic>, D::Error> {
|
||||
pub fn migrate_graphic<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Table<Graphic>, D::Error> {
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DynAny, Default, serde::Serialize, serde::Deserialize)]
|
||||
@@ -441,24 +441,24 @@ pub fn migrate_group<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Resul
|
||||
|
||||
Ok(match EitherFormat::deserialize(deserializer)? {
|
||||
EitherFormat::OldGraphicGroup(old) => {
|
||||
let mut group_table = Table::new();
|
||||
let mut graphic_table = Table::new();
|
||||
for (graphic, source_node_id) in old.elements {
|
||||
group_table.push(TableRow {
|
||||
graphic_table.push(TableRow {
|
||||
element: graphic,
|
||||
transform: old.transform,
|
||||
alpha_blending: old.alpha_blending,
|
||||
source_node_id,
|
||||
});
|
||||
}
|
||||
group_table
|
||||
graphic_table
|
||||
}
|
||||
EitherFormat::Table(value) => {
|
||||
// Try to deserialize as either table format
|
||||
if let Ok(old_table) = serde_json::from_value::<Table<GraphicGroup>>(value.clone()) {
|
||||
let mut group_table = Table::new();
|
||||
let mut graphic_table = Table::new();
|
||||
for row in old_table.iter() {
|
||||
for (graphic, source_node_id) in &row.element.elements {
|
||||
group_table.push(TableRow {
|
||||
graphic_table.push(TableRow {
|
||||
element: graphic.clone(),
|
||||
transform: *row.transform,
|
||||
alpha_blending: *row.alpha_blending,
|
||||
@@ -466,7 +466,7 @@ pub fn migrate_group<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Resul
|
||||
});
|
||||
}
|
||||
}
|
||||
group_table
|
||||
graphic_table
|
||||
} else if let Ok(new_table) = serde_json::from_value::<Table<Graphic>>(value) {
|
||||
new_table
|
||||
} else {
|
||||
|
||||
@@ -356,7 +356,7 @@ pub fn migrate_image_frame_row<'de, D: serde::Deserializer<'de>>(deserializer: D
|
||||
GraphicElement::RasterFrame(RasterFrame::ImageFrame(image)) => Self {
|
||||
image: image.iter().next().unwrap().element.clone(),
|
||||
},
|
||||
_ => panic!("Expected Image, found {:?}", element),
|
||||
_ => panic!("Expected Image, found {element:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@ impl<T: RenderComplexity> RenderComplexity for Table<T> {
|
||||
|
||||
impl RenderComplexity for Artboard {
|
||||
fn render_complexity(&self) -> usize {
|
||||
self.group.render_complexity()
|
||||
self.content.render_complexity()
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderComplexity for Graphic {
|
||||
fn render_complexity(&self) -> usize {
|
||||
match self {
|
||||
Self::Group(table) => table.render_complexity(),
|
||||
Self::Graphic(table) => table.render_complexity(),
|
||||
Self::Vector(table) => table.render_complexity(),
|
||||
Self::RasterCPU(table) => table.render_complexity(),
|
||||
Self::RasterGPU(table) => table.render_complexity(),
|
||||
|
||||
@@ -122,7 +122,7 @@ impl ClickTarget {
|
||||
}
|
||||
|
||||
// Check if shape is entirely within selection
|
||||
let any_point_from_subpath = subpath.manipulator_groups().first().map(|group| group.anchor);
|
||||
let any_point_from_subpath = subpath.manipulator_groups().first().map(|manipulators| manipulators.anchor);
|
||||
any_point_from_subpath.is_some_and(|shape_point| bezier_iter().map(|bezier| bezier.winding(shape_point)).sum::<i32>() != 0)
|
||||
}
|
||||
ClickTargetType::FreePoint(point) => bezier_iter().map(|bezier: bezier_rs::Bezier| bezier.winding(point.position)).sum::<i32>() != 0,
|
||||
|
||||
@@ -188,9 +188,9 @@ pub fn bezpath_to_manipulator_groups(bezpath: &BezPath) -> (Vec<ManipulatorGroup
|
||||
ManipulatorGroup::new(point_to_dvec2(point2), Some(point_to_dvec2(point1)), None)
|
||||
}
|
||||
kurbo::PathEl::ClosePath => {
|
||||
if let Some(last_group) = manipulator_groups.pop() {
|
||||
if let Some(first_group) = manipulator_groups.first_mut() {
|
||||
first_group.out_handle = last_group.in_handle;
|
||||
if let Some(last_manipulators) = manipulator_groups.pop() {
|
||||
if let Some(first_manipulators) = manipulator_groups.first_mut() {
|
||||
first_manipulators.out_handle = last_manipulators.in_handle;
|
||||
}
|
||||
}
|
||||
is_closed = true;
|
||||
|
||||
@@ -811,13 +811,13 @@ impl Vector {
|
||||
/// Construct a [`bezier_rs::Bezier`] curve from an iterator of segments with (handles, start point, end point) independently of discontinuities.
|
||||
pub fn subpath_from_segments_ignore_discontinuities(&self, segments: impl Iterator<Item = (BezierHandles, usize, usize)>) -> Option<bezier_rs::Subpath<PointId>> {
|
||||
let mut first_point = None;
|
||||
let mut groups = Vec::new();
|
||||
let mut manipulators_list = Vec::new();
|
||||
let mut last: Option<(usize, BezierHandles)> = None;
|
||||
|
||||
for (handle, start, end) in segments {
|
||||
first_point = Some(first_point.unwrap_or(start));
|
||||
|
||||
groups.push(ManipulatorGroup {
|
||||
manipulators_list.push(ManipulatorGroup {
|
||||
anchor: self.point_domain.positions()[start],
|
||||
in_handle: last.and_then(|(_, handle)| handle.end()),
|
||||
out_handle: handle.start(),
|
||||
@@ -827,13 +827,13 @@ impl Vector {
|
||||
last = Some((end, handle));
|
||||
}
|
||||
|
||||
let closed = groups.len() > 1 && last.map(|(point, _)| point) == first_point;
|
||||
let closed = manipulators_list.len() > 1 && last.map(|(point, _)| point) == first_point;
|
||||
|
||||
if let Some((end, last_handle)) = last {
|
||||
if closed {
|
||||
groups[0].in_handle = last_handle.end();
|
||||
manipulators_list[0].in_handle = last_handle.end();
|
||||
} else {
|
||||
groups.push(ManipulatorGroup {
|
||||
manipulators_list.push(ManipulatorGroup {
|
||||
anchor: self.point_domain.positions()[end],
|
||||
in_handle: last_handle.end(),
|
||||
out_handle: None,
|
||||
@@ -842,7 +842,7 @@ impl Vector {
|
||||
}
|
||||
}
|
||||
|
||||
Some(bezier_rs::Subpath::new(groups, closed))
|
||||
Some(bezier_rs::Subpath::new(manipulators_list, closed))
|
||||
}
|
||||
|
||||
/// Construct a [`bezier_rs::Bezier`] curve for each region, skipping invalid regions.
|
||||
@@ -905,7 +905,7 @@ impl Vector {
|
||||
|
||||
/// Construct a [`bezier_rs::Bezier`] curve for stroke.
|
||||
pub fn stroke_bezier_paths(&self) -> impl Iterator<Item = bezier_rs::Subpath<PointId>> {
|
||||
self.build_stroke_path_iter().map(|(group, closed)| bezier_rs::Subpath::new(group, closed))
|
||||
self.build_stroke_path_iter().map(|(manipulators_list, closed)| bezier_rs::Subpath::new(manipulators_list, closed))
|
||||
}
|
||||
|
||||
/// Construct and return an iterator of Vec of `(bezier_rs::ManipulatorGroup<PointId>], bool)` for stroke.
|
||||
@@ -916,15 +916,15 @@ impl Vector {
|
||||
|
||||
/// Construct a [`kurbo::BezPath`] curve for stroke.
|
||||
pub fn stroke_bezpath_iter(&self) -> impl Iterator<Item = kurbo::BezPath> {
|
||||
self.build_stroke_path_iter().map(|(group, closed)| {
|
||||
self.build_stroke_path_iter().map(|(manipulators_list, closed)| {
|
||||
let mut bezpath = kurbo::BezPath::new();
|
||||
let mut out_handle;
|
||||
|
||||
let Some(first) = group.first() else { return bezpath };
|
||||
let Some(first) = manipulators_list.first() else { return bezpath };
|
||||
bezpath.move_to(dvec2_to_point(first.anchor));
|
||||
out_handle = first.out_handle;
|
||||
|
||||
for manipulator in group.iter().skip(1) {
|
||||
for manipulator in manipulators_list.iter().skip(1) {
|
||||
match (out_handle, manipulator.in_handle) {
|
||||
(Some(handle_start), Some(handle_end)) => bezpath.curve_to(dvec2_to_point(handle_start), dvec2_to_point(handle_end), dvec2_to_point(manipulator.anchor)),
|
||||
(None, None) => bezpath.line_to(dvec2_to_point(manipulator.anchor)),
|
||||
@@ -954,7 +954,7 @@ impl Vector {
|
||||
|
||||
pub fn manipulator_group_id(&self, id: impl Into<PointId>) -> Option<ManipulatorGroup<PointId>> {
|
||||
let id = id.into();
|
||||
self.manipulator_groups().find(|group| group.id == id)
|
||||
self.manipulator_groups().find(|manipulators| manipulators.id == id)
|
||||
}
|
||||
|
||||
pub fn transform(&mut self, transform: DAffine2) {
|
||||
@@ -1047,13 +1047,13 @@ impl Iterator for StrokePathIter<'_> {
|
||||
|
||||
// There will always be one (seeing as we checked above)
|
||||
let mut point_index = current_start;
|
||||
let mut groups = Vec::new();
|
||||
let mut manipulators_list = Vec::new();
|
||||
let mut in_handle = None;
|
||||
let mut closed = false;
|
||||
loop {
|
||||
let Some(val) = self.points[point_index].take_first() else {
|
||||
// Dead end
|
||||
groups.push(ManipulatorGroup {
|
||||
manipulators_list.push(ManipulatorGroup {
|
||||
anchor: self.vector.point_domain.positions()[point_index],
|
||||
in_handle,
|
||||
out_handle: None,
|
||||
@@ -1072,7 +1072,7 @@ impl Iterator for StrokePathIter<'_> {
|
||||
} else {
|
||||
self.vector.segment_domain.end_point()[val.segment_index]
|
||||
};
|
||||
groups.push(ManipulatorGroup {
|
||||
manipulators_list.push(ManipulatorGroup {
|
||||
anchor: self.vector.point_domain.positions()[point_index],
|
||||
in_handle,
|
||||
out_handle: handles.start(),
|
||||
@@ -1085,12 +1085,12 @@ impl Iterator for StrokePathIter<'_> {
|
||||
self.points[next_point_index].take_eq(val.flipped());
|
||||
if next_point_index == current_start {
|
||||
closed = true;
|
||||
groups[0].in_handle = in_handle;
|
||||
manipulators_list[0].in_handle = in_handle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Some((groups, closed))
|
||||
Some((manipulators_list, closed))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ async fn assign_colors<T>(
|
||||
_: impl Ctx,
|
||||
#[implementations(Table<Graphic>, Table<Vector>)]
|
||||
#[widget(ParsedWidgetOverride::Hidden)]
|
||||
/// The vector elements, or group of vector elements, to apply the fill and/or stroke style to.
|
||||
/// The content with vector paths to apply the fill and/or stroke style to.
|
||||
mut content: T,
|
||||
#[default(true)]
|
||||
/// Whether to style the fill.
|
||||
@@ -118,7 +118,7 @@ async fn fill<F: Into<Fill> + 'n + Send, V>(
|
||||
Table<Graphic>,
|
||||
Table<Graphic>
|
||||
)]
|
||||
/// The vector elements, or group of vector elements, to apply the fill to.
|
||||
/// The content with vector paths to apply the fill style to.
|
||||
mut content: V,
|
||||
#[implementations(
|
||||
Fill,
|
||||
@@ -156,7 +156,7 @@ where
|
||||
async fn stroke<C: Into<Option<Color>> + 'n + Send, V>(
|
||||
_: impl Ctx,
|
||||
#[implementations(Table<Vector>, Table<Vector>, Table<Graphic>, Table<Graphic>)]
|
||||
/// The vector elements, or group of vector elements, to apply the stroke to.
|
||||
/// The content with vector paths to apply the stroke style to.
|
||||
mut content: Table<V>,
|
||||
#[implementations(
|
||||
Option<Color>,
|
||||
@@ -447,7 +447,7 @@ async fn round_corners(
|
||||
let source_node_id = source.source_node_id;
|
||||
let source = source.element;
|
||||
|
||||
let upstream_group = source.upstream_group.clone();
|
||||
let upstream_nested_layers = source.upstream_nested_layers.clone();
|
||||
|
||||
// Flip the roundness to help with user intuition
|
||||
let roundness = 1. - roundness;
|
||||
@@ -532,7 +532,7 @@ async fn round_corners(
|
||||
result.append_bezpath(rounded_subpath);
|
||||
}
|
||||
|
||||
result.upstream_group = upstream_group;
|
||||
result.upstream_nested_layers = upstream_nested_layers;
|
||||
|
||||
TableRow {
|
||||
element: result,
|
||||
@@ -687,18 +687,18 @@ async fn auto_tangents(
|
||||
for mut subpath in source.stroke_bezier_paths() {
|
||||
subpath.apply_transform(transform);
|
||||
|
||||
let groups = subpath.manipulator_groups();
|
||||
if groups.len() < 2 {
|
||||
let manipulators_list = subpath.manipulator_groups();
|
||||
if manipulators_list.len() < 2 {
|
||||
// Not enough points for softening or handle removal
|
||||
result.append_subpath(subpath, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut new_groups = Vec::with_capacity(groups.len());
|
||||
let mut new_manipulators_list = Vec::with_capacity(manipulators_list.len());
|
||||
let is_closed = subpath.closed();
|
||||
|
||||
for i in 0..groups.len() {
|
||||
let curr = &groups[i];
|
||||
for i in 0..manipulators_list.len() {
|
||||
let curr = &manipulators_list[i];
|
||||
|
||||
if preserve_existing {
|
||||
// Check if this point has handles that are meaningfully different from the anchor
|
||||
@@ -706,15 +706,15 @@ async fn auto_tangents(
|
||||
|| (curr.out_handle.is_some() && !curr.out_handle.unwrap().abs_diff_eq(curr.anchor, 1e-5));
|
||||
|
||||
// If the point already has handles, or if it's an endpoint of an open path, keep it as is.
|
||||
if has_handles || (!is_closed && (i == 0 || i == groups.len() - 1)) {
|
||||
new_groups.push(*curr);
|
||||
if has_handles || (!is_closed && (i == 0 || i == manipulators_list.len() - 1)) {
|
||||
new_manipulators_list.push(*curr);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If spread is 0, remove handles for this point, making it a sharp corner.
|
||||
if spread == 0. {
|
||||
new_groups.push(ManipulatorGroup {
|
||||
new_manipulators_list.push(ManipulatorGroup {
|
||||
anchor: curr.anchor,
|
||||
in_handle: None,
|
||||
out_handle: None,
|
||||
@@ -724,12 +724,12 @@ async fn auto_tangents(
|
||||
}
|
||||
|
||||
// Get previous and next points for auto-tangent calculation
|
||||
let prev_idx = if i == 0 { if is_closed { groups.len() - 1 } else { i } } else { i - 1 };
|
||||
let next_idx = if i == groups.len() - 1 { if is_closed { 0 } else { i } } else { i + 1 };
|
||||
let prev_idx = if i == 0 { if is_closed { manipulators_list.len() - 1 } else { i } } else { i - 1 };
|
||||
let next_idx = if i == manipulators_list.len() - 1 { if is_closed { 0 } else { i } } else { i + 1 };
|
||||
|
||||
let prev = groups[prev_idx].anchor;
|
||||
let prev = manipulators_list[prev_idx].anchor;
|
||||
let curr_pos = curr.anchor;
|
||||
let next = groups[next_idx].anchor;
|
||||
let next = manipulators_list[next_idx].anchor;
|
||||
|
||||
// Calculate directions from current point to adjacent points
|
||||
let dir_prev = (prev - curr_pos).normalize_or_zero();
|
||||
@@ -738,7 +738,7 @@ async fn auto_tangents(
|
||||
// Check if we have valid directions (e.g., points are not coincident)
|
||||
if dir_prev.length_squared() < 1e-5 || dir_next.length_squared() < 1e-5 {
|
||||
// Fallback: keep the original manipulator group (which has no active handles here)
|
||||
new_groups.push(*curr);
|
||||
new_manipulators_list.push(*curr);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -758,7 +758,7 @@ async fn auto_tangents(
|
||||
let out_length = (next - curr_pos).length() / 3. * spread;
|
||||
|
||||
// Create new manipulator group with calculated auto-tangents
|
||||
new_groups.push(ManipulatorGroup {
|
||||
new_manipulators_list.push(ManipulatorGroup {
|
||||
anchor: curr_pos,
|
||||
in_handle: Some(curr_pos + handle_dir * in_length),
|
||||
out_handle: Some(curr_pos - handle_dir * out_length),
|
||||
@@ -766,7 +766,7 @@ async fn auto_tangents(
|
||||
});
|
||||
}
|
||||
|
||||
let mut softened_bezpath = bezpath_from_manipulator_groups(&new_groups, is_closed);
|
||||
let mut softened_bezpath = bezpath_from_manipulator_groups(&new_manipulators_list, is_closed);
|
||||
softened_bezpath.apply_affine(Affine::new(transform.inverse().to_cols_array()));
|
||||
result.append_bezpath(softened_bezpath);
|
||||
}
|
||||
@@ -985,7 +985,7 @@ where
|
||||
output.element.style = row.element.style.clone();
|
||||
}
|
||||
}
|
||||
Graphic::Group(graphic) => {
|
||||
Graphic::Graphic(graphic) => {
|
||||
let mut graphic = graphic.clone();
|
||||
for row in graphic.iter_mut() {
|
||||
*row.transform = *current_element.transform * *row.transform;
|
||||
@@ -1032,7 +1032,7 @@ async fn sample_polyline(
|
||||
region_domain: Default::default(),
|
||||
colinear_manipulators: Default::default(),
|
||||
style: std::mem::take(&mut row.element.style),
|
||||
upstream_group: std::mem::take(&mut row.element.upstream_group),
|
||||
upstream_nested_layers: std::mem::take(&mut row.element.upstream_nested_layers),
|
||||
};
|
||||
// Transfer the stroke transform from the input vector content to the result.
|
||||
result.style.set_stroke_transform(row.transform);
|
||||
@@ -1343,7 +1343,7 @@ async fn spline(_: impl Ctx, content: Table<Vector>) -> Table<Vector> {
|
||||
|
||||
let mut segment_domain = SegmentDomain::default();
|
||||
for (manipulator_groups, closed) in row.element.stroke_manipulator_groups() {
|
||||
let positions = manipulator_groups.iter().map(|group| group.anchor).collect::<Vec<_>>();
|
||||
let positions = manipulator_groups.iter().map(|manipulators| manipulators.anchor).collect::<Vec<_>>();
|
||||
let closed = closed && positions.len() > 2;
|
||||
|
||||
// Compute control point handles for Bezier spline.
|
||||
@@ -2075,7 +2075,14 @@ mod test {
|
||||
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().next().unwrap().element;
|
||||
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(|manipulators| manipulators.anchor)
|
||||
.collect::<Vec<DVec2>>();
|
||||
|
||||
assert_eq!(&manipulator_groups_anchors[..4], &[DVec2::NEG_ONE, DVec2::new(1., -1.), DVec2::ONE, DVec2::new(-1., 1.),]);
|
||||
|
||||
@@ -2086,7 +2093,14 @@ mod test {
|
||||
let bounding_box = BoundingBoxNode { content: FutureWrapperNode(square) }.eval(Footprint::default()).await;
|
||||
let bounding_box = bounding_box.iter().next().unwrap().element;
|
||||
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(|manipulators| manipulators.anchor)
|
||||
.collect::<Vec<DVec2>>();
|
||||
|
||||
let expected_bounding_box = [DVec2::NEG_ONE, DVec2::new(1., -1.), DVec2::ONE, DVec2::new(-1., 1.)];
|
||||
for i in 0..4 {
|
||||
@@ -2108,7 +2122,7 @@ mod test {
|
||||
|
||||
for (index, (_, manipulator_groups)) in flattened_copy_to_points.region_manipulator_groups().enumerate() {
|
||||
let offset = expected_points[index];
|
||||
let manipulator_groups_anchors = manipulator_groups.iter().map(|group| group.anchor).collect::<Vec<DVec2>>();
|
||||
let manipulator_groups_anchors = manipulator_groups.iter().map(|manipulators| manipulators.anchor).collect::<Vec<DVec2>>();
|
||||
assert_eq!(
|
||||
&manipulator_groups_anchors,
|
||||
&[offset + DVec2::NEG_ONE, offset + DVec2::new(1., -1.), offset + DVec2::ONE, offset + DVec2::new(-1., 1.),]
|
||||
|
||||
@@ -29,8 +29,10 @@ pub struct Vector {
|
||||
pub segment_domain: SegmentDomain,
|
||||
pub region_domain: RegionDomain,
|
||||
|
||||
// Used to store the upstream group during destructive Boolean Operations (and other nodes with a similar effect) so that click targets can be preserved.
|
||||
pub upstream_group: Option<Table<Graphic>>,
|
||||
/// Used to store the upstream group/folder of nested layers during destructive Boolean Operations (and other nodes with a similar effect) so that click targets can be preserved for the child layers.
|
||||
/// Without this, the tools would be working with a collapsed version of the data which has no reference to the original child layers that were booleaned together, resulting in the inner layers not being editable.
|
||||
#[serde(alias = "upstream_group")]
|
||||
pub upstream_nested_layers: Option<Table<Graphic>>,
|
||||
}
|
||||
|
||||
impl Default for Vector {
|
||||
@@ -41,7 +43,7 @@ impl Default for Vector {
|
||||
point_domain: PointDomain::new(),
|
||||
segment_domain: SegmentDomain::new(),
|
||||
region_domain: RegionDomain::new(),
|
||||
upstream_group: None,
|
||||
upstream_nested_layers: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -468,15 +470,12 @@ pub fn migrate_vector<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Resu
|
||||
|
||||
pub style: PathStyle,
|
||||
|
||||
/// A list of all manipulator groups (referenced in `subpaths`) that have colinear handles (where they're locked at 180° angles from one another).
|
||||
/// This gets read in `graph_operation_message_handler.rs` by calling `inputs.as_mut_slice()` (search for the string `"Shape does not have both `subpath` and `colinear_manipulators` inputs"` to find it).
|
||||
pub colinear_manipulators: Vec<[HandleId; 2]>,
|
||||
|
||||
pub point_domain: PointDomain,
|
||||
pub segment_domain: SegmentDomain,
|
||||
pub region_domain: RegionDomain,
|
||||
|
||||
// Used to store the upstream group during destructive Boolean Operations (and other nodes with a similar effect) so that click targets can be preserved.
|
||||
pub upstream_graphic_group: Option<Table<Graphic>>,
|
||||
}
|
||||
|
||||
@@ -498,7 +497,7 @@ pub fn migrate_vector<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Resu
|
||||
point_domain: old.point_domain,
|
||||
segment_domain: old.segment_domain,
|
||||
region_domain: old.region_domain,
|
||||
upstream_group: old.upstream_graphic_group,
|
||||
upstream_nested_layers: old.upstream_graphic_group,
|
||||
});
|
||||
*vector_table.iter_mut().next().unwrap().transform = old.transform;
|
||||
*vector_table.iter_mut().next().unwrap().alpha_blending = old.alpha_blending;
|
||||
|
||||
Reference in New Issue
Block a user