aboutsummaryrefslogtreecommitdiff
path: root/svg-flatten
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2022-06-20 16:19:53 +0200
committerjaseg <git@jaseg.de>2022-06-20 16:19:53 +0200
commit9e9cc2bc019f0e67720ad5da16315e7cd6781e78 (patch)
treedd0531eef230fa8042143019db669e2841170f8a /svg-flatten
parent0e1c8507bbda04f131ae0733e38b5f18996531b1 (diff)
downloadgerbolyze-9e9cc2bc019f0e67720ad5da16315e7cd6781e78.tar.gz
gerbolyze-9e9cc2bc019f0e67720ad5da16315e7cd6781e78.tar.bz2
gerbolyze-9e9cc2bc019f0e67720ad5da16315e7cd6781e78.zip
svg-flatten: add export of patterns via aperture macros
Diffstat (limited to 'svg-flatten')
-rw-r--r--svg-flatten/include/gerbolyze.hpp28
-rw-r--r--svg-flatten/src/main.cpp17
-rw-r--r--svg-flatten/src/out_gerber.cpp38
-rw-r--r--svg-flatten/src/out_scaler.cpp23
-rw-r--r--svg-flatten/src/out_sexp.cpp2
-rw-r--r--svg-flatten/src/out_svg.cpp2
-rw-r--r--svg-flatten/src/svg_doc.cpp11
-rw-r--r--svg-flatten/src/svg_pattern.cpp20
-rw-r--r--svg-flatten/src/svg_pattern.h2
9 files changed, 136 insertions, 7 deletions
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<pair<Polygon, GerberPolarityToken>> &polys) : m_polys(polys) {}
+ vector<pair<Polygon, GerberPolarityToken>> &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<double>(0.1); /* mm */
double curve_tolerance = args["curve_tolerance"].as<double>(0.1); /* mm */
- double drill_test_polsby_popper_tolerance = args["drill_test_polsby_popper_tolerance"].as<double>(0.1); /* mm */
+ double drill_test_polsby_popper_tolerance = args["drill_test_polsby_popper_tolerance"].as<double>(0.1);
+ double aperture_rect_test_tolerance = args["aperture_rect_test_tolerance"].as<double>(0.1);
+ double aperture_circle_test_tolerance = args["aperture_circle_test_tolerance"].as<double>(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<string>() : "");
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<pair<Polygon, GerberPolarityToken>> new_polys;
+ for (size_t i=0; i<tok.m_polys.size(); i++) {
+ Polygon poly(tok.m_polys[i].first.size());
+ for (size_t j=0; j<poly.size(); j++) {
+ d2p new_point = tok.m_polys[i].first[j];
+ new_point[0] *= m_scale;
+ new_point[1] *= m_scale;
+ poly[j] = new_point;
+ }
+ new_polys.emplace_back(pair<Polygon, GerberPolarityToken>{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<pair<Polygon, GerberPolarityToken>> out;
+ LambdaPolygonSink list_sink([&out](const Polygon &poly, GerberPolarityToken pol) {
+ out.emplace_back(pair<Polygon, GerberPolarityToken>{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;
};