ENH: add Clipper2::Union and fix a command line hang issue
jira: STUDIO-9623 Change-Id: I8b40f66fed0fc9e5b13f0f10337267065fef1056
This commit is contained in:
parent
4f1ad8016e
commit
b5e3b96764
|
@ -295,7 +295,8 @@ namespace Clipper2Lib {
|
|||
typedef typename std::vector<PolyPath64*>::const_iterator pp64_itor;
|
||||
public:
|
||||
PolyPath64(PolyPath64* parent = nullptr) : PolyPath(parent) {}
|
||||
PolyPath64* operator [] (size_t index) { return static_cast<PolyPath64*>(childs_[index]); }
|
||||
PolyPath64 *operator[](size_t index) { return static_cast<PolyPath64 *>(childs_[index]); }
|
||||
PolyPath64 *Childs(size_t index) const { return static_cast<PolyPath64 *>(childs_[index]); }
|
||||
pp64_itor begin() const { return childs_.cbegin(); }
|
||||
pp64_itor end() const { return childs_.cend(); }
|
||||
|
||||
|
|
|
@ -781,7 +781,7 @@ const Polygons& WallToolPaths::getInnerContour()
|
|||
}
|
||||
return inner_contour;
|
||||
}
|
||||
|
||||
Polygons EmptyPolygons;
|
||||
const Polygons& WallToolPaths::getFirstWallContour()
|
||||
{
|
||||
if (!toolpaths_generated && inset_count > 0)
|
||||
|
@ -790,7 +790,7 @@ const Polygons& WallToolPaths::getFirstWallContour()
|
|||
}
|
||||
else if(inset_count == 0)
|
||||
{
|
||||
return {};
|
||||
return EmptyPolygons;
|
||||
}
|
||||
return first_wall_contour;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include "Clipper2Utils.hpp"
|
||||
#include "libslic3r.h"
|
||||
#include "clipper2/clipper.h"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -33,6 +35,66 @@ Clipper2Lib::Paths64 Slic3rPoints_to_Paths64(const std::vector<T>& in)
|
|||
return out;
|
||||
}
|
||||
|
||||
Points Path64ToPoints(const Clipper2Lib::Path64& path64)
|
||||
{
|
||||
Points points;
|
||||
points.reserve(path64.size());
|
||||
for (const Clipper2Lib::Point64 &point64 : path64) points.emplace_back(std::move(Slic3r::Point(point64.x, point64.y)));
|
||||
return points;
|
||||
}
|
||||
|
||||
static ExPolygons PolyTreeToExPolygons(Clipper2Lib::PolyTree64 &&polytree)
|
||||
{
|
||||
struct Inner
|
||||
{
|
||||
static void PolyTreeToExPolygonsRecursive(Clipper2Lib::PolyTree64 &&polynode, ExPolygons *expolygons)
|
||||
{
|
||||
size_t cnt = expolygons->size();
|
||||
expolygons->resize(cnt + 1);
|
||||
(*expolygons)[cnt].contour.points = Path64ToPoints(polynode.Polygon());
|
||||
|
||||
(*expolygons)[cnt].holes.resize(polynode.Count());
|
||||
for (int i = 0; i < polynode.Count(); ++i) {
|
||||
(*expolygons)[cnt].holes[i].points = Path64ToPoints(polynode[i]->Polygon());
|
||||
// Add outer polygons contained by (nested within) holes.
|
||||
for (int j = 0; j < polynode[i]->Count(); ++j) PolyTreeToExPolygonsRecursive(std::move(*polynode[i]->Childs(j)), expolygons);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t PolyTreeCountExPolygons(const Clipper2Lib::PolyPath64& polynode)
|
||||
{
|
||||
size_t cnt = 1;
|
||||
for (size_t i = 0; i < polynode.Count(); ++i) {
|
||||
for (size_t j = 0; j < polynode.Childs(i)->Count(); ++j) cnt += PolyTreeCountExPolygons(*polynode.Childs(i)->Childs(j));
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
};
|
||||
|
||||
ExPolygons retval;
|
||||
size_t cnt = 0;
|
||||
for (int i = 0; i < polytree.Count(); ++i) cnt += Inner::PolyTreeCountExPolygons(*polytree[i]);
|
||||
retval.reserve(cnt);
|
||||
for (int i = 0; i < polytree.Count(); ++i) Inner::PolyTreeToExPolygonsRecursive(std::move(*polytree[i]), &retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
Clipper2Lib::Paths64 Slic3rExPolygons_to_Paths64(const ExPolygons& in)
|
||||
{
|
||||
Clipper2Lib::Paths64 out;
|
||||
out.reserve(in.size());
|
||||
for (const ExPolygon& expolygon : in) {
|
||||
for (size_t i = 0; i < expolygon.num_contours(); i++) {
|
||||
const auto &poly = expolygon.contour_or_hole(i);
|
||||
Clipper2Lib::Path64 path;
|
||||
path.reserve(poly.points.size());
|
||||
for (const Slic3r::Point &point : poly.points) path.emplace_back(std::move(Clipper2Lib::Point64(point.x(), point.y())));
|
||||
out.emplace_back(std::move(path));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Polylines _clipper2_pl_open(Clipper2Lib::ClipType clipType, const Slic3r::Polylines& subject, const Slic3r::Polygons& clip)
|
||||
{
|
||||
Clipper2Lib::Clipper64 c;
|
||||
|
@ -57,4 +119,19 @@ Slic3r::Polylines intersection_pl_2(const Slic3r::Polylines& subject, const Slic
|
|||
Slic3r::Polylines diff_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip)
|
||||
{ return _clipper2_pl_open(Clipper2Lib::ClipType::Difference, subject, clip); }
|
||||
|
||||
ExPolygons union_ex2(const ExPolygons& expolygons)
|
||||
{
|
||||
Clipper2Lib::Clipper64 c;
|
||||
c.AddSubject(Slic3rExPolygons_to_Paths64(expolygons));
|
||||
|
||||
Clipper2Lib::ClipType ct = Clipper2Lib::ClipType::Union;
|
||||
Clipper2Lib::FillRule fr = Clipper2Lib::FillRule::NonZero;
|
||||
Clipper2Lib::PolyTree64 solution;
|
||||
c.Execute(ct, fr, solution);
|
||||
|
||||
ExPolygons results = PolyTreeToExPolygons(std::move(solution));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef slic3r_Clipper2Utils_hpp_
|
||||
#define slic3r_Clipper2Utils_hpp_
|
||||
|
||||
#include "libslic3r.h"
|
||||
#include "clipper2/clipper.h"
|
||||
#include "Polygon.hpp"
|
||||
#include "Polyline.hpp"
|
||||
|
||||
|
@ -10,7 +8,7 @@ namespace Slic3r {
|
|||
|
||||
Slic3r::Polylines intersection_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip);
|
||||
Slic3r::Polylines diff_pl_2(const Slic3r::Polylines& subject, const Slic3r::Polygons& clip);
|
||||
|
||||
ExPolygons union_ex2(const ExPolygons &expolygons);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#include "SVG.hpp"
|
||||
#include <iostream>
|
||||
|
||||
// #include "pugixml/pugixml.hpp"
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -86,7 +87,7 @@ void SVG::draw(const Lines &lines, std::string stroke, coordf_t stroke_width)
|
|||
void SVG::draw(const ExPolygon &expolygon, std::string fill, const float fill_opacity)
|
||||
{
|
||||
this->fill = fill;
|
||||
|
||||
|
||||
std::string d;
|
||||
for (const Polygon &p : to_polygons(expolygon))
|
||||
d += this->get_path_d(p, true) + " ";
|
||||
|
@ -201,7 +202,7 @@ void SVG::draw(const Point &point, std::string fill, coord_t iradius)
|
|||
svg << " <circle cx=\"" << to_svg_x(point(0) - origin(0)) << "\" cy=\"" << to_svg_y(point(1) - origin(1))
|
||||
<< "\" r=\"" << radius << "\" "
|
||||
<< "style=\"stroke: none; fill: " << fill << "\" />";
|
||||
|
||||
|
||||
fprintf(this->f, "%s\n", svg.str().c_str());
|
||||
}
|
||||
|
||||
|
@ -247,7 +248,7 @@ void SVG::path(const std::string &d, bool fill, coordf_t stroke_width, const flo
|
|||
d.c_str(),
|
||||
fill ? this->fill.c_str() : "none",
|
||||
this->stroke.c_str(),
|
||||
lineWidth,
|
||||
lineWidth,
|
||||
(this->arrows && !fill) ? " marker-end=\"url(#endArrow)\"" : "",
|
||||
fill_opacity
|
||||
);
|
||||
|
@ -331,6 +332,132 @@ void SVG::add_comment(const std::string comment)
|
|||
fprintf(this->f, "<!-- %s -->\n", comment.c_str());
|
||||
}
|
||||
|
||||
// Function to parse the SVG path data
|
||||
Points ParseSVGPath(const std::string &pathData)
|
||||
{
|
||||
Points points;
|
||||
Vec2d currentPoint = {0, 0};
|
||||
char command = 0;
|
||||
std::istringstream stream(pathData);
|
||||
|
||||
while (stream) {
|
||||
// Read the command or continue with the previous command
|
||||
if (!std::isdigit(stream.peek()) && stream.peek() != '-' && stream.peek() != '.') { stream >> command; }
|
||||
|
||||
if (command == 'M' || command == 'm') { // Move to
|
||||
double x, y;
|
||||
stream >> x;
|
||||
stream.ignore(1, ','); // Skip the comma, if present
|
||||
stream >> y;
|
||||
|
||||
if (command == 'm') { // Relative
|
||||
currentPoint.x() += x;
|
||||
currentPoint.y() += y;
|
||||
} else { // Absolute
|
||||
currentPoint.x() = x;
|
||||
currentPoint.y() = y;
|
||||
}
|
||||
points.push_back(scaled<coord_t>(currentPoint));
|
||||
} else if (command == 'L' || command == 'l') { // Line to
|
||||
double x, y;
|
||||
stream >> x;
|
||||
stream.ignore(1, ','); // Skip the comma, if present
|
||||
stream >> y;
|
||||
|
||||
if (command == 'l') { // Relative
|
||||
currentPoint.x() += x;
|
||||
currentPoint.y() += y;
|
||||
} else { // Absolute
|
||||
currentPoint.x() = x;
|
||||
currentPoint.y() = y;
|
||||
}
|
||||
points.push_back(scaled<coord_t>(currentPoint));
|
||||
} else if (command == 'Z' || command == 'z') { // Close path
|
||||
if (!points.empty()) {
|
||||
points.push_back(points.front()); // Close the polygon by returning to the start
|
||||
}
|
||||
} else if (command == 'H' || command == 'h') { // Horizontal line
|
||||
double x;
|
||||
stream >> x;
|
||||
|
||||
if (command == 'h') { // Relative
|
||||
currentPoint.x() += x;
|
||||
} else { // Absolute
|
||||
currentPoint.x() = x;
|
||||
}
|
||||
points.push_back(scaled<coord_t>(currentPoint));
|
||||
} else if (command == 'V' || command == 'v') { // Vertical line
|
||||
double y;
|
||||
stream >> y;
|
||||
|
||||
if (command == 'v') { // Relative
|
||||
currentPoint.y() += y;
|
||||
} else { // Absolute
|
||||
currentPoint.y() = y;
|
||||
}
|
||||
points.push_back(scaled<coord_t>(currentPoint));
|
||||
} else if (command == 'z') {
|
||||
if (!points.empty()) {
|
||||
points.push_back(points.front()); // Close path
|
||||
}
|
||||
} else {
|
||||
stream.ignore(1); // Skip invalid commands or extra spaces
|
||||
}
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
// Convert SVG path to ExPolygon
|
||||
ExPolygon ConvertToExPolygon(const std::vector<std::string> &svgPaths)
|
||||
{
|
||||
ExPolygon exPolygon;
|
||||
|
||||
for (const auto &pathData : svgPaths) {
|
||||
auto points = ParseSVGPath(pathData);
|
||||
if (exPolygon.contour.empty()) {
|
||||
exPolygon.contour.points = points; // First path is outer
|
||||
} else {
|
||||
exPolygon.holes.emplace_back(points); // Subsequent paths are holes
|
||||
}
|
||||
}
|
||||
|
||||
return exPolygon;
|
||||
}
|
||||
|
||||
// Function to load SVG and convert paths to ExPolygons
|
||||
std::vector<ExPolygon> SVG::load(const std::string &svgFilePath)
|
||||
{
|
||||
std::vector<ExPolygon> polygons;
|
||||
/* pugi::xml_document doc;
|
||||
pugi::xml_parse_result result = doc.load_file(svgFilePath.c_str());
|
||||
if (!result) {
|
||||
std::cerr << "Failed to load SVG file: " << result.description() << "\n";
|
||||
return polygons;
|
||||
}
|
||||
|
||||
|
||||
// Find the root <svg> element
|
||||
pugi::xml_node svgNode = doc.child("svg");
|
||||
if (!svgNode) {
|
||||
std::cerr << "No <svg> element found in file.\n";
|
||||
return polygons;
|
||||
}
|
||||
|
||||
// Iterate over <path> elements
|
||||
for (pugi::xml_node pathNode : svgNode.children("path")) {
|
||||
const char *pathData = pathNode.attribute("d").value();
|
||||
if (pathData) {
|
||||
std::vector<std::string> paths = {std::string(pathData)}; // For simplicity, assuming one path per element. You could extract more complex paths if necessary.
|
||||
ExPolygon exPolygon = ConvertToExPolygon(paths);
|
||||
polygons.push_back(exPolygon);
|
||||
}
|
||||
}
|
||||
*/
|
||||
return polygons;
|
||||
}
|
||||
|
||||
|
||||
void SVG::Close()
|
||||
{
|
||||
fprintf(this->f, "</svg>\n");
|
||||
|
@ -411,4 +538,234 @@ void SVG::export_expolygons(const char *path, const std::vector<std::pair<Slic3r
|
|||
svg.Close();
|
||||
}
|
||||
|
||||
|
||||
// JSON serialization for Point using compact format [x, y]
|
||||
void to_json(nlohmann::json &j, const Point &p) { j = nlohmann::json{p.x(), p.y()}; }
|
||||
|
||||
void from_json(const nlohmann::json &j, Point &p)
|
||||
{
|
||||
if (j.is_array() && j.size() == 2) {
|
||||
p.x() = j[0].get<coord_t>();
|
||||
p.y() = j[1].get<coord_t>();
|
||||
} else {
|
||||
throw std::runtime_error("Invalid Point JSON format. Expected [x, y].");
|
||||
}
|
||||
}
|
||||
|
||||
// Serialization for Polygon
|
||||
void to_json(nlohmann::json &j, const Polygon &polygon)
|
||||
{
|
||||
j = nlohmann::json::array();
|
||||
for (const auto &point : polygon.points) {
|
||||
j.push_back(point); // Push each point (serialized as [x, y])
|
||||
}
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json &j, Polygon &polygon)
|
||||
{
|
||||
if (j.is_array()) {
|
||||
polygon.clear();
|
||||
for (const auto &item : j) { polygon.append(item.get<Point>()); }
|
||||
} else {
|
||||
throw std::runtime_error("Invalid Polygon JSON format. Expected array of points.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Serialization for ExPolygon
|
||||
void to_json(nlohmann::json &j, const ExPolygon &exPolygon) {
|
||||
j = nlohmann::json{{"contour", exPolygon.contour}, {"holes", exPolygon.holes}};
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json &j, ExPolygon &exPolygon)
|
||||
{
|
||||
if (j.contains("contour")) {
|
||||
j.at("contour").get_to(exPolygon.contour);
|
||||
if (j.contains("holes")) {
|
||||
j.at("holes").get_to(exPolygon.holes);
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Invalid ExPolygon JSON format. Missing 'contour' or 'holes'.");
|
||||
}
|
||||
}
|
||||
|
||||
// Serialization for ExPolygons
|
||||
void to_json(nlohmann::json &j, const std::vector<ExPolygon> &exPolygons)
|
||||
{
|
||||
j = nlohmann::json::array();
|
||||
for (const auto &exPolygon : exPolygons) {
|
||||
j.push_back(exPolygon); // Serialize each ExPolygon
|
||||
}
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json& j, std::vector<ExPolygon>& exPolygons)
|
||||
{
|
||||
if (j.is_array()) {
|
||||
exPolygons.clear();
|
||||
for (const auto& item : j) {
|
||||
exPolygons.push_back(item.get<ExPolygon>());
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Invalid ExPolygons JSON format. Expected array of ExPolygons.");
|
||||
}
|
||||
}
|
||||
|
||||
// Function to dump ExPolygons to JSON
|
||||
void dumpExPolygonToJson(const ExPolygon &exPolygon, const std::string &filePath)
|
||||
{
|
||||
nlohmann::json j = exPolygon;
|
||||
|
||||
// Write JSON to a file
|
||||
std::ofstream file(filePath);
|
||||
if (!file) {
|
||||
std::cerr << "Error: Cannot open file for writing: " << filePath << "\n";
|
||||
return;
|
||||
}
|
||||
file << j.dump(4); // Pretty print with 4 spaces of indentation
|
||||
file.close();
|
||||
|
||||
std::cout << "ExPolygons dumped to " << filePath << "\n";
|
||||
}
|
||||
|
||||
// Function to dump ExPolygons to JSON
|
||||
void dumpExPolygonsToJson(const std::vector<ExPolygon> &exPolygons, const std::string &filePath)
|
||||
{
|
||||
nlohmann::json j = exPolygons;
|
||||
|
||||
// Write JSON to a file
|
||||
std::ofstream file(filePath);
|
||||
if (!file) {
|
||||
std::cerr << "Error: Cannot open file for writing: " << filePath << "\n";
|
||||
return;
|
||||
}
|
||||
file << j.dump(4); // Pretty print with 4 spaces of indentation
|
||||
file.close();
|
||||
|
||||
std::cout << "ExPolygons dumped to " << filePath << "\n";
|
||||
}
|
||||
|
||||
// Function to load ExPolygons from JSON
|
||||
std::vector<ExPolygon> loadExPolygonsFromJson(const std::string &filePath)
|
||||
{
|
||||
std::vector<ExPolygon> exPolygons;
|
||||
|
||||
std::ifstream file(filePath);
|
||||
if (!file) {
|
||||
std::cerr << "Error: Cannot open file for reading: " << filePath << "\n";
|
||||
return exPolygons;
|
||||
}
|
||||
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
std::string content = buffer.str(); // Read entire file into string
|
||||
|
||||
nlohmann::json j;
|
||||
try {
|
||||
j = nlohmann::json::parse(content);
|
||||
//file >> j; // Parse JSON from file
|
||||
} catch (const nlohmann::json::parse_error &e) {
|
||||
std::cerr << "JSON parsing error: " << e.what() << std::endl;
|
||||
return exPolygons; // Return empty vector on failure
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "Error: " << e.what() << "\n";
|
||||
file.close();
|
||||
return exPolygons;
|
||||
}
|
||||
file.close();
|
||||
|
||||
// Deserialize JSON to std::vector<ExPolygon>
|
||||
//exPolygons = j.get<std::vector<ExPolygon>>();
|
||||
if (j.is_array()) {
|
||||
for (const auto& item : j) {
|
||||
exPolygons.push_back(item.get<ExPolygon>());
|
||||
}
|
||||
} else if (j.is_object()) {
|
||||
exPolygons.push_back(j.get<ExPolygon>());
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Invalid ExPolygons JSON format. Expected array of ExPolygons.");
|
||||
}
|
||||
|
||||
return exPolygons;
|
||||
}
|
||||
|
||||
// Save ExPolygons to a file
|
||||
void dumpExPolygonsToTxt(const std::vector<ExPolygon> &exPolygons, const std::string &filePath)
|
||||
{
|
||||
std::ofstream file(filePath);
|
||||
if (!file) {
|
||||
std::cerr << "Error: Cannot open file for writing: " << filePath << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < exPolygons.size(); ++i) {
|
||||
const auto &exPolygon = exPolygons[i];
|
||||
file << "# ExPolygon " << i + 1 << "\n";
|
||||
|
||||
// Save the outer contour
|
||||
file << "contour:";
|
||||
for (const auto &point : exPolygon.contour) { file << " " << point.x() << " " << point.y(); }
|
||||
file << "\n";
|
||||
|
||||
// Save the holes
|
||||
for (const auto &hole : exPolygon.holes) {
|
||||
file << "hole:";
|
||||
for (const auto &point : hole) { file << " " << point.x() << " " << point.y(); }
|
||||
file << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
std::cout << "ExPolygons saved to " << filePath << std::endl;
|
||||
}
|
||||
|
||||
// Load ExPolygons from a file
|
||||
std::vector<ExPolygon> loadExPolygonsFromTxt(const std::string &filePath)
|
||||
{
|
||||
std::vector<ExPolygon> exPolygons;
|
||||
|
||||
std::ifstream file(filePath);
|
||||
if (!file) {
|
||||
std::cerr << "Error: Cannot open file for reading: " << filePath << std::endl;
|
||||
return exPolygons;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
ExPolygon currentPolygon;
|
||||
while (std::getline(file, line)) {
|
||||
if (line.empty() || line[0] == '#') {
|
||||
// Start of a new polygon
|
||||
if (!currentPolygon.contour.empty() || !currentPolygon.holes.empty()) {
|
||||
exPolygons.push_back(currentPolygon);
|
||||
currentPolygon = ExPolygon();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
std::istringstream stream(line);
|
||||
std::string keyword;
|
||||
stream >> keyword;
|
||||
|
||||
if (keyword == "contour:") {
|
||||
currentPolygon.contour.clear();
|
||||
coord_t x, y;
|
||||
while (stream >> x >> y) { currentPolygon.contour.append({x, y}); }
|
||||
} else if (keyword == "hole:") {
|
||||
Polygon hole;
|
||||
coord_t x, y;
|
||||
while (stream >> x >> y) { hole.append({x, y}); }
|
||||
currentPolygon.holes.push_back(hole);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the last polygon if any
|
||||
if (!currentPolygon.contour.empty() || !currentPolygon.holes.empty()) { exPolygons.push_back(currentPolygon); }
|
||||
|
||||
file.close();
|
||||
std::cout << "Loaded " << exPolygons.size() << " ExPolygons from " << filePath << std::endl;
|
||||
return exPolygons;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -80,6 +80,8 @@ public:
|
|||
void draw_grid(const BoundingBox& bbox, const std::string& stroke = "black", coordf_t stroke_width = scale_(0.05), coordf_t step=scale_(1.0));
|
||||
void add_comment(const std::string comment);
|
||||
|
||||
static ExPolygons load(const std::string& filename);
|
||||
|
||||
void Close();
|
||||
|
||||
private:
|
||||
|
@ -177,6 +179,12 @@ private:
|
|||
float to_svg_y(float x) const throw() { return flipY ? this->height - to_svg_coord(x) : to_svg_coord(x); }
|
||||
};
|
||||
|
||||
void dumpExPolygonToJson(const ExPolygon &exPolygon, const std::string &filePath);
|
||||
void dumpExPolygonsToJson(const std::vector<ExPolygon> &exPolygons, const std::string &filePath);
|
||||
std::vector<ExPolygon> loadExPolygonsFromJson(const std::string &filePath);
|
||||
|
||||
void dumpExPolygonsToTxt(const std::vector<ExPolygon> &exPolygons, const std::string &filePath);
|
||||
std::vector<ExPolygon> loadExPolygonsFromTxt(const std::string &filePath);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "format.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Clipper2Utils.hpp"
|
||||
#include "Fill/FillBase.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "Layer.hpp"
|
||||
|
@ -629,6 +630,7 @@ TreeSupport::TreeSupport(PrintObject& object, const SlicingParameters &slicing_p
|
|||
SVG svg(debug_out_path("machine_boarder.svg"), m_object->bounding_box());
|
||||
if (svg.is_opened()) svg.draw(m_machine_border, "yellow");
|
||||
#endif
|
||||
BOOST_LOG_TRIVIAL(debug) << "tree support construct finish";
|
||||
}
|
||||
|
||||
void add_overhang(Layer *layer, const ExPolygon &overhang, int type)
|
||||
|
@ -3871,14 +3873,16 @@ TreeSupportData::TreeSupportData(const PrintObject &object, coordf_t xy_distance
|
|||
m_max_move_distances.resize(object.layers().size(), 0);
|
||||
m_layer_outlines.resize(object.layers().size());
|
||||
m_layer_outlines_below.resize(object.layer_count());
|
||||
for (std::size_t layer_nr = 0; layer_nr < object.layers().size(); ++layer_nr)
|
||||
{
|
||||
for (std::size_t layer_nr = 0; layer_nr < object.layers().size(); ++layer_nr) {
|
||||
// BOOST_LOG_TRIVIAL(debug) << "TreeSupportData construct "<< layer_nr<<"/"<<object.layer_count();
|
||||
const Layer* layer = object.get_layer(layer_nr);
|
||||
m_max_move_distances[layer_nr] = layer->height * branch_scale_factor;
|
||||
ExPolygons &outline = m_layer_outlines[layer_nr];
|
||||
for (const ExPolygon& poly : layer->lslices) {
|
||||
poly.simplify(scale_(m_radius_sample_resolution), &outline);
|
||||
}
|
||||
outline.clear();
|
||||
outline.reserve(layer->lslices.size());
|
||||
for (const ExPolygon &poly : layer->lslices) { append(outline, to_expolygons( poly.simplify_p(scale_(m_radius_sample_resolution)))); }
|
||||
if (layer_nr % 10 == 0)
|
||||
outline = union_ex(outline);
|
||||
|
||||
if (layer_nr == 0)
|
||||
m_layer_outlines_below[layer_nr] = outline;
|
||||
|
@ -3886,7 +3890,7 @@ TreeSupportData::TreeSupportData(const PrintObject &object, coordf_t xy_distance
|
|||
m_layer_outlines_below[layer_nr] = m_layer_outlines_below[layer_nr - 1];
|
||||
m_layer_outlines_below[layer_nr].insert(m_layer_outlines_below[layer_nr].end(), outline.begin(), outline.end());
|
||||
if (layer_nr%10==0)
|
||||
m_layer_outlines_below[layer_nr] = union_ex(m_layer_outlines_below[layer_nr]);
|
||||
m_layer_outlines_below[layer_nr] = union_ex2(m_layer_outlines_below[layer_nr]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue