aboutsummaryrefslogtreecommitdiff
path: root/svg-flatten/include
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2021-04-25 00:09:57 +0200
committerjaseg <git@jaseg.de>2021-04-25 00:20:51 +0200
commit1180ebdc1f18044a74f22f17b4d500ce7d6543fa (patch)
treed2de84bc7b73feaae3d2a3b191e97531a1a9dd32 /svg-flatten/include
parent776e0bd2069af0cfff7ce794cf3b345b613e1c02 (diff)
downloadgerbolyze-1180ebdc1f18044a74f22f17b4d500ce7d6543fa.tar.gz
gerbolyze-1180ebdc1f18044a74f22f17b4d500ce7d6543fa.tar.bz2
gerbolyze-1180ebdc1f18044a74f22f17b4d500ce7d6543fa.zip
Remove cairo dependencywip-nocairo
We initially used Cairo for its bezier flattening algorithm. That algorithm turned out to be a bit too imprecise at the scales we're working at here (#17), so I ended up porting over some code from Antigrain Graphics. The only other thing we used Cairo for was debug output and coordinate transforms, so I just wrote the relevant vector math in a small header file, deleted all debug output code and thus eliminated the cairo dependency. This is a step towards Windows builds.
Diffstat (limited to 'svg-flatten/include')
-rw-r--r--svg-flatten/include/flatten.hpp6
-rw-r--r--svg-flatten/include/geom2d.hpp157
-rw-r--r--svg-flatten/include/gerbolyze.hpp22
3 files changed, 168 insertions, 17 deletions
diff --git a/svg-flatten/include/flatten.hpp b/svg-flatten/include/flatten.hpp
index b620890..92cbf38 100644
--- a/svg-flatten/include/flatten.hpp
+++ b/svg-flatten/include/flatten.hpp
@@ -5,9 +5,9 @@ namespace gerbolyze {
class curve4_div {
public:
curve4_div(double distance_tolerance=0.1, double angle_tolerance=0.0, double cusp_limit=0.0)
- : m_distance_tolerance_square(0.25*distance_tolerance*distance_tolerance),
- m_angle_tolerance(angle_tolerance),
- m_cusp_limit(cusp_limit)
+ : m_cusp_limit(cusp_limit),
+ m_distance_tolerance_square(0.25*distance_tolerance*distance_tolerance),
+ m_angle_tolerance(angle_tolerance)
{
}
diff --git a/svg-flatten/include/geom2d.hpp b/svg-flatten/include/geom2d.hpp
new file mode 100644
index 0000000..ac56628
--- /dev/null
+++ b/svg-flatten/include/geom2d.hpp
@@ -0,0 +1,157 @@
+/*
+ * This file is part of gerbolyze, a vector image preprocessing toolchain
+ * Copyright (C) 2021 Jan Sebastian Götte <gerbolyze@jaseg.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <array>
+#include <string>
+#include <sstream>
+#include <cmath>
+#include <algorithm>
+
+#include <clipper.hpp>
+
+#include "svg_import_defs.h"
+
+using namespace std;
+
+namespace gerbolyze {
+
+ typedef std::array<double, 2> d2p;
+ typedef std::vector<d2p> Polygon;
+
+ class xform2d {
+ public:
+ xform2d(double xx, double yx, double xy, double yy, double x0=0.0, double y0=0.0) :
+ xx(xx), yx(yx), xy(xy), yy(yy), x0(x0), y0(y0) {}
+
+ xform2d() : xform2d(1.0, 0.0, 0.0, 1.0) {}
+
+ xform2d(const string &svg_transform) : xform2d() {
+ if (svg_transform.empty())
+ return;
+
+ string start("matrix(");
+ if (svg_transform.substr(0, start.length()) != start)
+ return;
+ if (svg_transform.back() != ')')
+ return;
+
+ const string &foo = svg_transform.substr(start.length(), svg_transform.length());
+ const string &bar = foo.substr(0, foo.length() - 1);
+
+ istringstream xform(bar);
+
+ double a, c, e,
+ b, d, f;
+ xform >> a >> b >> c >> d >> e >> f;
+ if (xform.fail())
+ return;
+
+ xx=a, yx=b, xy=c, yy=d, x0=e, y0=f;
+ }
+
+ xform2d &translate(double x, double y) {
+ x0 += x;
+ y0 += y;
+ return *this;
+ }
+
+ xform2d &scale(double x, double y) {
+ xx *= x; yx *= y; xy *= x;
+ yy *= y; x0 *= x; y0 *= y;
+ return *this;
+ }
+
+ xform2d &transform(const xform2d &other) {
+ double n_xx = xx * other.xx + yx * other.xy;
+ double n_yx = xx * other.yx + yx * other.yy;
+
+ double n_xy = xy * other.xx + yy * other.xy;
+ double n_yy = xy * other.yx + yy * other.yy;
+
+ double n_x0 = x0 * other.xx + y0 * other.xy + other.x0;
+ double n_y0 = x0 * other.yx + y0 * other.yy + other.y0;
+
+ xx = n_xx;
+ yx = n_yx;
+ xy = n_xy;
+ yy = n_yy;
+ x0 = n_x0;
+ y0 = n_y0;
+
+ return *this;
+ };
+
+ double doc2phys_dist(double dist_doc) {
+ return xx * dist_doc;
+ }
+
+ double phys2doc_dist(double dist_doc) {
+ return xx * dist_doc;
+ }
+
+ d2p doc2phys(const d2p p) {
+ return d2p {
+ xx * p[0] + xy * p[1] + x0,
+ xy * p[1] + yy * p[1] + y0
+ };
+ }
+
+ xform2d &invert(bool *success_out=nullptr) {
+ /* From Cairo source */
+
+ /* inv (A) = 1/det (A) * adj (A) */
+ double det = xx*yy - yx*xy;
+
+ if (det == 0 || !isfinite(det)) {
+ if (success_out)
+ *success_out = false;
+ *this = xform2d(); /* unity matrix */
+ return *this;
+ }
+
+ *this = xform2d(yy/det, -yx/det,
+ -xy/det, xx/det,
+ (xy*y0 - yy*x0)/det, (yx*x0 - xx*y0)/det);
+
+ if (success_out)
+ *success_out = true;
+ return *this;
+ }
+
+ /* Transform given clipper paths */
+ void transform_paths(ClipperLib::Paths &paths) {
+ for (auto &p : paths) {
+ std::transform(p.begin(), p.end(), p.begin(),
+ [this](ClipperLib::IntPoint p) -> ClipperLib::IntPoint {
+ d2p out(this->doc2phys(d2p{p.X / clipper_scale, p.Y / clipper_scale}));
+ return {
+ (ClipperLib::cInt)round(out[0] * clipper_scale),
+ (ClipperLib::cInt)round(out[1] * clipper_scale)
+ };
+ });
+ }
+ }
+
+ private:
+ double xx, yx,
+ xy, yy,
+ x0, y0;
+ };
+}
diff --git a/svg-flatten/include/gerbolyze.hpp b/svg-flatten/include/gerbolyze.hpp
index ed93bbc..d1d5f85 100644
--- a/svg-flatten/include/gerbolyze.hpp
+++ b/svg-flatten/include/gerbolyze.hpp
@@ -22,16 +22,17 @@
#include <iostream>
#include <string>
#include <array>
+
#include <pugixml.hpp>
+
#include "svg_pattern.h"
+#include "geom2d.hpp"
namespace gerbolyze {
constexpr char lib_version[] = "2.0";
- typedef std::array<double, 2> d2p;
typedef std::function<std::vector<d2p> *(double, double, double)> sampling_fun;
- typedef std::vector<d2p> Polygon;
enum GerberPolarityToken {
GRB_POL_CLEAR,
@@ -121,7 +122,7 @@ namespace gerbolyze {
class ImageVectorizer {
public:
virtual ~ImageVectorizer() {};
- virtual void vectorize_image(cairo_t *cr, const pugi::xml_node &node, ClipperLib::Paths &clip_path, cairo_matrix_t &viewport_matrix, PolygonSink &sink, double min_feature_size_px) = 0;
+ virtual void vectorize_image(xform2d &mat, const pugi::xml_node &node, ClipperLib::Paths &clip_path, PolygonSink &sink, double min_feature_size_px) = 0;
};
ImageVectorizer *makeVectorizer(const std::string &name);
@@ -147,11 +148,10 @@ namespace gerbolyze {
class SVGDocument {
public:
SVGDocument() : _valid(false) {}
- ~SVGDocument();
/* true -> load successful */
- bool load(std::istream &in, std::string debug_out_filename="/tmp/kicad_svg_debug.svg");
- bool load(std::string filename, std::string debug_out_filename="/tmp/kicad_svg_debug.svg");
+ bool load(std::istream &in);
+ bool load(std::string filename);
/* true -> load successful */
bool valid() const { return _valid; }
operator bool() const { return valid(); }
@@ -168,13 +168,11 @@ namespace gerbolyze {
private:
friend class Pattern;
- cairo_t *cairo() { return cr; }
const ClipperLib::Paths *lookup_clip_path(const pugi::xml_node &node);
Pattern *lookup_pattern(const std::string id);
- void export_svg_group(const RenderSettings &rset, const pugi::xml_node &group, ClipperLib::Paths &parent_clip_path, const ElementSelector *sel=nullptr, bool included=true, bool is_root=false);
- void export_svg_path(const RenderSettings &rset, const pugi::xml_node &node, ClipperLib::Paths &clip_path);
- void setup_debug_output(std::string filename="");
+ void export_svg_group(xform2d &mat, const RenderSettings &rset, const pugi::xml_node &group, ClipperLib::Paths &parent_clip_path, const ElementSelector *sel=nullptr, bool included=true, bool is_root=false);
+ void export_svg_path(xform2d &mat, const RenderSettings &rset, const pugi::xml_node &node, ClipperLib::Paths &clip_path);
void setup_viewport_clip();
void load_clips(const RenderSettings &rset);
void load_patterns();
@@ -188,12 +186,8 @@ namespace gerbolyze {
double page_w_mm, page_h_mm;
std::map<std::string, Pattern> pattern_map;
std::map<std::string, ClipperLib::Paths> clip_path_map;
- cairo_matrix_t viewport_matrix;
ClipperLib::Paths vb_paths; /* viewport clip rect */
- cairo_t *cr = nullptr;
- cairo_surface_t *surface = nullptr;
-
PolygonSink *polygon_sink = nullptr;
static constexpr double dbg_fill_alpha = 0.8;