From da9d7280d5d099c65f3e8d134a60b4778a5bcfb2 Mon Sep 17 00:00:00 2001 From: jaseg Date: Wed, 17 Feb 2021 18:58:11 +0100 Subject: svg-flatten: add curve flattening tolerance command line param --- svg-flatten/include/gerbolyze.hpp | 3 ++- svg-flatten/src/main.cpp | 10 ++++++---- svg-flatten/src/svg_doc.cpp | 13 ++++++++----- svg-flatten/src/svg_path.cpp | 4 ++-- svg-flatten/src/svg_path.h | 2 +- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/svg-flatten/include/gerbolyze.hpp b/svg-flatten/include/gerbolyze.hpp index 96a4103..dc06c89 100644 --- a/svg-flatten/include/gerbolyze.hpp +++ b/svg-flatten/include/gerbolyze.hpp @@ -139,6 +139,7 @@ namespace gerbolyze { class RenderSettings { public: double m_minimum_feature_size_mm = 0.1; + double curve_tolerance_mm; VectorizerSelectorizer &m_vec_sel; }; @@ -174,7 +175,7 @@ namespace gerbolyze { void export_svg_path(const RenderSettings &rset, const pugi::xml_node &node, ClipperLib::Paths &clip_path); void setup_debug_output(std::string filename=""); void setup_viewport_clip(); - void load_clips(); + void load_clips(const RenderSettings &rset); void load_patterns(); bool _valid; diff --git a/svg-flatten/src/main.cpp b/svg-flatten/src/main.cpp index 3427373..0abe3d1 100644 --- a/svg-flatten/src/main.cpp +++ b/svg-flatten/src/main.cpp @@ -42,6 +42,9 @@ int main(int argc, char **argv) { {"min_feature_size", {"-d", "--trace-space"}, "Minimum feature size of elements in vectorized graphics (trace/space) in mm. Default: 0.1mm.", 1}, + {"curve_tolerance", {"-c", "--curve-tolerance"}, + "Tolerance for curve flattening in mm. Default: 0.1mm.", + 1}, {"no_header", {"--no-header"}, "Do not export output format header/footer, only export the primitives themselves", 0}, @@ -243,10 +246,8 @@ int main(int argc, char **argv) { } delete vec; - double min_feature_size = 0.1; /* mm */ - if (args["min_feature_size"]) { - min_feature_size = args["min_feature_size"].as(); - } + double min_feature_size = args["min_feature_size"].as(0.1); /* mm */ + double curve_tolerance = args["curve_tolerance"].as(0.1); /* mm */ string ending = ""; auto idx = in_f_name.rfind("."); @@ -411,6 +412,7 @@ int main(int argc, char **argv) { VectorizerSelectorizer vec_sel(vectorizer, args["vectorizer_map"] ? args["vectorizer_map"].as() : ""); RenderSettings rset { min_feature_size, + curve_tolerance, vec_sel, }; diff --git a/svg-flatten/src/svg_doc.cpp b/svg-flatten/src/svg_doc.cpp index f387bcc..00c4bd6 100644 --- a/svg-flatten/src/svg_doc.cpp +++ b/svg-flatten/src/svg_doc.cpp @@ -86,7 +86,6 @@ bool gerbolyze::SVGDocument::load(istream &in, string debug_out_filename) { setup_debug_output(debug_out_filename); setup_viewport_clip(); - load_clips(); load_patterns(); _valid = true; @@ -142,10 +141,14 @@ bool IDElementSelector::match(const pugi::xml_node &node, bool included, bool is /* Recursively export all SVG elements in the given group. */ void gerbolyze::SVGDocument::export_svg_group(const RenderSettings &rset, const pugi::xml_node &group, Paths &parent_clip_path, const ElementSelector *sel, bool included, bool is_root) { + + /* Load clip paths from defs given bezier flattening tolerance from rset */ + load_clips(rset); + /* Enter the group's coordinate system */ cairo_save(cr); apply_cairo_transform_from_svg(cr, group.attribute("transform").value()); - + /* Fetch clip path from global registry and transform it into document coordinates. */ Paths clip_path; auto *lookup = lookup_clip_path(group); @@ -237,7 +240,7 @@ void gerbolyze::SVGDocument::export_svg_path(const RenderSettings &rset, const p PolyTree ptree_stroke; PolyTree ptree_fill; PolyTree ptree; - load_svg_path(cr, node, ptree_stroke, ptree_fill); + load_svg_path(cr, node, ptree_stroke, ptree_fill, rset.curve_tolerance_mm); double _y = 0; cairo_user_to_device_distance(cr, &stroke_width, &_y); @@ -462,7 +465,7 @@ void gerbolyze::SVGDocument::load_patterns() { } } -void gerbolyze::SVGDocument::load_clips() { +void gerbolyze::SVGDocument::load_clips(const RenderSettings &rset) { /* Set up document-wide clip path registry: Extract clip path definitions from element */ for (const auto &node : defs_node.children("clipPath")) { cairo_save(cr); @@ -481,7 +484,7 @@ void gerbolyze::SVGDocument::load_clips() { cairo_save(cr); /* TODO: we currently only support clipPathUnits="userSpaceOnUse", not "objectBoundingBox". */ apply_cairo_transform_from_svg(cr, child.attribute("transform").value()); - load_svg_path(cr, child, ptree_stroke, ptree_fill); + load_svg_path(cr, child, ptree_stroke, ptree_fill, rset.curve_tolerance_mm); cairo_restore (cr); Paths paths; diff --git a/svg-flatten/src/svg_path.cpp b/svg-flatten/src/svg_path.cpp index 68003ad..ce2775d 100644 --- a/svg-flatten/src/svg_path.cpp +++ b/svg-flatten/src/svg_path.cpp @@ -110,14 +110,14 @@ static pair path_to_clipper_via_cairo(cairo_t *cr, ClipperLib::Clipp return {has_closed, num_subpaths > 1}; } -void gerbolyze::load_svg_path(cairo_t *cr, const pugi::xml_node &node, ClipperLib::PolyTree &ptree_stroke, ClipperLib::PolyTree &ptree_fill) { +void gerbolyze::load_svg_path(cairo_t *cr, const pugi::xml_node &node, ClipperLib::PolyTree &ptree_stroke, ClipperLib::PolyTree &ptree_fill, double curve_tolerance) { auto *path_data = node.attribute("d").value(); auto fill_rule = clipper_fill_rule(node); /* For open paths, clipper does not correctly remove self-intersections. Thus, we pass everything into * clipper twice: Once with all paths set to "closed" to compute fill areas, and once with correct * open/closed properties for stroke offsetting. */ - cairo_set_tolerance (cr, 0.1); /* FIXME make configurable, scale properly for units */ + cairo_set_tolerance (cr, curve_tolerance); /* FIXME make configurable, scale properly for units */ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); ClipperLib::Clipper c_stroke; diff --git a/svg-flatten/src/svg_path.h b/svg-flatten/src/svg_path.h index 689af63..2ab29ec 100644 --- a/svg-flatten/src/svg_path.h +++ b/svg-flatten/src/svg_path.h @@ -23,7 +23,7 @@ #include "svg_geom.h" namespace gerbolyze { -void load_svg_path(cairo_t *cr, const pugi::xml_node &node, ClipperLib::PolyTree &ptree_stroke, ClipperLib::PolyTree &ptree_fill); +void load_svg_path(cairo_t *cr, const pugi::xml_node &node, ClipperLib::PolyTree &ptree_stroke, ClipperLib::PolyTree &ptree_fill, double curve_tolerance); void parse_dasharray(const pugi::xml_node &node, std::vector &out); void dash_path(const ClipperLib::Path &in, ClipperLib::Paths &out, const std::vector dasharray, double dash_offset=0.0); } -- cgit