rasterize/
path.rs

1use crate::{
2    BBox, Cubic, Curve, EPSILON, EllipArc, ImageMut, LinColor, Line, Paint, Point, Quad, Scalar,
3    ScalarFormatter, Segment, Size, SvgParserError, SvgPathParser, Transform, curve::line_offset,
4    rasterize::Rasterizer, utils::clamp,
5};
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8use std::{
9    fmt,
10    io::{Cursor, Read, Write},
11    str::FromStr,
12};
13
14/// Default flatness used during rasterization.
15/// Value of 0.05px gives good accuracy tradeoff.
16pub const DEFAULT_FLATNESS: Scalar = 0.05;
17
18/// The algorithm to use to determine the inside part of a shape, when filling it.
19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
20#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
21pub enum FillRule {
22    /// Fill area with non-zero winding number
23    #[default]
24    #[cfg_attr(feature = "serde", serde(rename = "nonzero"))]
25    NonZero,
26    /// Fill area with odd winding number
27    #[cfg_attr(feature = "serde", serde(rename = "evenodd"))]
28    EvenOdd,
29}
30
31impl FillRule {
32    pub fn alpha_from_winding(&self, winding: Scalar) -> Scalar {
33        match self {
34            FillRule::EvenOdd => ((winding + 1.0).rem_euclid(2.0) - 1.0).abs(),
35            FillRule::NonZero => {
36                let value = winding.abs();
37                if value >= 1.0 {
38                    1.0
39                } else if value < 1e-6 {
40                    0.0
41                } else {
42                    value
43                }
44            }
45        }
46    }
47}
48
49impl FromStr for FillRule {
50    type Err = SvgParserError;
51
52    fn from_str(s: &str) -> Result<Self, Self::Err> {
53        match s {
54            "nonzero" => Ok(FillRule::NonZero),
55            "evenodd" => Ok(FillRule::EvenOdd),
56            _ => Err(SvgParserError::InvalidFillRule),
57        }
58    }
59}
60
61impl fmt::Display for FillRule {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        match self {
64            FillRule::NonZero => "nonzero".fmt(f),
65            FillRule::EvenOdd => "evenodd".fmt(f),
66        }
67    }
68}
69
70/// `LineJoin` defines the shape to be used at the corners of paths when they are stroked.
71/// See [SVG specification](https://www.w3.org/TR/SVG2/painting.html#LineJoin) for more details.
72#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
73#[cfg_attr(
74    feature = "serde",
75    derive(Serialize, Deserialize),
76    serde(rename_all = "lowercase")
77)]
78pub enum LineJoin {
79    /// Continue path segments with lines until they intersect. But only
80    /// if `miter_length = stroke-width / sin(0.5 * eta)` is less than the miter argument.
81    Miter(Scalar),
82    /// Connect path segments with straight line.
83    Bevel,
84    /// Round corner is to be used to join path segments.
85    /// The corner is a circular sector centered on the join point.
86    Round,
87}
88
89impl Default for LineJoin {
90    fn default() -> Self {
91        Self::Miter(4.0)
92    }
93}
94
95/// `LineCap` specifies the shape to be used at the end of open sub-paths when they are stroked.
96/// See [SVG specification](https://www.w3.org/TR/SVG2/painting.html#LineCaps) for more details.
97#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
98#[cfg_attr(
99    feature = "serde",
100    derive(Serialize, Deserialize),
101    serde(rename_all = "lowercase")
102)]
103pub enum LineCap {
104    /// Connect path segments with straight line.
105    #[default]
106    Butt,
107    /// Add half-square to the end of the segments
108    Square,
109    /// Add half-circle to the end of the segments
110    Round,
111}
112
113/// Style used to generate stroke
114#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
115#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
116pub struct StrokeStyle {
117    /// Width of the stroke
118    pub width: Scalar,
119    /// How to join offset segments
120    #[cfg_attr(
121        feature = "serde",
122        serde(default, skip_serializing_if = "crate::utils::is_default")
123    )]
124    pub line_join: LineJoin,
125    /// How to join segments at the ends of the path
126    #[cfg_attr(
127        feature = "serde",
128        serde(default, skip_serializing_if = "crate::utils::is_default")
129    )]
130    pub line_cap: LineCap,
131}
132
133/// Non-empty collections of segments where end of each segments coincides with the start of the next one.
134#[derive(Clone, Copy, PartialEq)]
135pub struct SubPath<'a> {
136    /// List of segments representing SubPath
137    segments: &'a [Segment],
138    /// Whether SubPath contains an implicit line segment connecting start and the end of it.
139    closed: bool,
140}
141
142impl fmt::Debug for SubPath<'_> {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        for segment in self.segments.iter() {
145            writeln!(f, "{:?}", segment)?;
146        }
147        if self.closed {
148            writeln!(f, "Close")?;
149        } else {
150            writeln!(f, "End")?
151        }
152        Ok(())
153    }
154}
155
156impl<'a> SubPath<'a> {
157    pub fn new(segments: &'a [Segment], closed: bool) -> Option<Self> {
158        if segments.is_empty() {
159            None
160        } else {
161            Some(Self { segments, closed })
162        }
163    }
164
165    /// Whether sub-path is closed or not
166    pub fn is_closed(&self) -> bool {
167        self.closed
168    }
169
170    pub fn segments(&self) -> &[Segment] {
171        self.segments
172    }
173
174    /// First segment in the sub-path
175    pub fn first(&self) -> Segment {
176        *self.segments.first().expect("SubPath is never emtpy")
177    }
178
179    /// Last segment in the sub-path
180    pub fn last(&self) -> Segment {
181        *self.segments.last().expect("SubPath is never empty")
182    }
183
184    pub fn flatten(
185        &self,
186        tr: Transform,
187        flatness: Scalar,
188        close: bool,
189    ) -> impl Iterator<Item = Line> + '_ {
190        let last = if self.closed || close {
191            Some(Line::new(self.end(), self.start()).transform(tr))
192        } else {
193            None
194        };
195        self.segments
196            .iter()
197            .flat_map(move |segment| segment.flatten(tr, flatness))
198            .chain(last)
199    }
200
201    /// Start point of the sub-path
202    pub fn start(&self) -> Point {
203        self.first().start()
204    }
205
206    /// End point of the sub-path
207    pub fn end(&self) -> Point {
208        self.last().end()
209    }
210
211    /// Bounding box of the sub-path
212    pub fn bbox(&self, init: Option<BBox>, tr: Transform) -> BBox {
213        self.segments
214            .iter()
215            .fold(init, |bbox, seg| Some(seg.transform(tr).bbox(bbox)))
216            .expect("SubPath is never empty")
217    }
218}
219
220/// Collection of the SubPath treated as a single unit. Represents the same concept
221/// as an [SVG path](https://www.w3.org/TR/SVG11/paths.html)
222#[derive(Clone, PartialEq, Default)]
223pub struct Path {
224    segments: Vec<Segment>,
225    /// segments[subpath[i]..subpath[i+1]] represents i-th subpath
226    subpaths: Vec<usize>,
227    closed: Vec<bool>,
228}
229
230impl Path {
231    pub fn new(segments: Vec<Segment>, subpaths: Vec<usize>, closed: Vec<bool>) -> Self {
232        Self {
233            segments,
234            subpaths,
235            closed,
236        }
237    }
238
239    /// Create empty path
240    pub fn empty() -> Self {
241        Self {
242            segments: Vec::new(),
243            subpaths: Vec::new(),
244            closed: Vec::new(),
245        }
246    }
247
248    /// Check if the path is empty
249    pub fn is_empty(&self) -> bool {
250        self.subpaths.is_empty()
251    }
252
253    /// Number of sub-paths in the path
254    pub fn len(&self) -> usize {
255        if self.subpaths.len() < 2 {
256            0
257        } else {
258            self.subpaths.len() - 1
259        }
260    }
261
262    /// Calculate winding number of a point
263    pub fn winding_at(&self, point: impl Into<Point>) -> i32 {
264        let point = point.into();
265        // We are using horizontal line `y = point.y` to calculate winding number
266        // - Find all segments that can potentially intersect this line.
267        //   If all control points are on one side of the line then it is not going to
268        //   intersect it as bezier curve is always bound by all its control points.
269        // - Find intersection and based on tangent direction assign 1 or -1, throw away
270        //   all intersections with `x > point.x`
271        let y = point.y();
272        let tr = Transform::new_translate(0.0, -y);
273        let mut winding = 0;
274        for subpath in self.subpaths() {
275            let last = if subpath.closed {
276                Some(Line::new(subpath.end(), subpath.start()).into())
277            } else {
278                None
279            };
280            for segment in subpath.segments().iter().chain(&last) {
281                let points: &[Point] = match segment {
282                    Segment::Line(Line(points)) => points,
283                    Segment::Quad(Quad(points)) => points,
284                    Segment::Cubic(Cubic(points)) => points,
285                };
286                let (above, below) = points.iter().fold((false, false), |(above, below), ctrl| {
287                    if ctrl.y() > point.y() {
288                        (true, below)
289                    } else {
290                        (above, true)
291                    }
292                });
293                if !above || !below {
294                    // will not intersect horizontal line
295                    continue;
296                }
297                for root_t in segment.transform(tr).roots() {
298                    let root = segment.at(root_t);
299                    if root.x() > point.x() {
300                        continue;
301                    }
302                    let deriv = segment.deriv().at(root_t);
303                    if deriv.y() > 0.0 {
304                        winding += 1;
305                    } else if deriv.y() < 0.0 {
306                        winding -= 1;
307                    }
308                }
309            }
310        }
311        winding
312    }
313
314    /// Get sub-path
315    pub fn get(&self, index: usize) -> Option<SubPath<'_>> {
316        let start = *self.subpaths.get(index)?;
317        let end = *self.subpaths.get(index + 1)?;
318        let segments = self.segments.get(start..end)?;
319        let closed = *self.closed.get(index)?;
320        Some(SubPath { segments, closed })
321    }
322
323    /// List of sub-paths
324    pub fn subpaths(&self) -> PathIter<'_> {
325        PathIter {
326            path: self,
327            index: 0,
328        }
329    }
330
331    pub fn push(&mut self, segments: &[Segment], closed: bool) {
332        if segments.is_empty() {
333            return;
334        }
335        if self.subpaths.is_empty() {
336            self.subpaths.push(0);
337        }
338        self.segments.extend(segments.iter().copied());
339        self.subpaths.push(self.segments.len());
340        self.closed.push(closed);
341    }
342
343    /// Convenience method to create [`PathBuilder`]
344    pub fn builder() -> PathBuilder {
345        PathBuilder::new()
346    }
347
348    /// Convert path into a path builder so it can be extended
349    pub fn into_builder(self) -> PathBuilder {
350        PathBuilder::from_path(self)
351    }
352
353    /// Apply transformation to the path in place
354    pub fn transform(&mut self, tr: Transform) {
355        self.segments.iter_mut().for_each(|segment| {
356            *segment = segment.transform(tr);
357        });
358    }
359
360    /// Number of segments in the path
361    pub fn segments_count(&self) -> usize {
362        self.segments.len()
363    }
364
365    /// Stroke path
366    ///
367    /// Stroked path is the path constructed from original by offsetting by `distance/2` and
368    /// joining it with the path offset by `-distance/2`.
369    pub fn stroke(&self, style: StrokeStyle) -> Path {
370        let mut result = Path::empty();
371        let mut segments = Vec::new();
372        for subpath in self.subpaths() {
373            // forward
374            for segment in subpath.segments() {
375                stroke_segment(&mut segments, *segment, style, Segment::line_join);
376            }
377            let mut backward = subpath.segments.iter().rev().map(Segment::reverse);
378            // close subpath
379            if subpath.is_closed() {
380                stroke_close(subpath, &mut segments, style, true);
381                result.push(&segments, true);
382                segments.clear();
383            } else {
384                // cap
385                if let Some(segment) = backward.next() {
386                    stroke_segment(&mut segments, segment, style, Segment::line_cap);
387                }
388            }
389            // backward
390            for segment in backward {
391                stroke_segment(&mut segments, segment, style, Segment::line_join);
392            }
393            // close subpath
394            if subpath.is_closed() {
395                stroke_close(subpath, &mut segments, style, false);
396                result.push(&segments, true);
397                segments.clear();
398            } else {
399                // cap
400                let last = segments.last().copied();
401                let first = segments.first().copied();
402                if let (Some(last), Some(first)) = (last, first) {
403                    segments.extend(last.line_cap(first, style));
404                }
405                result.push(&segments, true);
406                segments.clear();
407            }
408        }
409        result
410    }
411
412    /// Convert path to an iterator over line segments
413    pub fn flatten(
414        &self,
415        tr: Transform,
416        flatness: Scalar,
417        close: bool,
418    ) -> impl Iterator<Item = Line> + '_ {
419        PathFlattenIter::new(self, tr, flatness, close)
420    }
421
422    /// Bounding box of the path after provided transformation is applied.
423    pub fn bbox(&self, tr: Transform) -> Option<BBox> {
424        self.subpaths()
425            .fold(None, |bbox, subpath| Some(subpath.bbox(bbox, tr)))
426    }
427
428    /// Calculate size of the image required to render the path
429    ///
430    /// Returns:
431    ///   - Size of the image
432    ///   - Transformation required
433    ///   - Position of lowest x and y point of the image
434    pub fn size(&self, tr: Transform) -> Option<(Size, Transform, Point)> {
435        let bbox = self.bbox(tr)?;
436        let Point([min_x, min_y]) = bbox.min();
437        let Point([max_x, max_y]) = bbox.max();
438        let min = Point::new(min_x.floor() - 1.0, min_y.floor() - 1.0);
439        let max = Point::new(max_x.ceil() + 1.0, max_y.ceil() + 1.0);
440        let size = Size {
441            width: (max.x() - min.x()).round() as usize,
442            height: (max.y() - min.y()).round() as usize,
443        };
444        let shift = Transform::new_translate(1.0 - min_x, 1.0 - min_y);
445        Some((size, shift * tr, min))
446    }
447
448    /// Reverse order and direction of all segments
449    pub fn reverse(&mut self) {
450        if self.segments.is_empty() {
451            return;
452        }
453
454        // reverse segments
455        let mut left = 0;
456        let mut right = self.segments.len() - 1;
457        while left < right {
458            let left_segment = self.segments[left].reverse();
459            let right_segment = self.segments[right].reverse();
460            self.segments[left] = right_segment;
461            self.segments[right] = left_segment;
462            left += 1;
463            right -= 1;
464        }
465        if left == right {
466            let left_segment = self.segments[left].reverse();
467            self.segments[left] = left_segment;
468        }
469
470        // reverse sub-paths offsets
471        for index in 0..(self.subpaths.len() - 1) {
472            self.subpaths[index] = self.subpaths[index + 1] - self.subpaths[index];
473        }
474        self.subpaths.reverse();
475        self.subpaths[0] = 0;
476        let mut offset = 0;
477        for index in 1..self.subpaths.len() {
478            offset += self.subpaths[index];
479            self.subpaths[index] = offset;
480        }
481
482        // reverse closed
483        self.closed.reverse();
484    }
485
486    /// Fill path with the provided paint
487    pub fn fill<R, P, I>(
488        &self,
489        rasterizer: R,
490        tr: Transform,
491        fill_rule: FillRule,
492        paint: P,
493        mut img: I,
494    ) -> I
495    where
496        R: Rasterizer,
497        P: Paint,
498        I: ImageMut<Pixel = LinColor>,
499    {
500        rasterizer.fill(self, tr, fill_rule, &paint, &mut img);
501        img
502    }
503
504    /// Rasterize mast for the path in into a provided image.
505    ///
506    /// Everything that is outside of the image will be cropped. Image is assumed
507    /// to contain zeros.
508    pub fn mask<R, I>(&self, rasterizer: R, tr: Transform, fill_rule: FillRule, mut img: I) -> I
509    where
510        R: Rasterizer,
511        I: ImageMut<Pixel = Scalar>,
512    {
513        rasterizer.mask(self, tr, &mut img, fill_rule);
514        img
515    }
516
517    /// Save path in SVG path format.
518    pub fn write_svg_path(&self, mut out: impl Write) -> std::io::Result<()> {
519        write!(out, "{}", self)
520    }
521
522    /// Load path from SVG path representation
523    pub fn read_svg_path(input: impl Read) -> std::io::Result<Self> {
524        let mut builder = PathBuilder::new();
525        for cmd in SvgPathParser::new(input) {
526            cmd?.apply(&mut builder)
527        }
528        Ok(builder.build())
529    }
530
531    pub fn display(&self, relative: bool, tr: Transform) -> PathSvgDisplay<'_> {
532        PathSvgDisplay {
533            path: self,
534            relative,
535            tr,
536        }
537    }
538
539    /// Returns struct that prints command per line on debug formatting.
540    pub fn verbose_debug(&self) -> PathVerboseDebug<'_> {
541        PathVerboseDebug { path: self }
542    }
543}
544
545impl fmt::Debug for Path {
546    fn fmt(&self, out: &mut fmt::Formatter<'_>) -> fmt::Result {
547        use std::fmt::Display;
548        self.display(false, Transform::identity()).fmt(out)
549    }
550}
551
552impl fmt::Display for Path {
553    fn fmt(&self, out: &mut fmt::Formatter<'_>) -> fmt::Result {
554        self.display(false, Transform::identity()).fmt(out)
555    }
556}
557
558pub struct PathVerboseDebug<'a> {
559    path: &'a Path,
560}
561
562impl fmt::Debug for PathVerboseDebug<'_> {
563    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
564        if self.path.subpaths.is_empty() {
565            write!(f, "Empty")?;
566        } else {
567            for subpath in self.path.subpaths.iter() {
568                subpath.fmt(f)?
569            }
570        }
571        Ok(())
572    }
573}
574
575pub struct PathSvgDisplay<'a> {
576    path: &'a Path,
577    relative: bool,
578    tr: Transform,
579}
580
581impl PathSvgDisplay<'_> {
582    fn fmt_point(
583        &self,
584        out: &mut fmt::Formatter<'_>,
585        formatter: &mut ScalarFormatter,
586        point: Point,
587        previous: Option<Point>,
588        sep: bool,
589    ) -> Result<Point, fmt::Error> {
590        let point_tr = self.tr.apply(point);
591        let point = previous.map_or_else(|| point_tr, |point_prev| point_tr - point_prev);
592        let x = point.x();
593        let y = point.y();
594        if sep && x >= 0.0 {
595            out.write_str(" ")?;
596        }
597        out.write_str(formatter.format_str(x))?;
598        if y >= 0.0 {
599            out.write_str(",")?;
600        }
601        out.write_str(formatter.format_str(y))?;
602        Ok(point_tr)
603    }
604}
605
606impl fmt::Display for PathSvgDisplay<'_> {
607    fn fmt(&self, out: &mut fmt::Formatter<'_>) -> fmt::Result {
608        let mut formatter = ScalarFormatter::new_fmt(out);
609        let mut previous: Option<Point> = None;
610        for subpath in self.path.subpaths() {
611            out.write_str(if self.relative && previous.is_some() {
612                "m"
613            } else {
614                "M"
615            })?;
616            let point_last =
617                self.fmt_point(out, &mut formatter, subpath.start(), previous, false)?;
618            if self.relative {
619                previous = Some(point_last);
620            }
621
622            for segment in subpath.segments().iter() {
623                let point_last = match segment {
624                    Segment::Line(line) => {
625                        out.write_str(if self.relative { "l" } else { "L" })?;
626                        self.fmt_point(out, &mut formatter, line.end(), previous, false)?
627                    }
628                    Segment::Quad(quad) => {
629                        out.write_str(if self.relative { "q" } else { "Q" })?;
630                        let [_, p1, p2] = quad.points();
631                        self.fmt_point(out, &mut formatter, p1, previous, false)?;
632                        self.fmt_point(out, &mut formatter, p2, previous, true)?
633                    }
634                    Segment::Cubic(cubic) => {
635                        out.write_str(if self.relative { "c" } else { "C" })?;
636                        let [_, p1, p2, p3] = cubic.points();
637                        self.fmt_point(out, &mut formatter, p1, previous, false)?;
638                        self.fmt_point(out, &mut formatter, p2, previous, true)?;
639                        self.fmt_point(out, &mut formatter, p3, previous, true)?
640                    }
641                };
642                if self.relative {
643                    previous = Some(point_last);
644                }
645            }
646            if subpath.is_closed() {
647                write!(out, "Z")?;
648            }
649        }
650        Ok(())
651    }
652}
653
654pub struct PathIter<'a> {
655    path: &'a Path,
656    index: usize,
657}
658
659impl<'a> Iterator for PathIter<'a> {
660    type Item = SubPath<'a>;
661
662    fn next(&mut self) -> Option<Self::Item> {
663        let result = self.path.get(self.index)?;
664        self.index += 1;
665        Some(result)
666    }
667}
668
669impl<'a> IntoIterator for &'a Path {
670    type Item = SubPath<'a>;
671    type IntoIter = PathIter<'a>;
672
673    fn into_iter(self) -> Self::IntoIter {
674        self.subpaths()
675    }
676}
677
678impl<'a> Extend<SubPath<'a>> for Path {
679    fn extend<T: IntoIterator<Item = SubPath<'a>>>(&mut self, iter: T) {
680        for subpath in iter {
681            self.push(subpath.segments, subpath.closed);
682        }
683    }
684}
685
686/// Extend segments with the offset segment and join between those segments.
687fn stroke_segment<F, S>(segments: &mut Vec<Segment>, segment: Segment, style: StrokeStyle, join: F)
688where
689    F: Fn(Segment, Segment, StrokeStyle) -> S,
690    S: IntoIterator<Item = Segment>,
691{
692    let offset = segments.len();
693    segment.offset(style.width / 2.0, segments);
694    if offset != 0 {
695        let src = segments.get(offset - 1).copied();
696        let dst = segments.get(offset).copied();
697        if let (Some(src), Some(dst)) = (src, dst) {
698            segments.splice(offset..offset, join(src, dst, style));
699        }
700    }
701}
702
703fn stroke_close(
704    subpath: SubPath<'_>,
705    segments: &mut Vec<Segment>,
706    style: StrokeStyle,
707    forward: bool,
708) {
709    let (first, last) = match (segments.first(), segments.last()) {
710        (Some(first), Some(last)) => (*first, *last),
711        _ => return,
712    };
713    let close = if forward {
714        Line::new(subpath.end(), subpath.start())
715    } else {
716        Line::new(subpath.start(), subpath.end())
717    };
718    match line_offset(close, style.width / 2.0) {
719        Some(close) if close.length() * 100.0 > style.width => {
720            let close = Segment::from(close);
721            segments.extend(last.line_join(close, style));
722            segments.push(close);
723            segments.extend(close.line_join(first, style));
724        }
725        _ => segments.extend(last.line_join(first, style)),
726    }
727}
728
729pub struct PathFlattenIter<'a> {
730    path: &'a Path,
731    transform: Transform,
732    flatness: Scalar,
733    close: bool,
734    subpath_index: usize,
735    segment_index: usize,
736    stack: Vec<Segment>,
737}
738
739impl<'a> PathFlattenIter<'a> {
740    fn new(path: &'a Path, transform: Transform, flatness: Scalar, close: bool) -> Self {
741        Self {
742            path,
743            transform,
744            flatness: 16.0 * flatness * flatness,
745            close,
746            subpath_index: 0,
747            segment_index: 0,
748            stack: Default::default(),
749        }
750    }
751}
752
753impl Iterator for PathFlattenIter<'_> {
754    type Item = Line;
755
756    fn next(&mut self) -> Option<Self::Item> {
757        loop {
758            match self.stack.pop() {
759                Some(segment) => {
760                    if segment.has_nans() {
761                        panic!("cannot flatten segment with NaN");
762                    }
763                    if segment.flatness() < self.flatness {
764                        return Some(Line::new(segment.start(), segment.end()));
765                    }
766                    let (s0, s1) = segment.split();
767                    self.stack.push(s1);
768                    self.stack.push(s0);
769                }
770                None => {
771                    let subpath = self.path.get(self.subpath_index)?;
772                    match subpath.segments().get(self.segment_index) {
773                        None => {
774                            self.subpath_index += 1;
775                            self.segment_index = 0;
776                            if subpath.closed || self.close {
777                                let line = Line::new(subpath.end(), subpath.start())
778                                    .transform(self.transform);
779                                return Some(line);
780                            }
781                        }
782                        Some(segment) => {
783                            self.segment_index += 1;
784                            self.stack.push(segment.transform(self.transform));
785                        }
786                    }
787                }
788            }
789        }
790    }
791}
792
793/// Path builder similar to Canvas/Cairo interface.
794#[derive(Clone)]
795pub struct PathBuilder {
796    position: Point,
797    segments: Vec<Segment>,
798    subpaths: Vec<usize>,
799    closed: Vec<bool>,
800}
801
802impl Default for PathBuilder {
803    fn default() -> Self {
804        Self::new()
805    }
806}
807
808impl PathBuilder {
809    pub fn new() -> Self {
810        Self {
811            position: Point::new(0.0, 0.0),
812            segments: Vec::new(),
813            subpaths: Vec::new(),
814            closed: Vec::new(),
815        }
816    }
817
818    pub fn from_path(path: Path) -> Self {
819        let mut builder = Self::new();
820        builder.segments = path.segments;
821        builder.subpaths = path.subpaths;
822        builder.closed = path.closed;
823        builder
824    }
825
826    /// Build path
827    pub fn build(&mut self) -> Path {
828        self.subpath_finish(false);
829        let PathBuilder {
830            segments,
831            subpaths,
832            closed,
833            ..
834        } = std::mem::take(self);
835        Path::new(segments, subpaths, closed)
836    }
837
838    pub fn push(&mut self, segments: &[Segment], closed: bool) {
839        self.segments.extend(segments.iter().copied());
840        self.subpath_finish(closed);
841    }
842
843    /// Finish current subpath
844    fn subpath_finish(&mut self, close: bool) {
845        if self.segments.is_empty() || self.subpaths.last().copied() == Some(self.segments.len()) {
846            return;
847        }
848        if self.subpaths.is_empty() {
849            self.subpaths.push(0);
850        }
851        if close {
852            // if we close subpath, current position is set to start of the current subpath
853            if let Some(subpath_start) = self
854                .subpaths
855                .last()
856                .and_then(|first_index| Some(self.segments.get(*first_index)?.start()))
857            {
858                self.position = subpath_start;
859            }
860        }
861        self.subpaths.push(self.segments.len());
862        self.closed.push(close);
863    }
864
865    /// Extend path from string, which is specified in the same format as SVGs path element.
866    pub fn append_svg_path(
867        &mut self,
868        string: impl AsRef<[u8]>,
869    ) -> Result<&mut Self, SvgParserError> {
870        for cmd in SvgPathParser::new(Cursor::new(string)) {
871            cmd?.apply(self);
872        }
873        Ok(self)
874    }
875
876    /// Move current position, ending current subpath
877    pub fn move_to(&mut self, p: impl Into<Point>) -> &mut Self {
878        self.subpath_finish(false);
879        self.position = p.into();
880        self
881    }
882
883    /// Close current subpath
884    pub fn close(&mut self) -> &mut Self {
885        self.subpath_finish(true);
886        self
887    }
888
889    /// Add line from the current position to the specified point
890    pub fn line_to(&mut self, p: impl Into<Point>) -> &mut Self {
891        let p = p.into();
892        if !self.position.is_close_to(p) {
893            let line = Line::new(self.position, p);
894            self.position = line.end();
895            self.segments.push(line.into());
896        }
897        self
898    }
899
900    /// Add quadratic bezier curve
901    pub fn quad_to(&mut self, p1: impl Into<Point>, p2: impl Into<Point>) -> &mut Self {
902        let quad = Quad::new(self.position, p1, p2);
903        self.position = quad.end();
904        self.segments.push(quad.into());
905        self
906    }
907
908    /// Add smooth quadratic bezier curve
909    pub fn quad_smooth_to(&mut self, p2: impl Into<Point>) -> &mut Self {
910        let p1 = match self.segments.last() {
911            Some(Segment::Quad(quad)) => quad.smooth(),
912            _ => self.position,
913        };
914        self.quad_to(p1, p2)
915    }
916
917    /// Add cubic bezier curve
918    pub fn cubic_to(
919        &mut self,
920        p1: impl Into<Point>,
921        p2: impl Into<Point>,
922        p3: impl Into<Point>,
923    ) -> &mut Self {
924        let cubic = Cubic::new(self.position, p1, p2, p3);
925        self.position = cubic.end();
926        self.segments.push(cubic.into());
927        self
928    }
929
930    /// Add smooth cubic bezier curve
931    pub fn cubic_smooth_to(&mut self, p2: impl Into<Point>, p3: impl Into<Point>) -> &mut Self {
932        let p1 = match self.segments.last() {
933            Some(Segment::Cubic(cubic)) => cubic.smooth(),
934            _ => self.position,
935        };
936        self.cubic_to(p1, p2, p3)
937    }
938
939    /// Add elliptic arc segment
940    pub fn arc_to(
941        &mut self,
942        radii: impl Into<Point>,
943        x_axis_rot: Scalar,
944        large: bool,
945        sweep: bool,
946        p: impl Into<Point>,
947    ) -> &mut Self {
948        let radii: Point = radii.into();
949        let p = p.into();
950        let arc = EllipArc::new_param(
951            self.position,
952            p,
953            radii.x(),
954            radii.y(),
955            x_axis_rot,
956            large,
957            sweep,
958        );
959        match arc {
960            None => self.line_to(p),
961            Some(arc) => {
962                self.segments.extend(arc.to_cubics().map(Segment::from));
963                self.position = p;
964                self
965            }
966        }
967    }
968
969    /// Add circle with the center at current position and provided radius.
970    ///
971    /// Current position is not changed after invocation.
972    pub fn circle(&mut self, radius: Scalar) -> &mut Self {
973        // https://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves
974        // (4/3)*tan(pi/8) = 4*(sqrt(2)-1)/3 = 0.5522847498307935
975        let offset = 0.5522847498307935 * radius;
976        let x_offset = Point::new(offset, 0.0);
977        let y_offset = Point::new(0.0, offset);
978        let center = self.position();
979        let p0 = center - Point::new(radius, 0.0);
980        let p1 = center - Point::new(0.0, radius);
981        let p2 = center + Point::new(radius, 0.0);
982        let p3 = center + Point::new(0.0, radius);
983
984        self.move_to(p0)
985            .cubic_to(p0 - y_offset, p1 - x_offset, p1)
986            .cubic_to(p1 + x_offset, p2 - y_offset, p2)
987            .cubic_to(p2 + y_offset, p3 + x_offset, p3)
988            .cubic_to(p3 - x_offset, p0 + y_offset, p0)
989            .close()
990            .move_to(center)
991    }
992
993    /// Add box with rounded corners, with current position being low-x and low-y coordinate
994    pub fn rbox(&mut self, size: impl Into<Point>, radii: impl Into<Point>) -> &mut Self {
995        let init = self.position;
996        let bbox = BBox::new(self.position, self.position + size.into());
997        let Point([lx, ly]) = bbox.min();
998        let Point([hx, hy]) = bbox.max();
999
1000        let Point([rx, ry]) = radii.into();
1001        let rx = clamp(rx.abs(), 0.0, hx - lx);
1002        let ry = clamp(ry.abs(), 0.0, hy - ly);
1003        let radii = Point::new(rx, ry);
1004        let rounded = rx > EPSILON && ry > EPSILON;
1005
1006        self.move_to((lx + rx, ly)).line_to((hx - rx, ly));
1007        if rounded {
1008            self.arc_to(radii, 0.0, false, true, (hx, ly + ry));
1009        }
1010        self.line_to((hx, hy - ry));
1011        if rounded {
1012            self.arc_to(radii, 0.0, false, true, (hx - rx, hy));
1013        }
1014        self.line_to((lx + rx, hy));
1015        if rounded {
1016            self.arc_to(radii, 0.0, false, true, (lx, hy - ry));
1017        }
1018        self.line_to((lx, ly + ry));
1019        if rounded {
1020            self.arc_to(radii, 0.0, false, true, (lx + rx, ly));
1021        }
1022        self.close().move_to(init)
1023    }
1024
1025    /// Create checker board path inside bounding, useful to draw transparent area
1026    pub fn checkerboard(&mut self, bbox: BBox, cell_size: Scalar) -> &mut Self {
1027        let mut x = bbox.x();
1028        let mut y = bbox.y();
1029        while y < bbox.max().y() {
1030            while x < bbox.max().x() {
1031                let offset = Point::new(x, y);
1032                self.move_to(offset)
1033                    .line_to(offset + Point::new(cell_size, 0.0))
1034                    .line_to(offset + Point::new(cell_size, 2.0 * cell_size))
1035                    .line_to(offset + Point::new(2.0 * cell_size, 2.0 * cell_size))
1036                    .line_to(offset + Point::new(2.0 * cell_size, cell_size))
1037                    .line_to(offset + Point::new(0.0, cell_size))
1038                    .close();
1039                x += 2.0 * cell_size;
1040            }
1041            x = bbox.x();
1042            y += 2.0 * cell_size;
1043        }
1044        self.move_to(bbox.min())
1045    }
1046
1047    /// Current position of the builder
1048    pub fn position(&self) -> Point {
1049        self.position
1050    }
1051}
1052
1053impl FromStr for Path {
1054    type Err = SvgParserError;
1055
1056    fn from_str(text: &str) -> Result<Path, Self::Err> {
1057        Ok(Path::read_svg_path(Cursor::new(text))?)
1058    }
1059}
1060
1061#[cfg(feature = "serde")]
1062impl Serialize for Path {
1063    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1064    where
1065        S: serde::Serializer,
1066    {
1067        serializer.collect_str(self)
1068    }
1069}
1070
1071#[cfg(feature = "serde")]
1072impl<'de> Deserialize<'de> for Path {
1073    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1074    where
1075        D: serde::Deserializer<'de>,
1076    {
1077        std::borrow::Cow::<'de, str>::deserialize(deserializer)?
1078            .parse()
1079            .map_err(serde::de::Error::custom)
1080    }
1081}
1082
1083#[cfg(test)]
1084mod tests {
1085    use super::*;
1086    use crate::{PI, assert_approx_eq};
1087
1088    fn assert_path_eq(p0: &Path, p1: &Path) {
1089        assert_eq!(format!("{:#}", p0), format!("{:#}", p1));
1090    }
1091
1092    #[test]
1093    fn test_bbox() {
1094        let path: Path = SQUIRREL.parse().unwrap();
1095        let bbox = path.bbox(Transform::identity()).unwrap();
1096        assert_approx_eq!(bbox.x(), 0.25);
1097        assert_approx_eq!(bbox.y(), 1.0);
1098        assert_approx_eq!(bbox.width(), 15.75);
1099        assert_approx_eq!(bbox.height(), 14.0);
1100    }
1101
1102    const SQUIRREL: &str = r#"
1103    M12 1C9.79 1 8 2.31 8 3.92c0 1.94.5 3.03 0 6.08 0-4.5-2.77-6.34-4-6.34.05-.5-.48
1104    -.66-.48-.66s-.22.11-.3.34c-.27-.31-.56-.27-.56-.27l-.13.58S.7 4.29 .68 6.87c.2.33
1105    1.53.6 2.47.43.89.05.67.79.47.99C2.78 9.13 2 8 1 8S0 9 1 9s1 1 3 1c-3.09 1.2 0 4 0 4
1106    H3c-1 0-1 1-1 1h6c3 0 5-1 5-3.47 0-.85-.43-1.79 -1-2.53-1.11-1.46.23-2.68 1-2
1107    .77.68 3 1 3-2 0-2.21-1.79-4-4-4zM2.5 6 c-.28 0-.5-.22-.5-.5s.22-.5.5-.5.5.22.5.5
1108    -.22.5-.5.5z
1109    "#;
1110
1111    #[test]
1112    fn test_path_parse() -> Result<(), SvgParserError> {
1113        // complicated path
1114        let path: Path = SQUIRREL.parse()?;
1115        let reference = Path::builder()
1116            .move_to((12.0, 1.0))
1117            .cubic_to((9.79, 1.0), (8.0, 2.31), (8.0, 3.92))
1118            .cubic_to((8.0, 5.86), (8.5, 6.95), (8.0, 10.0))
1119            .cubic_to((8.0, 5.5), (5.23, 3.66), (4.0, 3.66))
1120            .cubic_to((4.05, 3.16), (3.52, 3.0), (3.52, 3.0))
1121            .cubic_to((3.52, 3.0), (3.3, 3.11), (3.22, 3.34))
1122            .cubic_to((2.95, 3.03), (2.66, 3.07), (2.66, 3.07))
1123            .line_to((2.53, 3.65))
1124            .cubic_to((2.53, 3.65), (0.7, 4.29), (0.68, 6.87))
1125            .cubic_to((0.88, 7.2), (2.21, 7.47), (3.15, 7.3))
1126            .cubic_to((4.04, 7.35), (3.82, 8.09), (3.62, 8.29))
1127            .cubic_to((2.78, 9.13), (2.0, 8.0), (1.0, 8.0))
1128            .cubic_to((0.0, 8.0), (0.0, 9.0), (1.0, 9.0))
1129            .cubic_to((2.0, 9.0), (2.0, 10.0), (4.0, 10.0))
1130            .cubic_to((0.91, 11.2), (4.0, 14.0), (4.0, 14.0))
1131            .line_to((3.0, 14.0))
1132            .cubic_to((2.0, 14.0), (2.0, 15.0), (2.0, 15.0))
1133            .line_to((8.0, 15.0))
1134            .cubic_to((11.0, 15.0), (13.0, 14.0), (13.0, 11.53))
1135            .cubic_to((13.0, 10.68), (12.57, 9.74), (12.0, 9.0))
1136            .cubic_to((10.89, 7.54), (12.23, 6.32), (13.0, 7.0))
1137            .cubic_to((13.77, 7.68), (16.0, 8.0), (16.0, 5.0))
1138            .cubic_to((16.0, 2.79), (14.21, 1.0), (12.0, 1.0))
1139            .close()
1140            .move_to((2.5, 6.0))
1141            .cubic_to((2.22, 6.0), (2.0, 5.78), (2.0, 5.5))
1142            .cubic_to((2.0, 5.22), (2.22, 5.0), (2.5, 5.0))
1143            .cubic_to((2.78, 5.0), (3.0, 5.22), (3.0, 5.5))
1144            .cubic_to((3.0, 5.78), (2.78, 6.0), (2.5, 6.0))
1145            .close()
1146            .build();
1147        assert_path_eq(&path, &reference);
1148
1149        let path: Path = " M0,0L1-1L1,0ZL0,1 L1,1Z ".parse()?;
1150        let reference = Path::builder()
1151            .move_to((0.0, 0.0))
1152            .line_to((1.0, -1.0))
1153            .line_to((1.0, 0.0))
1154            .close()
1155            .move_to((0.0, 0.0))
1156            .line_to((0.0, 1.0))
1157            .line_to((1.0, 1.0))
1158            .close()
1159            .build();
1160        assert_path_eq(&path, &reference);
1161
1162        let reference = Path::builder()
1163            .move_to((0.5, -3.0))
1164            .line_to((-11.0, -0.11))
1165            .build();
1166        // not separated scalars, implicit line segment
1167        let p1: Path = "M.5-3-11-.11".parse()?;
1168        // other spaces, implicit relative line segment
1169        let p2: Path = " m.5,-3 -11.5\n2.89 ".parse()?;
1170        assert_path_eq(&reference, &p1);
1171        assert_path_eq(&reference, &p2);
1172
1173        Ok(())
1174    }
1175
1176    #[test]
1177    fn test_save_load() -> std::io::Result<()> {
1178        let path: Path = SQUIRREL.parse()?;
1179        let mut path_save = Vec::new();
1180        path.write_svg_path(&mut path_save)?;
1181        let path_load = Path::read_svg_path(std::io::Cursor::new(path_save))?;
1182        assert_path_eq(&path, &path_load);
1183        Ok(())
1184    }
1185
1186    #[test]
1187    fn test_flatten() -> Result<(), SvgParserError> {
1188        let path: Path = SQUIRREL.parse()?;
1189        let tr = Transform::new_rotate(PI / 3.0).pre_translate(-10.0, -20.0);
1190        let lines: Vec<_> = path.flatten(tr, DEFAULT_FLATNESS, true).collect();
1191        let mut reference = Vec::new();
1192        for subpath in path.subpaths() {
1193            let subpath_lines: Vec<_> = subpath.flatten(tr, DEFAULT_FLATNESS, false).collect();
1194            // line are connected
1195            for ls in subpath_lines.windows(2) {
1196                assert!(ls[0].end().is_close_to(ls[1].start()));
1197            }
1198            reference.extend(subpath_lines);
1199        }
1200        assert_eq!(reference.len(), lines.len());
1201        for (l0, l1) in lines.iter().zip(reference.iter()) {
1202            assert!(l0.start().is_close_to(l1.start()));
1203            assert!(l0.end().is_close_to(l1.end()));
1204        }
1205        Ok(())
1206    }
1207
1208    #[test]
1209    fn test_winding() -> Result<(), SvgParserError> {
1210        let path: Path = SQUIRREL.parse()?;
1211        assert_eq!(path.winding_at((2.4, 5.4)), 0);
1212        assert_eq!(path.winding_at((3.5, 3.155)), 1);
1213        assert_eq!(path.winding_at((3.92, 3.155)), 0);
1214        assert_eq!(path.winding_at((12.46, 6.87)), 0);
1215        assert_eq!(path.winding_at((14.24, 7.455)), 1);
1216        Ok(())
1217    }
1218
1219    #[test]
1220    fn test_stroke() -> Result<(), SvgParserError> {
1221        // open path
1222        let path: Path = "M2,2L8,2C11,2 11,8 8,8L5,4".parse()?;
1223
1224        let path_stroke = path.stroke(StrokeStyle {
1225            width: 1.0,
1226            ..Default::default()
1227        });
1228        let path_reference: Path = r#"
1229        M2,1.5 L8,1.5 C9.80902,1.5 10.75,3.38197 10.75,5 10.75,6.61803 9.80902,8.5 8,8.5 L7.75,8.5 7.6,8.3 4.6,4.3
1230        5.4,3.7 8.4,7.7 8,7.5 C9.19098,7.5 9.75,6.38197 9.75,5 9.75,3.61803 9.19098,2.5 8,2.5 L2,2.5 2,1.5 Z
1231        "#.parse()?;
1232        assert_path_eq(&path_reference, &path_stroke);
1233
1234        let path_stroke = path.stroke(StrokeStyle {
1235            width: 1.0,
1236            line_cap: LineCap::Round,
1237            line_join: LineJoin::Round,
1238        });
1239        let path_reference: Path = r#"
1240        M2,1.5 L8,1.5 C9.80902,1.5 10.75,3.38197 10.75,5 10.75,6.61803 9.80902,8.5 8,8.5 7.84274,8.5 7.69436,8.42581
1241        7.6,8.3 L4.6,4.3 C4.43542,4.08057 4.48057,3.76458 4.7,3.6 4.91943,3.43542 5.23542,3.48057 5.4,3.7 L8.4,7.7 8,7.5
1242        C9.19098,7.5 9.75,6.38197 9.75,5 9.75,3.61803 9.19098,2.5 8,2.5 L2,2.5 C1.72571,2.5 1.5,2.27429 1.5,2
1243        1.5,1.72571 1.72571,1.5 2,1.5 Z
1244        "#.parse()?;
1245        assert_path_eq(&path_reference, &path_stroke);
1246
1247        // closed path
1248        let path: Path = "M2,2L8,2C11,2 11,8 8,8L5,4Z".parse()?;
1249
1250        let path_stroke = path.stroke(StrokeStyle {
1251            width: 1.0,
1252            line_cap: LineCap::Round,
1253            line_join: LineJoin::Round,
1254        });
1255        let path_reference: Path = r#"
1256        M2,1.5 L8,1.5 C9.80902,1.5 10.75,3.38197 10.75,5 10.75,6.61803 9.80902,8.5 8,8.5 7.84274,8.5 7.69436,8.42581
1257        7.6,8.3 L4.6,4.3 4.72265,4.41603 1.72265,2.41603 C1.53984,2.29415 1.45778,2.06539 1.52145,1.85511 1.58512,1.64482
1258        1.78029,1.5 2,1.5 ZM5.4,3.7 L8.4,7.7 8,7.5 C9.19098,7.5 9.75,6.38197 9.75,5 9.75,3.61803 9.19098,2.5 8,2.5
1259        L2,2.5 2.27735,1.58397 5.27735,3.58397 C5.32451,3.61542 5.36599,3.65465 5.4,3.7 Z
1260        "#.parse()?;
1261        assert_path_eq(&path_reference, &path_stroke);
1262
1263        Ok(())
1264    }
1265
1266    #[test]
1267    fn test_reverse() -> Result<(), SvgParserError> {
1268        let mut path: Path =
1269            "M2,2L8,2C11,2 11,8 8,8L5,4ZM7,3L8,6C9,6 10,5 9,4ZM2,4Q2,8 3,8L5,8C6,8 2,3 2,4Z"
1270                .parse()?;
1271        path.reverse();
1272        let path_reference =
1273            "M2,4C2,3 6,8 5,8L3,8Q2,8 2,4ZM9,4C10,5 9,6 8,6L7,3ZM5,4L8,8C11,8 11,2 8,2L2,2Z"
1274                .parse()?;
1275        assert_path_eq(&path_reference, &path);
1276        Ok(())
1277    }
1278
1279    #[test]
1280    fn test_display() -> Result<(), SvgParserError> {
1281        let path: Path = SQUIRREL.parse()?;
1282
1283        let path_display = format!("{:#}", path);
1284        assert_path_eq(&path, &path_display.parse()?);
1285        let path_reference = "M12,1C9.79,1 8,2.31 8,3.92C8,5.86 8.5,6.95 8,10C8,5.5 5.23,3.66 4,3.66C4.05,3.16 3.52,3 3.52,3C3.52,3 3.3,3.11 3.22,3.34C2.95,3.03 2.66,3.07 2.66,3.07L2.53,3.65C2.53,3.65 0.7,4.29 0.68,6.87C0.88,7.2 2.21,7.47 3.15,7.3C4.04,7.35 3.82,8.09 3.62,8.29C2.78,9.13 2,8 1,8C0,8 0,9 1,9C2,9 2,10 4,10C0.91,11.2 4,14 4,14L3,14C2,14 2,15 2,15L8,15C11,15 13,14 13,11.53C13,10.68 12.57,9.74 12,9C10.89,7.54 12.23,6.32 13,7C13.77,7.68 16,8 16,5C16,2.79 14.21,1 12,1ZM2.5,6C2.22,6 2,5.78 2,5.5C2,5.22 2.22,5 2.5,5C2.78,5 3,5.22 3,5.5C3,5.78 2.78,6 2.5,6Z";
1286        assert_eq!(path_reference, path_display.as_str());
1287
1288        let path_relative = format!("{:#}", path.display(true, Transform::identity()));
1289        assert_path_eq(&path, &path_relative.parse()?);
1290        let path_reference = "M12,1c-2.21,0-4,1.31-4,2.92c0,1.94 0.5,3.03 0,6.08c0-4.5-2.77-6.34-4-6.34c0.05-0.5-0.48-0.66-0.48-0.66c0,0-0.22,0.11-0.3,0.34c-0.27-0.31-0.56-0.27-0.56-0.27l-0.13,0.58c0,0-1.83,0.64-1.85,3.22c0.2,0.33 1.53,0.6 2.47,0.43c0.89,0.05 0.67,0.79 0.47,0.99c-0.84,0.84-1.62-0.29-2.62-0.29c-1,0-1,1 0,1c1,0 1,1 3,1c-3.09,1.2 0,4 0,4l-1,0c-1,0-1,1-1,1l6,0c3,0 5-1 5-3.47c0-0.85-0.43-1.79-1-2.53c-1.11-1.46 0.23-2.68 1-2c0.77,0.68 3,1 3-2c0-2.21-1.79-4-4-4Zm-9.5,5c-0.28,0-0.5-0.22-0.5-0.5c0-0.28 0.22-0.5 0.5-0.5c0.28,0 0.5,0.22 0.5,0.5c0,0.28-0.22,0.5-0.5,0.5Z";
1291        assert_eq!(path_reference, path_relative.as_str());
1292
1293        Ok(())
1294    }
1295}