aboutsummaryrefslogtreecommitdiff
path: root/svg-flatten
diff options
context:
space:
mode:
authorjaseg <git-bigdata-wsl-arch@jaseg.de>2022-06-18 17:29:27 +0200
committerjaseg <git-bigdata-wsl-arch@jaseg.de>2022-06-18 17:29:27 +0200
commit14e9d7fbc2a935ec9c2e6eb9d68e8d250f9614d4 (patch)
tree9f86768b8ffc04a39db9b614aa4cc11956dda29b /svg-flatten
parent1622e9c9435d263c3c275718947b1030ad9b6b48 (diff)
downloadgerbolyze-14e9d7fbc2a935ec9c2e6eb9d68e8d250f9614d4.tar.gz
gerbolyze-14e9d7fbc2a935ec9c2e6eb9d68e8d250f9614d4.tar.bz2
gerbolyze-14e9d7fbc2a935ec9c2e6eb9d68e8d250f9614d4.zip
svg-flatten: add drill handling to outline mode
Diffstat (limited to 'svg-flatten')
-rw-r--r--svg-flatten/include/gerbolyze.hpp16
-rw-r--r--svg-flatten/src/main.cpp5
-rw-r--r--svg-flatten/src/nopencv.cpp27
-rw-r--r--svg-flatten/src/nopencv.hpp2
-rw-r--r--svg-flatten/src/out_dilater.cpp4
-rw-r--r--svg-flatten/src/out_flattener.cpp10
-rw-r--r--svg-flatten/src/out_gerber.cpp12
-rw-r--r--svg-flatten/src/out_scaler.cpp10
-rw-r--r--svg-flatten/src/out_sexp.cpp4
-rw-r--r--svg-flatten/src/out_svg.cpp4
-rw-r--r--svg-flatten/src/svg_doc.cpp31
11 files changed, 122 insertions, 3 deletions
diff --git a/svg-flatten/include/gerbolyze.hpp b/svg-flatten/include/gerbolyze.hpp
index 9311a98..cd837ba 100644
--- a/svg-flatten/include/gerbolyze.hpp
+++ b/svg-flatten/include/gerbolyze.hpp
@@ -50,6 +50,12 @@ namespace gerbolyze {
double m_size = 0.0;
};
+ class DrillToken {
+ public:
+ DrillToken(d2p center) : m_center(center) {}
+ d2p m_center;
+ };
+
class PolygonSink {
public:
virtual ~PolygonSink() {}
@@ -73,6 +79,7 @@ namespace gerbolyze {
virtual PolygonSink &operator<<(const LayerNameToken &) { return *this; };
virtual PolygonSink &operator<<(GerberPolarityToken pol) = 0;
virtual PolygonSink &operator<<(const ApertureToken &) { return *this; };
+ virtual PolygonSink &operator<<(const DrillToken &) { return *this; };
virtual void footer() {}
};
@@ -85,6 +92,8 @@ namespace gerbolyze {
virtual Flattener &operator<<(const Polygon &poly);
virtual Flattener &operator<<(const LayerNameToken &layer_name);
virtual Flattener &operator<<(GerberPolarityToken pol);
+ virtual Flattener &operator<<(const ApertureToken &tok);
+ virtual Flattener &operator<<(const DrillToken &tok);
virtual void footer();
private:
@@ -102,6 +111,7 @@ namespace gerbolyze {
virtual Dilater &operator<<(const Polygon &poly);
virtual Dilater &operator<<(const LayerNameToken &layer_name);
virtual Dilater &operator<<(GerberPolarityToken pol);
+ virtual Dilater &operator<<(const ApertureToken &ap);
virtual void footer();
private:
@@ -117,6 +127,8 @@ namespace gerbolyze {
virtual PolygonScaler &operator<<(const Polygon &poly);
virtual PolygonScaler &operator<<(const LayerNameToken &layer_name);
virtual PolygonScaler &operator<<(GerberPolarityToken pol);
+ virtual PolygonScaler &operator<<(const ApertureToken &tok);
+ virtual PolygonScaler &operator<<(const DrillToken &tok);
virtual void footer();
private:
@@ -181,6 +193,7 @@ namespace gerbolyze {
public:
double m_minimum_feature_size_mm = 0.1;
double curve_tolerance_mm;
+ double drill_test_polsby_popper_tolerance = 0.01;
VectorizerSelectorizer &m_vec_sel;
bool outline_mode = false;
bool flip_color_interpretation = false;
@@ -289,6 +302,7 @@ namespace gerbolyze {
virtual ~SimpleGerberOutput() {}
virtual SimpleGerberOutput &operator<<(const Polygon &poly);
virtual SimpleGerberOutput &operator<<(GerberPolarityToken pol);
+ virtual SimpleGerberOutput &operator<<(const DrillToken &tok);
virtual SimpleGerberOutput &operator<<(const ApertureToken &ap);
virtual void header_impl(d2p origin, d2p size);
virtual void footer_impl();
@@ -313,6 +327,7 @@ namespace gerbolyze {
virtual ~SimpleSVGOutput() {}
virtual SimpleSVGOutput &operator<<(const Polygon &poly);
virtual SimpleSVGOutput &operator<<(GerberPolarityToken pol);
+ virtual SimpleSVGOutput &operator<<(const DrillToken &tok);
virtual void header_impl(d2p origin, d2p size);
virtual void footer_impl();
@@ -330,6 +345,7 @@ namespace gerbolyze {
virtual ~KicadSexpOutput() {}
virtual KicadSexpOutput &operator<<(const Polygon &poly);
virtual KicadSexpOutput &operator<<(const LayerNameToken &layer_name);
+ virtual KicadSexpOutput &operator<<(const DrillToken &tok);
virtual KicadSexpOutput &operator<<(GerberPolarityToken pol);
virtual void header_impl(d2p origin, d2p size);
virtual void footer_impl();
diff --git a/svg-flatten/src/main.cpp b/svg-flatten/src/main.cpp
index 817ba67..188aa57 100644
--- a/svg-flatten/src/main.cpp
+++ b/svg-flatten/src/main.cpp
@@ -79,6 +79,9 @@ int main(int argc, char **argv) {
{"curve_tolerance", {"-c", "--curve-tolerance"},
"Tolerance for curve flattening in mm. Default: 0.1mm.",
1},
+ {"drill_test_polsby_popper_tolerance", {"--drill-test-tolerance"},
+ "Tolerance for identifying circles as drills in outline mode",
+ 1},
{"no_header", {"--no-header"},
"Do not export output format header/footer, only export the primitives themselves",
0},
@@ -291,6 +294,7 @@ 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 */
string ending = "";
auto idx = in_f_name.rfind(".");
@@ -423,6 +427,7 @@ int main(int argc, char **argv) {
RenderSettings rset {
min_feature_size,
curve_tolerance,
+ drill_test_polsby_popper_tolerance,
vec_sel,
outline_mode,
flip_svg_colors,
diff --git a/svg-flatten/src/nopencv.cpp b/svg-flatten/src/nopencv.cpp
index 121e9e1..e157ab5 100644
--- a/svg-flatten/src/nopencv.cpp
+++ b/svg-flatten/src/nopencv.cpp
@@ -483,6 +483,33 @@ double gerbolyze::nopencv::polygon_area(Polygon_i &poly) {
return acc / 2;
}
+double gerbolyze::nopencv::polygon_perimeter(Polygon_i &poly) {
+ double acc = 0;
+ size_t prev = poly.size() - 1;
+ for (size_t cur=0; cur<poly.size(); cur++) {
+ double dx = poly[cur][0] - poly[prev][0];
+ double dy = poly[cur][1] - poly[prev][1];
+ acc += sqrt(dx*dx + dy*dy);
+ prev = cur;
+ }
+ return acc;
+}
+
+d2p gerbolyze::nopencv::polygon_centroid(Polygon_i &poly) {
+ double acc_x = 0, acc_y = 0;
+
+ double area = polygon_area(poly);
+ size_t prev = poly.size() - 1;
+ for (size_t cur=0; cur<poly.size(); cur++) {
+ double a = poly[prev][1]*poly[cur][0] - poly[cur][1]*poly[prev][0];
+ acc_x += (poly[prev][0] + poly[cur][0]) * a;
+ acc_y += (poly[prev][1] + poly[cur][1]) * a;
+ prev = cur;
+ }
+
+ return { acc_x / (6*area), acc_y / (6*area) };
+}
+
template<typename T>
gerbolyze::nopencv::Image<T>::Image(int size_x, int size_y, const T *data) {
assert(size_x > 0 && size_x < 100000);
diff --git a/svg-flatten/src/nopencv.hpp b/svg-flatten/src/nopencv.hpp
index 5dd399d..bbc190b 100644
--- a/svg-flatten/src/nopencv.hpp
+++ b/svg-flatten/src/nopencv.hpp
@@ -119,6 +119,8 @@ namespace gerbolyze {
ContourCallback simplify_contours_douglas_peucker(ContourCallback cb);
double polygon_area(Polygon_i &poly);
+ double polygon_perimeter(Polygon_i &poly);
+ d2p polygon_centroid(Polygon_i &poly);
}
}
diff --git a/svg-flatten/src/out_dilater.cpp b/svg-flatten/src/out_dilater.cpp
index e9aefa8..a5b0619 100644
--- a/svg-flatten/src/out_dilater.cpp
+++ b/svg-flatten/src/out_dilater.cpp
@@ -84,3 +84,7 @@ Dilater &Dilater::operator<<(const Polygon &poly) {
return *this;
}
+Dilater &Dilater::operator<<(const ApertureToken &ap) {
+ m_sink << ApertureToken(ap.m_size + 2*m_dilation);
+ return *this;
+}
diff --git a/svg-flatten/src/out_flattener.cpp b/svg-flatten/src/out_flattener.cpp
index 8868ca2..0eae854 100644
--- a/svg-flatten/src/out_flattener.cpp
+++ b/svg-flatten/src/out_flattener.cpp
@@ -152,6 +152,16 @@ Flattener &Flattener::operator<<(const LayerNameToken &layer_name) {
return *this;
}
+Flattener &Flattener::operator<<(const DrillToken &tok) {
+ m_sink << tok;
+ return *this;
+}
+
+Flattener &Flattener::operator<<(const ApertureToken &tok) {
+ m_sink << tok;
+ return *this;
+}
+
Flattener &Flattener::operator<<(const Polygon &poly) {
if (m_current_polarity == GRB_POL_DARK) {
d->add_dark_polygon(poly);
diff --git a/svg-flatten/src/out_gerber.cpp b/svg-flatten/src/out_gerber.cpp
index b1c5875..c43d07d 100644
--- a/svg-flatten/src/out_gerber.cpp
+++ b/svg-flatten/src/out_gerber.cpp
@@ -65,6 +65,7 @@ SimpleGerberOutput& SimpleGerberOutput::operator<<(const ApertureToken &ap) {
if (ap.m_size == m_current_aperture) {
return *this;
}
+
m_current_aperture = ap.m_size;
m_aperture_num += 1;
@@ -123,6 +124,17 @@ SimpleGerberOutput& SimpleGerberOutput::operator<<(const Polygon &poly) {
return *this;
}
+SimpleGerberOutput &SimpleGerberOutput::operator<<(const DrillToken &tok) {
+ double x = round((tok.m_center[0] * m_scale + m_offset[0]) * m_gerber_scale);
+ double y = round((m_height - tok.m_center[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;
+}
+
void SimpleGerberOutput::footer_impl() {
m_out << "M02*" << endl;
}
diff --git a/svg-flatten/src/out_scaler.cpp b/svg-flatten/src/out_scaler.cpp
index 9b7de4e..0320d69 100644
--- a/svg-flatten/src/out_scaler.cpp
+++ b/svg-flatten/src/out_scaler.cpp
@@ -29,6 +29,7 @@
using namespace gerbolyze;
using namespace std;
+/* FIXME thoroughly test ApertureToken scale handling */
void PolygonScaler::header(d2p origin, d2p size) {
m_sink.header({origin[0] * m_scale, origin[1] * m_scale}, {size[0] * m_scale, size[1] * m_scale});
}
@@ -45,7 +46,11 @@ PolygonScaler &PolygonScaler::operator<<(const LayerNameToken &layer_name) {
PolygonScaler &PolygonScaler::operator<<(GerberPolarityToken pol) {
m_sink << pol;
+ return *this;
+}
+PolygonScaler &PolygonScaler::operator<<(const ApertureToken &tok) {
+ m_sink << ApertureToken(tok.m_size * m_scale);
return *this;
}
@@ -59,3 +64,8 @@ PolygonScaler &PolygonScaler::operator<<(const Polygon &poly) {
return *this;
}
+PolygonScaler &PolygonScaler::operator<<(const DrillToken &tok) {
+ d2p new_center { tok.m_center[0] * m_scale, tok.m_center[1] * m_scale };
+ m_sink << DrillToken(new_center);
+ return *this;
+}
diff --git a/svg-flatten/src/out_sexp.cpp b/svg-flatten/src/out_sexp.cpp
index 1a7f1d0..6760920 100644
--- a/svg-flatten/src/out_sexp.cpp
+++ b/svg-flatten/src/out_sexp.cpp
@@ -135,6 +135,10 @@ KicadSexpOutput &KicadSexpOutput::operator<<(const Polygon &poly) {
return *this;
}
+KicadSexpOutput &KicadSexpOutput::operator<<(const DrillToken &tok) {
+ return *this;
+}
+
void KicadSexpOutput::footer_impl() {
m_out << ")" << endl;
}
diff --git a/svg-flatten/src/out_svg.cpp b/svg-flatten/src/out_svg.cpp
index d94edc0..4ecd979 100644
--- a/svg-flatten/src/out_svg.cpp
+++ b/svg-flatten/src/out_svg.cpp
@@ -77,6 +77,10 @@ SimpleSVGOutput &SimpleSVGOutput::operator<<(const Polygon &poly) {
return *this;
}
+SimpleSVGOutput &SimpleSVGOutput::operator<<(const DrillToken &tok) {
+ return *this;
+}
+
void SimpleSVGOutput::footer_impl() {
//cerr << "svg: footer" << endl;
m_out << "</svg>" << endl;
diff --git a/svg-flatten/src/svg_doc.cpp b/svg-flatten/src/svg_doc.cpp
index fb8d311..7ff0a11 100644
--- a/svg-flatten/src/svg_doc.cpp
+++ b/svg-flatten/src/svg_doc.cpp
@@ -18,6 +18,7 @@
#include <iostream>
#include <fstream>
+#include <cmath>
#include <gerbolyze.hpp>
#include "svg_import_defs.h"
@@ -25,6 +26,7 @@
#include "svg_geom.h"
#include "svg_path.h"
#include "vec_core.h"
+#include "nopencv.hpp"
using namespace gerbolyze;
using namespace std;
@@ -243,7 +245,6 @@ void gerbolyze::SVGDocument::export_svg_path(RenderContext &ctx, const pugi::xml
}
/* Load path from SVG path data and transform into document units. */
- /* FIXME transform stroke width here? */
stroke_width = ctx.mat().doc2phys_dist(stroke_width);
Paths stroke_open, stroke_closed;
@@ -260,6 +261,31 @@ void gerbolyze::SVGDocument::export_svg_path(RenderContext &ctx, const pugi::xml
/* Skip filling for transparent fills. In outline mode, skip filling if a stroke is also set to avoid double lines.
*/
if (has_fill && !(ctx.settings().outline_mode && has_stroke)) {
+ /* In outline mode, identify drills before applying clip */
+ if (ctx.settings().outline_mode && fill_color != GRB_PATTERN_FILL) {
+ /* Polsby-Popper test */
+ for (auto &p : fill_paths) {
+ Polygon_i geom_poly(p.size());
+ for (size_t i=0; i<p.size(); i++) {
+ geom_poly[i] = { p[i].X, p[i].Y };
+ }
+
+ double area = nopencv::polygon_area(geom_poly);
+ double polsby_popper = 4*M_PI * area / pow(nopencv::polygon_perimeter(geom_poly), 2);
+ polsby_popper = fabs(fabs(polsby_popper) - 1.0);
+ if (polsby_popper < ctx.settings().drill_test_polsby_popper_tolerance) {
+ d2p centroid = nopencv::polygon_centroid(geom_poly);
+ centroid[0] /= clipper_scale;
+ centroid[1] /= clipper_scale;
+ double diameter = sqrt(4*fabs(area)/M_PI) / clipper_scale;
+ diameter = ctx.mat().doc2phys_dist(diameter); /* FIXME is this correct w.r.t. PolygonScaler? */
+ diameter = round(diameter * 1000.0) / 1000.0; /* Round to micrometer precsion; FIXME: make configurable */
+ ctx.sink() << ApertureToken(diameter) << DrillToken(ctx.mat().doc2phys(centroid));
+ }
+ }
+ return;
+ }
+
/* Clip paths. Consider all paths closed for filling. */
if (!ctx.clip().empty()) {
Clipper c;
@@ -306,7 +332,7 @@ void gerbolyze::SVGDocument::export_svg_path(RenderContext &ctx, const pugi::xml
if (ctx.settings().outline_mode && !out.empty())
out.push_back(out[0]);
- ctx.sink() << (fill_color == GRB_DARK ? GRB_POL_DARK : GRB_POL_CLEAR) << out;
+ ctx.sink() << ApertureToken() << (fill_color == GRB_DARK ? GRB_POL_DARK : GRB_POL_CLEAR) << out;
}
}
}
@@ -396,7 +422,6 @@ void gerbolyze::SVGDocument::export_svg_path(RenderContext &ctx, const pugi::xml
ctx.sink() << ApertureToken() << (stroke_color == GRB_DARK ? GRB_POL_DARK : GRB_POL_CLEAR) << s_polys;
}
}
- ctx.sink() << ApertureToken();
}
void gerbolyze::SVGDocument::render(const RenderSettings &rset, PolygonSink &sink, const ElementSelector &sel) {