diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index a9336b5f4f..a02abefd94 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -4395,7 +4395,7 @@ static std::unique_ptr calculate_layer_edge_grid(const Layer& la } -std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, double speed) +std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, double speed, const ExtrusionEntitiesPtr& region_perimeters) { // get a copy; don't modify the orientation of the original loop object otherwise // next copies (if any) would not detect the correct orientation @@ -4440,8 +4440,12 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou // extrude along the path std::string gcode; + // Orca: // Port of "wipe inside before extruding an external perimeter" feature from super slicer - if (m_config.wipe_before_external_loop.value && !paths.empty() && paths.front().size() > 1 && paths.back().size() > 1 && paths.front().role() == erExternalPerimeter) { + // If region perimeters size not greater than or equal to 2, then skip the wipe inside move as we will extrude in mid air + // as no neighbouring perimeter exists. If an internal perimeter exists, we should find 2 perimeters touching the de-retraction point + // 1 - the currently printed external perimeter and 2 - the neighbouring internal perimeter. + if (m_config.wipe_before_external_loop.value && !paths.empty() && paths.front().size() > 1 && paths.back().size() > 1 && paths.front().role() == erExternalPerimeter && region_perimeters.size() > 1) { const bool is_full_loop_ccw = loop.polygon().is_counter_clockwise(); bool is_hole_loop = (loop.loop_role() & ExtrusionLoopRole::elrHole) != 0; // loop.make_counter_clockwise(); const double nozzle_diam = EXTRUDER_CONFIG(nozzle_diameter); @@ -4482,11 +4486,28 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou pt.rotate(angle, current_point); pt = (current_pos + vec_dist * (2 * dist / vec_norm)).cast(); pt.rotate(angle, current_point); - - // use extrude instead of travel_to_xy to trigger the unretract - ExtrusionPath fake_path_wipe(Polyline{pt, current_point}, paths.front()); - fake_path_wipe.mm3_per_mm = 0; - gcode += extrude_path(fake_path_wipe, "move inwards before retraction/seam", speed); + + // Search region perimeters for lines that are touching the de-retraction point. + // If an internal perimeter exists, we should find 2 perimeters touching the de-retraction point + // 1: the currently printed external perimeter and 2: the neighbouring internal perimeter. + int discoveredTouchingLines = 0; + for (const ExtrusionEntity* ee : region_perimeters){ + auto potential_touching_line = ee->as_polyline(); + AABBTreeLines::LinesDistancer potential_touching_line_distancer{potential_touching_line.lines()}; + auto touching_line = potential_touching_line_distancer.all_lines_in_radius(pt, scale_(nozzle_diam)); + if(touching_line.size()){ + discoveredTouchingLines ++; + if(discoveredTouchingLines > 1) break; // found 2 touching lines. End the search early. + } + } + // found 2 perimeters touching the de-retraction point. Its safe to deretract as the point will be + // inside the model + if(discoveredTouchingLines > 1){ + // use extrude instead of travel_to_xy to trigger the unretract + ExtrusionPath fake_path_wipe(Polyline{pt, current_point}, paths.front()); + fake_path_wipe.mm3_per_mm = 0; + gcode += extrude_path(fake_path_wipe, "move inwards before retraction/seam", speed); + } } @@ -4579,14 +4600,14 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string return gcode; } -std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string description, double speed) +std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string description, double speed, const ExtrusionEntitiesPtr& region_perimeters) { if (const ExtrusionPath* path = dynamic_cast(&entity)) return this->extrude_path(*path, description, speed); else if (const ExtrusionMultiPath* multipath = dynamic_cast(&entity)) return this->extrude_multi_path(*multipath, description, speed); else if (const ExtrusionLoop* loop = dynamic_cast(&entity)) - return this->extrude_loop(*loop, description, speed); + return this->extrude_loop(*loop, description, speed, region_perimeters); else throw Slic3r::InvalidArgument("Invalid argument supplied to extrude()"); return ""; @@ -4613,7 +4634,7 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vectorextrude_entity(*ee, "perimeter", -1.); + gcode += this->extrude_entity(*ee, "perimeter", -1., region.perimeters); } return gcode; } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 481a005d55..e3b6b65a88 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -347,8 +347,12 @@ private: std::string preamble(); // BBS std::string change_layer(coordf_t print_z); - std::string extrude_entity(const ExtrusionEntity &entity, std::string description = "", double speed = -1.); - std::string extrude_loop(ExtrusionLoop loop, std::string description, double speed = -1.); + // Orca: pass the complete collection of region perimeters to the extrude loop to check whether the wipe before external loop + // should be executed + std::string extrude_entity(const ExtrusionEntity &entity, std::string description = "", double speed = -1., const ExtrusionEntitiesPtr& region_perimeters = ExtrusionEntitiesPtr()); + // Orca: pass the complete collection of region perimeters to the extrude loop to check whether the wipe before external loop + // should be executed + std::string extrude_loop(ExtrusionLoop loop, std::string description, double speed = -1., const ExtrusionEntitiesPtr& region_perimeters = ExtrusionEntitiesPtr()); std::string extrude_multi_path(ExtrusionMultiPath multipath, std::string description = "", double speed = -1.); std::string extrude_path(ExtrusionPath path, std::string description = "", double speed = -1.);