smooth_frame/output/
path.rs1use crate::types::Point;
2
3use super::format::{PathFormatter, SvgPathFormat};
4
5#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct CubicSegment {
8 pub from: Point,
10 pub ctrl1: Point,
12 pub ctrl2: Point,
14 pub to: Point,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq)]
20pub enum PathCommand {
21 MoveTo(Point),
23 LineTo(Point),
25 CubicTo {
27 ctrl1: Point,
29 ctrl2: Point,
31 to: Point,
33 },
34 Close,
36}
37
38#[derive(Debug, Clone, PartialEq, Default)]
40pub struct SmoothPath {
41 commands: Vec<PathCommand>,
42}
43
44impl SmoothPath {
45 #[must_use]
47 pub fn new() -> Self {
48 Self::default()
49 }
50
51 #[must_use]
53 pub fn commands(&self) -> &[PathCommand] {
54 &self.commands
55 }
56
57 #[must_use]
59 pub fn cubics(&self) -> Vec<CubicSegment> {
60 let mut cubics = Vec::new();
61 let mut current = None;
62 let mut subpath_start = None;
63
64 for command in &self.commands {
65 match *command {
66 PathCommand::MoveTo(point) => {
67 current = Some(point);
68 subpath_start = Some(point);
69 }
70 PathCommand::LineTo(point) => {
71 current = Some(point);
72 }
73 PathCommand::CubicTo { ctrl1, ctrl2, to } => {
74 if let Some(from) = current {
75 cubics.push(CubicSegment {
76 from,
77 ctrl1,
78 ctrl2,
79 to,
80 });
81 }
82 current = Some(to);
83 }
84 PathCommand::Close => {
85 current = subpath_start;
86 }
87 }
88 }
89
90 cubics
91 }
92
93 pub fn move_to(&mut self, point: Point) {
95 self.commands.push(PathCommand::MoveTo(point));
96 }
97
98 pub fn line_to(&mut self, point: Point) {
100 self.commands.push(PathCommand::LineTo(point));
101 }
102
103 pub fn cubic_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) {
105 self.commands
106 .push(PathCommand::CubicTo { ctrl1, ctrl2, to });
107 }
108
109 pub fn close(&mut self) {
111 self.commands.push(PathCommand::Close);
112 }
113
114 pub fn export_with<F>(&self, formatter: &F) -> F::Output
119 where
120 F: PathFormatter + ?Sized,
121 {
122 formatter.format(self.commands())
123 }
124
125 #[must_use]
127 pub fn to_svg_path(&self) -> String {
128 self.export_with(&SvgPathFormat::default())
129 }
130
131 #[must_use]
133 pub fn to_svg_path_with_precision(&self, precision: usize) -> String {
134 self.export_with(&SvgPathFormat::new(precision))
135 }
136}