109 lines
2.4 KiB
Rust
109 lines
2.4 KiB
Rust
use super::{
|
|
ProjectedPoint,
|
|
DrawPath,
|
|
};
|
|
|
|
pub struct PathSink {
|
|
pub path: String,
|
|
pub stroke_path: Option<String>,
|
|
}
|
|
|
|
impl PathSink {
|
|
pub fn new() -> Self {
|
|
PathSink {
|
|
path: String::new(),
|
|
stroke_path: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PathSink {
|
|
fn _write(&mut self, path: std::fmt::Arguments<'_>) {
|
|
use std::fmt::Write;
|
|
self.path.write_fmt(path).unwrap();
|
|
if let Some(stroke_path) = &mut self.stroke_path {
|
|
stroke_path.write_fmt(path).unwrap();
|
|
}
|
|
}
|
|
|
|
fn _write2(&mut self, path_stroke: std::fmt::Arguments<'_>, path_no_stroke: std::fmt::Arguments<'_>) {
|
|
use std::fmt::Write;
|
|
let stroke_path = {
|
|
let path = &self.path;
|
|
self.stroke_path.get_or_insert_with(|| path.clone())
|
|
};
|
|
self.path.write_fmt(path_no_stroke).unwrap();
|
|
stroke_path.write_fmt(path_stroke).unwrap();
|
|
}
|
|
|
|
pub fn draw_path(&mut self) -> impl DrawPath<Point = ProjectedPoint> + '_ {
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
enum State {
|
|
Ring,
|
|
Path,
|
|
}
|
|
|
|
struct Draw<'a> {
|
|
sink: &'a mut PathSink,
|
|
empty: bool,
|
|
state: Option<State>,
|
|
};
|
|
|
|
impl DrawPath for Draw<'_> {
|
|
type Point = ProjectedPoint;
|
|
|
|
fn line(&mut self, to: ProjectedPoint, stroke: bool) {
|
|
let state = self.state.expect("need to be in some active geometry (path, ring)");
|
|
if self.empty {
|
|
self.sink._write(format_args!("M{:.3},{:.3}", to.x, to.y));
|
|
self.empty = false;
|
|
} else if stroke {
|
|
self.sink._write(format_args!("L{:.3},{:.3}", to.x, to.y));
|
|
} else if state == State::Path {
|
|
// "no stroke" in path is simple move
|
|
self.sink._write(format_args!("M{:.3},{:.3}", to.x, to.y));
|
|
} else {
|
|
self.sink._write2(
|
|
format_args!("M{:.3},{:.3}", to.x, to.y),
|
|
format_args!("L{:.3},{:.3}", to.x, to.y),
|
|
);
|
|
}
|
|
}
|
|
|
|
fn ring_start(&mut self) {
|
|
assert_eq!(self.state, None);
|
|
assert!(self.empty);
|
|
self.state = Some(State::Ring);
|
|
}
|
|
|
|
fn ring_end(&mut self) {
|
|
assert_eq!(self.state, Some(State::Ring));
|
|
if !self.empty {
|
|
self.sink._write(format_args!("Z"));
|
|
self.empty = true;
|
|
}
|
|
self.state = None;
|
|
}
|
|
|
|
// open path, not filled
|
|
fn path_start(&mut self) {
|
|
assert_eq!(self.state, None);
|
|
assert!(self.empty);
|
|
self.state = Some(State::Path);
|
|
}
|
|
|
|
fn path_end(&mut self) {
|
|
assert_eq!(self.state, Some(State::Path));
|
|
self.empty = true;
|
|
self.state = None;
|
|
}
|
|
}
|
|
|
|
Draw {
|
|
sink: self,
|
|
empty: true,
|
|
state: None,
|
|
}
|
|
}
|
|
}
|