Fix of
Number of solid top/bottom layers ignored, Ensure Vertical Shell Thickness interferes with solid top layer count https://github.com/prusa3d/Slic3r/issues/79 https://github.com/prusa3d/Slic3r/issues/60
This commit is contained in:
parent
479f716625
commit
17db5bff8d
@ -278,7 +278,9 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
||||
|
||||
// 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);
|
||||
@ -291,26 +293,22 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
||||
return output;
|
||||
}
|
||||
|
||||
// This is a safe variant of the polygon offset, tailored for a single ExPolygon:
|
||||
// a single polygon with multiple non-overlapping holes.
|
||||
// Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours.
|
||||
// This is a safe variant of the polygons offset, tailored for multiple ExPolygons.
|
||||
// It is required, that the input expolygons do not overlap and that the holes of each ExPolygon don't intersect with their respective outer contours.
|
||||
// Each ExPolygon is offsetted separately, then the offsetted ExPolygons are united.
|
||||
ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delta,
|
||||
ClipperLib::JoinType joinType, double miterLimit)
|
||||
{
|
||||
// printf("new ExPolygon offset\n");
|
||||
const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
|
||||
ClipperLib::Paths contours;
|
||||
ClipperLib::Paths holes;
|
||||
contours.reserve(expolygons.size());
|
||||
{
|
||||
size_t n_holes = 0;
|
||||
for (size_t i = 0; i < expolygons.size(); ++ i)
|
||||
n_holes += expolygons[i].holes.size();
|
||||
holes.reserve(n_holes);
|
||||
}
|
||||
|
||||
// Offsetted ExPolygons before they are united.
|
||||
ClipperLib::Paths contours_cummulative;
|
||||
contours_cummulative.reserve(expolygons.size());
|
||||
// How many non-empty offsetted expolygons were actually collected into contours_cummulative?
|
||||
// If only one, then there is no need to do a final union.
|
||||
size_t expolygons_collected = 0;
|
||||
for (Slic3r::ExPolygons::const_iterator it_expoly = expolygons.begin(); it_expoly != expolygons.end(); ++ it_expoly) {
|
||||
// 1) Offset the outer contour.
|
||||
ClipperLib::Paths contours;
|
||||
{
|
||||
ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(it_expoly->contour);
|
||||
scaleClipperPolygon(input);
|
||||
@ -320,37 +318,81 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
|
||||
ClipperLib::Paths out;
|
||||
co.Execute(out, delta_scaled);
|
||||
contours.insert(contours.end(), out.begin(), out.end());
|
||||
co.Execute(contours, delta_scaled);
|
||||
}
|
||||
if (contours.empty())
|
||||
// No need to try to offset the holes.
|
||||
continue;
|
||||
|
||||
// 2) Offset the holes one by one, collect the results.
|
||||
{
|
||||
for (Polygons::const_iterator it_hole = it_expoly->holes.begin(); it_hole != it_expoly->holes.end(); ++ it_hole) {
|
||||
ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole);
|
||||
scaleClipperPolygon(input);
|
||||
ClipperLib::ClipperOffset co;
|
||||
if (joinType == jtRound)
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
|
||||
ClipperLib::Paths out;
|
||||
co.Execute(out, - delta_scaled);
|
||||
holes.insert(holes.end(), out.begin(), out.end());
|
||||
if (it_expoly->holes.empty()) {
|
||||
// No need to subtract holes from the offsetted expolygon, we are done.
|
||||
contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end());
|
||||
++ expolygons_collected;
|
||||
} else {
|
||||
// 2) Offset the holes one by one, collect the offsetted holes.
|
||||
ClipperLib::Paths holes;
|
||||
{
|
||||
for (Polygons::const_iterator it_hole = it_expoly->holes.begin(); it_hole != it_expoly->holes.end(); ++ it_hole) {
|
||||
ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole);
|
||||
scaleClipperPolygon(input);
|
||||
ClipperLib::ClipperOffset co;
|
||||
if (joinType == jtRound)
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
|
||||
ClipperLib::Paths out;
|
||||
co.Execute(out, - delta_scaled);
|
||||
holes.insert(holes.end(), out.begin(), out.end());
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
if (holes.empty()) {
|
||||
// No hole remaining after an offset. Just copy the outer contour.
|
||||
contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end());
|
||||
++ expolygons_collected;
|
||||
} else if (delta < 0) {
|
||||
// Negative offset. There is a chance, that the offsetted hole intersects the outer contour.
|
||||
// Subtract the offsetted holes from the offsetted contours.
|
||||
ClipperLib::Clipper clipper;
|
||||
clipper.Clear();
|
||||
clipper.AddPaths(contours, ClipperLib::ptSubject, true);
|
||||
clipper.AddPaths(holes, ClipperLib::ptClip, true);
|
||||
ClipperLib::Paths output;
|
||||
clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
if (! output.empty()) {
|
||||
contours_cummulative.insert(contours_cummulative.end(), output.begin(), output.end());
|
||||
++ expolygons_collected;
|
||||
} else {
|
||||
// The offsetted holes have eaten up the offsetted outer contour.
|
||||
}
|
||||
} else {
|
||||
// Positive offset. As long as the Clipper offset does what one expects it to do, the offsetted hole will have a smaller
|
||||
// area than the original hole or even disappear, therefore there will be no new intersections.
|
||||
// Just collect the reversed holes.
|
||||
contours_cummulative.reserve(contours.size() + holes.size());
|
||||
contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end());
|
||||
// Reverse the holes in place.
|
||||
for (size_t i = 0; i < holes.size(); ++ i)
|
||||
std::reverse(holes[i].begin(), holes[i].end());
|
||||
contours_cummulative.insert(contours_cummulative.end(), holes.begin(), holes.end());
|
||||
++ expolygons_collected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
// 4) Unite the offsetted expolygons.
|
||||
ClipperLib::Paths output;
|
||||
{
|
||||
if (expolygons_collected > 1 && delta > 0) {
|
||||
// There is a chance that the outwards offsetted expolygons may intersect. Perform a union.
|
||||
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);
|
||||
clipper.Clear();
|
||||
clipper.AddPaths(contours_cummulative, ClipperLib::ptSubject, true);
|
||||
clipper.Execute(ClipperLib::ctUnion, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
} else {
|
||||
// Negative offset. The shrunk expolygons shall not mutually intersect. Just copy the output.
|
||||
output = std::move(contours_cummulative);
|
||||
}
|
||||
|
||||
// 4) Unscale the output.
|
||||
|
@ -302,8 +302,10 @@ LayerRegion::process_external_surfaces(const Layer* lower_layer)
|
||||
polygons_append(polys, STDMOVE(s1));
|
||||
for (size_t j = i + 1; j < top.size(); ++ j) {
|
||||
Surface &s2 = top[j];
|
||||
if (! s2.empty() && surfaces_could_merge(s1, s2))
|
||||
if (! s2.empty() && surfaces_could_merge(s1, s2)) {
|
||||
polygons_append(polys, STDMOVE(s2));
|
||||
s2.clear();
|
||||
}
|
||||
}
|
||||
if (s1.surface_type == stTop)
|
||||
// Trim the top surfaces by the bottom surfaces. This gives the priority to the bottom surfaces.
|
||||
@ -326,8 +328,10 @@ LayerRegion::process_external_surfaces(const Layer* lower_layer)
|
||||
polygons_append(polys, STDMOVE(s1));
|
||||
for (size_t j = i + 1; j < internal.size(); ++ j) {
|
||||
Surface &s2 = internal[j];
|
||||
if (! s2.empty() && surfaces_could_merge(s1, s2))
|
||||
if (! s2.empty() && surfaces_could_merge(s1, s2)) {
|
||||
polygons_append(polys, STDMOVE(s2));
|
||||
s2.clear();
|
||||
}
|
||||
}
|
||||
ExPolygons new_expolys = diff_ex(polys, new_polygons);
|
||||
polygons_append(new_polygons, to_polygons(new_expolys));
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
operator Polygons() const;
|
||||
double area() const;
|
||||
bool empty() const { return expolygon.empty(); }
|
||||
void clear() { expolygon.clear(); }
|
||||
bool is_solid() const;
|
||||
bool is_external() const;
|
||||
bool is_internal() const;
|
||||
|
Loading…
Reference in New Issue
Block a user