From 9e9cc2bc019f0e67720ad5da16315e7cd6781e78 Mon Sep 17 00:00:00 2001 From: jaseg Date: Mon, 20 Jun 2022 16:19:53 +0200 Subject: svg-flatten: add export of patterns via aperture macros --- svg-flatten/include/gerbolyze.hpp | 28 ++++++++++++++++++++++++++++ svg-flatten/src/main.cpp | 17 ++++++++++++++++- svg-flatten/src/out_gerber.cpp | 38 +++++++++++++++++++++++++++++++++++++- svg-flatten/src/out_scaler.cpp | 23 +++++++++++++++++++++++ svg-flatten/src/out_sexp.cpp | 2 +- svg-flatten/src/out_svg.cpp | 2 +- svg-flatten/src/svg_doc.cpp | 11 +++++++++++ svg-flatten/src/svg_pattern.cpp | 20 ++++++++++++++++++-- svg-flatten/src/svg_pattern.h | 2 +- 9 files changed, 136 insertions(+), 7 deletions(-) (limited to 'svg-flatten') diff --git a/svg-flatten/include/gerbolyze.hpp b/svg-flatten/include/gerbolyze.hpp index 9de5572..d62cbcc 100644 --- a/svg-flatten/include/gerbolyze.hpp +++ b/svg-flatten/include/gerbolyze.hpp @@ -56,6 +56,18 @@ namespace gerbolyze { d2p m_center; }; + class PatternToken { + public: + PatternToken(vector> &polys) : m_polys(polys) {} + vector> &m_polys; + }; + + class FlashToken { + public: + FlashToken(d2p offset) : m_offset(offset) {} + d2p m_offset; + }; + class PolygonSink { public: virtual ~PolygonSink() {} @@ -80,6 +92,11 @@ namespace gerbolyze { virtual PolygonSink &operator<<(GerberPolarityToken pol) = 0; virtual PolygonSink &operator<<(const ApertureToken &) { return *this; }; virtual PolygonSink &operator<<(const DrillToken &) { return *this; }; + virtual PolygonSink &operator<<(const FlashToken &) { return *this; }; + virtual PolygonSink &operator<<(const PatternToken &) { + cerr << "Error: pattern to aperture mapping is not supporte for this output." << endl; + return *this; + }; virtual void footer() {} }; @@ -129,6 +146,8 @@ namespace gerbolyze { virtual PolygonScaler &operator<<(GerberPolarityToken pol); virtual PolygonScaler &operator<<(const ApertureToken &tok); virtual PolygonScaler &operator<<(const DrillToken &tok); + virtual PolygonScaler &operator<<(const FlashToken &tok); + virtual PolygonScaler &operator<<(const PatternToken &tok); virtual void footer(); private: @@ -194,10 +213,13 @@ namespace gerbolyze { double m_minimum_feature_size_mm = 0.1; double curve_tolerance_mm; double drill_test_polsby_popper_tolerance = 0.01; + double aperture_circle_test_tolerance = 0.01; + double aperture_rect_test_tolerance = 0.01; VectorizerSelectorizer &m_vec_sel; bool outline_mode = false; bool flip_color_interpretation = false; bool pattern_complete_tiles_only = false; + bool use_apertures_for_patterns = false; }; class RenderContext { @@ -212,6 +234,9 @@ namespace gerbolyze { xform2d transform, ClipperLib::Paths &clip, bool included); + RenderContext(RenderContext &parent, + PolygonSink &sink, + ClipperLib::Paths &clip); PolygonSink &sink() { return m_sink; } const ElementSelector &sel() { return m_sel; } @@ -305,6 +330,8 @@ namespace gerbolyze { virtual SimpleGerberOutput &operator<<(GerberPolarityToken pol); virtual SimpleGerberOutput &operator<<(const DrillToken &tok); virtual SimpleGerberOutput &operator<<(const ApertureToken &ap); + virtual SimpleGerberOutput &operator<<(const FlashToken &tok); + virtual SimpleGerberOutput &operator<<(const PatternToken &tok); virtual void header_impl(d2p origin, d2p size); virtual void footer_impl(); @@ -319,6 +346,7 @@ namespace gerbolyze { bool m_flip_pol; bool m_outline_mode; double m_current_aperture; + bool m_macro_aperture; unsigned int m_aperture_num; }; diff --git a/svg-flatten/src/main.cpp b/svg-flatten/src/main.cpp index 35fcbfb..812db5d 100644 --- a/svg-flatten/src/main.cpp +++ b/svg-flatten/src/main.cpp @@ -76,6 +76,9 @@ int main(int argc, char **argv) { {"pattern_complete_tiles_only", {"--pattern-complete-tiles-only"}, "Break SVG spec by only rendering complete pattern tiles, i.e. pattern tiles that entirely fit the target area, instead of performing clipping.", 0}, + {"use_apertures_for_patterns", {"--use-apertures-for-patterns"}, + "Try to use apertures to represent svg patterns where possible.", + 0}, {"min_feature_size", {"-d", "--trace-space"}, "Minimum feature size of elements in vectorized graphics (trace/space) in mm. Default: 0.1mm.", 1}, @@ -85,6 +88,12 @@ int main(int argc, char **argv) { {"drill_test_polsby_popper_tolerance", {"--drill-test-tolerance"}, "Tolerance for identifying circles as drills in outline mode", 1}, + {"aperture_circle_test_tolerance", {"--circle-test-tolerance"}, + "Tolerance for identifying circles as apertures in patterns (--use-apertures-for-patterns)", + 1}, + {"aperture_rect_test_tolerance", {"--rect-test-tolerance"}, + "Tolerance for identifying rectangles as apertures in patterns (--use-apertures-for-patterns)", + 1}, {"no_header", {"--no-header"}, "Do not export output format header/footer, only export the primitives themselves", 0}, @@ -297,7 +306,9 @@ int main(int argc, char **argv) { double min_feature_size = args["min_feature_size"].as(0.1); /* mm */ double curve_tolerance = args["curve_tolerance"].as(0.1); /* mm */ - double drill_test_polsby_popper_tolerance = args["drill_test_polsby_popper_tolerance"].as(0.1); /* mm */ + double drill_test_polsby_popper_tolerance = args["drill_test_polsby_popper_tolerance"].as(0.1); + double aperture_rect_test_tolerance = args["aperture_rect_test_tolerance"].as(0.1); + double aperture_circle_test_tolerance = args["aperture_circle_test_tolerance"].as(0.1); string ending = ""; auto idx = in_f_name.rfind("."); @@ -427,15 +438,19 @@ int main(int argc, char **argv) { VectorizerSelectorizer vec_sel(vectorizer, args["vectorizer_map"] ? args["vectorizer_map"].as() : ""); bool flip_svg_colors = args["flip_svg_color_interpretation"]; bool pattern_complete_tiles_only = args["pattern_complete_tiles_only"]; + bool use_apertures_for_patterns = args["use_apertures_for_patterns"]; RenderSettings rset { min_feature_size, curve_tolerance, drill_test_polsby_popper_tolerance, + aperture_circle_test_tolerance, + aperture_rect_test_tolerance, vec_sel, outline_mode, flip_svg_colors, pattern_complete_tiles_only, + use_apertures_for_patterns, }; SVGDocument doc; diff --git a/svg-flatten/src/out_gerber.cpp b/svg-flatten/src/out_gerber.cpp index c43d07d..0b0a6bf 100644 --- a/svg-flatten/src/out_gerber.cpp +++ b/svg-flatten/src/out_gerber.cpp @@ -36,6 +36,7 @@ SimpleGerberOutput::SimpleGerberOutput(ostream &out, bool only_polys, int digits m_flip_pol(flip_polarity), m_outline_mode(outline_mode), m_current_aperture(0.0), + m_macro_aperture(false), m_aperture_num(10) /* See gerber standard */ { assert(1 <= digits_int && digits_int <= 9); @@ -62,10 +63,11 @@ void SimpleGerberOutput::header_impl(d2p origin, d2p size) { } SimpleGerberOutput& SimpleGerberOutput::operator<<(const ApertureToken &ap) { - if (ap.m_size == m_current_aperture) { + if (!m_macro_aperture && ap.m_size == m_current_aperture) { return *this; } + m_macro_aperture = false; m_current_aperture = ap.m_size; m_aperture_num += 1; @@ -139,3 +141,37 @@ void SimpleGerberOutput::footer_impl() { m_out << "M02*" << endl; } + +SimpleGerberOutput &SimpleGerberOutput::operator<<(const FlashToken &tok) { + double x = round((tok.m_offset[0] * m_scale + m_offset[0]) * m_gerber_scale); + double y = round((m_height - tok.m_offset[1] * m_scale + m_offset[1]) * m_gerber_scale); + + m_out << "X" << setw(m_digits_int + m_digits_frac) << setfill('0') << std::internal /* isn't C++ a marvel of engineering? */ << (long long int)x + << "Y" << setw(m_digits_int + m_digits_frac) << setfill('0') << std::internal << (long long int)y + << "D03*" << endl; + + return *this; +} + +SimpleGerberOutput &SimpleGerberOutput::operator<<(const PatternToken &tok) { + m_macro_aperture = true; + m_aperture_num += 1; + + m_out << "%AMmacro" << m_aperture_num << "*" << endl; + + for (auto &pair : tok.m_polys) { + int exposure = (pair.second == GRB_POL_DARK) ? 1 : 0; + m_out << 4 << "," << exposure << "," << pair.first.size(); + for (auto &pt : pair.first) { + m_out << "," << pt[0] << "," << pt[1]; + } + m_out << "," << pair.first.back()[0] << "," << pair.first.back()[1] << "*" << endl; + } + + m_out << "%" << endl; + m_out << "%ADD" << m_aperture_num << "macro" << m_aperture_num << "*%" << endl; + m_out << "D" << m_aperture_num << "*" << endl; + + return *this; +} + diff --git a/svg-flatten/src/out_scaler.cpp b/svg-flatten/src/out_scaler.cpp index 0320d69..fb54145 100644 --- a/svg-flatten/src/out_scaler.cpp +++ b/svg-flatten/src/out_scaler.cpp @@ -69,3 +69,26 @@ PolygonScaler &PolygonScaler::operator<<(const DrillToken &tok) { m_sink << DrillToken(new_center); return *this; } + +PolygonScaler &PolygonScaler::operator<<(const FlashToken &tok) { + d2p new_offset = { tok.m_offset[0] * m_scale, tok.m_offset[1] * m_scale}; + m_sink << FlashToken(new_offset); + return *this; +} + +PolygonScaler &PolygonScaler::operator<<(const PatternToken &tok) { + vector> new_polys; + for (size_t i=0; i{poly, tok.m_polys[i].second}); + } + m_sink << PatternToken(new_polys); + return *this; +} + diff --git a/svg-flatten/src/out_sexp.cpp b/svg-flatten/src/out_sexp.cpp index 6760920..f872b90 100644 --- a/svg-flatten/src/out_sexp.cpp +++ b/svg-flatten/src/out_sexp.cpp @@ -135,7 +135,7 @@ KicadSexpOutput &KicadSexpOutput::operator<<(const Polygon &poly) { return *this; } -KicadSexpOutput &KicadSexpOutput::operator<<(const DrillToken &tok) { +KicadSexpOutput &KicadSexpOutput::operator<<(const DrillToken &) { return *this; } diff --git a/svg-flatten/src/out_svg.cpp b/svg-flatten/src/out_svg.cpp index 4ecd979..66f0c94 100644 --- a/svg-flatten/src/out_svg.cpp +++ b/svg-flatten/src/out_svg.cpp @@ -77,7 +77,7 @@ SimpleSVGOutput &SimpleSVGOutput::operator<<(const Polygon &poly) { return *this; } -SimpleSVGOutput &SimpleSVGOutput::operator<<(const DrillToken &tok) { +SimpleSVGOutput &SimpleSVGOutput::operator<<(const DrillToken &) { return *this; } diff --git a/svg-flatten/src/svg_doc.cpp b/svg-flatten/src/svg_doc.cpp index e8c02db..7716a2e 100644 --- a/svg-flatten/src/svg_doc.cpp +++ b/svg-flatten/src/svg_doc.cpp @@ -557,3 +557,14 @@ gerbolyze::RenderContext::RenderContext(RenderContext &parent, xform2d transform m_mat.transform(transform); } +gerbolyze::RenderContext::RenderContext(RenderContext &parent, PolygonSink &sink, ClipperLib::Paths &clip) : + m_sink(sink), + m_settings(parent.settings()), + m_mat(parent.mat()), + m_root(false), + m_included(false), + m_sel(parent.sel()), + m_clip(clip) +{ +} + diff --git a/svg-flatten/src/svg_pattern.cpp b/svg-flatten/src/svg_pattern.cpp index fc74d73..e8fb851 100644 --- a/svg-flatten/src/svg_pattern.cpp +++ b/svg-flatten/src/svg_pattern.cpp @@ -25,7 +25,7 @@ using namespace std; -gerbolyze::Pattern::Pattern(const pugi::xml_node &node, SVGDocument &doc) : _node(node), doc(&doc) { +gerbolyze::Pattern::Pattern(const pugi::xml_node &node, SVGDocument &doc) : m_node(node), doc(&doc) { /* Read pattern attributes from SVG node */ x = usvg_double_attr(node, "x"); y = usvg_double_attr(node, "y"); @@ -87,6 +87,17 @@ void gerbolyze::Pattern::tile (gerbolyze::RenderContext &ctx) { /* Switch to pattern coordinates */ RenderContext pat_ctx(ctx, patternTransform); + if (ctx.settings().use_apertures_for_patterns) { + vector> out; + LambdaPolygonSink list_sink([&out](const Polygon &poly, GerberPolarityToken pol) { + out.emplace_back(pair{poly, pol}); + }); + ClipperLib::Paths empty_clip; + RenderContext macro_ctx(pat_ctx, list_sink, empty_clip); + doc->export_svg_group(macro_ctx, m_node); + pat_ctx.sink() << PatternToken(out); + } + /* Iterate over all pattern tiles in pattern coordinates */ for (double inst_off_x = fmod(inst_x, inst_w) - 2*inst_w; inst_off_x < bx + bw + 2*inst_w; @@ -131,7 +142,12 @@ void gerbolyze::Pattern::tile (gerbolyze::RenderContext &ctx) { } } - doc->export_svg_group(elem_ctx, _node); + if (ctx.settings().use_apertures_for_patterns) { + /* use inst_h offset to compensate for gerber <-> svg "y" coordinate spaces */ + elem_ctx.sink() << FlashToken(elem_ctx.mat().doc2phys({0, inst_h})); + } else { + doc->export_svg_group(elem_ctx, m_node); + } } } } diff --git a/svg-flatten/src/svg_pattern.h b/svg-flatten/src/svg_pattern.h index 73efe5a..368087a 100644 --- a/svg-flatten/src/svg_pattern.h +++ b/svg-flatten/src/svg_pattern.h @@ -47,7 +47,7 @@ private: xform2d patternTransform_inv; enum RelativeUnits patternUnits; enum RelativeUnits patternContentUnits; - const pugi::xml_node _node; + const pugi::xml_node m_node; SVGDocument *doc = nullptr; }; -- cgit