rust-galmon-web/src/ui/main/world_geo/path_sink.rs

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,
}
}
}