From e76d257220cb98cf8286b077cad248de62a6abc8 Mon Sep 17 00:00:00 2001
From: jaseg <git@jaseg.de>
Date: Tue, 21 Jun 2022 16:23:09 +0200
Subject: [PATCH] svg-flatten: fix failing tests

---
 svg-flatten/include/gerbolyze.hpp |  3 +++
 svg-flatten/src/out_scaler.cpp    |  4 ++++
 svg-flatten/src/svg_doc.cpp       | 16 +++++++++++-----
 svg-flatten/src/svg_path.cpp      |  6 +++++-
 4 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/svg-flatten/include/gerbolyze.hpp b/svg-flatten/include/gerbolyze.hpp
index a24236b..06cbebc 100644
--- a/svg-flatten/include/gerbolyze.hpp
+++ b/svg-flatten/include/gerbolyze.hpp
@@ -68,6 +68,7 @@ namespace gerbolyze {
         public:
             virtual ~PolygonSink() {}
             virtual void header(d2p origin, d2p size) {(void) origin; (void) size;}
+            virtual bool can_do_apertures() { return false; }
             virtual PolygonSink &operator<<(const Polygon &poly) = 0;
             virtual PolygonSink &operator<<(const ClipperLib::Paths paths) {
                 for (const auto &poly : paths) {
@@ -137,6 +138,7 @@ namespace gerbolyze {
         public:
             PolygonScaler(PolygonSink &sink, double scale=1.0) : m_sink(sink), m_scale(scale) {}
             virtual void header(d2p origin, d2p size);
+            virtual bool can_do_apertures();
             virtual PolygonScaler &operator<<(const Polygon &poly);
             virtual PolygonScaler &operator<<(const LayerNameToken &layer_name);
             virtual PolygonScaler &operator<<(GerberPolarityToken pol);
@@ -326,6 +328,7 @@ namespace gerbolyze {
         virtual SimpleGerberOutput &operator<<(const ApertureToken &ap);
         virtual SimpleGerberOutput &operator<<(const FlashToken &tok);
         virtual SimpleGerberOutput &operator<<(const PatternToken &tok);
+        virtual bool can_do_apertures() { return true; }
         virtual void header_impl(d2p origin, d2p size);
         virtual void footer_impl();
 
diff --git a/svg-flatten/src/out_scaler.cpp b/svg-flatten/src/out_scaler.cpp
index ab65ab0..fe0bfd7 100644
--- a/svg-flatten/src/out_scaler.cpp
+++ b/svg-flatten/src/out_scaler.cpp
@@ -38,6 +38,10 @@ void PolygonScaler::footer() {
     m_sink.footer();
 }
 
+bool PolygonScaler::can_do_apertures() {
+    return m_sink.can_do_apertures();
+}
+
 PolygonScaler &PolygonScaler::operator<<(const LayerNameToken &layer_name) {
     m_sink << layer_name;
 
diff --git a/svg-flatten/src/svg_doc.cpp b/svg-flatten/src/svg_doc.cpp
index 1999876..3d02741 100644
--- a/svg-flatten/src/svg_doc.cpp
+++ b/svg-flatten/src/svg_doc.cpp
@@ -365,14 +365,19 @@ void gerbolyze::SVGDocument::export_svg_path(RenderContext &ctx, const pugi::xml
         
         /* Calculate out dashes: A closed path becomes a number of open paths when it is dashed. */
         if (!dasharray.empty()) {
-            for (auto &poly : stroke_closed) {
-                if (poly.empty()) {
-                    continue;
-                }
+            auto open_copy(stroke_open);
+            stroke_open.clear();
 
+            for (auto &poly : stroke_closed) {
                 poly.push_back(poly[0]);
                 dash_path(poly, stroke_open, dasharray, stroke_dashoffset);
             }
+
+            stroke_closed.clear();
+
+            for (auto &poly : open_copy) {
+                dash_path(poly, stroke_open, dasharray, stroke_dashoffset);
+            }
         }
 
         if (stroke_color != GRB_PATTERN_FILL) {
@@ -420,7 +425,7 @@ void gerbolyze::SVGDocument::export_svg_path(RenderContext &ctx, const pugi::xml
             // cerr << "  ends_can_be_mapped = " << ends_can_be_mapped << endl;
             // cerr << "  joins_can_be_mapped = " << joins_can_be_mapped << endl;
             /* Accept loss of precision in outline mode. */
-            if (ctx.settings().outline_mode || gerber_lossless ) {
+            if (ctx.sink().can_do_apertures() && (ctx.settings().outline_mode || gerber_lossless )) {
                 // cerr << "  -> converting directly" << endl;
                 ctx.sink() << ApertureToken(stroke_width);
                 for (auto &path : stroke_closed) {
@@ -442,6 +447,7 @@ void gerbolyze::SVGDocument::export_svg_path(RenderContext &ctx, const pugi::xml
         offx.ArcTolerance = 0.01 * clipper_scale; /* 10µm; TODO: Make this configurable */
         offx.MiterLimit = stroke_miterlimit;
 
+        //cerr << "offsetting " << stroke_closed.size() << " closed and " << stroke_open.size() << " open paths" << endl;
         /* For stroking we have to separately handle open and closed paths since coincident start and end points may
          * render differently than joined start and end points. */
         offx.AddPaths(stroke_closed, join_type, etClosedLine);
diff --git a/svg-flatten/src/svg_path.cpp b/svg-flatten/src/svg_path.cpp
index f122626..71c7bd2 100644
--- a/svg-flatten/src/svg_path.cpp
+++ b/svg-flatten/src/svg_path.cpp
@@ -185,7 +185,6 @@ void gerbolyze::parse_dasharray(const pugi::xml_node &node, vector<double> &out)
 /* Take a Clipper path in clipper-scaled document units, and apply the given SVG dash array to it. Do this by walking
  * the path from start to end while emitting dashes. */
 void gerbolyze::dash_path(const ClipperLib::Path &in, ClipperLib::Paths &out, const vector<double> dasharray, double dash_offset) {
-    out.clear();
     if (dasharray.empty() || in.size() < 2) {
         out.push_back(in);
         return;
@@ -225,6 +224,7 @@ void gerbolyze::dash_path(const ClipperLib::Path &in, ClipperLib::Paths &out, co
             /* end this dash */
             current_dash.push_back(intermediate);
             if (dash_idx%2 == 0) { /* dash */
+                //cerr << "dash of size " << current_dash.size() << " from " << (current_dash[0].X/clipper_scale) << ", " << (current_dash[0].Y/clipper_scale) << " to " << (current_dash.back().X/clipper_scale) << ", " << (current_dash.back().Y/clipper_scale) << endl;
                 out.push_back(current_dash);
             } /* else space */
             dash_idx = (dash_idx + 1) % num_dashes;
@@ -246,6 +246,7 @@ void gerbolyze::dash_path(const ClipperLib::Path &in, ClipperLib::Paths &out, co
                 /* end this dash */
                 current_dash.push_back(intermediate);
                 if (dash_idx%2 == 0) { /* dash */
+                    //cerr << "dash of size " << current_dash.size() << " from " << (current_dash[0].X/clipper_scale) << ", " << (current_dash[0].Y/clipper_scale) << " to " << (current_dash.back().X/clipper_scale) << ", " << (current_dash.back().Y/clipper_scale) << endl;
                     out.push_back(current_dash);
                 } /* else space */
                 dash_idx = (dash_idx + 1) % num_dashes;
@@ -262,7 +263,10 @@ void gerbolyze::dash_path(const ClipperLib::Path &in, ClipperLib::Paths &out, co
 
     /* Finish last dash */
     if (current_dash.size() > 0 && (dash_idx%2 == 0)) {
+        //cerr << "dash of size " << current_dash.size() << " from " << (current_dash[0].X/clipper_scale) << ", " << (current_dash[0].Y/clipper_scale) << " to " << (current_dash.back().X/clipper_scale) << ", " << (current_dash.back().Y/clipper_scale) << endl;
+
         out.push_back(current_dash);
     }
+    //cerr << "out now has " << out.size() << " elements" << endl;
 }