Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYuSanka <yusanka@gmail.com>2019-11-03 21:34:34 +0300
committerYuSanka <yusanka@gmail.com>2019-11-03 21:34:34 +0300
commitc564f693e906d1764fffadba7bf7a29aecfb6742 (patch)
tree762edc1a458bd72090cd83b624234e19bce5e3be /src
parent674c6ce1c53f4b0cf9b3340de5f5e75087a8f5a1 (diff)
parentbb8d59391fdd21317a68e4b83c54fc3f3fe88c0a (diff)
Merge remote-tracking branch 'origin/master' into ys_color_print_extension
Diffstat (limited to 'src')
-rw-r--r--src/libslic3r/Arrange.cpp2
-rw-r--r--src/libslic3r/CMakeLists.txt3
-rw-r--r--src/libslic3r/ClipperUtils.cpp330
-rw-r--r--src/libslic3r/ClipperUtils.hpp5
-rw-r--r--src/libslic3r/EdgeGrid.cpp144
-rw-r--r--src/libslic3r/EdgeGrid.hpp33
-rw-r--r--src/libslic3r/ElephantFootCompensation.cpp321
-rw-r--r--src/libslic3r/ElephantFootCompensation.hpp16
-rw-r--r--src/libslic3r/ExPolygon.hpp14
-rw-r--r--src/libslic3r/Format/AMF.cpp21
-rw-r--r--src/libslic3r/GCode.cpp38
-rw-r--r--src/libslic3r/GCode/Analyzer.cpp24
-rw-r--r--src/libslic3r/GCode/Analyzer.hpp3
-rw-r--r--src/libslic3r/GCode/SpiralVase.hpp4
-rw-r--r--src/libslic3r/GCode/WipeTower.cpp9
-rw-r--r--src/libslic3r/Geometry.cpp35
-rw-r--r--src/libslic3r/Geometry.hpp4
-rw-r--r--src/libslic3r/Layer.cpp8
-rw-r--r--src/libslic3r/LayerRegion.cpp1
-rw-r--r--src/libslic3r/Polygon.cpp5
-rw-r--r--src/libslic3r/Polygon.hpp16
-rw-r--r--src/libslic3r/PolygonTrimmer.cpp5
-rw-r--r--src/libslic3r/PrintObject.cpp47
-rw-r--r--src/libslic3r/SVG.cpp4
-rw-r--r--src/libslic3r/SVG.hpp10
-rw-r--r--src/libslic3r/utils.cpp17
-rw-r--r--src/qhull/CMakeLists.txt4
-rw-r--r--src/slic3r/Config/Version.cpp5
-rw-r--r--src/slic3r/GUI/BackgroundSlicingProcess.cpp1
-rw-r--r--src/slic3r/GUI/Field.cpp40
-rw-r--r--src/slic3r/GUI/GLCanvas3D.cpp2
-rw-r--r--src/slic3r/GUI/GUI_App.hpp9
-rw-r--r--src/slic3r/GUI/GUI_ObjectList.cpp4
-rw-r--r--src/slic3r/GUI/GUI_ObjectManipulation.cpp6
-rw-r--r--src/slic3r/GUI/GUI_Preview.cpp2
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmosManager.hpp9
-rw-r--r--src/slic3r/GUI/OptionsGroup.cpp2
-rw-r--r--src/slic3r/GUI/Plater.cpp4
-rw-r--r--src/slic3r/GUI/wxExtensions.cpp2
39 files changed, 1068 insertions, 141 deletions
diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp
index aed6e41f7..3fa7e1841 100644
--- a/src/libslic3r/Arrange.cpp
+++ b/src/libslic3r/Arrange.cpp
@@ -375,7 +375,7 @@ public:
for(unsigned idx = 0; idx < fixeditems.size(); ++idx) {
Item& itm = fixeditems[idx];
- itm.markAsFixedInBin(0);
+ itm.markAsFixedInBin(itm.binId());
}
m_pck.configure(m_pconf);
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index cbaa24e9c..0388b1ac0 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -22,6 +22,8 @@ add_library(libslic3r STATIC
Config.hpp
EdgeGrid.cpp
EdgeGrid.hpp
+ ElephantFootCompensation.cpp
+ ElephantFootCompensation.hpp
ExPolygon.cpp
ExPolygon.hpp
ExPolygonCollection.cpp
@@ -222,6 +224,7 @@ target_link_libraries(libslic3r
qhull
semver
TBB::tbb
+ # OpenVDB::openvdb
${CMAKE_DL_LIBS}
)
diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp
index b863b4712..3db2f1f00 100644
--- a/src/libslic3r/ClipperUtils.cpp
+++ b/src/libslic3r/ClipperUtils.cpp
@@ -107,8 +107,7 @@ void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, ExPolygons* ex
}
}
-ExPolygons
-PolyTreeToExPolygons(ClipperLib::PolyTree& polytree)
+ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree& polytree)
{
ExPolygons retval;
for (int i = 0; i < polytree.ChildCount(); ++i)
@@ -151,8 +150,7 @@ Slic3r::Polylines ClipperPaths_to_Slic3rPolylines(const ClipperLib::Paths &input
return retval;
}
-ExPolygons
-ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input)
+ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input)
{
// init Clipper
ClipperLib::Clipper clipper;
@@ -167,8 +165,7 @@ ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input)
return PolyTreeToExPolygons(polytree);
}
-ClipperLib::Path
-Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input)
+ClipperLib::Path Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input)
{
ClipperLib::Path retval;
for (Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit)
@@ -176,8 +173,7 @@ Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input)
return retval;
}
-ClipperLib::Path
-Slic3rMultiPoint_to_ClipperPath_reversed(const Slic3r::MultiPoint &input)
+ClipperLib::Path Slic3rMultiPoint_to_ClipperPath_reversed(const Slic3r::MultiPoint &input)
{
ClipperLib::Path output;
output.reserve(input.points.size());
@@ -521,7 +517,7 @@ T _clipper_do(const ClipperLib::ClipType clipType,
// Fix of #117: A large fractal pyramid takes ages to slice
// The Clipper library has difficulties processing overlapping polygons.
-// Namely, the function Clipper::JoinCommonEdges() has potentially a terrible time complexity if the output
+// Namely, the function ClipperLib::JoinCommonEdges() has potentially a terrible time complexity if the output
// of the operation is of the PolyTree type.
// This function implmenets a following workaround:
// 1) Peform the Clipper operation with the output to Paths. This method handles overlaps in a reasonable time.
@@ -918,4 +914,320 @@ Polygons top_level_islands(const Slic3r::Polygons &polygons)
return out;
}
+// Outer offset shall not split the input contour into multiples. It is expected, that the solution will be non empty and it will contain just a single polygon.
+ClipperLib::Paths fix_after_outer_offset(const ClipperLib::Path &input, ClipperLib::PolyFillType filltype, bool reverse_result)
+{
+ ClipperLib::Paths solution;
+ if (! input.empty()) {
+ ClipperLib::Clipper clipper;
+ clipper.AddPath(input, ClipperLib::ptSubject, true);
+ clipper.ReverseSolution(reverse_result);
+ clipper.Execute(ClipperLib::ctUnion, solution, filltype, filltype);
+ }
+ return solution;
+}
+
+// Inner offset may split the source contour into multiple contours, but one shall not be inside the other.
+ClipperLib::Paths fix_after_inner_offset(const ClipperLib::Path &input, ClipperLib::PolyFillType filltype, bool reverse_result)
+{
+ ClipperLib::Paths solution;
+ if (! input.empty()) {
+ ClipperLib::Clipper clipper;
+ clipper.AddPath(input, ClipperLib::ptSubject, true);
+ ClipperLib::IntRect r = clipper.GetBounds();
+ r.left -= 10; r.top -= 10; r.right += 10; r.bottom += 10;
+ if (filltype == ClipperLib::pftPositive)
+ clipper.AddPath({ ClipperLib::IntPoint(r.left, r.bottom), ClipperLib::IntPoint(r.left, r.top), ClipperLib::IntPoint(r.right, r.top), ClipperLib::IntPoint(r.right, r.bottom) }, ClipperLib::ptSubject, true);
+ else
+ clipper.AddPath({ ClipperLib::IntPoint(r.left, r.bottom), ClipperLib::IntPoint(r.right, r.bottom), ClipperLib::IntPoint(r.right, r.top), ClipperLib::IntPoint(r.left, r.top) }, ClipperLib::ptSubject, true);
+ clipper.ReverseSolution(reverse_result);
+ clipper.Execute(ClipperLib::ctUnion, solution, filltype, filltype);
+ if (! solution.empty())
+ solution.erase(solution.begin());
+ }
+ return solution;
+}
+
+ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::vector<float> &deltas, double miter_limit)
+{
+ assert(contour.size() == deltas.size());
+#ifndef NDEBUG
+ // Verify that the deltas are either all positive, or all negative.
+ bool positive = false;
+ bool negative = false;
+ for (float delta : deltas)
+ if (delta < 0.f)
+ negative = true;
+ else if (delta > 0.f)
+ positive = true;
+ assert(! (negative && positive));
+#endif /* NDEBUG */
+
+ ClipperLib::Path out;
+
+ if (deltas.size() > 2)
+ {
+ out.reserve(contour.size() * 2);
+
+ // Clamp miter limit to 2.
+ miter_limit = (miter_limit > 2.) ? 2. / (miter_limit * miter_limit) : 0.5;
+
+ // perpenduclar vector
+ auto perp = [](const Vec2d &v) -> Vec2d { return Vec2d(v.y(), - v.x()); };
+
+ // Add a new point to the output, scale by CLIPPER_OFFSET_SCALE and round to ClipperLib::cInt.
+ auto add_offset_point = [&out](Vec2d pt) {
+ pt *= double(CLIPPER_OFFSET_SCALE);
+ pt += Vec2d(0.5 - (pt.x() < 0), 0.5 - (pt.y() < 0));
+ out.emplace_back(ClipperLib::cInt(pt.x()), ClipperLib::cInt(pt.y()));
+ };
+
+ // Minimum edge length, squared.
+ double lmin = *std::max_element(deltas.begin(), deltas.end()) * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR;
+ double l2min = lmin * lmin;
+ // Minimum angle to consider two edges to be parallel.
+ double sin_min_parallel = EPSILON + 1. / double(CLIPPER_OFFSET_SCALE);
+
+ // Find the last point further from pt by l2min.
+ Vec2d pt = contour.front().cast<double>();
+ size_t iprev = contour.size() - 1;
+ Vec2d ptprev;
+ for (; iprev > 0; -- iprev) {
+ ptprev = contour[iprev].cast<double>();
+ if ((ptprev - pt).squaredNorm() > l2min)
+ break;
+ }
+
+ if (iprev != 0) {
+ size_t ilast = iprev;
+ // Normal to the (pt - ptprev) segment.
+ Vec2d nprev = perp(pt - ptprev).normalized();
+ for (size_t i = 0; ; ) {
+ // Find the next point further from pt by l2min.
+ size_t j = i + 1;
+ Vec2d ptnext;
+ for (; j <= ilast; ++ j) {
+ ptnext = contour[j].cast<double>();
+ double l2 = (ptnext - pt).squaredNorm();
+ if (l2 > l2min)
+ break;
+ }
+ if (j > ilast)
+ ptnext = contour.front().cast<double>();
+
+ // Normal to the (ptnext - pt) segment.
+ Vec2d nnext = perp(ptnext - pt).normalized();
+
+ double delta = deltas[i];
+ double sin_a = clamp(-1., 1., cross2(nprev, nnext));
+ double convex = sin_a * delta;
+ if (convex <= - sin_min_parallel) {
+ // Concave corner.
+ add_offset_point(pt + nprev * delta);
+ add_offset_point(pt);
+ add_offset_point(pt + nnext * delta);
+ } else if (convex < sin_min_parallel) {
+ // Nearly parallel.
+ add_offset_point((nprev.dot(nnext) > 0.) ? (pt + nprev * delta) : pt);
+ } else {
+ // Convex corner
+ double dot = nprev.dot(nnext);
+ double r = 1. + dot;
+ if (r >= miter_limit)
+ add_offset_point(pt + (nprev + nnext) * (delta / r));
+ else {
+ double dx = std::tan(std::atan2(sin_a, dot) / 4.);
+ Vec2d newpt1 = pt + (nprev - perp(nprev) * dx) * delta;
+ Vec2d newpt2 = pt + (nnext + perp(nnext) * dx) * delta;
+#ifndef NDEBUG
+ Vec2d vedge = 0.5 * (newpt1 + newpt2) - pt;
+ double dist_norm = vedge.norm();
+ assert(std::abs(dist_norm - delta) < EPSILON);
+#endif /* NDEBUG */
+ add_offset_point(newpt1);
+ add_offset_point(newpt2);
+ }
+ }
+
+ if (i == ilast)
+ break;
+
+ ptprev = pt;
+ nprev = nnext;
+ pt = ptnext;
+ i = j;
+ }
+ }
+ }
+
+#if 0
+ {
+ ClipperLib::Path polytmp(out);
+ unscaleClipperPolygon(polytmp);
+ Slic3r::Polygon offsetted = ClipperPath_to_Slic3rPolygon(polytmp);
+ BoundingBox bbox = get_extents(contour);
+ bbox.merge(get_extents(offsetted));
+ static int iRun = 0;
+ SVG svg(debug_out_path("mittered_offset_path_scaled-%d.svg", iRun ++).c_str(), bbox);
+ svg.draw_outline(Polygon(contour), "blue", scale_(0.01));
+ svg.draw_outline(offsetted, "red", scale_(0.01));
+ svg.draw(contour, "blue", scale_(0.03));
+ svg.draw((Points)offsetted, "blue", scale_(0.03));
+ }
+#endif
+
+ return out;
+}
+
+Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
+{
+#ifndef NDEBUG
+ // Verify that the deltas are all non positive.
+ for (const std::vector<float> &ds : deltas)
+ for (float delta : ds)
+ assert(delta <= 0.);
+ assert(expoly.holes.size() + 1 == deltas.size());
+#endif /* NDEBUG */
+
+ // 1) Offset the outer contour.
+ ClipperLib::Paths contours = fix_after_inner_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftNegative, true);
+
+ // 2) Offset the holes one by one, collect the results.
+ ClipperLib::Paths holes;
+ holes.reserve(expoly.holes.size());
+ for (const Polygon& hole : expoly.holes)
+ append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, false));
+
+ // 3) Subtract holes from the contours.
+ ClipperLib::Paths output;
+ if (holes.empty())
+ output = std::move(contours);
+ else {
+ ClipperLib::Clipper clipper;
+ clipper.Clear();
+ clipper.AddPaths(contours, ClipperLib::ptSubject, true);
+ clipper.AddPaths(holes, ClipperLib::ptClip, true);
+ clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
+ }
+
+ // 4) Unscale the output.
+ unscaleClipperPolygons(output);
+ return ClipperPaths_to_Slic3rPolygons(output);
+}
+
+Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
+{
+#ifndef NDEBUG
+ // Verify that the deltas are all non positive.
+for (const std::vector<float>& ds : deltas)
+ for (float delta : ds)
+ assert(delta >= 0.);
+ assert(expoly.holes.size() + 1 == deltas.size());
+#endif /* NDEBUG */
+
+ // 1) Offset the outer contour.
+ ClipperLib::Paths contours = fix_after_outer_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftPositive, false);
+
+ // 2) Offset the holes one by one, collect the results.
+ ClipperLib::Paths holes;
+ holes.reserve(expoly.holes.size());
+ for (const Polygon& hole : expoly.holes)
+ append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true));
+
+ // 3) Subtract holes from the contours.
+ ClipperLib::Paths output;
+ if (holes.empty())
+ output = std::move(contours);
+ else {
+ ClipperLib::Clipper clipper;
+ clipper.Clear();
+ clipper.AddPaths(contours, ClipperLib::ptSubject, true);
+ clipper.AddPaths(holes, ClipperLib::ptClip, true);
+ clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
+ }
+
+ // 4) Unscale the output.
+ unscaleClipperPolygons(output);
+ return ClipperPaths_to_Slic3rPolygons(output);
+}
+
+ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
+{
+#ifndef NDEBUG
+ // Verify that the deltas are all non positive.
+for (const std::vector<float>& ds : deltas)
+ for (float delta : ds)
+ assert(delta >= 0.);
+ assert(expoly.holes.size() + 1 == deltas.size());
+#endif /* NDEBUG */
+
+ // 1) Offset the outer contour.
+ ClipperLib::Paths contours = fix_after_outer_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftPositive, false);
+
+ // 2) Offset the holes one by one, collect the results.
+ ClipperLib::Paths holes;
+ holes.reserve(expoly.holes.size());
+ for (const Polygon& hole : expoly.holes)
+ append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true));
+
+ // 3) Subtract holes from the contours.
+ unscaleClipperPolygons(contours);
+ ExPolygons output;
+ if (holes.empty()) {
+ output.reserve(contours.size());
+ for (ClipperLib::Path &path : contours)
+ output.emplace_back(ClipperPath_to_Slic3rPolygon(path));
+ } else {
+ ClipperLib::Clipper clipper;
+ unscaleClipperPolygons(holes);
+ clipper.AddPaths(contours, ClipperLib::ptSubject, true);
+ clipper.AddPaths(holes, ClipperLib::ptClip, true);
+ ClipperLib::PolyTree polytree;
+ clipper.Execute(ClipperLib::ctDifference, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
+ output = PolyTreeToExPolygons(polytree);
+ }
+
+ return output;
+}
+
+
+ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit)
+{
+#ifndef NDEBUG
+ // Verify that the deltas are all non positive.
+for (const std::vector<float>& ds : deltas)
+ for (float delta : ds)
+ assert(delta <= 0.);
+ assert(expoly.holes.size() + 1 == deltas.size());
+#endif /* NDEBUG */
+
+ // 1) Offset the outer contour.
+ ClipperLib::Paths contours = fix_after_inner_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftNegative, false);
+
+ // 2) Offset the holes one by one, collect the results.
+ ClipperLib::Paths holes;
+ holes.reserve(expoly.holes.size());
+ for (const Polygon& hole : expoly.holes)
+ append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, true));
+
+ // 3) Subtract holes from the contours.
+ unscaleClipperPolygons(contours);
+ ExPolygons output;
+ if (holes.empty()) {
+ output.reserve(contours.size());
+ for (ClipperLib::Path &path : contours)
+ output.emplace_back(ClipperPath_to_Slic3rPolygon(path));
+ } else {
+ ClipperLib::Clipper clipper;
+ unscaleClipperPolygons(holes);
+ clipper.AddPaths(contours, ClipperLib::ptSubject, true);
+ clipper.AddPaths(holes, ClipperLib::ptClip, true);
+ ClipperLib::PolyTree polytree;
+ clipper.Execute(ClipperLib::ctDifference, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
+ output = PolyTreeToExPolygons(polytree);
+ }
+
+ return output;
+}
+
}
diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp
index d8f8a8f94..5a41a6a90 100644
--- a/src/libslic3r/ClipperUtils.hpp
+++ b/src/libslic3r/ClipperUtils.hpp
@@ -238,6 +238,11 @@ void safety_offset(ClipperLib::Paths* paths);
Polygons top_level_islands(const Slic3r::Polygons &polygons);
+Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
+Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
+ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
+ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
+
}
#endif
diff --git a/src/libslic3r/EdgeGrid.cpp b/src/libslic3r/EdgeGrid.cpp
index a97210da6..52ac4a0aa 100644
--- a/src/libslic3r/EdgeGrid.cpp
+++ b/src/libslic3r/EdgeGrid.cpp
@@ -113,6 +113,7 @@ void EdgeGrid::Grid::create(const ExPolygonCollection &expolygons, coord_t resol
// m_contours has been initialized. Now fill in the edge grid.
void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
{
+ assert(resolution > 0);
// 1) Measure the bounding box.
for (size_t i = 0; i < m_contours.size(); ++ i) {
const Slic3r::Points &pts = *m_contours[i];
@@ -281,7 +282,11 @@ void EdgeGrid::Grid::create_from_m_contours(coord_t resolution)
Visitor(std::vector<std::pair<size_t, size_t>> &cell_data, std::vector<Cell> &cells, size_t cols) :
cell_data(cell_data), cells(cells), cols(cols), i(0), j(0) {}
- void operator()(coord_t iy, coord_t ix) { cell_data[cells[iy*cols + ix].end++] = std::pair<size_t, size_t>(i, j); }
+ inline bool operator()(coord_t iy, coord_t ix) {
+ cell_data[cells[iy*cols + ix].end++] = std::pair<size_t, size_t>(i, j);
+ // Continue traversing the grid along the edge.
+ return true;
+ }
std::vector<std::pair<size_t, size_t>> &cell_data;
std::vector<Cell> &cells;
@@ -1017,8 +1022,139 @@ float EdgeGrid::Grid::signed_distance_bilinear(const Point &pt) const
return f;
}
-
-bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radius, coordf_t &result_min_dist, bool *pon_segment) const {
+
+EdgeGrid::Grid::ClosestPointResult EdgeGrid::Grid::closest_point(const Point &pt, coord_t search_radius) const
+{
+ BoundingBox bbox;
+ bbox.min = bbox.max = Point(pt(0) - m_bbox.min(0), pt(1) - m_bbox.min(1));
+ bbox.defined = true;
+ // Upper boundary, round to grid and test validity.
+ bbox.max(0) += search_radius;
+ bbox.max(1) += search_radius;
+ ClosestPointResult result;
+ if (bbox.max(0) < 0 || bbox.max(1) < 0)
+ return result;
+ bbox.max(0) /= m_resolution;
+ bbox.max(1) /= m_resolution;
+ if ((size_t)bbox.max(0) >= m_cols)
+ bbox.max(0) = m_cols - 1;
+ if ((size_t)bbox.max(1) >= m_rows)
+ bbox.max(1) = m_rows - 1;
+ // Lower boundary, round to grid and test validity.
+ bbox.min(0) -= search_radius;
+ bbox.min(1) -= search_radius;
+ if (bbox.min(0) < 0)
+ bbox.min(0) = 0;
+ if (bbox.min(1) < 0)
+ bbox.min(1) = 0;
+ bbox.min(0) /= m_resolution;
+ bbox.min(1) /= m_resolution;
+ // Is the interval empty?
+ if (bbox.min(0) > bbox.max(0) ||
+ bbox.min(1) > bbox.max(1))
+ return result;
+ // Traverse all cells in the bounding box.
+ double d_min = double(search_radius);
+ // Signum of the distance field at pt.
+ int sign_min = 0;
+ double l2_seg_min = 1.;
+ for (int r = bbox.min(1); r <= bbox.max(1); ++ r) {
+ for (int c = bbox.min(0); c <= bbox.max(0); ++ c) {
+ const Cell &cell = m_cells[r * m_cols + c];
+ for (size_t i = cell.begin; i < cell.end; ++ i) {
+ const size_t contour_idx = m_cell_data[i].first;
+ const Slic3r::Points &pts = *m_contours[contour_idx];
+ size_t ipt = m_cell_data[i].second;
+ // End points of the line segment.
+ const Slic3r::Point &p1 = pts[ipt];
+ const Slic3r::Point &p2 = pts[(ipt + 1 == pts.size()) ? 0 : ipt + 1];
+ const Slic3r::Point v_seg = p2 - p1;
+ const Slic3r::Point v_pt = pt - p1;
+ // dot(p2-p1, pt-p1)
+ int64_t t_pt = int64_t(v_seg(0)) * int64_t(v_pt(0)) + int64_t(v_seg(1)) * int64_t(v_pt(1));
+ // l2 of seg
+ int64_t l2_seg = int64_t(v_seg(0)) * int64_t(v_seg(0)) + int64_t(v_seg(1)) * int64_t(v_seg(1));
+ if (t_pt < 0) {
+ // Closest to p1.
+ double dabs = sqrt(int64_t(v_pt(0)) * int64_t(v_pt(0)) + int64_t(v_pt(1)) * int64_t(v_pt(1)));
+ if (dabs < d_min) {
+ // Previous point.
+ const Slic3r::Point &p0 = pts[(ipt == 0) ? (pts.size() - 1) : ipt - 1];
+ Slic3r::Point v_seg_prev = p1 - p0;
+ int64_t t2_pt = int64_t(v_seg_prev(0)) * int64_t(v_pt(0)) + int64_t(v_seg_prev(1)) * int64_t(v_pt(1));
+ if (t2_pt > 0) {
+ // Inside the wedge between the previous and the next segment.
+ d_min = dabs;
+ // Set the signum depending on whether the vertex is convex or reflex.
+ int64_t det = int64_t(v_seg_prev(0)) * int64_t(v_seg(1)) - int64_t(v_seg_prev(1)) * int64_t(v_seg(0));
+ assert(det != 0);
+ sign_min = (det > 0) ? 1 : -1;
+ result.contour_idx = contour_idx;
+ result.start_point_idx = ipt;
+ result.t = 0.;
+#ifndef NDEBUG
+ Vec2d vfoot = (p1 - pt).cast<double>();
+ double dist_foot = vfoot.norm();
+ double dist_foot_err = dist_foot - d_min;
+ assert(std::abs(dist_foot_err) < 1e-7 * d_min);
+#endif /* NDEBUG */
+ }
+ }
+ }
+ else if (t_pt > l2_seg) {
+ // Closest to p2. Then p2 is the starting point of another segment, which shall be discovered in the same cell.
+ continue;
+ } else {
+ // Closest to the segment.
+ assert(t_pt >= 0 && t_pt <= l2_seg);
+ int64_t d_seg = int64_t(v_seg(1)) * int64_t(v_pt(0)) - int64_t(v_seg(0)) * int64_t(v_pt(1));
+ double d = double(d_seg) / sqrt(double(l2_seg));
+ double dabs = std::abs(d);
+ if (dabs < d_min) {
+ d_min = dabs;
+ sign_min = (d_seg < 0) ? -1 : ((d_seg == 0) ? 0 : 1);
+ l2_seg_min = l2_seg;
+ result.contour_idx = contour_idx;
+ result.start_point_idx = ipt;
+ result.t = t_pt;
+#ifndef NDEBUG
+ Vec2d foot = p1.cast<double>() * (1. - result.t / l2_seg_min) + p2.cast<double>() * (result.t / l2_seg_min);
+ Vec2d vfoot = foot - pt.cast<double>();
+ double dist_foot = vfoot.norm();
+ double dist_foot_err = dist_foot - d_min;
+ assert(std::abs(dist_foot_err) < 1e-7 * d_min);
+#endif /* NDEBUG */
+ }
+ }
+ }
+ }
+ }
+ if (result.contour_idx != -1 && d_min <= double(search_radius)) {
+ result.distance = d_min * sign_min;
+ result.t /= l2_seg_min;
+ assert(result.t >= 0. && result.t < 1.);
+#ifndef NDEBUG
+ {
+ const Slic3r::Points &pts = *m_contours[result.contour_idx];
+ const Slic3r::Point &p1 = pts[result.start_point_idx];
+ const Slic3r::Point &p2 = pts[(result.start_point_idx + 1 == pts.size()) ? 0 : result.start_point_idx + 1];
+ Vec2d vfoot;
+ if (result.t == 0)
+ vfoot = p1.cast<double>() - pt.cast<double>();
+ else
+ vfoot = p1.cast<double>() * (1. - result.t) + p2.cast<double>() * result.t - pt.cast<double>();
+ double dist_foot = vfoot.norm();
+ double dist_foot_err = dist_foot - std::abs(result.distance);
+ assert(std::abs(dist_foot_err) < 1e-7 * std::abs(result.distance));
+ }
+#endif /* NDEBUG */
+ } else
+ result = ClosestPointResult();
+ return result;
+}
+
+bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radius, coordf_t &result_min_dist, bool *pon_segment) const
+{
BoundingBox bbox;
bbox.min = bbox.max = Point(pt(0) - m_bbox.min(0), pt(1) - m_bbox.min(1));
bbox.defined = true;
@@ -1047,7 +1183,7 @@ bool EdgeGrid::Grid::signed_distance_edges(const Point &pt, coord_t search_radiu
bbox.min(1) > bbox.max(1))
return false;
// Traverse all cells in the bounding box.
- float d_min = search_radius;
+ double d_min = double(search_radius);
// Signum of the distance field at pt.
int sign_min = 0;
bool on_segment = false;
diff --git a/src/libslic3r/EdgeGrid.hpp b/src/libslic3r/EdgeGrid.hpp
index cad20e07b..92cee8362 100644
--- a/src/libslic3r/EdgeGrid.hpp
+++ b/src/libslic3r/EdgeGrid.hpp
@@ -25,6 +25,8 @@ public:
void create(const ExPolygons &expolygons, coord_t resolution);
void create(const ExPolygonCollection &expolygons, coord_t resolution);
+ const std::vector<const Slic3r::Points*>& contours() const { return m_contours; }
+
#if 0
// Test, whether the edges inside the grid intersect with the polygons provided.
bool intersect(const MultiPoint &polyline, bool closed);
@@ -46,7 +48,19 @@ public:
float signed_distance_bilinear(const Point &pt) const;
// Calculate a signed distance to the contours in search_radius from the point.
- bool signed_distance_edges(const Point &pt, coord_t search_radius, coordf_t &result_min_dist, bool *pon_segment = NULL) const;
+ struct ClosestPointResult {
+ size_t contour_idx = size_t(-1);
+ size_t start_point_idx = size_t(-1);
+ // Signed distance to the closest point.
+ double distance = std::numeric_limits<double>::max();
+ // Parameter of the closest point on edge starting with start_point_idx <0, 1)
+ double t = 0.;
+
+ bool valid() const { return contour_idx != size_t(-1); }
+ };
+ ClosestPointResult closest_point(const Point &pt, coord_t search_radius) const;
+
+ bool signed_distance_edges(const Point &pt, coord_t search_radius, coordf_t &result_min_dist, bool *pon_segment = nullptr) const;
// Calculate a signed distance to the contours in search_radius from the point. If no edge is found in search_radius,
// return an interpolated value from m_signed_distance_field, if it exists.
@@ -65,7 +79,7 @@ public:
std::vector<std::pair<ContourEdge, ContourEdge>> intersecting_edges() const;
bool has_intersecting_edges() const;
- template<typename FUNCTION> void visit_cells_intersecting_line(Slic3r::Point p1, Slic3r::Point p2, FUNCTION func) const
+ template<typename VISITOR> void visit_cells_intersecting_line(Slic3r::Point p1, Slic3r::Point p2, VISITOR &visitor) const
{
// End points of the line segment.
p1(0) -= m_bbox.min(0);
@@ -82,8 +96,7 @@ public:
assert(ixb >= 0 && size_t(ixb) < m_cols);
assert(iyb >= 0 && size_t(iyb) < m_rows);
// Account for the end points.
- func(iy, ix);
- if (ix == ixb && iy == iyb)
+ if (! visitor(iy, ix) || (ix == ixb && iy == iyb))
// Both ends fall into the same cell.
return;
// Raster the centeral part of the line.
@@ -113,7 +126,8 @@ public:
ey = int64_t(dx) * m_resolution;
iy += 1;
}
- func(iy, ix);
+ if (! visitor(iy, ix))
+ return;
} while (ix != ixb || iy != iyb);
}
else {
@@ -131,7 +145,8 @@ public:
ey = int64_t(dx) * m_resolution;
iy -= 1;
}
- func(iy, ix);
+ if (! visitor(iy, ix))
+ return;
} while (ix != ixb || iy != iyb);
}
}
@@ -153,7 +168,8 @@ public:
ey = int64_t(dx) * m_resolution;
iy += 1;
}
- func(iy, ix);
+ if (! visitor(iy, ix))
+ return;
} while (ix != ixb || iy != iyb);
}
else {
@@ -185,7 +201,8 @@ public:
ey = int64_t(dx) * m_resolution;
iy -= 1;
}
- func(iy, ix);
+ if (! visitor(iy, ix))
+ return;
} while (ix != ixb || iy != iyb);
}
}
diff --git a/src/libslic3r/ElephantFootCompensation.cpp b/src/libslic3r/ElephantFootCompensation.cpp
new file mode 100644
index 000000000..5bdeaa954
--- /dev/null
+++ b/src/libslic3r/ElephantFootCompensation.cpp
@@ -0,0 +1,321 @@
+#include "clipper/clipper_z.hpp"
+
+#include "libslic3r.h"
+#include "ClipperUtils.hpp"
+#include "EdgeGrid.hpp"
+#include "ExPolygon.hpp"
+#include "ElephantFootCompensation.hpp"
+#include "Flow.hpp"
+#include "Geometry.hpp"
+#include "SVG.hpp"
+
+#include <cmath>
+#include <cassert>
+
+// #define CONTOUR_DISTANCE_DEBUG_SVG
+
+namespace Slic3r {
+
+struct ResampledPoint {
+ ResampledPoint(size_t idx_src, bool interpolated, double curve_parameter) : idx_src(idx_src), interpolated(interpolated), curve_parameter(curve_parameter) {}
+
+ size_t idx_src;
+ // Is this point interpolated or initial?
+ bool interpolated;
+ // Euclidean distance along the curve from the 0th point.
+ double curve_parameter;
+};
+
+std::vector<float> contour_distance(const EdgeGrid::Grid &grid, const size_t idx_contour, const Slic3r::Points &contour, const std::vector<ResampledPoint> &resampled_point_parameters, double search_radius)
+{
+ assert(! contour.empty());
+ assert(contour.size() >= 2);
+
+ std::vector<float> out;
+
+ if (contour.size() > 2)
+ {
+#ifdef CONTOUR_DISTANCE_DEBUG_SVG
+ static int iRun = 0;
+ ++ iRun;
+ BoundingBox bbox = get_extents(contour);
+ bbox.merge(grid.bbox());
+ ExPolygon expoly_grid;
+ expoly_grid.contour = Polygon(*grid.contours().front());
+ for (size_t i = 1; i < grid.contours().size(); ++ i)
+ expoly_grid.holes.emplace_back(Polygon(*grid.contours()[i]));
+#endif
+ struct Visitor {
+ Visitor(const EdgeGrid::Grid &grid, const size_t idx_contour, const std::vector<ResampledPoint> &resampled_point_parameters, double dist_same_contour_reject) :
+ grid(grid), idx_contour(idx_contour), resampled_point_parameters(resampled_point_parameters), dist_same_contour_reject(dist_same_contour_reject) {}
+
+ void init(const size_t aidx_point_start, const Point &apt_start, Vec2d dir, const double radius) {
+ this->idx_point_start = aidx_point_start;
+ this->pt = apt_start.cast<double>() + SCALED_EPSILON * dir;
+ dir *= radius;
+ this->pt_start = this->pt.cast<coord_t>();
+ // Trim the vector by the grid's bounding box.
+ const BoundingBox &bbox = this->grid.bbox();
+ double t = 1.;
+ for (size_t axis = 0; axis < 2; ++ axis) {
+ double dx = std::abs(dir(axis));
+ if (dx >= EPSILON) {
+ double tedge = (dir(axis) > 0) ? (double(bbox.max(axis)) - EPSILON - this->pt(axis)) : (this->pt(axis) - double(bbox.min(axis)) - EPSILON);
+ if (tedge < dx)
+ t = tedge / dx;
+ }
+ }
+ this->dir = dir;
+ if (t < 1.)
+ dir *= t;
+ this->pt_end = (this->pt + dir).cast<coord_t>();
+ this->t_min = 1.;
+ }
+
+ bool operator()(coord_t iy, coord_t ix) {
+ // Called with a row and colum of the grid cell, which is intersected by a line.
+ auto cell_data_range = this->grid.cell_data_range(iy, ix);
+ bool valid = true;
+ for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++ it_contour_and_segment) {
+ // End points of the line segment and their vector.
+ auto segment = this->grid.segment(*it_contour_and_segment);
+ if (Geometry::segments_intersect(segment.first, segment.second, this->pt_start, this->pt_end)) {
+ // The two segments intersect. Calculate the intersection.
+ Vec2d pt2 = segment.first.cast<double>();
+ Vec2d dir2 = segment.second.cast<double>() - pt2;
+ Vec2d vptpt2 = pt - pt2;
+ double denom = dir(0) * dir2(1) - dir2(0) * dir(1);
+
+ if (std::abs(denom) >= EPSILON) {
+ double t = cross2(dir2, vptpt2) / denom;
+ assert(t > 0. && t <= 1.);
+ bool this_valid = true;
+ if (it_contour_and_segment->first == idx_contour) {
+ // The intersected segment originates from the same contour as the starting point.
+ // Reject the intersection if it is close to the starting point.
+ // Find the start and end points of this segment
+ double param_lo = resampled_point_parameters[idx_point_start].curve_parameter;
+ double param_hi;
+ double param_end = resampled_point_parameters.back().curve_parameter;
+ {
+ const Slic3r::Points &ipts = *grid.contours()[it_contour_and_segment->first];
+ size_t ipt = it_contour_and_segment->second;
+ ResampledPoint key(ipt, false, 0.);
+ auto lower = [](const ResampledPoint& l, const ResampledPoint r) { return l.idx_src < r.idx_src || (l.idx_src == r.idx_src && int(l.interpolated) > int(r.interpolated)); };
+ auto it = std::lower_bound(resampled_point_parameters.begin(), resampled_point_parameters.end(), key, lower);
+ assert(it != resampled_point_parameters.end() && it->idx_src == ipt && ! it->interpolated);
+ double t2 = cross2(dir, vptpt2) / denom;
+ assert(t2 >= 0. && t2 <= 1.);
+ if (++ ipt == ipts.size())
+ param_hi = t2 * dir2.norm();
+ else
+ param_hi = it->curve_parameter + t2 * dir2.norm();
+ }
+ if (param_lo > param_hi)
+ std::swap(param_lo, param_hi);
+ assert(param_lo >= 0. && param_lo <= param_end);
+ assert(param_hi >= 0. && param_hi <= param_end);
+ this_valid = param_hi > param_lo + dist_same_contour_reject && param_hi - param_end < param_lo - dist_same_contour_reject;
+ }
+ if (t < this->t_min) {
+ this->t_min = t;
+ valid = this_valid;
+ }
+ }
+ }
+ if (! valid)
+ this->t_min = 1.;
+ }
+ // Continue traversing the grid along the edge.
+ return true;
+ }
+
+ const EdgeGrid::Grid &grid;
+ const size_t idx_contour;
+ const std::vector<ResampledPoint> &resampled_point_parameters;
+ const double dist_same_contour_reject;
+
+ size_t idx_point_start;
+ Point pt_start;
+ Point pt_end;
+ Vec2d pt;
+ Vec2d dir;
+ // Minium parameter along the vector (pt_end - pt_start).
+ double t_min;
+ } visitor(grid, idx_contour, resampled_point_parameters, search_radius);
+
+ const Point *pt_this = &contour.back();
+ size_t idx_pt_this = contour.size() - 1;
+ const Point *pt_prev = pt_this - 1;
+ // perpenduclar vector
+ auto perp = [](const Vec2d& v) -> Vec2d { return Vec2d(v.y(), -v.x()); };
+ Vec2d vprev = (*pt_this - *pt_prev).cast<double>().normalized();
+ out.reserve(contour.size() + 1);
+ for (const Point &pt_next : contour) {
+ Vec2d vnext = (pt_next - *pt_this).cast<double>().normalized();
+ Vec2d dir = - (perp(vprev) + perp(vnext)).normalized();
+ Vec2d dir_perp = perp(dir);
+ double cross = cross2(vprev, vnext);
+ double dot = vprev.dot(vnext);
+ double a = (cross < 0 || dot > 0.5) ? (M_PI / 3.) : (0.48 * acos(std::min(1., - dot)));
+ // Throw rays, collect distances.
+ std::vector<double> distances;
+ int num_rays = 15;
+
+#ifdef CONTOUR_DISTANCE_DEBUG_SVG
+ SVG svg(debug_out_path("contour_distance_raycasted-%d-%d.svg", iRun, &pt_next - contour.data()).c_str(), bbox);
+ svg.draw(expoly_grid);
+ svg.draw_outline(Polygon(contour), "blue", scale_(0.01));
+ svg.draw(*pt_this, "red", scale_(0.1));
+#endif /* CONTOUR_DISTANCE_DEBUG_SVG */
+
+ for (int i = - num_rays + 1; i < num_rays; ++ i) {
+ double angle = a * i / (int)num_rays;
+ double c = cos(angle);
+ double s = sin(angle);
+ Vec2d v = c * dir + s * dir_perp;
+ visitor.init(idx_pt_this, *pt_this, v, search_radius);
+ grid.visit_cells_intersecting_line(visitor.pt_start, visitor.pt_end, visitor);
+ distances.emplace_back(visitor.t_min);
+#ifdef CONTOUR_DISTANCE_DEBUG_SVG
+ svg.draw(Line(visitor.pt_start, visitor.pt_end), "yellow", scale_(0.01));
+ if (visitor.t_min < 1.) {
+ Vec2d pt = visitor.pt + visitor.dir * visitor.t_min;
+ svg.draw(Point(pt), "red", scale_(0.1));
+ }
+#endif /* CONTOUR_DISTANCE_DEBUG_SVG */
+ }
+#ifdef CONTOUR_DISTANCE_DEBUG_SVG
+ svg.Close();
+#endif /* CONTOUR_DISTANCE_DEBUG_SVG */
+ std::sort(distances.begin(), distances.end());
+#if 0
+ double median = distances[distances.size() / 2];
+ double standard_deviation = 0;
+ for (double d : distances)
+ standard_deviation += (d - median) * (d - median);
+ standard_deviation = sqrt(standard_deviation / (distances.size() - 1));
+ double avg = 0;
+ size_t cnt = 0;
+ for (double d : distances)
+ if (d > median - standard_deviation - EPSILON && d < median + standard_deviation + EPSILON) {
+ avg += d;
+ ++ cnt;
+ }
+ avg /= double(cnt);
+ out.emplace_back(float(avg * search_radius));
+#else
+ out.emplace_back(float(distances.front() * search_radius));
+#endif
+#ifdef CONTOUR_DISTANCE_DEBUG_SVG
+ printf("contour_distance_raycasted-%d-%d.svg - distance %lf\n", iRun, &pt_next - contour.data(), unscale<double>(out.back()));
+#endif /* CONTOUR_DISTANCE_DEBUG_SVG */
+ pt_this = &pt_next;
+ idx_pt_this = &pt_next - contour.data();
+ vprev = vnext;
+ }
+ // Rotate the vector by one item.
+ out.emplace_back(out.front());
+ out.erase(out.begin());
+ }
+
+ return out;
+}
+
+Points resample_polygon(const Points &contour, double dist, std::vector<ResampledPoint> &resampled_point_parameters)
+{
+ Points out;
+ out.reserve(contour.size());
+ resampled_point_parameters.reserve(contour.size());
+ if (contour.size() > 2) {
+ Vec2d pt_prev = contour.back().cast<double>();
+ for (const Point &pt : contour) {
+ size_t idx_this = &pt - contour.data();
+ const Vec2d pt_this = pt.cast<double>();
+ const Vec2d v = pt_this - pt_prev;
+ const double l = v.norm();
+ const size_t n = size_t(ceil(l / dist));
+ const double l_step = l / n;
+ for (size_t i = 1; i < n; ++ i) {
+ double interpolation_parameter = double(i) / n;
+ Vec2d new_pt = pt_prev + v * interpolation_parameter;
+ out.emplace_back(new_pt.cast<coord_t>());
+ resampled_point_parameters.emplace_back(idx_this, true, l_step);
+ }
+ out.emplace_back(pt);
+ resampled_point_parameters.emplace_back(idx_this, false, l_step);
+ pt_prev = pt_this;
+ }
+ for (size_t i = 1; i < resampled_point_parameters.size(); ++i)
+ resampled_point_parameters[i].curve_parameter += resampled_point_parameters[i - 1].curve_parameter;
+ }
+ return out;
+}
+
+static inline void smooth_compensation(std::vector<float> &compensation, float strength, size_t num_iterations)
+{
+ std::vector<float> out(compensation);
+ for (size_t iter = 0; iter < num_iterations; ++ iter) {
+ for (size_t i = 0; i < compensation.size(); ++ i) {
+ float prev = (i == 0) ? compensation.back() : compensation[i - 1];
+ float next = (i + 1 == compensation.size()) ? compensation.front() : compensation[i + 1];
+ float laplacian = compensation[i] * (1.f - strength) + 0.5f * strength * (prev + next);
+ // Compensations are negative. Only apply the laplacian if it leads to lower compensation.
+ out[i] = std::max(laplacian, compensation[i]);
+ }
+ out.swap(compensation);
+ }
+}
+
+ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow &external_perimeter_flow, const double compensation)
+{
+ // The contour shall be wide enough to apply the external perimeter plus compensation on both sides.
+ double min_contour_width = double(external_perimeter_flow.scaled_width() + external_perimeter_flow.scaled_spacing());
+ double scaled_compensation = scale_(compensation);
+ double min_contour_width_compensated = min_contour_width + 2. * scaled_compensation;
+ // Make the search radius a bit larger for the averaging in contour_distance over a fan of rays to work.
+ double search_radius = min_contour_width_compensated + min_contour_width * 0.5;
+
+ EdgeGrid::Grid grid;
+ ExPolygon simplified = input_expoly.simplify(SCALED_EPSILON).front();
+ BoundingBox bbox = get_extents(simplified.contour);
+ bbox.offset(SCALED_EPSILON);
+ grid.set_bbox(bbox);
+ grid.create(simplified, coord_t(0.7 * search_radius));
+ std::vector<std::vector<float>> deltas;
+ deltas.reserve(simplified.holes.size() + 1);
+ ExPolygon resampled(simplified);
+ for (size_t idx_contour = 0; idx_contour <= simplified.holes.size(); ++ idx_contour) {
+ Polygon &poly = (idx_contour == 0) ? resampled.contour : resampled.holes[idx_contour - 1];
+ std::vector<ResampledPoint> resampled_point_parameters;
+ poly.points = resample_polygon(poly.points, scale_(0.5), resampled_point_parameters);
+ std::vector<float> dists = contour_distance(grid, idx_contour, poly.points, resampled_point_parameters, search_radius);
+ for (float &d : dists) {
+// printf("Point %d, Distance: %lf\n", int(&d - dists.data()), unscale<double>(d));
+ // Convert contour width to available compensation distance.
+ if (d < min_contour_width)
+ d = 0.f;
+ else if (d > min_contour_width_compensated)
+ d = - float(scaled_compensation);
+ else
+ d = - (d - float(min_contour_width)) / 2.f;
+ assert(d >= - float(scaled_compensation) && d <= 0.f);
+ }
+ smooth_compensation(dists, 0.4f, 10);
+ deltas.emplace_back(dists);
+ }
+
+ ExPolygons out = variable_offset_inner_ex(resampled, deltas, 2.);
+ return out.front();
+}
+
+ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &external_perimeter_flow, const double compensation)
+{
+ ExPolygons out;
+ out.reserve(input.size());
+ for (const ExPolygon &expoly : input)
+ out.emplace_back(elephant_foot_compensation(expoly, external_perimeter_flow, compensation));
+ return out;
+}
+
+} // namespace Slic3r
diff --git a/src/libslic3r/ElephantFootCompensation.hpp b/src/libslic3r/ElephantFootCompensation.hpp
new file mode 100644
index 000000000..0119df1af
--- /dev/null
+++ b/src/libslic3r/ElephantFootCompensation.hpp
@@ -0,0 +1,16 @@
+#ifndef slic3r_ElephantFootCompensation_hpp_
+#define slic3r_ElephantFootCompensation_hpp_
+
+#include "libslic3r.h"
+#include <vector>
+
+namespace Slic3r {
+
+class Flow;
+
+ExPolygon elephant_foot_compensation(const ExPolygon &input, const Flow &external_perimeter_flow, const double compensation);
+ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &external_perimeter_flow, const double compensation);
+
+} // Slic3r
+
+#endif /* slic3r_ElephantFootCompensation_hpp_ */
diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp
index c510b848f..7833c9c91 100644
--- a/src/libslic3r/ExPolygon.hpp
+++ b/src/libslic3r/ExPolygon.hpp
@@ -28,6 +28,8 @@ public:
explicit ExPolygon(Polygon &&contour, Polygon &&hole) : contour(std::move(contour)) { holes.emplace_back(std::move(hole)); }
explicit ExPolygon(const Points &contour, const Points &hole) : contour(contour) { holes.emplace_back(hole); }
explicit ExPolygon(Points &&contour, Polygon &&hole) : contour(std::move(contour)) { holes.emplace_back(std::move(hole)); }
+ ExPolygon(std::initializer_list<Point> contour) : contour(contour) {}
+ ExPolygon(std::initializer_list<Point> contour, std::initializer_list<Point> hole) : contour(contour), holes({ hole }) {}
ExPolygon& operator=(const ExPolygon &other) { contour = other.contour; holes = other.holes; return *this; }
ExPolygon& operator=(ExPolygon &&other) { contour = std::move(other.contour); holes = std::move(other.holes); return *this; }
@@ -77,6 +79,9 @@ public:
Lines lines() const;
};
+inline bool operator==(const ExPolygon &lhs, const ExPolygon &rhs) { return lhs.contour == rhs.contour && lhs.holes == rhs.holes; }
+inline bool operator!=(const ExPolygon &lhs, const ExPolygon &rhs) { return lhs.contour != rhs.contour || lhs.holes != rhs.holes; }
+
// Count a nuber of polygons stored inside the vector of expolygons.
// Useful for allocating space for polygons when converting expolygons to polygons.
inline size_t number_polygons(const ExPolygons &expolys)
@@ -301,6 +306,15 @@ inline bool expolygons_contain(ExPolygons &expolys, const Point &pt)
return false;
}
+inline ExPolygons expolygons_simplify(const ExPolygons &expolys, double tolerance)
+{
+ ExPolygons out;
+ out.reserve(expolys.size());
+ for (const ExPolygon &exp : expolys)
+ exp.simplify(tolerance, &out);
+ return out;
+}
+
extern BoundingBox get_extents(const ExPolygon &expolygon);
extern BoundingBox get_extents(const ExPolygons &expolygons);
extern BoundingBox get_extents_rotated(const ExPolygon &poly, double angle);
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index 2d77d3daa..181d6cb99 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -584,8 +584,16 @@ void AMFParserContext::endElement(const char * /* name */)
stl_get_size(&stl);
mesh.repair();
m_volume->set_mesh(std::move(mesh));
- // pass false if the mesh offset has been already taken from the data
- m_volume->center_geometry_after_creation(m_volume->source.input_file.empty());
+ if (m_volume->source.input_file.empty() && (m_volume->type() == ModelVolumeType::MODEL_PART))
+ {
+ m_volume->source.object_idx = (int)m_model.objects.size() - 1;
+ m_volume->source.volume_idx = (int)m_model.objects.back()->volumes.size() - 1;
+ m_volume->center_geometry_after_creation();
+ }
+ else
+ // pass false if the mesh offset has been already taken from the data
+ m_volume->center_geometry_after_creation(m_volume->source.input_file.empty());
+
m_volume->calculate_convex_hull();
m_volume_facets.clear();
m_volume = nullptr;
@@ -799,6 +807,15 @@ bool load_amf_file(const char *path, DynamicPrintConfig *config, Model *model)
if (result)
ctx.endDocument();
+ for (ModelObject* o : model->objects)
+ {
+ for (ModelVolume* v : o->volumes)
+ {
+ if (v->source.input_file.empty() && (v->type() == ModelVolumeType::MODEL_PART))
+ v->source.input_file = path;
+ }
+ }
+
return result;
}
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index f3fe802cc..2a74de41d 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -543,7 +543,7 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
//FIXME should we use the printing extruders instead?
double gap_over_supports = object.config().support_material_contact_distance;
// FIXME should we test object.config().support_material_synchronize_layers ? Currently the support layers are synchronized with object layers iff soluble supports.
- assert(gap_over_supports != 0. || object.config().support_material_synchronize_layers);
+ assert(! object.config().support_material || gap_over_supports != 0. || object.config().support_material_synchronize_layers);
if (gap_over_supports != 0.) {
gap_over_supports = std::max(0., gap_over_supports);
// Not a soluble support,
@@ -778,22 +778,26 @@ void GCode::_do_export(Print &print, FILE *file)
{
m_silent_time_estimator.reset();
m_silent_time_estimator.set_dialect(print.config().gcode_flavor);
- m_silent_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values[1]);
- m_silent_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values[1]);
- m_silent_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values[1]);
- m_silent_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values[1]);
- m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values[1]);
- m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values[1]);
- m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values[1]);
- m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values[1]);
- m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values[1]);
- m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values[1]);
- m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values[1]);
- m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values[1]);
- m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values[1]);
- m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values[1]);
- m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values[1]);
- m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values[1]);
+ /* "Stealth mode" values can be just a copy of "normal mode" values
+ * (when they aren't input for a printer preset).
+ * Thus, use back value from values, instead of second one, which could be absent
+ */
+ m_silent_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values.back());
+ m_silent_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values.back());
+ m_silent_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values.back());
+ m_silent_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values.back());
+ m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values.back());
+ m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values.back());
+ m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values.back());
+ m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values.back());
+ m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values.back());
+ m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values.back());
+ m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values.back());
+ m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values.back());
+ m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values.back());
+ m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values.back());
+ m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values.back());
+ m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values.back());
if (print.config().single_extruder_multi_material) {
// As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
// are considered to be active for the single extruder multi-material printers only.
diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp
index 78f6c6806..3f0b8735f 100644
--- a/src/libslic3r/GCode/Analyzer.cpp
+++ b/src/libslic3r/GCode/Analyzer.cpp
@@ -285,6 +285,11 @@ void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLi
_processM108orM135(line);
break;
}
+ case 132: // Recall stored home offsets
+ {
+ _processM132(line);
+ break;
+ }
case 401: // Repetier: Store x, y and z position
{
_processM401(line);
@@ -504,6 +509,25 @@ void GCodeAnalyzer::_processM108orM135(const GCodeReader::GCodeLine& line)
}
}
+void GCodeAnalyzer::_processM132(const GCodeReader::GCodeLine& line)
+{
+ // This command is used by Makerbot to load the current home position from EEPROM
+ // see: https://github.com/makerbot/s3g/blob/master/doc/GCodeProtocol.md
+ // Using this command to reset the axis origin to zero helps in fixing: https://github.com/prusa3d/PrusaSlicer/issues/3082
+
+ if (line.has_x())
+ _set_axis_origin(X, 0.0f);
+
+ if (line.has_y())
+ _set_axis_origin(Y, 0.0f);
+
+ if (line.has_z())
+ _set_axis_origin(Z, 0.0f);
+
+ if (line.has_e())
+ _set_axis_origin(E, 0.0f);
+}
+
void GCodeAnalyzer::_processM401(const GCodeReader::GCodeLine& line)
{
if (m_gcode_flavor != gcfRepetier)
diff --git a/src/libslic3r/GCode/Analyzer.hpp b/src/libslic3r/GCode/Analyzer.hpp
index e90175c49..df4f6f652 100644
--- a/src/libslic3r/GCode/Analyzer.hpp
+++ b/src/libslic3r/GCode/Analyzer.hpp
@@ -182,6 +182,9 @@ private:
// Set tool (MakerWare and Sailfish flavor)
void _processM108orM135(const GCodeReader::GCodeLine& line);
+ // Recall stored home offsets
+ void _processM132(const GCodeReader::GCodeLine& line);
+
// Repetier: Store x, y and z position
void _processM401(const GCodeReader::GCodeLine& line);
diff --git a/src/libslic3r/GCode/SpiralVase.hpp b/src/libslic3r/GCode/SpiralVase.hpp
index 7872b1d3c..e35ca640c 100644
--- a/src/libslic3r/GCode/SpiralVase.hpp
+++ b/src/libslic3r/GCode/SpiralVase.hpp
@@ -1,8 +1,8 @@
#ifndef slic3r_SpiralVase_hpp_
#define slic3r_SpiralVase_hpp_
-#include "libslic3r.h"
-#include "GCodeReader.hpp"
+#include "../libslic3r.h"
+#include "../GCodeReader.hpp"
namespace Slic3r {
diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp
index b464a39b8..73dc91c40 100644
--- a/src/libslic3r/GCode/WipeTower.cpp
+++ b/src/libslic3r/GCode/WipeTower.cpp
@@ -331,15 +331,18 @@ public:
// Let the firmware back up the active speed override value.
WipeTowerWriter& speed_override_backup()
- {
- m_gcode += "M220 B\n";
+ {
+ // This is only supported by Prusa at this point (https://github.com/prusa3d/PrusaSlicer/issues/3114)
+ if (m_gcode_flavor == gcfMarlin)
+ m_gcode += "M220 B\n";
return *this;
}
// Let the firmware restore the active speed override value.
WipeTowerWriter& speed_override_restore()
{
- m_gcode += "M220 R\n";
+ if (m_gcode_flavor == gcfMarlin)
+ m_gcode += "M220 R\n";
return *this;
}
diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp
index e926b9997..46d7ef154 100644
--- a/src/libslic3r/Geometry.cpp
+++ b/src/libslic3r/Geometry.cpp
@@ -663,7 +663,6 @@ namespace Voronoi { namespace Internal {
typedef boost::polygon::point_data<coordinate_type> point_type;
typedef boost::polygon::segment_data<coordinate_type> segment_type;
typedef boost::polygon::rectangle_data<coordinate_type> rect_type;
-// typedef voronoi_builder<int> VB;
typedef boost::polygon::voronoi_diagram<coordinate_type> VD;
typedef VD::cell_type cell_type;
typedef VD::cell_type::source_index_type source_index_type;
@@ -710,15 +709,15 @@ namespace Voronoi { namespace Internal {
if (cell1.contains_point() && cell2.contains_point()) {
point_type p1 = retrieve_point(segments, cell1);
point_type p2 = retrieve_point(segments, cell2);
- origin.x((p1(0) + p2(0)) * 0.5);
- origin.y((p1(1) + p2(1)) * 0.5);
- direction.x(p1(1) - p2(1));
- direction.y(p2(0) - p1(0));
+ origin.x((p1.x() + p2.x()) * 0.5);
+ origin.y((p1.y() + p2.y()) * 0.5);
+ direction.x(p1.y() - p2.y());
+ direction.y(p2.x() - p1.x());
} else {
origin = cell1.contains_segment() ? retrieve_point(segments, cell2) : retrieve_point(segments, cell1);
segment_type segment = cell1.contains_segment() ? segments[cell1.source_index()] : segments[cell2.source_index()];
- coordinate_type dx = high(segment)(0) - low(segment)(0);
- coordinate_type dy = high(segment)(1) - low(segment)(1);
+ coordinate_type dx = high(segment).x() - low(segment).x();
+ coordinate_type dy = high(segment).y() - low(segment).y();
if ((low(segment) == origin) ^ cell1.contains_point()) {
direction.x(dy);
direction.y(-dx);
@@ -727,19 +726,19 @@ namespace Voronoi { namespace Internal {
direction.y(dx);
}
}
- coordinate_type koef = bbox_max_size / (std::max)(fabs(direction(0)), fabs(direction(1)));
+ coordinate_type koef = bbox_max_size / (std::max)(fabs(direction.x()), fabs(direction.y()));
if (edge.vertex0() == NULL) {
clipped_edge->push_back(point_type(
- origin(0) - direction(0) * koef,
- origin(1) - direction(1) * koef));
+ origin.x() - direction.x() * koef,
+ origin.y() - direction.y() * koef));
} else {
clipped_edge->push_back(
point_type(edge.vertex0()->x(), edge.vertex0()->y()));
}
if (edge.vertex1() == NULL) {
clipped_edge->push_back(point_type(
- origin(0) + direction(0) * koef,
- origin(1) + direction(1) * koef));
+ origin.x() + direction.x() * koef,
+ origin.y() + direction.y() * koef));
} else {
clipped_edge->push_back(
point_type(edge.vertex1()->x(), edge.vertex1()->y()));
@@ -759,7 +758,7 @@ namespace Voronoi { namespace Internal {
} /* namespace Internal */ } // namespace Voronoi
-static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_diagram<double> &vd, const ThickPolylines *polylines, const char *path)
+static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ boost::polygon::voronoi_diagram<double> &vd, const ThickPolylines *polylines, const char *path)
{
const double scale = 0.2;
const std::string inputSegmentPointColor = "lightseagreen";
@@ -803,7 +802,7 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d
Voronoi::Internal::point_type(double(it->b(0)), double(it->b(1)))));
// Color exterior edges.
- for (voronoi_diagram<double>::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it)
+ for (boost::polygon::voronoi_diagram<double>::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it)
if (!it->is_finite())
Voronoi::Internal::color_exterior(&(*it));
@@ -818,11 +817,11 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d
#if 1
// Draw voronoi vertices.
- for (voronoi_diagram<double>::const_vertex_iterator it = vd.vertices().begin(); it != vd.vertices().end(); ++it)
+ for (boost::polygon::voronoi_diagram<double>::const_vertex_iterator it = vd.vertices().begin(); it != vd.vertices().end(); ++it)
if (! internalEdgesOnly || it->color() != Voronoi::Internal::EXTERNAL_COLOR)
- svg.draw(Point(coord_t((*it)(0)), coord_t((*it)(1))), voronoiPointColor, voronoiPointRadius);
+ svg.draw(Point(coord_t(it->x()), coord_t(it->y())), voronoiPointColor, voronoiPointRadius);
- for (voronoi_diagram<double>::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it) {
+ for (boost::polygon::voronoi_diagram<double>::const_edge_iterator it = vd.edges().begin(); it != vd.edges().end(); ++it) {
if (primaryEdgesOnly && !it->is_primary())
continue;
if (internalEdgesOnly && (it->color() == Voronoi::Internal::EXTERNAL_COLOR))
@@ -845,7 +844,7 @@ static inline void dump_voronoi_to_svg(const Lines &lines, /* const */ voronoi_d
color = voronoiLineColorSecondary;
}
for (std::size_t i = 0; i + 1 < samples.size(); ++i)
- svg.draw(Line(Point(coord_t(samples[i](0)), coord_t(samples[i](1))), Point(coord_t(samples[i+1](0)), coord_t(samples[i+1](1)))), color, voronoiLineWidth);
+ svg.draw(Line(Point(coord_t(samples[i].x()), coord_t(samples[i].y())), Point(coord_t(samples[i+1].x()), coord_t(samples[i+1].y()))), color, voronoiLineWidth);
}
#endif
diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp
index 44303711b..d996658f2 100644
--- a/src/libslic3r/Geometry.hpp
+++ b/src/libslic3r/Geometry.hpp
@@ -11,8 +11,6 @@
#include <cereal/access.hpp>
#include "boost/polygon/voronoi.hpp"
-using boost::polygon::voronoi_builder;
-using boost::polygon::voronoi_diagram;
namespace ClipperLib {
class PolyNode;
@@ -192,7 +190,7 @@ class MedialAxis {
void build(Polylines* polylines);
private:
- class VD : public voronoi_diagram<double> {
+ class VD : public boost::polygon::voronoi_diagram<double> {
public:
typedef double coord_type;
typedef boost::polygon::point_data<coordinate_type> point_type;
diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp
index 74deabf3e..53a7f2fc4 100644
--- a/src/libslic3r/Layer.cpp
+++ b/src/libslic3r/Layer.cpp
@@ -88,8 +88,12 @@ ExPolygons Layer::merged(float offset_scaled) const
offset_scaled2 = float(- EPSILON);
}
Polygons polygons;
- for (LayerRegion *layerm : m_regions)
- append(polygons, offset(to_expolygons(layerm->slices.surfaces), offset_scaled));
+ for (LayerRegion *layerm : m_regions) {
+ const PrintRegionConfig &config = layerm->region()->config();
+ // Our users learned to bend Slic3r to produce empty volumes to act as subtracters. Only add the region if it is non-empty.
+ if (config.bottom_solid_layers > 0 || config.top_solid_layers > 0 || config.fill_density > 0. || config.perimeters > 0)
+ append(polygons, offset(to_expolygons(layerm->slices.surfaces), offset_scaled));
+ }
ExPolygons out = union_ex(polygons);
if (offset_scaled2 != 0.f)
out = offset_ex(out, offset_scaled2);
diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp
index 658bcf709..35acaf998 100644
--- a/src/libslic3r/LayerRegion.cpp
+++ b/src/libslic3r/LayerRegion.cpp
@@ -88,7 +88,6 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Polygons *lower_layer_covered)
{
- const Surfaces &surfaces = this->fill_surfaces.surfaces;
const bool has_infill = this->region()->config().fill_density.value > 0.;
const float margin = float(scale_(EXTERNAL_INFILL_MARGIN));
diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp
index bd5ec3de5..e1e299144 100644
--- a/src/libslic3r/Polygon.cpp
+++ b/src/libslic3r/Polygon.cpp
@@ -254,6 +254,11 @@ Point Polygon::point_projection(const Point &point) const
return proj;
}
+BoundingBox get_extents(const Points &points)
+{
+ return BoundingBox(points);
+}
+
BoundingBox get_extents(const Polygon &poly)
{
return poly.bounding_box();
diff --git a/src/libslic3r/Polygon.hpp b/src/libslic3r/Polygon.hpp
index 19be3068b..8230b49f8 100644
--- a/src/libslic3r/Polygon.hpp
+++ b/src/libslic3r/Polygon.hpp
@@ -22,7 +22,8 @@ public:
const Point& operator[](Points::size_type idx) const { return this->points[idx]; }
Polygon() {}
- explicit Polygon(const Points &points): MultiPoint(points) {}
+ explicit Polygon(const Points &points) : MultiPoint(points) {}
+ Polygon(std::initializer_list<Point> points) : MultiPoint(points) {}
Polygon(const Polygon &other) : MultiPoint(other.points) {}
Polygon(Polygon &&other) : MultiPoint(std::move(other.points)) {}
static Polygon new_scale(const std::vector<Vec2d> &points) {
@@ -66,6 +67,10 @@ public:
Point point_projection(const Point &point) const;
};
+inline bool operator==(const Polygon &lhs, const Polygon &rhs) { return lhs.points == rhs.points; }
+inline bool operator!=(const Polygon &lhs, const Polygon &rhs) { return lhs.points != rhs.points; }
+
+extern BoundingBox get_extents(const Points &points);
extern BoundingBox get_extents(const Polygon &poly);
extern BoundingBox get_extents(const Polygons &polygons);
extern BoundingBox get_extents_rotated(const Polygon &poly, double angle);
@@ -102,6 +107,15 @@ inline void polygons_append(Polygons &dst, Polygons &&src)
}
}
+inline Polygons polygons_simplify(const Polygons &polys, double tolerance)
+{
+ Polygons out;
+ out.reserve(polys.size());
+ for (const Polygon &p : polys)
+ polygons_append(out, p.simplify(tolerance));
+ return out;
+}
+
inline void polygons_rotate(Polygons &polys, double angle)
{
const double cos_angle = cos(angle);
diff --git a/src/libslic3r/PolygonTrimmer.cpp b/src/libslic3r/PolygonTrimmer.cpp
index 3e3c9b498..2c4e06fc5 100644
--- a/src/libslic3r/PolygonTrimmer.cpp
+++ b/src/libslic3r/PolygonTrimmer.cpp
@@ -12,12 +12,11 @@ TrimmedLoop trim_loop(const Polygon &loop, const EdgeGrid::Grid &grid)
TrimmedLoop out;
if (loop.size() >= 2) {
- size_t cnt = loop.points.size();
struct Visitor {
Visitor(const EdgeGrid::Grid &grid, const Slic3r::Point *pt_prev, const Slic3r::Point *pt_this) : grid(grid), pt_prev(pt_prev), pt_this(pt_this) {}
- void operator()(coord_t iy, coord_t ix) {
+ bool operator()(coord_t iy, coord_t ix) {
// Called with a row and colum of the grid cell, which is intersected by a line.
auto cell_data_range = grid.cell_data_range(iy, ix);
for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++ it_contour_and_segment) {
@@ -27,6 +26,8 @@ TrimmedLoop trim_loop(const Polygon &loop, const EdgeGrid::Grid &grid)
// The two segments intersect. Add them to the output.
}
}
+ // Continue traversing the grid along the edge.
+ return true;
}
const EdgeGrid::Grid &grid;
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index d87e63c27..b334b70fc 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -1,6 +1,7 @@
#include "Print.hpp"
#include "BoundingBox.hpp"
#include "ClipperUtils.hpp"
+#include "ElephantFootCompensation.hpp"
#include "Geometry.hpp"
#include "I18N.hpp"
#include "SupportMaterial.hpp"
@@ -1769,6 +1770,7 @@ end:
Layer *layer = m_layers[layer_id];
// Apply size compensation and perform clipping of multi-part objects.
float delta = float(scale_(m_config.xy_size_compensation.value));
+ //FIXME only apply the compensation if no raft is enabled.
float elephant_foot_compensation = 0.f;
if (layer_id == 0)
elephant_foot_compensation = float(scale_(m_config.elefant_foot_compensation.value));
@@ -1789,19 +1791,8 @@ end:
to_expolygons(std::move(layerm->slices.surfaces)) :
offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta);
// Apply the elephant foot compensation.
- if (elephant_foot_compensation > 0) {
- float elephant_foot_spacing = float(layerm->flow(frExternalPerimeter).scaled_elephant_foot_spacing());
- float external_perimeter_nozzle = float(scale_(this->print()->config().nozzle_diameter.get_at(layerm->region()->config().perimeter_extruder.value - 1)));
- // Apply the elephant foot compensation by steps of 1/10 nozzle diameter.
- float steps = std::ceil(elephant_foot_compensation / (0.1f * external_perimeter_nozzle));
- size_t nsteps = size_t(steps);
- float step = elephant_foot_compensation / steps;
- for (size_t i = 0; i < nsteps; ++ i) {
- Polygons tmp = offset(expolygons, - step);
- append(tmp, diff(to_polygons(expolygons), offset(offset_ex(expolygons, -elephant_foot_spacing - step), elephant_foot_spacing + step)));
- expolygons = union_ex(tmp);
- }
- }
+ if (elephant_foot_compensation > 0)
+ expolygons = union_ex(Slic3r::elephant_foot_compensation(expolygons, layerm->flow(frExternalPerimeter), unscale<double>(elephant_foot_compensation)));
layerm->slices.set(std::move(expolygons), stInternal);
}
} else {
@@ -1825,33 +1816,17 @@ end:
layerm->slices.set(std::move(slices), stInternal);
}
}
- if (delta < 0.f) {
+ if (delta < 0.f || elephant_foot_compensation > 0.f) {
// Apply the negative XY compensation.
- Polygons trimming = offset(layer->merged(float(EPSILON)), delta - float(EPSILON));
+ Polygons trimming;
+ if (elephant_foot_compensation > 0.f) {
+ trimming = to_polygons(Slic3r::elephant_foot_compensation(offset_ex(layer->merged(float(EPSILON)), std::min(delta, 0.f) - float(EPSILON)),
+ layer->m_regions.front()->flow(frExternalPerimeter), unscale<double>(elephant_foot_compensation)));
+ } else
+ trimming = offset(layer->merged(float(EPSILON)), delta - float(EPSILON));
for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id)
layer->m_regions[region_id]->trim_surfaces(trimming);
}
- if (elephant_foot_compensation > 0.f) {
- // Apply the elephant foot compensation.
- std::vector<float> elephant_foot_spacing;
- elephant_foot_spacing.reserve(layer->m_regions.size());
- float external_perimeter_nozzle = 0.f;
- for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id) {
- LayerRegion *layerm = layer->m_regions[region_id];
- elephant_foot_spacing.emplace_back(float(layerm->flow(frExternalPerimeter).scaled_elephant_foot_spacing()));
- external_perimeter_nozzle += float(scale_(this->print()->config().nozzle_diameter.get_at(layerm->region()->config().perimeter_extruder.value - 1)));
- }
- external_perimeter_nozzle /= (float)layer->m_regions.size();
- // Apply the elephant foot compensation by steps of 1/10 nozzle diameter.
- float steps = std::ceil(elephant_foot_compensation / (0.1f * external_perimeter_nozzle));
- size_t nsteps = size_t(steps);
- float step = elephant_foot_compensation / steps;
- for (size_t i = 0; i < nsteps; ++ i) {
- Polygons trimming_polygons = offset(layer->merged(float(EPSILON)), - step - float(EPSILON));
- for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id)
- layer->m_regions[region_id]->elephant_foot_compensation_step(elephant_foot_spacing[region_id] + step, trimming_polygons);
- }
- }
}
// Merge all regions' slices to get islands, chain them by a shortest path.
layer->make_slices();
diff --git a/src/libslic3r/SVG.cpp b/src/libslic3r/SVG.cpp
index 03f55802e..6e4b973ea 100644
--- a/src/libslic3r/SVG.cpp
+++ b/src/libslic3r/SVG.cpp
@@ -368,6 +368,10 @@ void SVG::export_expolygons(const char *path, const std::vector<std::pair<Slic3r
color_holes = color_contour;
svg.draw_outline(exp_with_attr.first, color_contour, color_holes, exp_with_attr.second.outline_width);
}
+ for (const auto &exp_with_attr : expolygons_with_attributes)
+ if (exp_with_attr.second.radius_points > 0)
+ for (const ExPolygon &expoly : exp_with_attr.first)
+ svg.draw((Points)expoly, exp_with_attr.second.color_points, exp_with_attr.second.radius_points);
svg.Close();
}
diff --git a/src/libslic3r/SVG.hpp b/src/libslic3r/SVG.hpp
index 3a5602196..c1b387554 100644
--- a/src/libslic3r/SVG.hpp
+++ b/src/libslic3r/SVG.hpp
@@ -105,19 +105,25 @@ public:
const std::string &color_contour,
const std::string &color_holes,
const coord_t outline_width = scale_(0.05),
- const float fill_opacity = 0.5f) :
+ const float fill_opacity = 0.5f,
+ const std::string &color_points = "black",
+ const coord_t radius_points = 0) :
color_fill (color_fill),
color_contour (color_contour),
color_holes (color_holes),
outline_width (outline_width),
- fill_opacity (fill_opacity)
+ fill_opacity (fill_opacity),
+ color_points (color_points),
+ radius_points (radius_points)
{}
std::string color_fill;
std::string color_contour;
std::string color_holes;
+ std::string color_points;
coord_t outline_width;
float fill_opacity;
+ coord_t radius_points;
};
static void export_expolygons(const char *path, const std::vector<std::pair<Slic3r::ExPolygons, ExPolygonAttributes>> &expolygons_with_attributes);
diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp
index 8d2a6a866..678ad9ed2 100644
--- a/src/libslic3r/utils.cpp
+++ b/src/libslic3r/utils.cpp
@@ -424,14 +424,19 @@ int copy_file(const std::string &from, const std::string &to)
static const auto perms = boost::filesystem::owner_read | boost::filesystem::owner_write | boost::filesystem::group_read | boost::filesystem::others_read; // aka 644
// Make sure the file has correct permission both before and after we copy over it.
- try {
- if (boost::filesystem::exists(target))
- boost::filesystem::permissions(target, perms);
- boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists);
- boost::filesystem::permissions(target, perms);
- } catch (std::exception & /* ex */) {
+ // NOTE: error_code variants are used here to supress expception throwing.
+ // Error code of permission() calls is ignored on purpose - if they fail,
+ // the copy_file() function will fail appropriately and we don't want the permission()
+ // calls to cause needless failures on permissionless filesystems (ie. FATs on SD cards etc.)
+ // or when the target file doesn't exist.
+ boost::system::error_code ec;
+ boost::filesystem::permissions(target, perms, ec);
+ boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
+ if (ec) {
return -1;
}
+ boost::filesystem::permissions(target, perms, ec);
+
return 0;
}
diff --git a/src/qhull/CMakeLists.txt b/src/qhull/CMakeLists.txt
index 9ca0bdff2..ab9aba9af 100644
--- a/src/qhull/CMakeLists.txt
+++ b/src/qhull/CMakeLists.txt
@@ -18,11 +18,13 @@ if(Qhull_FOUND)
message(STATUS "Using qhull from system.")
if(SLIC3R_STATIC)
+ slic3r_remap_configs("Qhull::qhullcpp;Qhull::qhullstatic_r" RelWithDebInfo Release)
target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhullstatic_r)
else()
+ slic3r_remap_configs("Qhull::qhullcpp;Qhull::qhull_r" RelWithDebInfo Release)
target_link_libraries(qhull INTERFACE Qhull::qhullcpp Qhull::qhull_r)
endif()
-
+
else(Qhull_FOUND)
project(qhull)
diff --git a/src/slic3r/Config/Version.cpp b/src/slic3r/Config/Version.cpp
index 3f8f960f1..da522dd5e 100644
--- a/src/slic3r/Config/Version.cpp
+++ b/src/slic3r/Config/Version.cpp
@@ -235,9 +235,9 @@ size_t Index::load(const boost::filesystem::path &path)
value = left_trim(value + 1);
*key_end = 0;
boost::optional<Semver> semver;
- if (maybe_semver)
+ if (maybe_semver)
semver = Semver::parse(key);
- if (key_value_pair) {
+ if (key_value_pair) {
if (semver)
throw file_parser_error("Key cannot be a semantic version", path, idx_line);\
// Verify validity of the key / value pair.
@@ -288,7 +288,6 @@ Index::const_iterator Index::find(const Semver &ver) const
Index::const_iterator Index::recommended() const
{
- int idx = -1;
const_iterator highest = this->end();
for (const_iterator it = this->begin(); it != this->end(); ++ it)
if (it->is_current_slic3r_supported() &&
diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
index a1db6884e..6c138d4d0 100644
--- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
@@ -55,6 +55,7 @@ bool BackgroundSlicingProcess::select_technology(PrinterTechnology tech)
switch (tech) {
case ptFFF: m_print = m_fff_print; break;
case ptSLA: m_print = m_sla_print; break;
+ default: assert(false); break;
}
changed = true;
}
diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index 07d75c947..42e3448fc 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -150,7 +150,13 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
case coFloat:{
if (m_opt.type == coPercent && !str.IsEmpty() && str.Last() == '%')
str.RemoveLast();
- else if (check_value && !str.IsEmpty() && str.Last() == '%') {
+ else if (!str.IsEmpty() && str.Last() == '%')
+ {
+ if (!check_value) {
+ m_value.clear();
+ break;
+ }
+
wxString label = m_Label->GetLabel();
if (label.Last() == '\n') label.RemoveLast();
while (label.Last() == ' ') label.RemoveLast();
@@ -169,13 +175,21 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
{
if (m_opt.nullable && str == na_value())
val = ConfigOptionFloatsNullable::nil_value();
- else if (check_value && !str.ToCDouble(&val))
+ else if (!str.ToCDouble(&val))
{
+ if (!check_value) {
+ m_value.clear();
+ break;
+ }
show_error(m_parent, _(L("Invalid numeric input.")));
set_value(double_to_string(val), true);
}
- if (check_value && (m_opt.min > val || val > m_opt.max))
+ if (m_opt.min > val || val > m_opt.max)
{
+ if (!check_value) {
+ m_value.clear();
+ break;
+ }
show_error(m_parent, _(L("Input value is out of range")));
if (m_opt.min > val) val = m_opt.min;
if (val > m_opt.max) val = m_opt.max;
@@ -192,15 +206,24 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
double val = 0.;
// Replace the first occurence of comma in decimal number.
str.Replace(",", ".", false);
- if (check_value && !str.ToCDouble(&val))
+ if (!str.ToCDouble(&val))
{
+ if (!check_value) {
+ m_value.clear();
+ break;
+ }
show_error(m_parent, _(L("Invalid numeric input.")));
set_value(double_to_string(val), true);
}
- else if (check_value && ((m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max) ||
+ else if (((m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max) ||
(m_opt.sidetext.rfind("mm ") != std::string::npos && val > 1)) &&
(m_value.empty() || std::string(str.ToUTF8().data()) != boost::any_cast<std::string>(m_value)))
{
+ if (!check_value) {
+ m_value.clear();
+ break;
+ }
+
const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm";
const wxString stVal = double_to_string(val, 2);
const wxString msg_text = wxString::Format(_(L("Do you mean %s%% instead of %s %s?\n"
@@ -351,6 +374,7 @@ bool TextCtrl::value_was_changed()
boost::any val = m_value;
wxString ret_str = static_cast<wxTextCtrl*>(window)->GetValue();
// update m_value!
+ // ret_str might be changed inside get_value_by_opt_type
get_value_by_opt_type(ret_str);
switch (m_opt.type) {
@@ -396,8 +420,10 @@ void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/)
if (!change_event) {
wxString ret_str = static_cast<wxTextCtrl*>(window)->GetValue();
- // update m_value to correct work of next value_was_changed(),
- // but don't check/change inputed value and don't show a warning message
+ /* Update m_value to correct work of next value_was_changed().
+ * But after checking of entered value, don't fix the "incorrect" value and don't show a warning message,
+ * just clear m_value in this case.
+ */
get_value_by_opt_type(ret_str, false);
}
}
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 6b9232e1d..7e782dee3 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1949,7 +1949,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
if (it->new_geometry()) {
// New volume.
unsigned int old_id = find_old_volume_id(it->composite_id);
- if (old_id != -1)
+ if (old_id != (unsigned int)-1)
map_glvolume_old_to_new[old_id] = m_volumes.volumes.size();
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized);
m_volumes.volumes.back()->geometry_id = key.geometry_id;
diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp
index c5ddc0152..9bfc34543 100644
--- a/src/slic3r/GUI/GUI_App.hpp
+++ b/src/slic3r/GUI/GUI_App.hpp
@@ -87,7 +87,7 @@ class GUI_App : public wxApp
wxFont m_bold_font;
wxFont m_normal_font;
- size_t m_em_unit; // width of a "m"-symbol in pixels for current system font
+ int m_em_unit; // width of a "m"-symbol in pixels for current system font
// Note: for 100% Scale m_em_unit = 10 -> it's a good enough coefficient for a size setting of controls
std::unique_ptr<wxLocale> m_wxLocale;
@@ -105,7 +105,7 @@ public:
bool initialized() const { return m_initialized; }
GUI_App();
- ~GUI_App();
+ ~GUI_App() override;
static unsigned get_colour_approx_luma(const wxColour &colour);
static bool dark_mode();
@@ -124,8 +124,7 @@ public:
const wxFont& small_font() { return m_small_font; }
const wxFont& bold_font() { return m_bold_font; }
const wxFont& normal_font() { return m_normal_font; }
- size_t em_unit() const { return m_em_unit; }
- void set_em_unit(const size_t em_unit) { m_em_unit = em_unit; }
+ int em_unit() const { return m_em_unit; }
float toolbar_icon_scale(const bool is_limited = false) const;
void recreate_GUI();
@@ -155,7 +154,7 @@ public:
// Translate the language code to a code, for which Prusa Research maintains translations. Defaults to "en_US".
wxString current_language_code_safe() const;
- virtual bool OnExceptionInMainLoop();
+ virtual bool OnExceptionInMainLoop() override;
#ifdef __APPLE__
// wxWidgets override to get an event on open files.
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 377c26e79..1cbfc2bdf 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -445,7 +445,7 @@ void ObjectList::update_extruder_values_for_items(const size_t max_extruder)
auto object = (*m_objects)[i];
wxString extruder;
if (!object->config.has("extruder") ||
- object->config.option<ConfigOptionInt>("extruder")->value > max_extruder)
+ size_t(object->config.option<ConfigOptionInt>("extruder")->value) > max_extruder)
extruder = _(L("default"));
else
extruder = wxString::Format("%d", object->config.option<ConfigOptionInt>("extruder")->value);
@@ -457,7 +457,7 @@ void ObjectList::update_extruder_values_for_items(const size_t max_extruder)
item = m_objects_model->GetItemByVolumeId(i, id);
if (!item) continue;
if (!object->volumes[id]->config.has("extruder") ||
- object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value > max_extruder)
+ size_t(object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value) > max_extruder)
extruder = _(L("default"));
else
extruder = wxString::Format("%d", object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value);
diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
index d1cb1348c..5e939cb71 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
@@ -634,7 +634,11 @@ void ObjectManipulation::update_reset_buttons_visibility()
show_drop_to_bed = (std::abs(min_z) > EPSILON);
}
- wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed]{
+ wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] {
+ // There is a case (under OSX), when this function is called after the Manipulation panel is hidden
+ // So, let check if Manipulation panel is still shown for this moment
+ if (!this->IsShown())
+ return;
m_reset_rotation_button->Show(show_rotation);
m_reset_scale_button->Show(show_scale);
m_drop_to_bed_button->Show(show_drop_to_bed);
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 064fcb5c5..81367081f 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -375,6 +375,8 @@ void Preview::load_print(bool keep_z_range)
load_print_as_fff(keep_z_range);
else if (tech == ptSLA)
load_print_as_sla();
+
+ Layout();
}
void Preview::reload_print(bool keep_volumes)
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
index f649c98b2..0defb1348 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
@@ -114,8 +114,17 @@ public:
m_serializing = true;
+ // Following is needed to know which to be turn on, but not actually modify
+ // m_current prematurely, so activate_gizmo is not confused.
+ EType old_current = m_current;
ar(m_current);
+ EType new_current = m_current;
+ m_current = old_current;
+ // activate_gizmo call sets m_current and calls set_state for the gizmo
+ // it does nothing in case the gizmo is already activated
+ // it can safely be called for Undefined gizmo
+ activate_gizmo(new_current);
if (m_current != Undefined)
m_gizmos[m_current]->load(ar);
}
diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp
index 698c1e034..8b6f5bc30 100644
--- a/src/slic3r/GUI/OptionsGroup.cpp
+++ b/src/slic3r/GUI/OptionsGroup.cpp
@@ -233,7 +233,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n
add_undo_buttuns_to_sizer(sizer, field);
if (is_window_field(field))
- sizer->Add(field->getWindow(), option.opt.full_width ? 1 : 0, //(option.opt.full_width ? wxEXPAND : 0) |
+ sizer->Add(field->getWindow(), option.opt.full_width ? 1 : 0, //(option.opt.full_width ? wxEXPAND : 0) |
wxBOTTOM | wxTOP | (option.opt.full_width ? wxEXPAND : wxALIGN_CENTER_VERTICAL), (wxOSX || !staticbox) ? 0 : 2);
if (is_sizer_field(field))
sizer->Add(field->getSizer(), 1, /*(*/option.opt.full_width ? wxEXPAND : /*0) |*/ wxALIGN_CENTER_VERTICAL, 0);
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 5b1fdc91c..14fbdf72c 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -4794,7 +4794,7 @@ bool Plater::undo_redo_string_getter(const bool is_undo, int idx, const char** o
const std::vector<UndoRedo::Snapshot>& ss_stack = p->undo_redo_stack().snapshots();
const int idx_in_ss_stack = p->get_active_snapshot_index() + (is_undo ? -(++idx) : idx);
- if (0 < idx_in_ss_stack && idx_in_ss_stack < ss_stack.size() - 1) {
+ if (0 < idx_in_ss_stack && (size_t)idx_in_ss_stack < ss_stack.size() - 1) {
*out_text = ss_stack[idx_in_ss_stack].name.c_str();
return true;
}
@@ -4807,7 +4807,7 @@ void Plater::undo_redo_topmost_string_getter(const bool is_undo, std::string& ou
const std::vector<UndoRedo::Snapshot>& ss_stack = p->undo_redo_stack().snapshots();
const int idx_in_ss_stack = p->get_active_snapshot_index() + (is_undo ? -1 : 0);
- if (0 < idx_in_ss_stack && idx_in_ss_stack < ss_stack.size() - 1) {
+ if (0 < idx_in_ss_stack && (size_t)idx_in_ss_stack < ss_stack.size() - 1) {
out_text = ss_stack[idx_in_ss_stack].name;
return;
}
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 238860ce7..40f509ad7 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -1061,7 +1061,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
node_parent->GetChildren().Remove(node);
if (id > 0) {
- if(id == node_parent->GetChildCount()) id--;
+ if (size_t(id) == node_parent->GetChildCount()) id--;
ret_item = wxDataViewItem(node_parent->GetChildren().Item(id));
}