aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2021-01-27 01:26:54 +0100
committerjaseg <git@jaseg.de>2021-01-27 01:26:54 +0100
commit9711fabab7893fcdd0a5708c79a7d48f2ad15167 (patch)
treea0af6000c47a5acc1b7ac8f6c802529b8af43f97
parent5285b6dce8f0df37282b744ce625d4976b0f2541 (diff)
downloadgerbolyze-9711fabab7893fcdd0a5708c79a7d48f2ad15167.tar.gz
gerbolyze-9711fabab7893fcdd0a5708c79a7d48f2ad15167.tar.bz2
gerbolyze-9711fabab7893fcdd0a5708c79a7d48f2ad15167.zip
WIP render settings
-rw-r--r--include/gerbolyze.hpp27
-rw-r--r--src/main.cpp11
-rw-r--r--src/svg_doc.cpp31
-rw-r--r--src/svg_pattern.cpp4
-rw-r--r--src/svg_pattern.h5
-rw-r--r--src/vec_core.cpp9
-rw-r--r--src/vec_core.h11
-rw-r--r--src/vec_grid.cpp2
-rw-r--r--src/vec_grid.h2
9 files changed, 68 insertions, 34 deletions
diff --git a/include/gerbolyze.hpp b/include/gerbolyze.hpp
index b2634f0..3078a6f 100644
--- a/include/gerbolyze.hpp
+++ b/include/gerbolyze.hpp
@@ -29,6 +29,7 @@ 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 {
@@ -79,12 +80,28 @@ namespace gerbolyze {
class ElementSelector {
public:
- bool match(const pugi::xml_node &node, bool included) const;
+ virtual bool match(const pugi::xml_node &node, bool included) const = 0;
+ };
+
+ class IDElementSelector : public ElementSelector {
+ public:
+ virtual bool match(const pugi::xml_node &node, bool included) const;
std::vector<std::string> include;
std::vector<std::string> exclude;
};
+ class ImageVectorizer {
+ public:
+ 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;
+ };
+
+ class RenderSettings {
+ public:
+ double m_minimum_feature_size_mm = 0.1;
+ ImageVectorizer *m_vec = nullptr;
+ };
+
class SVGDocument {
public:
SVGDocument() : _valid(false) {}
@@ -103,8 +120,8 @@ namespace gerbolyze {
double width() const { return page_w_mm; }
double height() const { return page_h_mm; }
- void render(PolygonSink &sink, const ElementSelector *sel=nullptr);
- void render_to_list(std::vector<std::pair<Polygon, GerberPolarityToken>> &out, const ElementSelector *sel=nullptr);
+ void render(const RenderSettings &rset, PolygonSink &sink, const ElementSelector *sel=nullptr);
+ void render_to_list(const RenderSettings &rset, std::vector<std::pair<Polygon, GerberPolarityToken>> &out, const ElementSelector *sel=nullptr);
private:
friend class Pattern;
@@ -113,8 +130,8 @@ namespace gerbolyze {
const ClipperLib::Paths *lookup_clip_path(const pugi::xml_node &node);
Pattern *lookup_pattern(const std::string id);
- void export_svg_group(const pugi::xml_node &group, ClipperLib::Paths &parent_clip_path, const ElementSelector *sel=nullptr, bool included=true);
- void export_svg_path(const pugi::xml_node &node, ClipperLib::Paths &clip_path);
+ void export_svg_group(const RenderSettings &rset, const pugi::xml_node &group, ClipperLib::Paths &parent_clip_path, const ElementSelector *sel=nullptr, bool included=true);
+ void export_svg_path(const RenderSettings &rset, const pugi::xml_node &node, ClipperLib::Paths &clip_path);
void setup_debug_output(std::string filename="");
void setup_viewport_clip();
void load_clips();
diff --git a/src/main.cpp b/src/main.cpp
index 889fe6a..ba75204 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -6,6 +6,7 @@
#include <string>
#include <argagg.hpp>
#include <gerbolyze.hpp>
+#include "vec_core.h"
using argagg::parser_results;
using argagg::parser;
@@ -158,13 +159,19 @@ int main(int argc, char **argv) {
out.pop_back();
};
- ElementSelector sel;
+ IDElementSelector sel;
if (args["only_groups"])
id_match(args["only_groups"], sel.include);
if (args["exclude_groups"])
id_match(args["exclude_groups"], sel.exclude);
- doc.render(flattener ? *flattener : *sink, &sel);
+ VoronoiVectorizer vec(POISSON_DISC, true);
+ RenderSettings rset {
+ 0.1,
+ &vec
+ };
+
+ doc.render(rset, flattener ? *flattener : *sink, &sel);
return EXIT_SUCCESS;
}
diff --git a/src/svg_doc.cpp b/src/svg_doc.cpp
index 196cf60..5b36f35 100644
--- a/src/svg_doc.cpp
+++ b/src/svg_doc.cpp
@@ -19,6 +19,7 @@
#include <iostream>
#include <fstream>
+#include <gerbolyze.hpp>
#include "svg_import_defs.h"
#include "svg_color.h"
#include "svg_geom.h"
@@ -116,7 +117,7 @@ double gerbolyze::SVGDocument::doc_units_to_mm(double px) const {
return px / (vb_w / page_w_mm);
}
-bool ElementSelector::match(const pugi::xml_node &node, bool included) const {
+bool IDElementSelector::match(const pugi::xml_node &node, bool included) const {
if (include.empty() && exclude.empty())
return true;
@@ -131,7 +132,7 @@ bool ElementSelector::match(const pugi::xml_node &node, bool included) const {
}
/* Recursively export all SVG elements in the given group. */
-void gerbolyze::SVGDocument::export_svg_group(const pugi::xml_node &group, Paths &parent_clip_path, const ElementSelector *sel, bool included) {
+void gerbolyze::SVGDocument::export_svg_group(const RenderSettings &rset, const pugi::xml_node &group, Paths &parent_clip_path, const ElementSelector *sel, bool included) {
/* Enter the group's coordinate system */
cairo_save(cr);
apply_cairo_transform_from_svg(cr, group.attribute("transform").value());
@@ -166,15 +167,17 @@ void gerbolyze::SVGDocument::export_svg_group(const pugi::xml_node &group, Paths
string name(node.name());
if (name == "g") {
- export_svg_group(node, clip_path, sel, true);
+ export_svg_group(rset, node, clip_path, sel, true);
} else if (name == "path") {
- export_svg_path(node, clip_path);
+ export_svg_path(rset, node, clip_path);
} else if (name == "image") {
- double min_feature_size_mm = 0.1; /* TODO make configurable */
- double min_feature_size_px = mm_to_doc_units(min_feature_size_mm);
- vectorize_image(cr, node, min_feature_size_px, clip_path, viewport_matrix, *polygon_sink);
+ if (!rset.m_vec)
+ continue;
+
+ double min_feature_size_px = mm_to_doc_units(rset.m_minimum_feature_size_mm);
+ rset.m_vec->vectorize_image(cr, node, clip_path, viewport_matrix, *polygon_sink, min_feature_size_px);
} else if (name == "defs") {
/* ignore */
} else {
@@ -186,7 +189,7 @@ void gerbolyze::SVGDocument::export_svg_group(const pugi::xml_node &group, Paths
}
/* Export an SVG path element to gerber. Apply patterns and clip on the fly. */
-void gerbolyze::SVGDocument::export_svg_path(const pugi::xml_node &node, Paths &clip_path) {
+void gerbolyze::SVGDocument::export_svg_path(const RenderSettings &rset, const pugi::xml_node &node, Paths &clip_path) {
enum gerber_color fill_color = gerber_fill_color(node);
enum gerber_color stroke_color = gerber_stroke_color(node);
@@ -236,7 +239,7 @@ void gerbolyze::SVGDocument::export_svg_path(const pugi::xml_node &node, Paths &
} else {
Paths clip;
PolyTreeToPaths(ptree, clip);
- pattern->tile(clip);
+ pattern->tile(rset, clip);
}
} else { /* solid fill */
@@ -325,7 +328,7 @@ void gerbolyze::SVGDocument::export_svg_path(const pugi::xml_node &node, Paths &
} else {
Paths clip;
PolyTreeToPaths(ptree, clip);
- pattern->tile(clip);
+ pattern->tile(rset, clip);
}
} else {
@@ -359,7 +362,7 @@ void gerbolyze::SVGDocument::export_svg_path(const pugi::xml_node &node, Paths &
}
}
-void gerbolyze::SVGDocument::render(PolygonSink &sink, const ElementSelector *sel) {
+void gerbolyze::SVGDocument::render(const RenderSettings &rset, PolygonSink &sink, const ElementSelector *sel) {
assert(_valid);
/* Export the actual SVG document to both SVG for debuggin and to gerber. We do this as we go, i.e. we immediately
* process each element to gerber as we encounter it instead of first rendering everything to a giant list of gerber
@@ -371,15 +374,15 @@ void gerbolyze::SVGDocument::render(PolygonSink &sink, const ElementSelector *se
c.AddPaths(vb_paths, ptSubject, /* closed */ true);
ClipperLib::IntRect bbox = c.GetBounds();
cerr << "document viewbox clip: bbox={" << bbox.left << ", " << bbox.top << "} - {" << bbox.right << ", " << bbox.bottom << "}" << endl;
- export_svg_group(root_elem, vb_paths, sel, false);
+ export_svg_group(rset, root_elem, vb_paths, sel, false);
sink.footer();
}
-void gerbolyze::SVGDocument::render_to_list(vector<pair<Polygon, GerberPolarityToken>> &out, const ElementSelector *sel) {
+void gerbolyze::SVGDocument::render_to_list(const RenderSettings &rset, vector<pair<Polygon, GerberPolarityToken>> &out, const ElementSelector *sel) {
LambdaPolygonSink sink([&out](const Polygon &poly, GerberPolarityToken pol) {
out.emplace_back(pair<Polygon, GerberPolarityToken>{poly, pol});
});
- render(sink, sel);
+ render(rset, sink, sel);
}
void gerbolyze::SVGDocument::setup_debug_output(string filename) {
diff --git a/src/svg_pattern.cpp b/src/svg_pattern.cpp
index b7eec2e..b62df28 100644
--- a/src/svg_pattern.cpp
+++ b/src/svg_pattern.cpp
@@ -47,7 +47,7 @@ gerbolyze::Pattern::Pattern(const pugi::xml_node &node, SVGDocument &doc) : _nod
/* Tile pattern into gerber. Note that this function may be called several times in case the pattern is
* referenced from multiple places, so we must not clobber any of the object's state. */
-void gerbolyze::Pattern::tile (ClipperLib::Paths &clip) {
+void gerbolyze::Pattern::tile (const gerbolyze::RenderSettings &rset, ClipperLib::Paths &clip) {
assert(doc);
cairo_t *cr = doc->cairo();
assert(cr);
@@ -104,7 +104,7 @@ void gerbolyze::Pattern::tile (ClipperLib::Paths &clip) {
}
/* Export the pattern tile's content like a group */
- doc->export_svg_group(_node, clip);
+ doc->export_svg_group(rset, _node, clip);
cairo_restore(cr);
}
}
diff --git a/src/svg_pattern.h b/src/svg_pattern.h
index 3780d79..e6a6fe2 100644
--- a/src/svg_pattern.h
+++ b/src/svg_pattern.h
@@ -20,22 +20,21 @@
#include <string>
#include <cairo.h>
-
#include <pugixml.hpp>
#include <clipper.hpp>
-
#include "svg_import_util.h"
namespace gerbolyze {
class SVGDocument;
+class RenderSettings;
class Pattern {
public:
Pattern() {}
Pattern(const pugi::xml_node &node, SVGDocument &doc);
- void tile (ClipperLib::Paths &clip);
+ void tile (const gerbolyze::RenderSettings &rset, ClipperLib::Paths &clip);
private:
double x, y, w, h;
diff --git a/src/vec_core.cpp b/src/vec_core.cpp
index d329722..85b33b0 100644
--- a/src/vec_core.cpp
+++ b/src/vec_core.cpp
@@ -78,7 +78,7 @@ static void voronoi_relax_points(const jcv_diagram* diagram, jcv_point* points)
* 4. It scales each of these voronoi cell polygons to match the input images brightness at the spot covered by this
* cell.
*/
-void gerbolyze::vectorize_image(cairo_t *cr, const pugi::xml_node &node, double min_feature_size_px, ClipperLib::Paths &clip_path, cairo_matrix_t &viewport_matrix, PolygonSink &sink) {
+void gerbolyze::VoronoiVectorizer::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) {
/* Read XML node attributes */
auto x = usvg_double_attr(node, "x", 0.0);
auto y = usvg_double_attr(node, "y", 0.0);
@@ -167,8 +167,8 @@ void gerbolyze::vectorize_image(cairo_t *cr, const pugi::xml_node &node, double
grayscale interpolation. Larger values -> better grayscale resolution,
larger cells. */
double center_distance = min_feature_size_px * 2.0 * (1.0 / (1.0-grayscale_overhead));
- vector<d2p> *grid_centers = sample_poisson_disc(width, height, min_feature_size_px * 2.0 * 2.0);
- /* TODO make these alternative grids available to callers */
+ vector<d2p> *grid_centers = get_sampler(m_grid_type)(width, height, center_distance);
+ //vector<d2p> *grid_centers = sample_poisson_disc(width, height, min_feature_size_px * 2.0 * 2.0);
//vector<d2p> *grid_centers = sample_hexgrid(width, height, center_distance);
//vector<d2p> *grid_centers = sample_squaregrid(width, height, center_distance);
@@ -197,7 +197,8 @@ void gerbolyze::vectorize_image(cairo_t *cr, const pugi::xml_node &node, double
jcv_point *pts = reinterpret_cast<jcv_point *>(grid_centers->data()); /* hackety hack */
jcv_diagram_generate(grid_centers->size(), pts, &rect, 0, &diagram);
/* Relax points, i.e. wiggle them around a little bit to equalize differences between cell sizes a little bit. */
- voronoi_relax_points(&diagram, pts);
+ if (m_relax)
+ voronoi_relax_points(&diagram, pts);
memset(&diagram, 0, sizeof(jcv_diagram));
jcv_diagram_generate(grid_centers->size(), pts, &rect, 0, &diagram);
diff --git a/src/vec_core.h b/src/vec_core.h
index 643efc9..9df8598 100644
--- a/src/vec_core.h
+++ b/src/vec_core.h
@@ -25,6 +25,15 @@
#include "vec_grid.h"
namespace gerbolyze {
- void vectorize_image(cairo_t *cr, const pugi::xml_node &node, double min_feature_size_px, ClipperLib::Paths &clip_path, cairo_matrix_t &viewport_matrix, PolygonSink &sink);
+
+ class VoronoiVectorizer : public ImageVectorizer {
+ public:
+ VoronoiVectorizer(grid_type grid, bool relax=true) : m_relax(relax), m_grid_type(grid) {}
+
+ 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);
+ private:
+ double m_relax;
+ grid_type m_grid_type;
+ };
}
diff --git a/src/vec_grid.cpp b/src/vec_grid.cpp
index 2a61153..7c27543 100644
--- a/src/vec_grid.cpp
+++ b/src/vec_grid.cpp
@@ -39,7 +39,7 @@ sampling_fun gerbolyze::get_sampler(enum grid_type type) {
vector<d2p> *gerbolyze::sample_poisson_disc(double w, double h, double center_distance) {
d2p top_left {0, 0};
d2p bottom_right {w, h};
- return new auto(thinks::PoissonDiskSampling(center_distance, top_left, bottom_right));
+ return new auto(thinks::PoissonDiskSampling(center_distance/2.5, top_left, bottom_right));
}
vector<d2p> *gerbolyze::sample_hexgrid(double w, double h, double center_distance) {
diff --git a/src/vec_grid.h b/src/vec_grid.h
index b574484..f2ed55a 100644
--- a/src/vec_grid.h
+++ b/src/vec_grid.h
@@ -31,8 +31,6 @@ enum grid_type {
SQUAREGRID
};
-typedef std::function<std::vector<d2p> *(double, double, double)> sampling_fun;
-
sampling_fun get_sampler(enum grid_type type);
std::vector<d2p> *sample_poisson_disc(double w, double h, double center_distance);