Refactor and fix append_bezpath() method on vector data (#2649)

* refactor 'append_bezpath' method.

* fix a bug.

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Priyanshu 2025-05-19 01:45:13 +05:30 committed by GitHub
parent 2615d86934
commit ebf351277d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 95 additions and 61 deletions

View file

@ -7,7 +7,7 @@ use super::style::{PathStyle, Stroke};
use crate::instances::Instances;
use crate::{AlphaBlending, Color, GraphicGroupTable};
pub use attributes::*;
use bezier_rs::{BezierHandles, ManipulatorGroup};
use bezier_rs::ManipulatorGroup;
use core::borrow::Borrow;
use dyn_any::DynAny;
use glam::{DAffine2, DVec2};
@ -179,66 +179,7 @@ impl VectorData {
/// Appends a Kurbo BezPath to the vector data.
pub fn append_bezpath(&mut self, bezpath: kurbo::BezPath) {
let mut first_point_index = None;
let mut last_point_index = None;
let mut first_segment_id = None;
let mut last_segment_id = None;
let mut point_id = self.point_domain.next_id();
let mut segment_id = self.segment_domain.next_id();
let stroke_id = StrokeId::ZERO;
let fill_id = FillId::ZERO;
for element in bezpath.elements() {
match *element {
kurbo::PathEl::MoveTo(point) => {
let next_point_index = self.point_domain.ids().len();
self.point_domain.push(point_id.next_id(), point_to_dvec2(point));
first_point_index = Some(next_point_index);
last_point_index = Some(next_point_index);
}
kurbo::PathEl::ClosePath => match (first_point_index, last_point_index) {
(Some(first_point_index), Some(last_point_index)) => {
let next_segment_id = segment_id.next_id();
self.segment_domain.push(next_segment_id, first_point_index, last_point_index, BezierHandles::Linear, stroke_id);
let next_region_id = self.region_domain.next_id();
self.region_domain.push(next_region_id, first_segment_id.unwrap()..=next_segment_id, fill_id);
}
_ => {
error!("Empty bezpath cannot be closed.")
}
},
_ => {}
}
let mut append_path_element = |handle: BezierHandles, point: kurbo::Point| {
let next_point_index = self.point_domain.ids().len();
self.point_domain.push(point_id.next_id(), point_to_dvec2(point));
let next_segment_id = segment_id.next_id();
self.segment_domain.push(segment_id.next_id(), last_point_index.unwrap(), next_point_index, handle, stroke_id);
last_point_index = Some(next_point_index);
first_segment_id = Some(first_segment_id.unwrap_or(next_segment_id));
last_segment_id = Some(next_segment_id);
};
match *element {
kurbo::PathEl::LineTo(point) => append_path_element(BezierHandles::Linear, point),
kurbo::PathEl::QuadTo(handle, point) => append_path_element(BezierHandles::Quadratic { handle: point_to_dvec2(handle) }, point),
kurbo::PathEl::CurveTo(handle_start, handle_end, point) => append_path_element(
BezierHandles::Cubic {
handle_start: point_to_dvec2(handle_start),
handle_end: point_to_dvec2(handle_end),
},
point,
),
_ => {}
}
}
AppendBezpath::append_bezpath(self, bezpath);
}
/// Construct some new vector data from subpaths with an identity transform and black fill.

View file

@ -5,6 +5,7 @@ use crate::uuid::generate_uuid;
use bezier_rs::BezierHandles;
use core::hash::BuildHasher;
use dyn_any::DynAny;
use kurbo::{BezPath, PathEl};
use std::collections::{HashMap, HashSet};
/// Represents a procedural change to the [`PointDomain`] in [`VectorData`].
@ -552,3 +553,95 @@ where
let visitor = HashMapVisitor { marker: std::marker::PhantomData };
deserializer.deserialize_seq(visitor)
}
pub struct AppendBezpath<'a> {
first_point_index: Option<usize>,
last_point_index: Option<usize>,
first_segment_id: Option<SegmentId>,
last_segment_id: Option<SegmentId>,
next_handle: Option<BezierHandles>,
point_id: PointId,
segment_id: SegmentId,
vector_data: &'a mut VectorData,
}
impl<'a> AppendBezpath<'a> {
fn new(vector_data: &'a mut VectorData) -> Self {
Self {
first_point_index: None,
last_point_index: None,
first_segment_id: None,
last_segment_id: None,
next_handle: None,
point_id: vector_data.point_domain.next_id(),
segment_id: vector_data.segment_domain.next_id(),
vector_data,
}
}
fn append_path_element(&mut self, handle: BezierHandles, point: kurbo::Point, next_element: Option<&PathEl>) {
if let Some(PathEl::ClosePath) = next_element {
self.next_handle = Some(handle);
} else {
let next_point_index = self.vector_data.point_domain.ids().len();
self.vector_data.point_domain.push(self.point_id.next_id(), point_to_dvec2(point));
let next_segment_id = self.segment_id.next_id();
self.vector_data
.segment_domain
.push(self.segment_id.next_id(), self.last_point_index.unwrap(), next_point_index, handle, StrokeId::ZERO);
self.last_point_index = Some(next_point_index);
self.first_segment_id = Some(self.first_segment_id.unwrap_or(next_segment_id));
self.last_segment_id = Some(next_segment_id);
}
}
pub fn append_bezpath(vector_data: &'a mut VectorData, bezpath: BezPath) {
let mut this = Self::new(vector_data);
let stroke_id = StrokeId::ZERO;
let fill_id = FillId::ZERO;
for i in 0..bezpath.elements().len() {
let current_element = bezpath.elements()[i];
let next_element = bezpath.elements().get(i + 1);
match current_element {
kurbo::PathEl::MoveTo(point) => {
let next_point_index = this.vector_data.point_domain.ids().len();
this.vector_data.point_domain.push(this.point_id.next_id(), point_to_dvec2(point));
this.first_point_index = Some(next_point_index);
this.last_point_index = Some(next_point_index);
}
kurbo::PathEl::ClosePath => match (this.first_point_index, this.last_point_index) {
(Some(first_point_index), Some(last_point_index)) => {
let next_segment_id = this.segment_id.next_id();
this.vector_data
.segment_domain
.push(next_segment_id, last_point_index, first_point_index, this.next_handle.unwrap_or(BezierHandles::Linear), stroke_id);
let next_region_id = this.vector_data.region_domain.next_id();
// In case there is only one anchor point.
let first_segment_id = this.first_segment_id.unwrap_or(next_segment_id);
this.vector_data.region_domain.push(next_region_id, first_segment_id..=next_segment_id, fill_id);
}
_ => {
error!("Empty bezpath cannot be closed.")
}
},
kurbo::PathEl::LineTo(point) => this.append_path_element(BezierHandles::Linear, point, next_element),
kurbo::PathEl::QuadTo(handle, point) => this.append_path_element(BezierHandles::Quadratic { handle: point_to_dvec2(handle) }, point, next_element),
kurbo::PathEl::CurveTo(handle_start, handle_end, point) => this.append_path_element(
BezierHandles::Cubic {
handle_start: point_to_dvec2(handle_start),
handle_end: point_to_dvec2(handle_end),
},
point,
next_element,
),
}
}
}
}