From 5285b6dce8f0df37282b744ce625d4976b0f2541 Mon Sep 17 00:00:00 2001 From: jaseg Date: Wed, 27 Jan 2021 00:49:31 +0100 Subject: Add group id include/exclude matching --- include/gerbolyze.hpp | 14 +++++++++++--- src/main.cpp | 23 ++++++++++++++++++++++- src/svg_doc.cpp | 29 +++++++++++++++++++++++------ 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/include/gerbolyze.hpp b/include/gerbolyze.hpp index 6895f09..b2634f0 100644 --- a/include/gerbolyze.hpp +++ b/include/gerbolyze.hpp @@ -76,6 +76,14 @@ namespace gerbolyze { bool m_only_polys = false; std::ostream &m_out; }; + + class ElementSelector { + public: + bool match(const pugi::xml_node &node, bool included) const; + + std::vector include; + std::vector exclude; + }; class SVGDocument { public: @@ -95,8 +103,8 @@ namespace gerbolyze { double width() const { return page_w_mm; } double height() const { return page_h_mm; } - void render(PolygonSink &sink); - void render_to_list(std::vector> &out); + void render(PolygonSink &sink, const ElementSelector *sel=nullptr); + void render_to_list(std::vector> &out, const ElementSelector *sel=nullptr); private: friend class Pattern; @@ -105,7 +113,7 @@ namespace gerbolyze { const ClipperLib::Paths *lookup_clip_path(const pugi::xml_node &node); Pattern *lookup_pattern(const std::string id); - void export_svg_group(const pugi::xml_node &group, ClipperLib::Paths &parent_clip_path); + void export_svg_group(const pugi::xml_node &group, ClipperLib::Paths &parent_clip_path, const ElementSelector *sel=nullptr, bool included=true); void export_svg_path(const pugi::xml_node &node, ClipperLib::Paths &clip_path); void setup_debug_output(std::string filename=""); void setup_viewport_clip(); diff --git a/src/main.cpp b/src/main.cpp index 773b1a4..889fe6a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,6 +38,13 @@ int main(int argc, char **argv) { {"flatten", {"--flatten"}, "Flatten output so it only consists of non-overlapping white polygons. This perform composition at the vector level. Potentially slow.", 0}, + {"only_groups", {"-g", "--only-groups"}, + "Comma-separated list of group IDs to export.", + 1}, + {"exclude_groups", {"-e", "--exclude-groups"}, + "Comma-separated list of group IDs to exclude from export. Takes precedence over --only-groups.", + 1}, + }}; @@ -143,7 +150,21 @@ int main(int argc, char **argv) { flattener = new Flattener(*sink); } - doc.render(flattener ? *flattener : *sink); + /* Because the C++ stdlib is bullshit */ + auto id_match = [](string in, vector &out) { + stringstream ss(in); + while (getline(ss, out.emplace_back(), ',')) { + } + out.pop_back(); + }; + + ElementSelector sel; + if (args["only_groups"]) + id_match(args["only_groups"], sel.include); + if (args["exclude_groups"]) + id_match(args["exclude_groups"], sel.exclude); + + doc.render(flattener ? *flattener : *sink, &sel); return EXIT_SUCCESS; } diff --git a/src/svg_doc.cpp b/src/svg_doc.cpp index 518e7ed..196cf60 100644 --- a/src/svg_doc.cpp +++ b/src/svg_doc.cpp @@ -116,8 +116,22 @@ double gerbolyze::SVGDocument::doc_units_to_mm(double px) const { return px / (vb_w / page_w_mm); } +bool ElementSelector::match(const pugi::xml_node &node, bool included) const { + if (include.empty() && exclude.empty()) + return true; + + bool include_match = std::find(include.begin(), include.end(), node.attribute("id").value()) != include.end(); + bool exclude_match = std::find(exclude.begin(), exclude.end(), node.attribute("id").value()) != exclude.end(); + + if (exclude_match || (!included && !include_match)) { + return false; + } + + return true; +} + /* Recursively export all SVG elements in the given group. */ -void gerbolyze::SVGDocument::export_svg_group(const pugi::xml_node &group, Paths &parent_clip_path) { +void gerbolyze::SVGDocument::export_svg_group(const pugi::xml_node &group, Paths &parent_clip_path, const ElementSelector *sel, bool included) { /* Enter the group's coordinate system */ cairo_save(cr); apply_cairo_transform_from_svg(cr, group.attribute("transform").value()); @@ -147,9 +161,12 @@ void gerbolyze::SVGDocument::export_svg_group(const pugi::xml_node &group, Paths /* Iterate over the group's children, exporting them one by one. */ for (const auto &node : group.children()) { + if (sel && !sel->match(node, included)) + continue; + string name(node.name()); if (name == "g") { - export_svg_group(node, clip_path); + export_svg_group(node, clip_path, sel, true); } else if (name == "path") { export_svg_path(node, clip_path); @@ -342,7 +359,7 @@ void gerbolyze::SVGDocument::export_svg_path(const pugi::xml_node &node, Paths & } } -void gerbolyze::SVGDocument::render(PolygonSink &sink) { +void gerbolyze::SVGDocument::render(PolygonSink &sink, const ElementSelector *sel) { assert(_valid); /* Export the actual SVG document to both SVG for debuggin and to gerber. We do this as we go, i.e. we immediately * process each element to gerber as we encounter it instead of first rendering everything to a giant list of gerber @@ -354,15 +371,15 @@ void gerbolyze::SVGDocument::render(PolygonSink &sink) { c.AddPaths(vb_paths, ptSubject, /* closed */ true); ClipperLib::IntRect bbox = c.GetBounds(); cerr << "document viewbox clip: bbox={" << bbox.left << ", " << bbox.top << "} - {" << bbox.right << ", " << bbox.bottom << "}" << endl; - export_svg_group(root_elem, vb_paths); + export_svg_group(root_elem, vb_paths, sel, false); sink.footer(); } -void gerbolyze::SVGDocument::render_to_list(vector> &out) { +void gerbolyze::SVGDocument::render_to_list(vector> &out, const ElementSelector *sel) { LambdaPolygonSink sink([&out](const Polygon &poly, GerberPolarityToken pol) { out.emplace_back(pair{poly, pol}); }); - render(sink); + render(sink, sel); } void gerbolyze::SVGDocument::setup_debug_output(string filename) { -- cgit