Skip to content

Commit

Permalink
Optimise SVG path output
Browse files Browse the repository at this point in the history
  • Loading branch information
staticintlucas committed Aug 2, 2023
1 parent 64b38cc commit 9e20763
Showing 1 changed file with 52 additions and 16 deletions.
68 changes: 52 additions & 16 deletions src/drawing/svg.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
use kurbo::Affine;
use itertools::Itertools;
use kurbo::{Affine, PathEl, Point};
use svg::node::element::{Group, Path};
use svg::Document;

use crate::drawing::Drawing;

use super::{KeyDrawing, KeyPath};

fn fmt(num: f64) -> f64 {
(1e5 * num).round() / 1e5
macro_rules! fmt_num {
($fmt:literal, $($args:expr),*) => {
format!($fmt, $(($args * 1e5).round() / 1e5),*)
};
}

pub(crate) fn draw(drawing: &Drawing) -> String {
let size = drawing.bounds.size() * drawing.scale;
let view_box = drawing.bounds.scale_from_origin(1e3);

let document = Document::new()
.set("width", format!("{}", fmt(size.width)))
.set("height", format!("{}", fmt(size.height)))
.set("width", fmt_num!("{}", size.width))
.set("height", fmt_num!("{}", size.height))
.set(
"viewBox",
format!(
fmt_num!(
"{} {} {} {}",
fmt(view_box.origin().x),
fmt(view_box.origin().y),
fmt(view_box.size().width),
fmt(view_box.size().height)
view_box.origin().x,
view_box.origin().y,
view_box.size().width,
view_box.size().height
),
);

Expand All @@ -41,10 +44,7 @@ fn draw_key(key: &KeyDrawing, outline: f64) -> Group {
// scale from keyboard units to drawing units (milliunits)
let pos = Affine::scale(1e3) * key.origin;

let group = Group::new().set(
"transform",
format!("translate({}, {})", fmt(pos.x), fmt(pos.y)),
);
let group = Group::new().set("transform", fmt_num!("translate({}, {})", pos.x, pos.y));

key.paths
.iter()
Expand All @@ -53,13 +53,49 @@ fn draw_key(key: &KeyDrawing, outline: f64) -> Group {
}

fn draw_path(key: &KeyPath, outline: f64) -> Path {
let data = key.path.to_svg(); // TODO to_svg is far from optimal
let data = key
.path
.iter()
.scan((Point::ORIGIN, Point::ORIGIN), |(origin, point), el| {
let str = match el {
PathEl::MoveTo(p) => {
*origin = p;
*point = p;
fmt_num!("M{} {}", p.x, p.y)
}
PathEl::LineTo(p) => {
let d = p - *point;
*point = p;
fmt_num!("l{} {}", d.x, d.y)
}
PathEl::CurveTo(p1, p2, p) => {
let d1 = p1 - *point;
let d2 = p2 - *point;
let d = p - *point;
*point = p;
fmt_num!("c{} {} {} {} {} {}", d1.x, d1.y, d2.x, d2.y, d.x, d.y)
}
PathEl::QuadTo(p1, p) => {
let d1 = p1 - *point;
let d = p - *point;
*point = p;
fmt_num!("q{} {} {} {}", d1.x, d1.y, d.x, d.y)
}
PathEl::ClosePath => {
*point = *origin;
"z".into()
}
};

Some(str)
})
.join("");

let path = Path::new().set("d", data).set("fill", key.fill.to_string());

if outline > 1e-3 {
path.set("stroke", key.outline.to_string())
.set("stroke-width", format!("{}", fmt(outline)))
.set("stroke-width", fmt_num!("{}", outline))
} else {
path.set("stroke", "none")
}
Expand Down

0 comments on commit 9e20763

Please sign in to comment.