svg-flatten: add export of patterns via aperture macros
This commit is contained in:
parent
0e1c8507bb
commit
9e9cc2bc01
9 changed files with 136 additions and 7 deletions
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue