diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 2fa0c5c3c..35b4a331a 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -317,13 +317,16 @@ void Layer::build_up_down_graph(Layer& below, Layer& above) coord_t* end = srcs + 4; std::sort(begin, end); end = std::unique(begin, end); - assert(begin + 2 == end); - if (begin + 1 == end) + if (begin + 1 == end) { + // Self intersection may happen on source contour. Just copy the Z value. pt.z() = *begin; - else if (begin + 2 <= end) { - // store a -1 based negative index into the "intersections" vector here. - m_intersections.emplace_back(srcs[0], srcs[1]); - pt.z() = -coord_t(m_intersections.size()); + } else { + assert(begin + 2 == end); + if (begin + 2 <= end) { + // store a -1 based negative index into the "intersections" vector here. + m_intersections.emplace_back(srcs[0], srcs[1]); + pt.z() = -coord_t(m_intersections.size()); + } } } const std::vector>& intersections() const { return m_intersections; } diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 490fd54bf..875870fa8 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -397,22 +397,37 @@ static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path &subject, con ClipperLib_Z::Clipper clipper; clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot, const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) { + // The clipping contour may be simplified by clipping it with a bounding box of "subject" path. + // The clipping function used may produce self intersections outside of the "subject" bounding box. Such self intersections are + // harmless to the result of the clipping operation, + // Both ends of each edge belong to the same source: Either they are from subject or from clipping path. + assert(e1bot.z() >= 0 && e1top.z() >= 0); + assert(e2bot.z() >= 0 && e2top.z() >= 0); + assert((e1bot.z() == 0) == (e1top.z() == 0)); + assert((e2bot.z() == 0) == (e2top.z() == 0)); + + // Start & end points of the clipped polyline (extrusion path with a non-zero width). ClipperLib_Z::IntPoint start = e1bot; ClipperLib_Z::IntPoint end = e1top; - if (start.z() <= 0 && end.z() <= 0) { start = e2bot; end = e2top; } - assert(start.z() > 0 && end.z() > 0); + if (start.z() <= 0 && end.z() <= 0) { + // Self intersection on the source contour. + assert(start.z() == 0 && end.z() == 0); + pt.z() = 0; + } else { + // Interpolate extrusion line width. + assert(start.z() > 0 && end.z() > 0); - // Interpolate extrusion line width. - double length_sqr = (end - start).cast().squaredNorm(); - double dist_sqr = (pt - start).cast().squaredNorm(); - double t = std::sqrt(dist_sqr / length_sqr); + double length_sqr = (end - start).cast().squaredNorm(); + double dist_sqr = (pt - start).cast().squaredNorm(); + double t = std::sqrt(dist_sqr / length_sqr); - pt.z() = start.z() + coord_t((end.z() - start.z()) * t); + pt.z() = start.z() + coord_t((end.z() - start.z()) * t); + } }); clipper.AddPath(subject, ClipperLib_Z::ptSubject, false);