@@ -5,7 +5,7 @@ use crate::uuid::generate_uuid;
55use bezier_rs:: BezierHandles ;
66use core:: hash:: BuildHasher ;
77use dyn_any:: DynAny ;
8- use kurbo:: { BezPath , PathEl } ;
8+ use kurbo:: { BezPath , PathEl , Point } ;
99use std:: collections:: { HashMap , HashSet } ;
1010
1111/// Represents a procedural change to the [`PointDomain`] in [`VectorData`].
@@ -556,11 +556,12 @@ where
556556}
557557
558558pub struct AppendBezpath < ' a > {
559+ first_point : Option < Point > ,
560+ last_point : Option < Point > ,
559561 first_point_index : Option < usize > ,
560562 last_point_index : Option < usize > ,
561563 first_segment_id : Option < SegmentId > ,
562564 last_segment_id : Option < SegmentId > ,
563- next_handle : Option < BezierHandles > ,
564565 point_id : PointId ,
565566 segment_id : SegmentId ,
566567 vector_data : & ' a mut VectorData ,
@@ -569,79 +570,118 @@ pub struct AppendBezpath<'a> {
569570impl < ' a > AppendBezpath < ' a > {
570571 fn new ( vector_data : & ' a mut VectorData ) -> Self {
571572 Self {
573+ first_point : None ,
574+ last_point : None ,
572575 first_point_index : None ,
573576 last_point_index : None ,
574577 first_segment_id : None ,
575578 last_segment_id : None ,
576- next_handle : None ,
577579 point_id : vector_data. point_domain . next_id ( ) ,
578580 segment_id : vector_data. segment_domain . next_id ( ) ,
579581 vector_data,
580582 }
581583 }
582584
583- fn append_path_element ( & mut self , handle : BezierHandles , point : kurbo:: Point , next_element : Option < & PathEl > ) {
584- if let Some ( PathEl :: ClosePath ) = next_element {
585- self . next_handle = Some ( handle) ;
585+ fn append_segment_and_close_path ( & mut self , point : Point , handle : BezierHandles ) {
586+ let handle = if self . first_point . unwrap ( ) != point {
587+ // If the first point is not the same as the last point of the path then we append the segment
588+ // with given handle and point and then close the path with linear handle.
589+ self . append_segment ( point, handle) ;
590+ BezierHandles :: Linear
586591 } else {
587- let next_point_index = self . vector_data . point_domain . ids ( ) . len ( ) ;
588- self . vector_data . point_domain . push ( self . point_id . next_id ( ) , point_to_dvec2 ( point) ) ;
592+ // if the endpoints are the same then we close the path with given handle.
593+ handle
594+ } ;
595+
596+ // Create a new segment.
597+ let next_segment_id = self . segment_id . next_id ( ) ;
598+ self . vector_data
599+ . segment_domain
600+ . push ( next_segment_id, self . last_point_index . unwrap ( ) , self . first_point_index . unwrap ( ) , handle, StrokeId :: ZERO ) ;
601+
602+ // Create a new region.
603+ let next_region_id = self . vector_data . region_domain . next_id ( ) ;
604+ let first_segment_id = self . first_segment_id . unwrap_or ( next_segment_id) ;
605+ let last_segment_id = next_segment_id;
606+
607+ self . vector_data . region_domain . push ( next_region_id, first_segment_id..=last_segment_id, FillId :: ZERO ) ;
608+ }
589609
590- let next_segment_id = self . segment_id . next_id ( ) ;
591- self . vector_data
592- . segment_domain
593- . push ( self . segment_id . next_id ( ) , self . last_point_index . unwrap ( ) , next_point_index , handle , StrokeId :: ZERO ) ;
610+ fn append_segment ( & mut self , end_point : Point , handle : BezierHandles ) {
611+ // Append the point.
612+ let next_point_index = self . vector_data . point_domain . ids ( ) . len ( ) ;
613+ let next_point_id = self . point_id . next_id ( ) ;
594614
595- self . last_point_index = Some ( next_point_index) ;
596- self . first_segment_id = Some ( self . first_segment_id . unwrap_or ( next_segment_id) ) ;
597- self . last_segment_id = Some ( next_segment_id) ;
598- }
615+ self . vector_data . point_domain . push ( next_point_id, point_to_dvec2 ( end_point) ) ;
616+
617+ // Append the segment.
618+ let next_segment_id = self . segment_id . next_id ( ) ;
619+ self . vector_data
620+ . segment_domain
621+ . push ( next_segment_id, self . last_point_index . unwrap ( ) , next_point_index, handle, StrokeId :: ZERO ) ;
622+
623+ // Update the states.
624+ self . last_point = Some ( end_point) ;
625+ self . last_point_index = Some ( next_point_index) ;
626+
627+ self . first_segment_id = Some ( self . first_segment_id . unwrap_or ( next_segment_id) ) ;
628+ self . last_segment_id = Some ( next_segment_id) ;
599629 }
600630
601- pub fn append_bezpath ( vector_data : & ' a mut VectorData , bezpath : BezPath ) {
602- let mut this = Self :: new ( vector_data) ;
631+ fn append_first_point ( & mut self , point : Point ) {
632+ self . first_point = Some ( point) ;
633+ self . last_point = Some ( point) ;
603634
604- let stroke_id = StrokeId :: ZERO ;
605- let fill_id = FillId :: ZERO ;
635+ // Append the first point.
636+ let next_point_index = self . vector_data . point_domain . ids ( ) . len ( ) ;
637+ self . vector_data . point_domain . push ( self . point_id . next_id ( ) , point_to_dvec2 ( point) ) ;
606638
607- for i in 0 ..bezpath. elements ( ) . len ( ) {
608- let current_element = bezpath. elements ( ) [ i] ;
609- let next_element = bezpath. elements ( ) . get ( i + 1 ) ;
639+ // Update the state.
640+ self . first_point_index = Some ( next_point_index) ;
641+ self . last_point_index = Some ( next_point_index) ;
642+ }
610643
611- match current_element {
612- kurbo:: PathEl :: MoveTo ( point) => {
613- let next_point_index = this. vector_data . point_domain . ids ( ) . len ( ) ;
614- this. vector_data . point_domain . push ( this. point_id . next_id ( ) , point_to_dvec2 ( point) ) ;
615- this. first_point_index = Some ( next_point_index) ;
616- this. last_point_index = Some ( next_point_index) ;
644+ pub fn append_bezpath ( vector_data : & ' a mut VectorData , bezpath : BezPath ) {
645+ let mut this = Self :: new ( vector_data) ;
646+ let mut elements = bezpath. elements ( ) . iter ( ) . peekable ( ) ;
647+
648+ while let Some ( element) = elements. next ( ) {
649+ let close_path = elements. peek ( ) . is_some_and ( |elm| * * elm == PathEl :: ClosePath ) ;
650+
651+ match * element {
652+ PathEl :: MoveTo ( point) => this. append_first_point ( point) ,
653+ PathEl :: LineTo ( point) => {
654+ let handle = BezierHandles :: Linear ;
655+ if close_path {
656+ this. append_segment_and_close_path ( point, handle) ;
657+ } else {
658+ this. append_segment ( point, handle) ;
659+ }
617660 }
618- kurbo:: PathEl :: ClosePath => match ( this. first_point_index , this. last_point_index ) {
619- ( Some ( first_point_index) , Some ( last_point_index) ) => {
620- let next_segment_id = this. segment_id . next_id ( ) ;
621- this. vector_data
622- . segment_domain
623- . push ( next_segment_id, last_point_index, first_point_index, this. next_handle . unwrap_or ( BezierHandles :: Linear ) , stroke_id) ;
624-
625- let next_region_id = this. vector_data . region_domain . next_id ( ) ;
626- // In case there is only one anchor point.
627- let first_segment_id = this. first_segment_id . unwrap_or ( next_segment_id) ;
628-
629- this. vector_data . region_domain . push ( next_region_id, first_segment_id..=next_segment_id, fill_id) ;
661+ PathEl :: QuadTo ( point, point1) => {
662+ let handle = BezierHandles :: Quadratic { handle : point_to_dvec2 ( point) } ;
663+ if close_path {
664+ this. append_segment_and_close_path ( point1, handle) ;
665+ } else {
666+ this. append_segment ( point1, handle) ;
630667 }
631- _ => {
632- error ! ( "Empty bezpath cannot be closed." )
668+ }
669+ PathEl :: CurveTo ( point, point1, point2) => {
670+ let handle = BezierHandles :: Cubic {
671+ handle_start : point_to_dvec2 ( point) ,
672+ handle_end : point_to_dvec2 ( point1) ,
673+ } ;
674+
675+ if close_path {
676+ this. append_segment_and_close_path ( point2, handle) ;
677+ } else {
678+ this. append_segment ( point2, handle) ;
633679 }
634- } ,
635- kurbo:: PathEl :: LineTo ( point) => this. append_path_element ( BezierHandles :: Linear , point, next_element) ,
636- kurbo:: PathEl :: QuadTo ( handle, point) => this. append_path_element ( BezierHandles :: Quadratic { handle : point_to_dvec2 ( handle) } , point, next_element) ,
637- kurbo:: PathEl :: CurveTo ( handle_start, handle_end, point) => this. append_path_element (
638- BezierHandles :: Cubic {
639- handle_start : point_to_dvec2 ( handle_start) ,
640- handle_end : point_to_dvec2 ( handle_end) ,
641- } ,
642- point,
643- next_element,
644- ) ,
680+ }
681+ PathEl :: ClosePath => {
682+ // Already handled using `append_segment_and_close_path()`;
683+ break ;
684+ }
645685 }
646686 }
647687 }
0 commit comments