diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 98ad9e2e62..83b264803c 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -32,8 +32,8 @@ public: ExPolygon& operator=(const ExPolygon &other) = default; ExPolygon& operator=(ExPolygon &&other) = default; - Polygon contour; - Polygons holes; + Polygon contour; //CCW + Polygons holes; //CW void clear() { contour.points.clear(); holes.clear(); } void scale(double factor); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 09b35157c4..887caa8bf5 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -422,7 +422,8 @@ void PrintObject::generate_support_spots() PrintTryCancel cancel_func = m_print->make_try_cancel(); SupportSpotsGenerator::Params params{this->print()->m_config.filament_type.values, float(this->print()->m_config.perimeter_acceleration.getFloat()), - this->config().raft_layers.getInt()}; + this->config().raft_layers.getInt(), this->config().brim_type.value, + float(this->config().brim_width.getFloat())}; auto [supp_points, partial_objects] = SupportSpotsGenerator::full_search(this, cancel_func, params); this->m_shared_regions->generated_support_points = {this->trafo_centered(), supp_points}; m_print->throw_if_canceled(); @@ -430,27 +431,33 @@ void PrintObject::generate_support_spots() auto alert_fn = [&](PrintStateBase::WarningLevel level, SupportSpotsGenerator::SupportPointCause cause) { switch (cause) { case SupportSpotsGenerator::SupportPointCause::LongBridge: - this->active_step_add_warning(level, L("There are bridges longer than allowed distance. Consider adding supports. ")); + this->active_step_add_warning(level, L("There are bridges longer than recommended length. Consider adding supports.") + + (L("Object name")) + ": " + this->model_object()->name); break; case SupportSpotsGenerator::SupportPointCause::FloatingBridgeAnchor: - this->active_step_add_warning(level, L("Unsupported bridges will collapse. Supports are needed.")); + this->active_step_add_warning(level, L("Unsupported bridges will collapse. Supports are needed.") + (L("Object name")) + + ": " + this->model_object()->name); break; case SupportSpotsGenerator::SupportPointCause::FloatingExtrusion: if (level == PrintStateBase::WarningLevel::CRITICAL) { - this->active_step_add_warning(level, L("Clusters of unsupported extrusions found. Supports are needed.")); + this->active_step_add_warning(level, L("Clusters of unsupported extrusions found. Supports are needed.") + + (L("Object name")) + ": " + this->model_object()->name); } else { - this->active_step_add_warning(level, L("Some unspported extrusions found. Consider adding supports. ")); + this->active_step_add_warning(level, L("Some unspported extrusions found. Consider adding supports. ") + + (L("Object name")) + ": " + this->model_object()->name); } break; case SupportSpotsGenerator::SupportPointCause::SeparationFromBed: - this->active_step_add_warning(level, L("Object part may break from the bed. Consider adding brim and/or supports.")); + this->active_step_add_warning(level, L("Object part may break from the bed. Consider adding brim and/or supports.") + + (L("Object name")) + ": " + this->model_object()->name); break; case SupportSpotsGenerator::SupportPointCause::UnstableFloatingPart: - this->active_step_add_warning(level, L("Floating object parts detected. Supports are needed.")); + this->active_step_add_warning(level, L("Floating object parts detected. Supports are needed.") + (L("Object name")) + + ": " + this->model_object()->name); break; case SupportSpotsGenerator::SupportPointCause::WeakObjectPart: - this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, - L("Thin parts of the object may break. Supports are needed.")); + this->active_step_add_warning(level, L("Thin parts of the object may break. Consider adding supports.") + + (L("Object name")) + ": " + this->model_object()->name); break; } }; @@ -495,9 +502,9 @@ void PrintObject::estimate_curled_extrusions() // Estimate curling of support material and add it to the malformaition lines of each layer float support_flow_width = support_material_flow(this, this->config().layer_height).width(); SupportSpotsGenerator::Params params{this->print()->m_config.filament_type.values, - float(this->print()->config().perimeter_acceleration.getFloat()), - this->config().raft_layers.getInt() - }; + float(this->print()->m_config.perimeter_acceleration.getFloat()), + this->config().raft_layers.getInt(), this->config().brim_type.value, + float(this->config().brim_width.getFloat())}; SupportSpotsGenerator::estimate_supports_malformations(this->support_layers(), support_flow_width, params); SupportSpotsGenerator::estimate_malformations(this->layers(), params); m_print->throw_if_canceled(); @@ -609,6 +616,7 @@ bool PrintObject::invalidate_state_by_config_options( if ( opt_key == "brim_width" || opt_key == "brim_separation" || opt_key == "brim_type") { + steps.emplace_back(posSupportSpotsSearch); // Brim is printed below supports, support invalidates brim and skirt. steps.emplace_back(posSupportMaterial); } else if ( diff --git a/src/libslic3r/SupportSpotsGenerator.cpp b/src/libslic3r/SupportSpotsGenerator.cpp index 7eec832c18..7a77ae767d 100644 --- a/src/libslic3r/SupportSpotsGenerator.cpp +++ b/src/libslic3r/SupportSpotsGenerator.cpp @@ -11,6 +11,7 @@ #include "PrincipalComponents2D.hpp" #include "Print.hpp" #include "PrintBase.hpp" +#include "PrintConfig.hpp" #include "Tesselate.hpp" #include "libslic3r.h" #include "tbb/parallel_for.h" @@ -598,10 +599,11 @@ public: }; // return new object part and actual area covered by extrusions -std::tuple build_object_part_from_slice(const LayerSlice &slice, const Layer *layer, const Params& params) +std::tuple build_object_part_from_slice(const size_t &slice_idx, const Layer *layer, const Params& params) { ObjectPart new_object_part; float area_covered_by_extrusions = 0; + const LayerSlice& slice = layer->lslices_ex.at(slice_idx); auto add_extrusions_to_object = [&new_object_part, &area_covered_by_extrusions, ¶ms](const ExtrusionEntity *e, const LayerRegion *region) { @@ -659,6 +661,49 @@ std::tuple build_object_part_from_slice(const LayerSlice &sli } } + // BRIM HANDLING + if (layer->id() == params.raft_layers_count && params.raft_layers_count == 0 && params.brim_type != BrimType::btNoBrim) { + // 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. + ExPolygon slice_poly = layer->lslices[slice_idx]; + ExPolygons brim; + if (params.brim_type == BrimType::btOuterAndInner || params.brim_type == BrimType::btOuterOnly) { + Polygon brim_hole = slice_poly.contour; + brim_hole.reverse(); + brim.push_back(ExPolygon{expand(slice_poly.contour, scale_(params.brim_width)).front(), brim_hole}); + } + if (params.brim_type == BrimType::btOuterAndInner || params.brim_type == BrimType::btInnerOnly) { + Polygons brim_contours = slice_poly.holes; + polygons_reverse(brim_contours); + for (const Polygon &brim_contour : brim_contours) { + Polygons brim_holes = shrink({brim_contour}, scale_(params.brim_width)); + polygons_reverse(brim_holes); + ExPolygon inner_brim{brim_contour}; + inner_brim.holes = brim_holes; + brim.push_back(inner_brim); + } + } + + for (const Polygon &poly : to_polygons(brim)) { + Vec2f p0 = unscaled(poly.first_point()).cast(); + for (size_t i = 2; i < poly.points.size(); i++) { + Vec2f p1 = unscaled(poly.points[i - 1]).cast(); + Vec2f p2 = unscaled(poly.points[i]).cast(); + + float sign = cross2(p1 - p0, p2 - p1) > 0 ? 1.0f : -1.0f; + + auto [area, first_moment_of_area, second_moment_area, + second_moment_of_area_covariance] = compute_moments_of_area_of_triangle(p0, p1, p2); + new_object_part.sticking_area += sign * area; + new_object_part.sticking_centroid_accumulator += sign * Vec3f(first_moment_of_area.x(), first_moment_of_area.y(), + layer->print_z * area); + new_object_part.sticking_second_moment_of_area_accumulator += sign * second_moment_area; + new_object_part.sticking_second_moment_of_area_covariance_accumulator += sign * second_moment_of_area_covariance; + } + } + } + return {new_object_part, area_covered_by_extrusions}; } @@ -730,7 +775,7 @@ std::tuple check_stability(const PrintObject *po, for (size_t slice_idx = 0; slice_idx < layer->lslices_ex.size(); ++slice_idx) { const LayerSlice &slice = layer->lslices_ex.at(slice_idx); - auto [new_part, covered_area] = build_object_part_from_slice(slice, layer, params); + auto [new_part, covered_area] = build_object_part_from_slice(slice_idx, layer, params); SliceConnection connection_to_below = estimate_slice_connection(slice_idx, layer); #ifdef DETAILED_DEBUG_LOGS @@ -1146,13 +1191,6 @@ void raise_alerts_for_issues(const SupportPoints } } - for (const SupportPoint &sp : support_points) { - if (sp.cause == SupportPointCause::WeakObjectPart) { - alert_fn(PrintStateBase::WarningLevel::CRITICAL, SupportPointCause::WeakObjectPart); - return; - } - } - std::vector ext_supp_points{}; ext_supp_points.reserve(support_points.size()); for (const SupportPoint &sp : support_points) { @@ -1189,8 +1227,15 @@ void raise_alerts_for_issues(const SupportPoints for (const SupportPoint &sp : support_points) { if (sp.cause == SupportPointCause::LongBridge) { - alert_fn(PrintStateBase::WarningLevel::CRITICAL, SupportPointCause::LongBridge); - return; + alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::LongBridge); + break; + } + } + + for (const SupportPoint &sp : support_points) { + if (sp.cause == SupportPointCause::WeakObjectPart) { + alert_fn(PrintStateBase::WarningLevel::NON_CRITICAL, SupportPointCause::WeakObjectPart); + break; } } } diff --git a/src/libslic3r/SupportSpotsGenerator.hpp b/src/libslic3r/SupportSpotsGenerator.hpp index bd33018745..23fb5dad0b 100644 --- a/src/libslic3r/SupportSpotsGenerator.hpp +++ b/src/libslic3r/SupportSpotsGenerator.hpp @@ -4,6 +4,7 @@ #include "Layer.hpp" #include "Line.hpp" #include "PrintBase.hpp" +#include "PrintConfig.hpp" #include #include #include @@ -14,8 +15,9 @@ namespace SupportSpotsGenerator { struct Params { - Params(const std::vector &filament_types, float max_acceleration, int raft_layers_count) - : max_acceleration(max_acceleration), raft_layers_count(raft_layers_count) + Params( + const std::vector &filament_types, float max_acceleration, int raft_layers_count, BrimType brim_type, float brim_width) + : max_acceleration(max_acceleration), raft_layers_count(raft_layers_count), brim_type(brim_type), brim_width(brim_width) { if (filament_types.size() > 1) { BOOST_LOG_TRIVIAL(warning) @@ -37,6 +39,9 @@ struct Params const int raft_layers_count; std::string filament_type; + BrimType brim_type; + const float brim_width; + const std::pair malformation_distance_factors = std::pair { 0.4, 1.2 }; const float max_curled_height_factor = 10.0f; @@ -53,7 +58,7 @@ struct Params // MPa * 1e^6 = (g*mm/s^2)/mm^2 = g/(mm*s^2); yield strength of the bed surface double get_bed_adhesion_yield_strength() const { if (raft_layers_count > 0) { - return get_support_spots_adhesion_strength(); + return get_support_spots_adhesion_strength() * 2.0; } if (filament_type == "PLA") {