@@ -5,7 +5,7 @@ use crate::uuid::generate_uuid;
5
5
use bezier_rs:: BezierHandles ;
6
6
use core:: hash:: BuildHasher ;
7
7
use dyn_any:: DynAny ;
8
- use kurbo:: { BezPath , PathEl } ;
8
+ use kurbo:: { BezPath , PathEl , Point } ;
9
9
use std:: collections:: { HashMap , HashSet } ;
10
10
11
11
/// Represents a procedural change to the [`PointDomain`] in [`VectorData`].
@@ -556,11 +556,12 @@ where
556
556
}
557
557
558
558
pub struct AppendBezpath < ' a > {
559
+ first_point : Option < Point > ,
560
+ last_point : Option < Point > ,
559
561
first_point_index : Option < usize > ,
560
562
last_point_index : Option < usize > ,
561
563
first_segment_id : Option < SegmentId > ,
562
564
last_segment_id : Option < SegmentId > ,
563
- next_handle : Option < BezierHandles > ,
564
565
point_id : PointId ,
565
566
segment_id : SegmentId ,
566
567
vector_data : & ' a mut VectorData ,
@@ -569,79 +570,118 @@ pub struct AppendBezpath<'a> {
569
570
impl < ' a > AppendBezpath < ' a > {
570
571
fn new ( vector_data : & ' a mut VectorData ) -> Self {
571
572
Self {
573
+ first_point : None ,
574
+ last_point : None ,
572
575
first_point_index : None ,
573
576
last_point_index : None ,
574
577
first_segment_id : None ,
575
578
last_segment_id : None ,
576
- next_handle : None ,
577
579
point_id : vector_data. point_domain . next_id ( ) ,
578
580
segment_id : vector_data. segment_domain . next_id ( ) ,
579
581
vector_data,
580
582
}
581
583
}
582
584
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
586
591
} 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
+ }
589
609
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 ( ) ;
594
614
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) ;
599
629
}
600
630
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) ;
603
634
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) ) ;
606
638
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
+ }
610
643
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
+ }
617
660
}
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) ;
630
667
}
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) ;
633
679
}
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
+ }
645
685
}
646
686
}
647
687
}
0 commit comments