From e29fbee967067c4d7a83e0bf974b5793cdf64f9a Mon Sep 17 00:00:00 2001 From: Joseph Lenox Date: Sat, 21 Oct 2017 17:13:44 -0500 Subject: [PATCH] Pull changes to SVG.cpp to (#4144) * Add lock/unlock using flock() for output gcode files. * Added description of unsupported_edges() from the cpp * Ported updates to SVG class from prusa3d/Slic3r. Thanks @bubnikv * Revert "Add lock/unlock using flock() for output gcode files." This reverts commit a0d42fe3dcda714a8ccc0230a113ed6f85159e6b. --- xs/src/libslic3r/BridgeDetector.hpp | 3 + xs/src/libslic3r/SVG.cpp | 218 +++++++++++++++++++++------- xs/src/libslic3r/SVG.hpp | 80 +++++++--- 3 files changed, 233 insertions(+), 68 deletions(-) diff --git a/xs/src/libslic3r/BridgeDetector.hpp b/xs/src/libslic3r/BridgeDetector.hpp index 98057c959..45062bc12 100644 --- a/xs/src/libslic3r/BridgeDetector.hpp +++ b/xs/src/libslic3r/BridgeDetector.hpp @@ -25,6 +25,9 @@ public: bool detect_angle(); Polygons coverage() const; Polygons coverage(double angle) const; + + /// Return the bridge edges that are not currently supported but would permit use of the supplied + /// bridge angle if it was supported. Polylines unsupported_edges(double angle = -1) const; private: diff --git a/xs/src/libslic3r/SVG.cpp b/xs/src/libslic3r/SVG.cpp index c0a2f1ff4..db914ea96 100644 --- a/xs/src/libslic3r/SVG.cpp +++ b/xs/src/libslic3r/SVG.cpp @@ -1,30 +1,37 @@ #include "SVG.hpp" #include -#define COORD(x) ((float)unscale(x)*10) +#define COORD(x) ((float)unscale((x))*10) namespace Slic3r { -SVG::SVG(const char* filename) - : arrows(false), fill("grey"), stroke("black"), filename(filename) +bool SVG::open(const char* afilename) { - this->f = fopen(filename, "w"); + this->filename = afilename; + this->f = fopen(afilename, "w"); + if (this->f == NULL) + return false; fprintf(this->f, "\n" "\n" "\n" - " \n" - " \n" - " \n" - ); + " \n" + " \n" + " \n" + ); + return true; } -SVG::SVG(const char* filename, const BoundingBox &bbox) - : arrows(false), fill("grey"), stroke("black"), origin(bbox.min), filename(filename) +bool SVG::open(const char* afilename, const BoundingBox &bbox, const coord_t bbox_offset, bool aflipY) { - this->f = fopen(filename, "w"); - float w = COORD(bbox.max.x - bbox.min.x); - float h = COORD(bbox.max.y - bbox.min.y); + this->filename = afilename; + this->origin = bbox.min - Point(bbox_offset, bbox_offset); + this->flipY = aflipY; + this->f = ::fopen(afilename, "w"); + if (f == NULL) + return false; + float w = COORD(bbox.max.x - bbox.min.x + 2 * bbox_offset); + float h = COORD(bbox.max.y - bbox.min.y + 2 * bbox_offset); fprintf(this->f, "\n" "\n" @@ -33,15 +40,11 @@ SVG::SVG(const char* filename, const BoundingBox &bbox) " \n" " \n", h, w); -} - -SVG::~SVG() -{ - this->Close(); + return true; } void -SVG::draw(const Line &line, std::string stroke, coord_t stroke_width) +SVG::draw(const Line &line, std::string stroke, coordf_t stroke_width) { fprintf(this->f, " f, "/>\n"); } -void SVG::draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coord_t stroke_width) +void SVG::draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coordf_t stroke_width) { Pointf dir(line.b.x-line.a.x, line.b.y-line.a.y); Pointf perp(-dir.y, dir.x); @@ -73,7 +76,7 @@ void SVG::draw(const ThickLine &line, const std::string &fill, const std::string } void -SVG::draw(const Lines &lines, std::string stroke, coord_t stroke_width) +SVG::draw(const Lines &lines, std::string stroke, coordf_t stroke_width) { for (Lines::const_iterator it = lines.begin(); it != lines.end(); ++it) this->draw(*it, stroke, stroke_width); @@ -87,42 +90,86 @@ SVG::draw(const IntersectionLines &lines, std::string stroke) } void -SVG::draw(const ExPolygon &expolygon, std::string fill) +SVG::draw(const ExPolygon &expolygon, std::string fill, const float fill_opacity) { this->fill = fill; std::string d; - for (const Polygon &p : (Polygons)expolygon) - d += this->get_path_d(p, true) + " "; - - this->path(d, true); + Polygons pp = expolygon; + for (Polygons::const_iterator p = pp.begin(); p != pp.end(); ++p) { + d += this->get_path_d(*p, true) + " "; + } + this->path(d, true, 0, fill_opacity); +} + +void +SVG::draw_outline(const ExPolygon &expolygon, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width) +{ + draw_outline(expolygon.contour, stroke_outer, stroke_width); + for (Polygons::const_iterator it = expolygon.holes.begin(); it != expolygon.holes.end(); ++ it) { + draw_outline(*it, stroke_holes, stroke_width); + } } void -SVG::draw(const ExPolygonCollection &coll, std::string fill) +SVG::draw(const ExPolygons &expolygons, std::string fill, const float fill_opacity) { - this->draw(coll.expolygons, fill); + for (ExPolygons::const_iterator it = expolygons.begin(); it != expolygons.end(); ++it) + this->draw(*it, fill, fill_opacity); +} + +void +SVG::draw_outline(const ExPolygons &expolygons, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width) +{ + for (ExPolygons::const_iterator it = expolygons.begin(); it != expolygons.end(); ++ it) + draw_outline(*it, stroke_outer, stroke_holes, stroke_width); } void -SVG::draw(const SurfaceCollection &coll, std::string fill) +SVG::draw(const Surface &surface, std::string fill, const float fill_opacity) { - for (const Surface &s : coll.surfaces) - this->draw(s.expolygon, fill); + draw(surface.expolygon, fill, fill_opacity); +} + +void +SVG::draw_outline(const Surface &surface, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width) +{ + draw_outline(surface.expolygon, stroke_outer, stroke_holes, stroke_width); } void -SVG::draw(const ExPolygons &expolygons, std::string fill) +SVG::draw(const Surfaces &surfaces, std::string fill, const float fill_opacity) { - for (const ExPolygon &e : expolygons) - this->draw(e, fill); + for (Surfaces::const_iterator it = surfaces.begin(); it != surfaces.end(); ++it) + this->draw(*it, fill, fill_opacity); +} + +void +SVG::draw_outline(const Surfaces &surfaces, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width) +{ + for (Surfaces::const_iterator it = surfaces.begin(); it != surfaces.end(); ++ it) + draw_outline(*it, stroke_outer, stroke_holes, stroke_width); +} + +void +SVG::draw(const SurfacesPtr &surfaces, std::string fill, const float fill_opacity) +{ + for (SurfacesPtr::const_iterator it = surfaces.begin(); it != surfaces.end(); ++it) + this->draw(*(*it), fill, fill_opacity); +} + +void +SVG::draw_outline(const SurfacesPtr &surfaces, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width) +{ + for (SurfacesPtr::const_iterator it = surfaces.begin(); it != surfaces.end(); ++ it) + draw_outline(*(*it), stroke_outer, stroke_holes, stroke_width); } void SVG::draw(const Polygon &polygon, std::string fill) { this->fill = fill; - this->path(this->get_path_d(polygon, true), !fill.empty()); + this->path(this->get_path_d(polygon, true), !fill.empty(), 0, 1.f); } void @@ -133,34 +180,34 @@ SVG::draw(const Polygons &polygons, std::string fill) } void -SVG::draw(const Polyline &polyline, std::string stroke, coord_t stroke_width) +SVG::draw(const Polyline &polyline, std::string stroke, coordf_t stroke_width) { this->stroke = stroke; - this->path(this->get_path_d(polyline, false), false, stroke_width); + this->path(this->get_path_d(polyline, false), false, stroke_width, 1.f); } void -SVG::draw(const Polylines &polylines, std::string stroke, coord_t stroke_width) +SVG::draw(const Polylines &polylines, std::string stroke, coordf_t stroke_width) { for (Polylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it) this->draw(*it, stroke, stroke_width); } -void SVG::draw(const ThickLines &thicklines, const std::string &fill, const std::string &stroke, coord_t stroke_width) +void SVG::draw(const ThickLines &thicklines, const std::string &fill, const std::string &stroke, coordf_t stroke_width) { for (ThickLines::const_iterator it = thicklines.begin(); it != thicklines.end(); ++it) this->draw(*it, fill, stroke, stroke_width); } void -SVG::draw(const ThickPolylines &polylines, const std::string &stroke, coord_t stroke_width) +SVG::draw(const ThickPolylines &polylines, const std::string &stroke, coordf_t stroke_width) { for (ThickPolylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it) this->draw((Polyline)*it, stroke, stroke_width); } void -SVG::draw(const ThickPolylines &thickpolylines, const std::string &fill, const std::string &stroke, coord_t stroke_width) +SVG::draw(const ThickPolylines &thickpolylines, const std::string &fill, const std::string &stroke, coordf_t stroke_width) { for (ThickPolylines::const_iterator it = thickpolylines.begin(); it != thickpolylines.end(); ++ it) draw(it->thicklines(), fill, stroke, stroke_width); @@ -185,8 +232,36 @@ SVG::draw(const Points &points, std::string fill, coord_t radius) this->draw(*it, fill, radius); } +void +SVG::draw(const ClipperLib::Path &polygon, double scale, std::string stroke, coordf_t stroke_width) +{ + this->stroke = stroke; + this->path(this->get_path_d(polygon, scale, true), false, stroke_width, 1.f); +} + +void +SVG::draw(const ClipperLib::Paths &polygons, double scale, std::string stroke, coordf_t stroke_width) +{ + for (ClipperLib::Paths::const_iterator it = polygons.begin(); it != polygons.end(); ++ it) + draw(*it, scale, stroke, stroke_width); +} + +void +SVG::draw_outline(const Polygon &polygon, std::string stroke, coordf_t stroke_width) +{ + this->stroke = stroke; + this->path(this->get_path_d(polygon, true), false, stroke_width, 1.f); +} + +void +SVG::draw_outline(const Polygons &polygons, std::string stroke, coordf_t stroke_width) +{ + for (Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++ it) + draw_outline(*it, stroke, stroke_width); +} + void -SVG::path(const std::string &d, bool fill, coord_t stroke_width) +SVG::path(const std::string &d, bool fill, coordf_t stroke_width, const float fill_opacity) { float lineWidth = 0.f; if (! fill) @@ -194,12 +269,13 @@ SVG::path(const std::string &d, bool fill, coord_t stroke_width) fprintf( this->f, - " \n", + " \n", d.c_str(), fill ? this->fill.c_str() : "none", this->stroke.c_str(), lineWidth, - (this->arrows && !fill) ? " marker-end=\"url(#endArrow)\"" : "" + (this->arrows && !fill) ? " marker-end=\"url(#endArrow)\"" : "", + fill_opacity ); } @@ -216,15 +292,57 @@ SVG::get_path_d(const MultiPoint &mp, bool closed) const return d.str(); } +std::string +SVG::get_path_d(const ClipperLib::Path &path, double scale, bool closed) const +{ + std::ostringstream d; + d << "M "; + for (ClipperLib::Path::const_iterator p = path.begin(); p != path.end(); ++p) { + d << COORD(scale * p->X - origin.x) << " "; + d << COORD(scale * p->Y - origin.y) << " "; + } + if (closed) d << "z"; + return d.str(); +} + +void SVG::draw_text(const Point &pt, const char *text, const char *color) +{ + fprintf(this->f, + "%s", + COORD(pt.x-origin.x), + COORD(pt.y-origin.y), + color, text); +} + +void SVG::draw_legend(const Point &pt, const char *text, const char *color) +{ + fprintf(this->f, + "", + COORD(pt.x-origin.x), + COORD(pt.y-origin.y), + color); + fprintf(this->f, + "%s", + COORD(pt.x-origin.x) + 20.f, + COORD(pt.y-origin.y), + "black", text); +} + void SVG::Close() { - if (this->f != NULL) { - fprintf(this->f, "\n"); - fclose(this->f); - this->f = NULL; - printf("SVG written to %s\n", this->filename.c_str()); - } + fprintf(this->f, "\n"); + fclose(this->f); + this->f = NULL; +// printf("SVG written to %s\n", this->filename.c_str()); +} + +void SVG::export_expolygons(const char *path, const BoundingBox &bbox, const Slic3r::ExPolygons &expolygons, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width) +{ + SVG svg(path, bbox); + svg.draw(expolygons); + svg.draw_outline(expolygons, stroke_outer, stroke_holes, stroke_width); + svg.Close(); } } diff --git a/xs/src/libslic3r/SVG.hpp b/xs/src/libslic3r/SVG.hpp index b66af152a..83bb586c9 100644 --- a/xs/src/libslic3r/SVG.hpp +++ b/xs/src/libslic3r/SVG.hpp @@ -2,11 +2,11 @@ #define slic3r_SVG_hpp_ #include "libslic3r.h" +#include "clipper.hpp" #include "ExPolygon.hpp" -#include "ExPolygonCollection.hpp" #include "Line.hpp" -#include "SurfaceCollection.hpp" #include "TriangleMesh.hpp" +#include "Surface.hpp" namespace Slic3r { @@ -16,35 +16,79 @@ class SVG bool arrows; std::string fill, stroke; Point origin; + bool flipY; - SVG(const char* filename); - SVG(const char* filename, const BoundingBox &bbox); - ~SVG(); - void draw(const Line &line, std::string stroke = "black", coord_t stroke_width = 0); - void draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coord_t stroke_width = 0); - void draw(const Lines &lines, std::string stroke = "black", coord_t stroke_width = 0); + SVG(const char* afilename) : + arrows(false), fill("grey"), stroke("black"), filename(afilename), flipY(false) + { open(filename); } + SVG(const char* afilename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool aflipY = false) : + arrows(false), fill("grey"), stroke("black"), filename(afilename), origin(bbox.min - Point(bbox_offset, bbox_offset)), flipY(aflipY) + { open(filename, bbox, bbox_offset, aflipY); } + SVG(const std::string &filename) : + arrows(false), fill("grey"), stroke("black"), filename(filename), flipY(false) + { open(filename); } + SVG(const std::string &filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool aflipY = false) : + arrows(false), fill("grey"), stroke("black"), filename(filename), origin(bbox.min - Point(bbox_offset, bbox_offset)), flipY(aflipY) + { open(filename, bbox, bbox_offset, aflipY); } + ~SVG() { if (f != NULL) Close(); } + + bool open(const char* filename); + bool open(const char* filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool flipY = false); + bool open(const std::string &filename) + { return open(filename.c_str()); } + bool open(const std::string &filename, const BoundingBox &bbox, const coord_t bbox_offset = scale_(1.), bool flipY = false) + { return open(filename.c_str(), bbox, bbox_offset, flipY); } + + void draw(const Line &line, std::string stroke = "black", coordf_t stroke_width = 0); + void draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coordf_t stroke_width = 0); + void draw(const Lines &lines, std::string stroke = "black", coordf_t stroke_width = 0); void draw(const IntersectionLines &lines, std::string stroke = "black"); - void draw(const ExPolygon &expolygon, std::string fill = "grey"); - void draw(const ExPolygons &expolygons, std::string fill = "grey"); - void draw(const ExPolygonCollection &coll, std::string fill = "grey"); - void draw(const SurfaceCollection &coll, std::string fill = "grey"); + + void draw(const ExPolygon &expolygon, std::string fill = "grey", const float fill_opacity=1.f); + void draw_outline(const ExPolygon &polygon, std::string stroke_outer = "black", std::string stroke_holes = "blue", coordf_t stroke_width = 0); + void draw(const ExPolygons &expolygons, std::string fill = "grey", const float fill_opacity=1.f); + void draw_outline(const ExPolygons &polygons, std::string stroke_outer = "black", std::string stroke_holes = "blue", coordf_t stroke_width = 0); + + void draw(const Surface &surface, std::string fill = "grey", const float fill_opacity=1.f); + void draw_outline(const Surface &surface, std::string stroke_outer = "black", std::string stroke_holes = "blue", coordf_t stroke_width = 0); + void draw(const Surfaces &surfaces, std::string fill = "grey", const float fill_opacity=1.f); + void draw_outline(const Surfaces &surfaces, std::string stroke_outer = "black", std::string stroke_holes = "blue", coordf_t stroke_width = 0); + void draw(const SurfacesPtr &surfaces, std::string fill = "grey", const float fill_opacity=1.f); + void draw_outline(const SurfacesPtr &surfaces, std::string stroke_outer = "black", std::string stroke_holes = "blue", coordf_t stroke_width = 0); + void draw(const Polygon &polygon, std::string fill = "grey"); + void draw_outline(const Polygon &polygon, std::string stroke = "black", coordf_t stroke_width = 0); void draw(const Polygons &polygons, std::string fill = "grey"); - void draw(const Polyline &polyline, std::string stroke = "black", coord_t stroke_width = 0); - void draw(const Polylines &polylines, std::string stroke = "black", coord_t stroke_width = 0); - void draw(const ThickLines &thicklines, const std::string &fill = "lime", const std::string &stroke = "black", coord_t stroke_width = 0); - void draw(const ThickPolylines &polylines, const std::string &stroke = "black", coord_t stroke_width = 0); - void draw(const ThickPolylines &thickpolylines, const std::string &fill, const std::string &stroke, coord_t stroke_width); + void draw_outline(const Polygons &polygons, std::string stroke = "black", coordf_t stroke_width = 0); + void draw(const Polyline &polyline, std::string stroke = "black", coordf_t stroke_width = 0); + void draw(const Polylines &polylines, std::string stroke = "black", coordf_t stroke_width = 0); + void draw(const ThickLines &thicklines, const std::string &fill = "lime", const std::string &stroke = "black", coordf_t stroke_width = 0); + void draw(const ThickPolylines &polylines, const std::string &stroke = "black", coordf_t stroke_width = 0); + void draw(const ThickPolylines &thickpolylines, const std::string &fill, const std::string &stroke, coordf_t stroke_width); void draw(const Point &point, std::string fill = "black", coord_t radius = 0); void draw(const Points &points, std::string fill = "black", coord_t radius = 0); + + // Support for rendering the ClipperLib paths + void draw(const ClipperLib::Path &polygon, double scale, std::string fill = "grey", coordf_t stroke_width = 0); + void draw(const ClipperLib::Paths &polygons, double scale, std::string fill = "grey", coordf_t stroke_width = 0); + + void draw_text(const Point &pt, const char *text, const char *color); + void draw_legend(const Point &pt, const char *text, const char *color); + void Close(); private: std::string filename; FILE* f; - void path(const std::string &d, bool fill, coord_t stroke_width = 0); + void path(const std::string &d, bool fill, coordf_t stroke_width, const float fill_opacity); std::string get_path_d(const MultiPoint &mp, bool closed = false) const; + std::string get_path_d(const ClipperLib::Path &mp, double scale, bool closed = false) const; + +public: + static void export_expolygons(const char *path, const BoundingBox &bbox, const Slic3r::ExPolygons &expolygons, std::string stroke_outer = "black", std::string stroke_holes = "blue", coordf_t stroke_width = 0); + static void export_expolygons(const std::string &path, const BoundingBox &bbox, const Slic3r::ExPolygons &expolygons, std::string stroke_outer = "black", std::string stroke_holes = "blue", coordf_t stroke_width = 0) + { export_expolygons(path.c_str(), bbox, expolygons, stroke_outer, stroke_holes, stroke_width); } }; }