From 7e6390c4b633fe79c94fc0eac547a93c51e4dcba Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 2 Feb 2017 18:49:33 +0100 Subject: [PATCH] Avoid placement of seams on bridging perimeters, if random seam is enabled. https://github.com/alexrj/Slic3r/issues/3526#issuecomment-263125049 --- xs/src/libslic3r/ExtrusionEntity.cpp | 42 +++++++++++++++++++--------- xs/src/libslic3r/ExtrusionEntity.hpp | 2 +- xs/src/libslic3r/GCode.cpp | 6 ++-- xs/xsp/ExtrusionLoop.xsp | 4 +-- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/xs/src/libslic3r/ExtrusionEntity.cpp b/xs/src/libslic3r/ExtrusionEntity.cpp index d960e2838..dc7cfe061 100644 --- a/xs/src/libslic3r/ExtrusionEntity.cpp +++ b/xs/src/libslic3r/ExtrusionEntity.cpp @@ -204,22 +204,38 @@ ExtrusionLoop::split_at_vertex(const Point &point) return false; } -void -ExtrusionLoop::split_at(const Point &point) +// Splitting an extrusion loop, possibly made of multiple segments, some of the segments may be bridging. +void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang) { - if (this->paths.empty()) return; + if (this->paths.empty()) + return; - // find the closest path and closest point belonging to that path + // Find the closest path and closest point belonging to that path. Avoid overhangs, if asked for. size_t path_idx = 0; - Point p = this->paths.front().first_point(); - double min = point.distance_to(p); - for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) { - Point p_tmp = point.projection_onto(path->polyline); - double dist = point.distance_to(p_tmp); - if (dist < min) { - p = p_tmp; - min = dist; - path_idx = path - this->paths.begin(); + Point p; + { + double min = std::numeric_limits::max(); + Point p_non_overhang; + size_t path_idx_non_overhang = 0; + double min_non_overhang = std::numeric_limits::max(); + for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) { + Point p_tmp = point.projection_onto(path->polyline); + double dist = point.distance_to(p_tmp); + if (dist < min) { + p = p_tmp; + min = dist; + path_idx = path - this->paths.begin(); + } + if (prefer_non_overhang && ! path->is_bridge() && dist < min_non_overhang) { + p_non_overhang = p_tmp; + min_non_overhang = dist; + path_idx_non_overhang = path - this->paths.begin(); + } + } + if (prefer_non_overhang && min_non_overhang != std::numeric_limits::max()) { + // Only apply the non-overhang point if there is one. + path_idx = path_idx_non_overhang; + p = p_non_overhang; } } diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index b414768a7..c4c95bbbc 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -218,7 +218,7 @@ class ExtrusionLoop : public ExtrusionEntity Polygon polygon() const; virtual double length() const; bool split_at_vertex(const Point &point); - void split_at(const Point &point); + void split_at(const Point &point, bool prefer_non_overhang); void clip_end(double distance, ExtrusionPaths* paths) const; // Test, whether the point is extruded by a bridging flow. // This used to be used to avoid placing seams on overhangs, but now the EdgeGrid is used instead. diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index b5714644b..6f3d3296f 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -571,7 +571,7 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed) // or randomize if requested Point last_pos = this->last_pos(); if (this->config.spiral_vase) { - loop.split_at(last_pos); + loop.split_at(last_pos, false); } else if (seam_position == spNearest || seam_position == spAligned) { Polygon polygon = loop.polygon(); const coordf_t nozzle_dmr = EXTRUDER_CONFIG(nozzle_diameter); @@ -682,7 +682,7 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed) // Split the loop at the point with a minium penalty. if (!loop.split_at_vertex(polygon.points[idx_min])) // The point is not in the original loop. Insert it. - loop.split_at(polygon.points[idx_min]); + loop.split_at(polygon.points[idx_min], true); } else if (seam_position == spRandom) { if (loop.role == elrContourInternalPerimeter) { @@ -696,7 +696,7 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed) last_pos = Point(polygon.bounding_box().max.x, centroid.y); last_pos.rotate(fmod((float)rand()/16.0, 2.0*PI), centroid); } - loop.split_at(last_pos); + loop.split_at(last_pos, true); } // clip the path to avoid the extruder to get exactly on the first point of the loop; diff --git a/xs/xsp/ExtrusionLoop.xsp b/xs/xsp/ExtrusionLoop.xsp index e46b4118e..21bfb350c 100644 --- a/xs/xsp/ExtrusionLoop.xsp +++ b/xs/xsp/ExtrusionLoop.xsp @@ -21,8 +21,8 @@ double length(); bool split_at_vertex(Point* point) %code{% RETVAL = THIS->split_at_vertex(*point); %}; - void split_at(Point* point) - %code{% THIS->split_at(*point); %}; + void split_at(Point* point, int prefer_non_overhang = 0) + %code{% THIS->split_at(*point, prefer_non_overhang != 0); %}; ExtrusionPaths clip_end(double distance) %code{% THIS->clip_end(distance, &RETVAL); %}; bool has_overhang_point(Point* point)