flo_canvas/conversion_streams/
path_stream.rs1use crate::draw::*;
2use crate::path::*;
3use crate::color::*;
4use crate::gradient::*;
5use crate::transform2d::*;
6
7use flo_stream::*;
8use flo_curves::geo::*;
9use flo_curves::bezier::path::*;
10
11use futures::prelude::*;
12
13use std::mem;
14
15#[derive(Copy, Clone, Debug)]
19pub enum PathAttribute {
20 Stroke(f32, Color),
22
23 StrokePixels(f32, Color),
25
26 Fill(Color),
28
29 FillTexture(TextureId, (f32, f32), (f32, f32), Option<Transform2D>),
31
32 FillGradient(GradientId, (f32, f32), (f32, f32), Option<Transform2D>)
34}
35
36pub fn drawing_to_paths<BezierPath, InStream>(draw_stream: InStream) -> impl Send+Unpin+Stream<Item=Vec<BezierPath>>
46where
47InStream: 'static+Send+Unpin+Stream<Item=Draw>,
48BezierPath: 'static+Send+BezierPathFactory,
49BezierPath::Point: Send+Coordinate2D {
50 generator_stream(move |yield_value| async move {
51 use self::PathOp::*;
52
53 let mut current_path: Option<BezierPathBuilder<_>> = None;
55 let mut current_components = vec![];
56 let mut start_point = None;
57
58 let mut draw_stream = draw_stream;
60
61 while let Some(draw) = draw_stream.next().await {
62 match draw {
63 Draw::Path(NewPath) => {
64 if let Some(path) = current_path.take() {
66 current_components.push(path.build());
67 }
68
69 if current_components.len() > 0 {
71 let mut next_path = vec![];
72 mem::swap(&mut next_path, &mut current_components);
73
74 yield_value(next_path).await;
75 }
76 }
77
78 Draw::Path(Move(x, y)) => {
79 if let Some(path) = current_path.take() {
81 current_components.push(path.build());
82 }
83
84 current_path = Some(BezierPathBuilder::start(BezierPath::Point::from_components(&[x as _, y as _])));
86 start_point = Some(BezierPath::Point::from_components(&[x as _, y as _]));
87 }
88
89 Draw::Path(Line(x, y)) => {
90 current_path = current_path.map(|current_path| {
92 current_path.line_to(BezierPath::Point::from_components(&[x as _, y as _]))
93 });
94 }
95
96 Draw::Path(BezierCurve(((cp1x, cp1y), (cp2x, cp2y)), (x1, y1))) => {
97 current_path = current_path.map(|current_path| {
99 current_path.curve_to(
100 (BezierPath::Point::from_components(&[cp1x as _, cp1y as _]), BezierPath::Point::from_components(&[cp2x as _, cp2y as _])),
101 BezierPath::Point::from_components(&[x1 as _, y1 as _])
102 )
103 });
104 }
105
106 Draw::Path(ClosePath) => {
107 if let Some(start_point) = &start_point {
108 current_path = current_path.map(|current_path| {
109 current_path.line_to(start_point.clone())
110 })
111 }
112 }
113
114 _ => { }
116 }
117 }
118
119 if let Some(path) = current_path.take() {
121 current_components.push(path.build());
122 }
123
124 if current_components.len() > 0 {
126 let mut next_path = vec![];
127 mem::swap(&mut next_path, &mut current_components);
128
129 yield_value(next_path).await;
130 }
131 })
132}
133pub fn drawing_to_attributed_paths<BezierPath, InStream>(draw_stream: InStream) -> impl Send+Unpin+Stream<Item=(Vec<PathAttribute>, Vec<BezierPath>)>
140where
141InStream: 'static+Send+Unpin+Stream<Item=Draw>,
142BezierPath: 'static+Send+BezierPathFactory,
143BezierPath::Point: Send+Coordinate2D {
144 generator_stream(move |yield_value| async move {
145 use self::PathOp::*;
146
147 let mut current_path: Option<BezierPathBuilder<_>> = None;
149 let mut current_components = vec![];
150 let mut current_attributes = vec![];
151 let mut start_point = None;
152
153 let mut fill_color = PathAttribute::Fill(Color::Rgba(0.0, 0.0, 0.0, 1.0));
154 let mut stroke_color = Color::Rgba(0.0, 0.0, 0.0, 1.0);
155 let mut line_width = None;
156 let mut line_width_pixels = None;
157
158 let mut state_stack = vec![];
159
160 let mut draw_stream = draw_stream;
162
163 while let Some(draw) = draw_stream.next().await {
164 match draw {
165 Draw::Path(NewPath) => {
166 if let Some(path) = current_path.take() {
168 current_components.push(path.build());
169 }
170
171 if current_components.len() > 0 && current_attributes.len() > 0 {
173 let next_path = mem::take(&mut current_components);
174 let next_attributes = mem::take(&mut current_attributes);
175
176 yield_value((next_attributes, next_path)).await;
177 }
178
179 current_attributes = vec![];
180 current_components = vec![];
181 }
182
183 Draw::Path(Move(x, y)) => {
184 if let Some(path) = current_path.take() {
186 current_components.push(path.build());
187 }
188
189 current_path = Some(BezierPathBuilder::start(BezierPath::Point::from_components(&[x as _, y as _])));
191 start_point = Some(BezierPath::Point::from_components(&[x as _, y as _]));
192 }
193
194 Draw::Path(Line(x, y)) => {
195 current_path = current_path.map(|current_path| {
197 current_path.line_to(BezierPath::Point::from_components(&[x as _, y as _]))
198 });
199 }
200
201 Draw::Path(BezierCurve(((cp1x, cp1y), (cp2x, cp2y)), (x1, y1))) => {
202 current_path = current_path.map(|current_path| {
204 current_path.curve_to(
205 (BezierPath::Point::from_components(&[cp1x as _, cp1y as _]), BezierPath::Point::from_components(&[cp2x as _, cp2y as _])),
206 BezierPath::Point::from_components(&[x1 as _, y1 as _])
207 )
208 });
209 }
210
211 Draw::Path(ClosePath) => {
212 if let Some(start_point) = &start_point {
213 current_path = current_path.map(|current_path| {
214 current_path.line_to(start_point.clone())
215 })
216 }
217 }
218
219 Draw::FillColor(new_fill_color) => {
220 fill_color = PathAttribute::Fill(new_fill_color);
221 }
222
223 Draw::FillGradient(gradient, (x1, y1), (x2, y2)) => {
224 fill_color = PathAttribute::FillGradient(gradient, (x1, y1), (x2, y2), None);
225 }
226
227 Draw::FillTexture(texture, (x1, y1), (x2, y2)) => {
228 fill_color = PathAttribute::FillTexture(texture, (x1, y1), (x2, y2), None);
229 }
230
231 Draw::FillTransform(transform) => {
232 fill_color = match fill_color {
233 PathAttribute::FillGradient(gradient, coord1, coord2, None) => PathAttribute::FillGradient(gradient, coord1, coord2, Some(transform)),
234 PathAttribute::FillTexture(texture, coord1, coord2, None) => PathAttribute::FillTexture(texture, coord1, coord2, Some(transform)),
235 PathAttribute::FillGradient(gradient, coord1, coord2, Some(existing_transform)) => PathAttribute::FillGradient(gradient, coord1, coord2, Some(existing_transform * transform)),
236 PathAttribute::FillTexture(texture, coord1, coord2, Some(existing_transform)) => PathAttribute::FillTexture(texture, coord1, coord2, Some(existing_transform * transform)),
237
238 other_fill_color => other_fill_color
239 };
240 }
241
242 Draw::StrokeColor(new_stroke_color) => {
243 stroke_color = new_stroke_color;
244 }
245
246 Draw::LineWidth(new_line_width) => {
247 line_width_pixels = None;
248 line_width = Some(new_line_width);
249 }
250
251 Draw::LineWidthPixels(new_line_width) => {
252 line_width_pixels = Some(new_line_width);
253 line_width = None;
254 }
255
256 Draw::PushState => {
257 state_stack.push((fill_color, stroke_color, line_width, line_width_pixels));
258 }
259
260 Draw::PopState => {
261 if let Some((new_fill_color, new_stroke_color, new_line_width, new_line_width_pixels)) = state_stack.pop() {
262 fill_color = new_fill_color;
263 stroke_color = new_stroke_color;
264 line_width = new_line_width;
265 line_width_pixels = new_line_width_pixels;
266 }
267 }
268
269 Draw::Fill => {
270 current_attributes.push(fill_color);
271 }
272
273 Draw::Stroke => {
274 if let Some(line_width) = line_width {
275 current_attributes.push(PathAttribute::Stroke(line_width, stroke_color));
276 }
277 if let Some(line_width_pixels) = line_width_pixels {
278 current_attributes.push(PathAttribute::StrokePixels(line_width_pixels, stroke_color));
279 }
280 }
281
282 _ => { }
284 }
285 }
286
287 if let Some(path) = current_path.take() {
289 current_components.push(path.build());
290 }
291
292 if current_components.len() > 0 && current_attributes.len() > 0 {
294 let next_path = mem::take(&mut current_components);
295 let next_attributes = mem::take(&mut current_attributes);
296
297 yield_value((next_attributes, next_path)).await;
298 }
299 })
300}
301
302#[cfg(test)]
303mod test {
304 use super::*;
305 use futures::stream;
306 use futures::executor;
307
308 #[test]
309 pub fn square_path() {
310 executor::block_on(async {
311 let square = vec![
313 Draw::Path(PathOp::NewPath),
314 Draw::Path(PathOp::Move(0.0, 0.0)),
315 Draw::Path(PathOp::Line(100.0, 0.0)),
316 Draw::Path(PathOp::Line(100.0, 100.0)),
317 Draw::Path(PathOp::Line(0.0, 100.0)),
318 Draw::Path(PathOp::ClosePath)
319 ];
320
321 let square_stream = stream::iter(square);
323 let path_stream = drawing_to_paths::<SimpleBezierPath, _>(square_stream);
324
325 let paths = path_stream.collect::<Vec<_>>().await;
327
328 assert!(paths.len() == 1);
330 assert!(paths[0].len() == 1);
331
332 let (start, curves) = &paths[0][0];
333
334 assert!(start == &Coord2(0.0, 0.0));
335 assert!(curves[0].2 == Coord2(100.0, 0.0));
336 assert!(curves[1].2 == Coord2(100.0, 100.0));
337 assert!(curves[2].2 == Coord2(0.0, 100.0));
338 assert!(curves[3].2 == Coord2(0.0, 0.0));
339
340 assert!(curves.len() == 4);
341 });
342 }
343}