diff --git a/resources/localization/fr/Slic3r.po b/resources/localization/fr/Slic3r.po index c686b1867f5..c43ab2d3091 100644 --- a/resources/localization/fr/Slic3r.po +++ b/resources/localization/fr/Slic3r.po @@ -11139,7 +11139,7 @@ msgstr "Mode simple" msgid "Simple widget to enable/disable the overhangs detection (using 55% and 75% for the two thresholds)\nUse the expert mode to get more detailled widgets" msgstr "" "Element graphique simplifié pour activer/désactiver la détection des " -"surplombs (utisant 55% et 75% pour els deux seuils)\n" +"surplombs (utisant 55% et 75% pour les deux seuils)\n" "Utiliser le mode expert permet de modifier les seuils." msgid "Simulate Prusa 'no thick bridge'" diff --git a/resources/localization/fr/fr_database.po b/resources/localization/fr/fr_database.po index 464e52fa6b5..652c058c468 100644 --- a/resources/localization/fr/fr_database.po +++ b/resources/localization/fr/fr_database.po @@ -11118,7 +11118,7 @@ msgstr "Mode simple" msgid "Simple widget to enable/disable the overhangs detection (using 55% and 75% for the two thresholds)\nUse the expert mode to get more detailled widgets" msgstr "" "Element graphique simplifié pour activer/désactiver la détection des " -"surplombs (utisant 55% et 75% pour els deux seuils)\n" +"surplombs (utisant 55% et 75% pour les deux seuils)\n" "Utiliser le mode expert permet de modifier les seuils." msgid "Simulate Prusa 'no thick bridge'" diff --git a/resources/ui_layout/default/print.ui b/resources/ui_layout/default/print.ui index a1b54e6b2b7..3fb60dcb189 100644 --- a/resources/ui_layout/default/print.ui +++ b/resources/ui_layout/default/print.ui @@ -37,11 +37,6 @@ group:Quality setting:label$_:ensure_vertical_shell_thickness setting:solid_over_perimeters end_line - line:Avoid crossing perimeters - setting:label$_:avoid_crossing_perimeters - setting:label_width$12:label$Not on first layer:avoid_crossing_not_first_layer - setting:sidetext_width$15:avoid_crossing_perimeters_max_detour - end_line line:Overlapping external perimeter setting:label$_:thin_perimeters setting:label_width$12:label$Also for all perimeters:thin_perimeters_all @@ -52,6 +47,15 @@ group:Quality setting:width$5:thin_walls_overlap setting:thin_walls_merge end_line +group:Avoid crossing perimeters + line:Activate + setting:label$_:avoid_crossing_perimeters + setting:sidetext_width$15:avoid_crossing_perimeters_max_detour + end_line + line:Modifiers + setting:label_width$12:label$Not on first layer:avoid_crossing_not_first_layer + setting:avoid_crossing_top + end_line group:label_width$12:Overhangs line:threshold for setting:script:bool:advanced:depends$overhangs_width_speed$overhangs_width:label$_:label_width$0:tooltip$Simple widget to enable/disable the overhangs detection (using 55% and 75% for the two thresholds)\nUse the expert mode to get more detailled widgets:s_overhangs diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index f3007aad739..bbc81a65899 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -700,6 +700,23 @@ class GetPathsVisitor : public ExtrusionVisitorRecursive { } }; + +#if _DEBUG +struct LoopAssertVisitor : public ExtrusionVisitorRecursiveConst { + virtual void default_use(const ExtrusionEntity& entity) override {}; + virtual void use(const ExtrusionLoop& loop) override { + for (auto it = std::next(loop.paths.begin()); it != loop.paths.end(); ++it) { + assert(it->polyline.size() >= 2); + assert(std::prev(it)->polyline.back() == it->polyline.front()); + } + for (auto it = loop.paths.begin(); it != loop.paths.end(); ++it) { + assert(it->length() > SCALED_EPSILON); + } + assert(loop.paths.front().first_point() == loop.paths.back().last_point()); + } +}; +#endif + } #endif diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 5fa9332fb6f..69545332479 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1294,7 +1294,7 @@ void GCode::_do_export(Print& print_mod, GCodeOutputStream &file, ThumbnailsGene //apply print config to m_config and m_writer, so we don't have to use print.config() instead // (and mostly to make m_writer.preamble() works) - this->apply_print_config(print.config()); + this->apply_print_configs(print); // modifies m_silent_time_estimator_enabled DoExport::init_gcode_processor(print.config(), m_processor, m_silent_time_estimator_enabled); @@ -2888,6 +2888,7 @@ LayerResult GCode::process_layer( uint16_t first_extruder_id = layer_tools.extruders.front(); // Initialize config with the 1st object to be printed at this layer. + m_config.apply(print.default_region_config(), true); m_config.apply(layer.object()->config(), true); // Check whether it is possible to apply the spiral vase logic for this layer. @@ -3197,6 +3198,8 @@ LayerResult GCode::process_layer( set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id); if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) { + //global skirt & brim use the global settings. + m_config.apply(print.default_object_config(), true); // before going to and from a global skirt, please ensure you are a a safe height set_extra_lift(m_last_layer_z, layer.id(), print.config(), m_writer, extruder_id); const std::pair loops = loops_it->second; @@ -3227,6 +3230,8 @@ LayerResult GCode::process_layer( // Extrude brim with the extruder of the 1st region. if (! m_brim_done) { + //global skirt & brim use the global settings. + m_config.apply(print.default_object_config(), true); this->set_origin(0., 0.); m_avoid_crossing_perimeters.use_external_mp(); for (const ExtrusionEntity* brim_entity : print.brim().entities()) { @@ -3248,6 +3253,8 @@ LayerResult GCode::process_layer( && extruder_id == layer_tools.extruders.front()) { const PrintObject *print_object = layers.front().object(); + //object skirt & brim use the object settings. + m_config.apply(print_object->config(), true); this->set_origin(unscale(print_object->instances()[single_object_instance_idx].shift)); if (this->m_layer != nullptr && (this->m_layer->id() < m_config.skirt_height || print.has_infinite_skirt() )) { if(first_layer && print.skirt_first_layer()) @@ -3264,6 +3271,8 @@ LayerResult GCode::process_layer( && extruder_id == layer_tools.extruders.front()) { const PrintObject* print_object = layers.front().object(); + //object skirt & brim use the object settings. + m_config.apply(print_object->config(), true); this->set_origin(unscale(print_object->instances()[single_object_instance_idx].shift)); if (this->m_layer != nullptr && this->m_layer->id() == 0) { m_avoid_crossing_perimeters.use_external_mp(true); @@ -3291,6 +3300,8 @@ LayerResult GCode::process_layer( bool first_object = true; for (InstanceToPrint &instance_to_print : instances_to_print) { const LayerToPrint &layer_to_print = layers[instance_to_print.layer_id]; + m_config.apply(instance_to_print.print_object.config(), true); + // To control print speed of the 1st object layer printed over raft interface. bool object_layer_over_raft = layer_to_print.object_layer && layer_to_print.object_layer->id() > 0 && instance_to_print.print_object.slicing_parameters().raft_layers() == layer_to_print.object_layer->id(); @@ -3310,7 +3321,6 @@ LayerResult GCode::process_layer( instance_id + "_copy_" + instance_copy; - m_config.apply(instance_to_print.print_object.config(), true); m_layer = layer_to_print.layer(); m_object_layer_over_raft = object_layer_over_raft; m_print_object_instance_id = static_cast(instance_to_print.instance_id); @@ -3545,11 +3555,15 @@ LayerResult GCode::process_layer( return result; } -void GCode::apply_print_config(const PrintConfig &print_config) +void GCode::apply_print_configs(const Print&print) { - m_writer.apply_print_config(print_config); - m_config.apply(print_config); - m_scaled_gcode_resolution = scaled(print_config.gcode_resolution.value); + //apply also default region & object, just in case, as they won't be applied since the first extrusion on a region / the first layer process on an object + m_writer.apply_print_config(print.config()); + m_writer.apply_print_region_config(print.default_region_config()); + m_config.apply(print.config()); + m_config.apply(print.default_object_config()); + m_config.apply(print.default_region_config()); + m_scaled_gcode_resolution = scale_d(print.config().gcode_resolution.value); } void GCode::append_full_config(const Print &print, std::string &str) @@ -5880,6 +5894,7 @@ Polyline GCode::travel_to(std::string &gcode, const Point &point, ExtrusionRole bool could_be_wipe_disabled = false; // Save state of use_external_mp_once for the case that will be needed to call twice m_avoid_crossing_perimeters.travel_to. const bool used_external_mp_once = m_avoid_crossing_perimeters.used_external_mp_once(); + const bool used_disabled_once = m_avoid_crossing_perimeters.disabled_once(); //can use the avoid crossing algo? bool can_avoid_cross_peri = m_config.avoid_crossing_perimeters @@ -5913,9 +5928,11 @@ Polyline GCode::travel_to(std::string &gcode, const Point &point, ExtrusionRole //if (could_be_wipe_disabled) { // m_wipe.reset_path(); //} else { + //check if it cross hull auto result = diff_pl(Polylines{ travel }, to_polygons(m_layer->lslices)); - if (result.empty()) + if (result.empty()) { m_wipe.reset_path(); + } //} } @@ -5935,6 +5952,9 @@ Polyline GCode::travel_to(std::string &gcode, const Point &point, ExtrusionRole // If in the previous call of m_avoid_crossing_perimeters.travel_to was use_external_mp_once set to true restore this value for next call. if (used_external_mp_once) m_avoid_crossing_perimeters.use_external_mp_once(); + if (used_disabled_once) + m_avoid_crossing_perimeters.disable_once(); + // Because of it, it is necessary to redo the thing travel = m_avoid_crossing_perimeters.travel_to(*this, point); updated_first_pos = true; diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index c2632d846ac..89653e6363c 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -187,7 +187,7 @@ class GCode : ExtrusionVisitorConst { // For Perl bindings, to be used exclusively by unit tests. unsigned int layer_count() const { return m_layer_count; } void set_layer_count(unsigned int value) { m_layer_count = value; } - void apply_print_config(const PrintConfig &print_config); + void apply_print_configs(const Print &print); // append full config to the given string static void append_full_config(const Print& print, std::string& str); diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp index d2157bae69b..aa319ed52e3 100644 --- a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp +++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp @@ -368,7 +368,7 @@ static void export_travel_to_svg(const Polygons &boundary, coordf_t stroke_width = scale_(0.05); BoundingBox bbox = get_extents(boundary); ::Slic3r::SVG svg(path, bbox); - svg.draw_outline(boundary, "green", stroke_width); + svg.draw(to_polylines(boundary), "green", stroke_width); svg.draw(original_travel, "blue", stroke_width); svg.draw(result_travel, "red", stroke_width); svg.draw(original_travel.a, "black", stroke_width); @@ -524,10 +524,9 @@ static float get_perimeter_spacing_external(const Layer &layer) } bool is_in_internal_boundary(const AvoidCrossingPerimeters::Boundary& boundary, const Point& pt) { - for (const std::pair& bound : boundary.boundary_growth) - for (const ExPolygon& poly : bound.second) - if (poly.contains(pt)) - return true; + for (const std::pair& bound : boundary.boundary_growth) + if (bound.second.contains(pt)) + return true; return false; } @@ -540,7 +539,7 @@ bool find_point_on_boundary(Point& pt_to_move, const AvoidCrossingPerimeters::Bo if (pt_closest.contour_idx == size_t(-1)) { //manual search on edges bool found = false; - for (const std::pair& bound : boundary.boundary_growth) + for (const std::pair& bound : boundary.boundary_growth) if (bound.first.contains(pt_to_move)) { coordf_t dist2 = std::numeric_limits::max(); for (const Polygon& poly : to_polygons(bound.second)) { @@ -597,20 +596,6 @@ static size_t avoid_perimeters_inner(const AvoidCrossingPerimeters::Boundary &bo if(extrusion_spacing > 0) if (!find_point_on_boundary(start, boundary, (extrusion_spacing * 3)/2) || !find_point_on_boundary(end, boundary, (extrusion_spacing * 3) / 2)) { BOOST_LOG_TRIVIAL(info) << "Fail to find a point in the contour for avoid_perimeter."; - //{ - // static int isazfn = 0; - // std::stringstream stri; - // stri << "avoid_peri_initbad_" << isazfn++ << ".svg"; - // SVG svg(stri.str()); - // for (auto elt : boundary.boundary_growth) - // svg.draw((elt.first), "grey"); - // for (auto elt : boundary.boundary_growth) - // svg.draw((elt.second), "pink"); - // //svg.draw((boundary.boundaries), "pink"); - // svg.draw((Line{ start,end }), "red"); - // svg.draw((Line{ real_start,real_end }), "green"); - // svg.Close(); - //} result_out = { {start,-1}, {end,-1} }; return 0; } @@ -632,7 +617,6 @@ static size_t avoid_perimeters_inner(const AvoidCrossingPerimeters::Boundary &bo const float search_radius = 2.f * get_perimeter_spacing(layer); // When the offset is too big, then original travel doesn't have to cross created boundaries. // These cases are fixed by calling extend_for_closest_lines. -//TODO: check if it isn't detrimental to changes for going around second perimeter... intersections = extend_for_closest_lines(intersections, boundary, start, end, search_radius); } @@ -1047,13 +1031,17 @@ static std::vector contour_distance(const EdgeGrid::Grid &grid, // Polygon offset which ensures that if a polygon breaks up into several separate parts, the original polygon will be used in these places. // ExPolygons are handled one by one so returned ExPolygons could intersect. -static ExPolygons inner_offset(const ExPolygons &ex_polygons, double offset) +static std::vector> inner_offset(const ExPolygons &ex_polygons, double offset) { const std::vector min_contour_width_values = {offset / 2., offset, 2. * offset + SCALED_EPSILON}; - ExPolygons ex_poly_result = ex_polygons; - resample_expolygons(ex_poly_result, offset / 2, scaled(0.5)); + std::vector> ex_poly_result; + for (const ExPolygon &expo : ex_polygons) { + ex_poly_result.emplace_back(expo, expo); + resample_expolygon(ex_poly_result.back().second, offset / 2, scaled(0.5)); + } - for (ExPolygon &ex_poly : ex_poly_result) { + for (std::pair &old_2_new : ex_poly_result) { + ExPolygon &ex_poly = old_2_new.second; BoundingBox bbox(get_extents(ex_poly)); bbox.offset(SCALED_EPSILON); @@ -1122,34 +1110,47 @@ static ExPolygons inner_offset(const ExPolygons &ex_polygons, double offset) //#define INCLUDE_SUPPORTS_IN_BOUNDARY // called by AvoidCrossingPerimeters::travel_to() -static ExPolygons get_boundary(const Layer &layer) +static ExPolygons get_boundary(const Layer &layer, std::vector> &slice_2_boundary) { const float perimeter_spacing = get_perimeter_spacing(layer); const float perimeter_offset = perimeter_spacing / 2.f; auto const *support_layer = dynamic_cast(&layer); - ExPolygons boundary = union_ex(inner_offset(layer.lslices, 1.5 * perimeter_spacing)); + ExPolygons boundary; + auto old_2_new_expolygons = inner_offset(layer.lslices, 1.5 * perimeter_spacing); + for (const std::pair &old_2_new_expoly : old_2_new_expolygons) { + boundary.push_back(old_2_new_expoly.second); + slice_2_boundary.push_back(std::move(old_2_new_expoly)); + } + boundary = union_ex(boundary); if(support_layer) { #ifdef INCLUDE_SUPPORTS_IN_BOUNDARY append(boundary, inner_offset(support_layer->support_islands.expolygons, 1.5 * perimeter_spacing)); #endif auto *layer_below = layer.object()->get_first_layer_bellow_printz(layer.print_z, EPSILON); - if (layer_below) //why? - append(boundary, inner_offset(layer_below->lslices, 1.5 * perimeter_spacing)); + if (layer_below) { // why? + auto old_2_new_expolygons_supp = inner_offset(layer_below->lslices, 1.5 * perimeter_spacing); + for (std::pair &old_2_new_supp : old_2_new_expolygons_supp) { + boundary.push_back(old_2_new_supp.second); + slice_2_boundary.push_back(std::move(old_2_new_supp)); + } + } // After calling inner_offset it is necessary to call union_ex because of the possibility of intersection ExPolygons boundary = union_ex(boundary); } // Collect all top layers that will not be crossed. size_t polygons_count = 0; for (const LayerRegion *layer_region : layer.regions()) - for (const Surface &surface : layer_region->fill_surfaces.surfaces) - if (surface.has_pos_top()) ++polygons_count; + if(layer_region->region().config().avoid_crossing_top) + for (const Surface &surface : layer_region->fill_surfaces.surfaces) + if (surface.has_pos_top()) ++polygons_count; if (polygons_count > 0) { ExPolygons top_layer_polygons; top_layer_polygons.reserve(polygons_count); for (const LayerRegion *layer_region : layer.regions()) - for (const Surface &surface : layer_region->fill_surfaces.surfaces) - if (surface.has_pos_top()) top_layer_polygons.emplace_back(surface.expolygon); + if(layer_region->region().config().avoid_crossing_top) + for (const Surface &surface : layer_region->fill_surfaces.surfaces) + if (surface.has_pos_top()) top_layer_polygons.emplace_back(surface.expolygon); top_layer_polygons = union_ex(top_layer_polygons); return diff_ex(boundary, offset_ex(top_layer_polygons, -perimeter_offset)); @@ -1262,30 +1263,9 @@ Polyline AvoidCrossingPerimeters::travel_to(const GCode &gcodegen, const Point & )) { // Initialize m_internal only when it is necessary. if (m_internal.boundaries.empty()) { - std::vector> boundary_growth; - //create better slice (on second perimeter instead of the first) - ExPolygons expoly_boundary; - //as we are going to reduce, do it expoli per expoli - for (const ExPolygon& origin : lslices) { - ExPolygons second_peri = offset_ex(origin, -perimeter_spacing * 1.5f); - //there is a collapse! try to add missing parts - if (second_peri.size() > 1) { - // get the bits that are collapsed - ExPolygons missing_parts = diff_ex(ExPolygons{ origin }, offset_ex(second_peri, perimeter_spacing * 1.51f), ApplySafetyOffset::Yes); - //have to grow a bit to be able to fit inside the reduced thing - // then intersect to be sure it don't stick out of the initial poly - missing_parts = intersection_ex(ExPolygons{ origin }, offset_ex(missing_parts, perimeter_spacing * 1.1f)); - // offset to second peri (-first) where possible, then union and reduce to the first. - second_peri = offset_ex(union_ex(missing_parts, offset_ex(origin, -perimeter_spacing * 0.9f)), -perimeter_spacing * .6f); - } else if (second_peri.size() == 0) { - // try again with the first perimeter (should be 0.5, but even with overlapping peri, it's almost never a 50% overlap, so it's better that way) - second_peri = offset_ex(origin, -perimeter_spacing * .6f); - } - append(expoly_boundary, second_peri); - boundary_growth.push_back({ origin, second_peri }); - } - init_boundary(&m_internal, to_polygons(expoly_boundary)); - m_internal.boundary_growth = boundary_growth; + std::vector> boundary_growth; + init_boundary(&m_internal, to_polygons(get_boundary(*gcodegen.layer(), boundary_growth))); + m_internal.boundary_growth = std::move(boundary_growth); } // Trim the travel line by the bounding box. diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp index ae70f36ce07..8964b294114 100644 --- a/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp +++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.hpp @@ -44,7 +44,7 @@ class AvoidCrossingPerimeters // Used for detection of intersection between line and any polygon from boundaries EdgeGrid::Grid grid; //used to move the point inside the boundary - std::vector> boundary_growth; + std::vector> boundary_growth; void clear() { diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index c19f3d60b79..99bb3e39d48 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -447,6 +447,9 @@ std::vector CoolingBuffer::parse_layer_gcode(const std:: line.type = CoolingLine::TYPE_G3; if (line.type) { // G0, G1 or G92 + if (m_config.use_relative_e_distances.value) + // Reset extruder accumulator. + current_pos[3] = 0.f; // Parse the G-code line. std::vector new_pos(current_pos); const char *c = sline.data() + 3; @@ -494,9 +497,6 @@ std::vector CoolingBuffer::parse_layer_gcode(const std:: } if ((line.type & CoolingLine::TYPE_G92) == 0) { // G0 or G1. Calculate the duration. - if (m_config.use_relative_e_distances.value) - // Reset extruder accumulator. - current_pos[3] = 0.f; float dif[4]; for (size_t i = 0; i < 4; ++ i) dif[i] = new_pos[i] - current_pos[i]; diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 37fcf91085a..9a4a7318e77 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -2,6 +2,7 @@ #include "BridgeDetector.hpp" #include "ClipperUtils.hpp" +#include "ExtrusionEntity.hpp" #include "ExtrusionEntityCollection.hpp" #include "Geometry.hpp" #include "ShortestPath.hpp" @@ -37,18 +38,6 @@ #endif namespace Slic3r { -#if _DEBUG -struct LoopAssertVisitor : public ExtrusionVisitorRecursiveConst { - virtual void default_use(const ExtrusionEntity& entity) override {}; - virtual void use(const ExtrusionLoop& loop) override { - for (auto it = std::next(loop.paths.begin()); it != loop.paths.end(); ++it) { - assert(it->polyline.size() >= 2); - assert(std::prev(it)->polyline.back() == it->polyline.front()); - } - assert(loop.paths.front().first_point() == loop.paths.back().last_point()); - } -}; -#endif PerimeterGeneratorLoops get_all_Childs(PerimeterGeneratorLoop loop) { PerimeterGeneratorLoops ret; for (PerimeterGeneratorLoop &child : loop.children) { @@ -3067,9 +3056,21 @@ void PerimeterGenerator::_merge_thin_walls(ExtrusionEntityCollection &extrusions searcher.search_result.path->polyline.set_points().erase( searcher.search_result.path->polyline.set_points().begin() + searcher.search_result.idx_line + 1, searcher.search_result.path->polyline.set_points().end()); - searcher.search_result.loop->paths[searcher.search_result.idx_path].polyline.append(point); - searcher.search_result.loop->paths.insert(searcher.search_result.loop->paths.begin() + 1 + searcher.search_result.idx_path, - ExtrusionPath(poly_after, *searcher.search_result.path)); + if (searcher.search_result.loop->paths[searcher.search_result.idx_path].polyline.empty() || + !searcher.search_result.loop->paths[searcher.search_result.idx_path] .polyline.back().coincides_with_epsilon(point)) + searcher.search_result.loop->paths[searcher.search_result.idx_path].polyline.append(point); + if (searcher.search_result.loop->paths[searcher.search_result.idx_path].size() < 2 || + searcher.search_result.loop->paths[searcher.search_result.idx_path].length() < SCALED_EPSILON) { + //if too small, replace + poly_after.points.front() = searcher.search_result.loop->paths[searcher.search_result.idx_path].polyline.front(); + searcher.search_result.loop->paths[searcher.search_result.idx_path] = ExtrusionPath(poly_after, *searcher.search_result.path); + }else{ + searcher.search_result.loop->paths.insert(searcher.search_result.loop->paths.begin() + 1 + searcher.search_result.idx_path, + ExtrusionPath(poly_after, *searcher.search_result.path)); + } + assert(searcher.search_result.loop->paths[searcher.search_result.idx_path].polyline.size() > 1); + assert(poly_after.size() > 1); + //create thin wall path exttrusion ExtrusionEntityCollection tws; tws.append(Geometry::thin_variable_width({ tw }, erThinWall, this->ext_perimeter_flow, std::max(ext_perimeter_flow.scaled_width() / 4, scale_t(this->print_config->resolution)), false)); @@ -3119,6 +3120,9 @@ void PerimeterGenerator::_merge_thin_walls(ExtrusionEntityCollection &extrusions //now add thinwalls that have no anchor (make them reversable) extrusions.append(Geometry::thin_variable_width(not_added, erThinWall, this->ext_perimeter_flow, std::max(ext_perimeter_flow.scaled_width() / 4, scale_t(this->print_config->resolution)), true)); +#if _DEBUG + extrusions.visit(LoopAssertVisitor{}); +#endif } PerimeterIntersectionPoint diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index bd32837407b..75e6a2471a4 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -1721,7 +1721,7 @@ void PlaceholderParser::append_custom_variables(std::map s_Preset_print_options { "allow_empty_layers", "avoid_crossing_perimeters", "avoid_crossing_not_first_layer", + "avoid_crossing_top", "thin_perimeters", "thin_perimeters_all", "overhangs_speed", "overhangs_speed_enforce", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index dbc6f89f469..ebaf8b197b8 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -64,6 +64,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver& /* ne "avoid_crossing_perimeters", "avoid_crossing_perimeters_max_detour", "avoid_crossing_not_first_layer", + "avoid_crossing_top", "bed_shape", "bed_temperature", "chamber_temperature", @@ -1271,6 +1272,14 @@ void Print::process() ); } } + +#if _DEBUG + for (PrintObject* obj : m_objects) { + for (auto &l : obj->m_layers) { + for (auto ® : l->regions()) { reg->perimeters.visit(LoopAssertVisitor{}); } + } + } +#endif m_timestamp_last_change = std::time(0); BOOST_LOG_TRIVIAL(info) << "Slicing process finished." << log_memory_info(); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 9161e72e4fd..b917eb1269d 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -610,7 +610,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Optimize travel moves in order to minimize the crossing of perimeters. " "This is mostly useful with Bowden extruders which suffer from oozing. " "This feature slows down both the print and the G-code generation."); - def->mode = comExpert | comPrusa; + def->mode = comAdvancedE | comPrusa; def->set_default_value(new ConfigOptionBool(false)); def = this->add("avoid_crossing_not_first_layer", coBool); @@ -618,7 +618,7 @@ void PrintConfigDef::init_fff_params() def->full_label = L("Don't avoid crossing on 1st layer"); def->category = OptionCategory::perimeter; def->tooltip = L("Disable 'Avoid crossing perimeters' for the first layer."); - def->mode = comExpert | comSuSi; + def->mode = comAdvancedE | comSuSi; def->set_default_value(new ConfigOptionBool(true)); def = this->add("avoid_crossing_perimeters_max_detour", coFloatOrPercent); @@ -633,6 +633,13 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert | comPrusa; def->set_default_value(new ConfigOptionFloatOrPercent(0., false)); + def = this->add("avoid_crossing_top", coBool); + def->label = L("Avoid top surface for travels"); + def->category = OptionCategory::perimeter; + def->tooltip = L("When using 'Avoid crossing perimeters', consider the top surfaces as a void, to avoid travelling over them if possible."); + def->mode = comAdvancedE | comSuSi; + def->set_default_value(new ConfigOptionBool(true)); + def = this->add("bed_temperature", coInts); def->label = L("Other layers"); def->category = OptionCategory::filament; @@ -7817,6 +7824,7 @@ std::unordered_set prusa_export_to_remove_keys = { "arc_fitting", "arc_fitting_tolerance", "avoid_crossing_not_first_layer", +"avoid_crossing_top", "bridge_fill_pattern", "bridge_internal_acceleration", "bridge_internal_fan_speed", diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index ed471275f96..e4361227a01 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -692,6 +692,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionEnum, brim_ears_pattern)) ((ConfigOptionBool, brim_per_object)) ((ConfigOptionFloat, brim_separation)) + ((ConfigOptionFloatOrPercent, brim_speed)) //((ConfigOptionEnum, brim_type)) ((ConfigOptionBool, clip_multipart_objects)) ((ConfigOptionBool, dont_support_bridges)) @@ -790,6 +791,7 @@ PRINT_CONFIG_CLASS_DEFINE( PRINT_CONFIG_CLASS_DEFINE( PrintRegionConfig, + ((ConfigOptionBool, avoid_crossing_top)) ((ConfigOptionFloat, bridge_angle)) ((ConfigOptionEnum, bridge_fill_pattern)) ((ConfigOptionEnum, bridge_type)) @@ -803,7 +805,6 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloatOrPercent, bridged_infill_margin)) ((ConfigOptionFloatOrPercent, bridge_speed)) ((ConfigOptionFloatOrPercent, bridge_speed_internal)) - ((ConfigOptionFloatOrPercent, brim_speed)) ((ConfigOptionFloat, curve_smoothing_precision)) ((ConfigOptionFloat, curve_smoothing_cutoff_dist)) ((ConfigOptionFloat, curve_smoothing_angle_convex)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 27928a2cfd3..c1f28c9cfe3 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1051,7 +1051,8 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "min_bead_width") { steps.emplace_back(posSlice); } else if ( - opt_key == "bridge_speed" + opt_key == "avoid_crossing_top" + || opt_key == "bridge_speed" || opt_key == "bridge_speed_internal" || opt_key == "external_perimeter_speed" || opt_key == "external_perimeters_vase" diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index a0a03ba6de7..aba0b1ef753 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -390,6 +390,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field(el, config->option>("fuzzy_skin")->value != FuzzySkinType::None); toggle_field("avoid_crossing_not_first_layer", config->opt_bool("avoid_crossing_perimeters")); + toggle_field("avoid_crossing_top", config->opt_bool("avoid_crossing_perimeters")); bool have_infill = config->option("fill_density")->value > 0; // infill_extruder uses the same logic as in Print::extruders()