diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index ffffd9d31..07031d7e4 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2308,7 +2308,8 @@ void GCode::process_layer_single_object( ExtrusionEntitiesPtr temp_fill_extrusions; if (const Layer *layer = layer_to_print.object_layer; layer) - for (const LayerSlice &lslice : layer->lslices_ex) { + for (size_t idx : layer->lslice_indices_sorted_by_print_order) { + const LayerSlice &lslice = layer->lslices_ex[idx]; auto extrude_infill_range = [&]( const LayerRegion &layerm, const ExtrusionEntityCollection &fills, LayerExtrusionRanges::const_iterator it_fill_ranges_begin, LayerExtrusionRanges::const_iterator it_fill_ranges_end, bool ironing) { diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 9b0004e98..378352be7 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -38,32 +38,37 @@ LayerRegion* Layer::add_region(const PrintRegion *print_region) // merge all regions' slices to get islands void Layer::make_slices() { - ExPolygons slices; - if (m_regions.size() == 1) { - // optimization: if we only have one region, take its slices - slices = to_expolygons(m_regions.front()->slices().surfaces); - } else { - Polygons slices_p; - for (LayerRegion *layerm : m_regions) - polygons_append(slices_p, to_polygons(layerm->slices().surfaces)); - slices = union_safety_offset_ex(slices_p); + { + ExPolygons slices; + if (m_regions.size() == 1) { + // optimization: if we only have one region, take its slices + slices = to_expolygons(m_regions.front()->slices().surfaces); + } else { + Polygons slices_p; + for (LayerRegion *layerm : m_regions) + polygons_append(slices_p, to_polygons(layerm->slices().surfaces)); + slices = union_safety_offset_ex(slices_p); + } + // lslices are sorted by topological order from outside to inside from the clipper union used above + this->lslices = slices; } - - this->lslices.clear(); - this->lslices.reserve(slices.size()); - + + // prepare lslices ordered by print order + this->lslice_indices_sorted_by_print_order.clear(); + this->lslice_indices_sorted_by_print_order.reserve(lslices.size()); // prepare ordering points Points ordering_points; - ordering_points.reserve(slices.size()); - for (const ExPolygon &ex : slices) + ordering_points.reserve( this->lslices.size()); + for (const ExPolygon &ex : this->lslices) ordering_points.push_back(ex.contour.first_point()); // sort slices std::vector order = chain_points(ordering_points); - + // populate slices vector - for (size_t i : order) - this->lslices.emplace_back(std::move(slices[i])); + for (size_t i : order) { + this->lslice_indices_sorted_by_print_order.emplace_back(i); + } } // used by Layer::build_up_down_graph() diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index cfeace67b..11193828c 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -336,6 +336,7 @@ public: // These lslices are also used to detect overhangs and overlaps between successive layers, therefore it is important // that the 1st lslice is not compensated by the Elephant foot compensation algorithm. ExPolygons lslices; + std::vector lslice_indices_sorted_by_print_order; LayerSlices lslices_ex; size_t region_count() const { return m_regions.size(); } diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index d6a4692f3..76f784d6d 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -444,7 +444,7 @@ static std::vector s_Preset_print_options { "top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed", "bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration", "bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield", - "min_skirt_length", "brim_width", "brim_separation", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers", + "min_skirt_length", "brim_width", "brim_separation", "brim_type", "check_for_issues_mode", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers", "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion", "support_material_pattern", "support_material_with_sheath", "support_material_spacing", "support_material_closing_radius", "support_material_style", "support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_bottom_interface_layers", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 1d0446ce2..8c0b0f928 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -537,7 +537,7 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionFloat(60)); def = this->add("enable_dynamic_overhang_speeds", coBool); - def->label = L("Enable dynamic overhang speeds (Experimental)"); + def->label = L("Enable dynamic overhang speeds"); def->category = L("Speed"); def->tooltip = L("This setting enables dynamic speed control on overhangs."); def->mode = comAdvanced; @@ -2589,6 +2589,14 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionEnum(SlicingMode::Regular)); + def = this->add("check_for_issues_mode", coBool); + def->label = L("Check for issues: "); + def->category = L("Support material"); + def->tooltip = L("Check for supportable issues that may appear during printing. " + "If enabled, slicer will make alerts when it detects " + "issues that may be resolved with supports and/or brim."); + def->set_default_value(new ConfigOptionBool(true)); + def = this->add("support_material", coBool); def->label = L("Generate support material"); def->category = L("Support material"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 6bfc7723d..bdf82e3be 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -516,6 +516,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionInt, wall_distribution_count)) ((ConfigOptionFloatOrPercent, min_feature_size)) ((ConfigOptionFloatOrPercent, min_bead_width)) + ((ConfigOptionBool, check_for_issues_mode)) ((ConfigOptionBool, support_material)) // Automatic supports (generated based fdm support point generator). ((ConfigOptionBool, support_material_auto)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 82b69baa3..8fc016950 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -462,7 +462,7 @@ void PrintObject::generate_support_spots() } }; - if (!this->has_support()) { + if (!this->has_support() && this->config().check_for_issues_mode.getBool()) { SupportSpotsGenerator::raise_alerts_for_issues(supp_points, partial_objects, alert_fn); } } @@ -619,6 +619,8 @@ bool PrintObject::invalidate_state_by_config_options( steps.emplace_back(posSupportSpotsSearch); // Brim is printed below supports, support invalidates brim and skirt. steps.emplace_back(posSupportMaterial); + }else if (opt_key == "check_for_issues_mode") { + steps.emplace_back(posSupportSpotsSearch); } else if ( opt_key == "perimeters" || opt_key == "extra_perimeters" diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 81e21f305..0d950b93e 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -799,7 +799,7 @@ void PrintObject::slice_volumes() layer->m_regions[region_id]->trim_surfaces(trimming); } } - // Merge all regions' slices to get islands, chain them by a shortest path. + // Merge all regions' slices to get islands sorted topologically, chain them by a shortest path in separate index list layer->make_slices(); } }); diff --git a/src/libslic3r/SupportSpotsGenerator.cpp b/src/libslic3r/SupportSpotsGenerator.cpp index 3820aa4d5..47e7228d4 100644 --- a/src/libslic3r/SupportSpotsGenerator.cpp +++ b/src/libslic3r/SupportSpotsGenerator.cpp @@ -260,8 +260,8 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit SupportPointCause potential_cause = std::abs(curr_point.curvature) > 0.1 ? SupportPointCause::FloatingBridgeAnchor : SupportPointCause::LongBridge; - float line_len = i > 0 ? ((annotated_points[i - 1].position - curr_point.position).norm()) : 0.0f; - Vec2d line_dir = (curr_point.position - prev_point.position).normalized(); + float line_len = i > 0 ? ((annotated_points[i - 1].position - curr_point.position).norm()) : 0.0f; + Vec2d line_dir = line_len > EPSILON ? Vec2d((curr_point.position - prev_point.position) / double(line_len)) : Vec2d::Zero(); ExtrusionLine line_out{i > 0 ? annotated_points[i - 1].position.cast() : curr_point.position.cast(), curr_point.position.cast(), line_len, entity}; @@ -335,14 +335,6 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit line_out.form_quality = 0.8f; bridged_distance += line_len; if (bridged_distance > max_bridge_len) { - std::cout << "Problem found A: " << std::endl; - std::cout << "bridged_distance: " << bridged_distance << std::endl; - std::cout << "max_bridge_len: " << max_bridge_len << std::endl; - std::cout << "line_out.form_quality: " << line_out.form_quality << std::endl; - std::cout << "curr_point.distance: " << curr_point.distance << std::endl; - std::cout << "curr_point.curvature: " << curr_point.curvature << std::endl; - std::cout << "flow_width: " << flow_width << std::endl; - line_out.support_point_generated = potential_cause; bridged_distance = 0.0f; } @@ -350,14 +342,6 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit bridged_distance += line_len; line_out.form_quality = nearest_prev_layer_line.form_quality - 0.3f; if (line_out.form_quality < 0 && bridged_distance > max_bridge_len) { - std::cout << "Problem found B: " << std::endl; - std::cout << "bridged_distance: " << bridged_distance << std::endl; - std::cout << "max_bridge_len: " << max_bridge_len << std::endl; - std::cout << "line_out.form_quality: " << line_out.form_quality << std::endl; - std::cout << "curr_point.distance: " << curr_point.distance << std::endl; - std::cout << "curr_point.curvature: " << curr_point.curvature << std::endl; - std::cout << "flow_width: " << flow_width << std::endl; - line_out.support_point_generated = potential_cause; line_out.form_quality = 0.5f; bridged_distance = 0.0f; @@ -662,7 +646,8 @@ std::tuple build_object_part_from_slice(const size_t &slice_i } // BRIM HANDLING - if (layer->id() == params.raft_layers_count && params.raft_layers_count == 0 && params.brim_type != BrimType::btNoBrim) { + if (layer->id() == params.raft_layers_count && params.raft_layers_count == 0 && params.brim_type != BrimType::btNoBrim && + params.brim_width > 0.0) { // TODO: The algorithm here should take into account that multiple slices may have coliding Brim areas and the final brim area is // smaller, // thus has lower adhesion. For now this effect will be neglected. @@ -921,7 +906,8 @@ std::tuple check_stability(const PrintObject *po, for (const auto &perimeter_idx : island.perimeters) { const ExtrusionEntity *entity = perimeter_region->perimeters().entities[perimeter_idx]; std::vector perims = check_extrusion_entity_stability(entity, perimeter_region, - prev_layer_ext_perim_lines,prev_layer_boundary, params); + prev_layer_ext_perim_lines, prev_layer_boundary, + params); for (const ExtrusionLine &perim : perims) { if (perim.support_point_generated.has_value()) { reckon_new_support_point(*perim.support_point_generated, create_support_point_position(perim.b), -EPSILON, @@ -932,6 +918,30 @@ std::tuple check_stability(const PrintObject *po, } } } + // DEBUG EXPORT, NOT USED NOW + // if (BR_bridge) { + // Lines scaledl; + // for (const auto &l : prev_layer_boundary.get_lines()) { + // scaledl.emplace_back(Point::new_scale(l.a), Point::new_scale(l.b)); + // } + + // Lines perimsl; + // for (const auto &l : current_slice_ext_perims_lines) { + // perimsl.emplace_back(Point::new_scale(l.a), Point::new_scale(l.b)); + // } + + // BoundingBox bb = get_extents(scaledl); + // bb.merge(get_extents(perimsl)); + + // ::Slic3r::SVG svg(debug_out_path( + // ("slice" + std::to_string(slice_idx) + "_" + std::to_string(layer_idx).c_str()).c_str()), + // get_extents(scaledl)); + // svg.draw(scaledl, "red", scale_(0.4)); + // svg.draw(perimsl, "blue", scale_(0.25)); + + + // svg.Close(); + // } } LD current_slice_lines_distancer(current_slice_ext_perims_lines); @@ -1165,13 +1175,6 @@ void raise_alerts_for_issues(const SupportPoints PartialObjects &partial_objects, std::function alert_fn) { - for (const SupportPoint &sp : support_points) { - if (sp.cause == SupportPointCause::SeparationFromBed) { - alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::SeparationFromBed); - break; - } - } - std::reverse(partial_objects.begin(), partial_objects.end()); std::sort(partial_objects.begin(), partial_objects.end(), [](const PartialObject &left, const PartialObject &right) { return left.volume > right.volume; }); @@ -1221,21 +1224,29 @@ void raise_alerts_for_issues(const SupportPoints } } - if (ext_supp_points.size() > 5) { - alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::FloatingExtrusion); - } - for (const SupportPoint &sp : support_points) { - if (sp.cause == SupportPointCause::LongBridge) { - alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::LongBridge); - break; + if (sp.cause == SupportPointCause::SeparationFromBed) { + alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::SeparationFromBed); + return; } } for (const SupportPoint &sp : support_points) { if (sp.cause == SupportPointCause::WeakObjectPart) { alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::WeakObjectPart); - break; + return; + } + } + + if (ext_supp_points.size() > 5) { + alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::FloatingExtrusion); + return; + } + + for (const SupportPoint &sp : support_points) { + if (sp.cause == SupportPointCause::LongBridge) { + alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::LongBridge); + return; } } } diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index c06947565..cbe1805ee 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -53,7 +53,7 @@ static SettingsFactory::Bundle FREQ_SETTINGS_BUNDLE_FFF = { { L("Layers and Perimeters"), { "layer_height" , "perimeters", "top_solid_layers", "bottom_solid_layers" } }, { L("Infill") , { "fill_density", "fill_pattern" } }, - { L("Support material") , { "support_material", "support_material_auto", "support_material_threshold", + { L("Support material") , { "check_for_issues_mode", "support_material", "support_material_auto", "support_material_threshold", "support_material_pattern", "support_material_interface_pattern", "support_material_buildplate_only", "support_material_spacing" } }, { L("Wipe options") , { "wipe_into_infill", "wipe_into_objects" } } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 43eaa1a22..e9c854774 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1495,6 +1495,7 @@ void TabPrint::build() page = add_options_page(L("Support material"), "support"); category_path = "support-material_1698#"; optgroup = page->new_optgroup(L("Support material")); + optgroup->append_single_option_line("check_for_issues_mode", category_path + "check-for-issues-mode"); optgroup->append_single_option_line("support_material", category_path + "generate-support-material"); optgroup->append_single_option_line("support_material_auto", category_path + "auto-generated-supports"); optgroup->append_single_option_line("support_material_threshold", category_path + "overhang-threshold");