From 19ca3ee715816ac9f1f71c2d8b326226fc7bbd3d Mon Sep 17 00:00:00 2001 From: igiannakas <59056762+igiannakas@users.noreply.github.com> Date: Sun, 10 Sep 2023 18:44:46 +0100 Subject: [PATCH] Porting curling calculations from Prusa Slier 2.6.1 --- src/libslic3r/ExtrusionEntityCollection.hpp | 8 + src/libslic3r/Print.cpp | 2 + src/libslic3r/Print.hpp | 3 +- src/libslic3r/PrintObject.cpp | 20 ++ src/libslic3r/SupportSpotsGenerator.cpp | 213 ++++++++++---------- src/libslic3r/SupportSpotsGenerator.hpp | 14 +- 6 files changed, 152 insertions(+), 108 deletions(-) diff --git a/src/libslic3r/ExtrusionEntityCollection.hpp b/src/libslic3r/ExtrusionEntityCollection.hpp index 413834db20..7d6f92a528 100644 --- a/src/libslic3r/ExtrusionEntityCollection.hpp +++ b/src/libslic3r/ExtrusionEntityCollection.hpp @@ -46,6 +46,13 @@ public: ~ExtrusionEntityCollection() { clear(); } explicit operator ExtrusionPaths() const; + ExtrusionEntitiesPtr::const_iterator cbegin() const { return this->entities.cbegin(); } + ExtrusionEntitiesPtr::const_iterator cend() const { return this->entities.cend(); } + ExtrusionEntitiesPtr::const_iterator begin() const { return this->entities.cbegin(); } + ExtrusionEntitiesPtr::const_iterator end() const { return this->entities.cend(); } + ExtrusionEntitiesPtr::iterator begin() { return this->entities.begin(); } + ExtrusionEntitiesPtr::iterator end() { return this->entities.end(); } + bool is_collection() const override { return true; } ExtrusionRole role() const override { ExtrusionRole out = erNone; @@ -112,6 +119,7 @@ public: Polygons polygons_covered_by_spacing(const float scaled_epsilon = 0.f) const { Polygons out; this->polygons_covered_by_spacing(out, scaled_epsilon); return out; } size_t items_count() const; + size_t size() const { return entities.size(); } /// Returns a flattened copy of this ExtrusionEntityCollection. That is, all of the items in its entities vector are not collections. /// You should be iterating over flatten().entities if you are interested in the underlying ExtrusionEntities (and don't care about hierarchy). /// \param preserve_ordering Flag to method that will flatten if and only if the underlying collection is sortable when True (default: False). diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index f59c9cd617..dbf71827be 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1693,6 +1693,7 @@ void Print::process(bool use_cache) PrintObject* obj = m_objects[i]; if (need_slicing_objects.count(obj) != 0) { obj->generate_support_material(); + obj->estimate_curled_extrusions(); } else { if (obj->set_started(posSupportMaterial)) @@ -1723,6 +1724,7 @@ void Print::process(bool use_cache) obj->infill(); obj->ironing(); obj->generate_support_material(); + obj->estimate_curled_extrusions(); } } } diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index f688e4ec3b..590bbb1af5 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -88,7 +88,7 @@ enum PrintStep { enum PrintObjectStep { posSlice, posPerimeters, posPrepareInfill, - posInfill, posIroning, posSupportMaterial, posSimplifyPath, posSimplifySupportPath, + posInfill, posIroning, posSupportMaterial, posSimplifyPath, posSimplifySupportPath, posEstimateCurledExtrusions, // BBS posSimplifyInfill, posDetectOverhangsForLift, @@ -468,6 +468,7 @@ private: void infill(); void ironing(); void generate_support_material(); + void estimate_curled_extrusions(); void simplify_extrusion_path(); void slice_volumes(); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index eb83c36209..06cb885855 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -8,6 +8,7 @@ #include "Layer.hpp" #include "MutablePolygon.hpp" #include "SupportMaterial.hpp" +#include "SupportSpotsGenerator.hpp" #include "Support/TreeSupport.hpp" #include "Surface.hpp" #include "Slicing.hpp" @@ -498,6 +499,25 @@ void PrintObject::generate_support_material() } } +void PrintObject::estimate_curled_extrusions() +{ + if (this->set_started(posEstimateCurledExtrusions)) { + if ( std::any_of(this->print()->m_print_regions.begin(), this->print()->m_print_regions.end(), + [](const PrintRegion *region) { return region->config().enable_overhang_speed.getBool(); })) { + + // 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()->m_config.inner_wall_acceleration.getFloat()), + this->config().raft_layers.getInt(), this->config().brim_type.value, + float(this->config().brim_width.getFloat())}; + SupportSpotsGenerator::estimate_malformations(this->layers(), params); + m_print->throw_if_canceled(); + } + this->set_done(posEstimateCurledExtrusions); + } +} + void PrintObject::simplify_extrusion_path() { if (this->set_started(posSimplifyPath)) { diff --git a/src/libslic3r/SupportSpotsGenerator.cpp b/src/libslic3r/SupportSpotsGenerator.cpp index 0b10a6b755..6c0f500c32 100644 --- a/src/libslic3r/SupportSpotsGenerator.cpp +++ b/src/libslic3r/SupportSpotsGenerator.cpp @@ -1,5 +1,5 @@ #include "SupportSpotsGenerator.hpp" -/* + #include "BoundingBox.hpp" #include "ExPolygon.hpp" #include "ExtrusionEntity.hpp" @@ -45,6 +45,7 @@ #include "libslic3r/Color.hpp" #endif + namespace Slic3r { class ExtrusionLine @@ -85,6 +86,112 @@ namespace SupportSpotsGenerator { using LD = AABBTreeLines::LinesDistancer; +float get_flow_width(const LayerRegion *region, ExtrusionRole role) +{ + if (role == ExtrusionRole::erBridgeInfill) return region->flow(FlowRole::frExternalPerimeter).width(); + if (role == ExtrusionRole::erExternalPerimeter) return region->flow(FlowRole::frExternalPerimeter).width(); + if (role == ExtrusionRole::erGapFill) return region->flow(FlowRole::frInfill).width(); + if (role == ExtrusionRole::erPerimeter) return region->flow(FlowRole::frPerimeter).width(); + if (role == ExtrusionRole::erSolidInfill) return region->flow(FlowRole::frSolidInfill).width(); + if (role == ExtrusionRole::erInternalInfill) return region->flow(FlowRole::frInfill).width(); + if (role == ExtrusionRole::erTopSolidInfill) return region->flow(FlowRole::frTopSolidInfill).width(); + // default + return region->flow(FlowRole::frPerimeter).width(); +} + +float estimate_curled_up_height( + float distance, float curvature, float layer_height, float flow_width, float prev_line_curled_height, Params params) +{ + float curled_up_height = 0; + if (fabs(distance) < 3.0 * flow_width) { + curled_up_height = std::max(prev_line_curled_height - layer_height * 0.75f, 0.0f); + } + + if (distance > params.malformation_distance_factors.first * flow_width && + distance < params.malformation_distance_factors.second * flow_width) { + // imagine the extrusion profile. The part that has been glued (melted) with the previous layer will be called anchored section + // and the rest will be called curling section + // float anchored_section = flow_width - point.distance; + float curling_section = distance; + + // after extruding, the curling (floating) part of the extrusion starts to shrink back to the rounded shape of the nozzle + // The anchored part not, because the melted material holds to the previous layer well. + // We can assume for simplicity perfect equalization of layer height and raising part width, from which: + float swelling_radius = (layer_height + curling_section) / 2.0f; + curled_up_height += std::max(0.f, (swelling_radius - layer_height) / 2.0f); + + // On convex turns, there is larger tension on the floating edge of the extrusion then on the middle section. + // The tension is caused by the shrinking tendency of the filament, and on outer edge of convex trun, the expansion is greater and + // thus shrinking force is greater. This tension will cause the curling section to curle up + if (curvature > 0.01) { + float radius = (1.0 / curvature); + float curling_t = sqrt(radius / 100); + float b = curling_t * flow_width; + float a = curling_section; + float c = sqrt(std::max(0.0f, a * a - b * b)); + + curled_up_height += c; + } + curled_up_height = std::min(curled_up_height, params.max_curled_height_factor * layer_height); + } + + return curled_up_height; +} + +void estimate_malformations(LayerPtrs &layers, const Params ¶ms) +{ + LD prev_layer_lines{}; + for (Layer *l : layers) { + l->curled_lines.clear(); + std::vector boundary_lines = l->lower_layer != nullptr ? to_unscaled_linesf(l->lower_layer->lslices) : std::vector(); + AABBTreeLines::LinesDistancer prev_layer_boundary{std::move(boundary_lines)}; + std::vector current_layer_lines; + for (const LayerRegion *layer_region : l->regions()) { + for (const ExtrusionEntity *extrusion : layer_region->perimeters.flatten().entities) { + if (extrusion->role() != Slic3r::erExternalPerimeter) + continue; + Points extrusion_pts; + extrusion->collect_points(extrusion_pts); + float flow_width = get_flow_width(layer_region, extrusion->role()); + auto annotated_points = estimate_points_properties(extrusion_pts, prev_layer_lines, flow_width, + params.bridge_distance); + for (size_t i = 0; i < annotated_points.size(); ++i) { + const ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i]; + const ExtendedPoint &b = annotated_points[i]; + ExtrusionLine line_out{a.position.cast(), b.position.cast(), float((a.position - b.position).norm()), + extrusion}; + Vec2f middle = 0.5 * (line_out.a + line_out.b); + auto [middle_distance, bottom_line_idx, x] = prev_layer_lines.distance_from_lines_extra(middle); + ExtrusionLine bottom_line = prev_layer_lines.get_lines().empty() ? ExtrusionLine{} : + prev_layer_lines.get_line(bottom_line_idx); + + // correctify the distance sign using slice polygons + float sign = (prev_layer_boundary.distance_from_lines(middle.cast()) + 0.5f * flow_width) < 0.0f ? -1.0f : 1.0f; + + line_out.curled_up_height = estimate_curled_up_height(middle_distance * sign, 0.5 * (a.curvature + b.curvature), + l->height, flow_width, bottom_line.curled_up_height, params); + + current_layer_lines.push_back(line_out); + } + } + } + + for (const ExtrusionLine &line : current_layer_lines) { + if (line.curled_up_height > params.curling_tolerance_limit) { + l->curled_lines.push_back(CurledLine{Point::new_scale(line.a), Point::new_scale(line.b), line.curled_up_height}); + } + } + + prev_layer_lines = LD{current_layer_lines}; + } + + + +} + +/* + + struct SupportGridFilter { private: @@ -169,18 +276,7 @@ struct SliceConnection } }; -float get_flow_width(const LayerRegion *region, ExtrusionRole role) -{ - if (role == ExtrusionRole::erBridgeInfill) return region->flow(FlowRole::frExternalPerimeter).width(); - if (role == ExtrusionRole::erExternalPerimeter) return region->flow(FlowRole::frExternalPerimeter).width(); - if (role == ExtrusionRole::erGapFill) return region->flow(FlowRole::frInfill).width(); - if (role == ExtrusionRole::erPerimeter) return region->flow(FlowRole::frPerimeter).width(); - if (role == ExtrusionRole::erSolidInfill) return region->flow(FlowRole::frSolidInfill).width(); - if (role == ExtrusionRole::erInternalInfill) return region->flow(FlowRole::frInfill).width(); - if (role == ExtrusionRole::erTopSolidInfill) return region->flow(FlowRole::frTopSolidInfill).width(); - // default - return region->flow(FlowRole::frPerimeter).width(); -} + std::vector to_short_lines(const ExtrusionEntity *e, float length_limit) { @@ -205,24 +301,7 @@ std::vector to_short_lines(const ExtrusionEntity *e, float length return lines; } -float estimate_curled_up_height( - const ExtendedPoint &point, float layer_height, float flow_width, float prev_line_curled_height, Params params) -{ - float curled_up_height = 0.0f; - if (fabs(point.distance) < 1.5 * flow_width) { - curled_up_height = 0.85 * prev_line_curled_height; - } - if (point.distance > params.malformation_distance_factors.first * flow_width && - point.distance < params.malformation_distance_factors.second * flow_width && point.curvature > -0.1f) { - float dist_factor = std::max(point.distance - params.malformation_distance_factors.first * flow_width, 0.01f) / - ((params.malformation_distance_factors.second - params.malformation_distance_factors.first) * flow_width); - curled_up_height = layer_height * sqrt(sqrt(dist_factor)) * std::clamp(3.0f * point.curvature, 1.0f, 3.0f); - curled_up_height = std::min(curled_up_height, params.max_curled_height_factor * layer_height); - } - - return curled_up_height; -} std::vector check_extrusion_entity_stability(const ExtrusionEntity *entity, const LayerRegion *layer_region, @@ -1104,78 +1183,7 @@ void estimate_supports_malformations(SupportLayerPtrs &layers, float flow_width, #endif } -void estimate_malformations(LayerPtrs &layers, const Params ¶ms) -{ -#ifdef DEBUG_FILES - FILE *debug_file = boost::nowide::fopen(debug_out_path("object_malformations.obj").c_str(), "w"); - FILE *full_file = boost::nowide::fopen(debug_out_path("object_full.obj").c_str(), "w"); -#endif - LD prev_layer_lines{}; - - for (Layer *l : layers) { - std::vector boundary_lines = l->lower_layer != nullptr ? to_unscaled_linesf(l->lower_layer->lslices) : std::vector(); - AABBTreeLines::LinesDistancer prev_layer_boundary{std::move(boundary_lines)}; - std::vector current_layer_lines; - for (const LayerRegion *layer_region : l->regions()) { - for (const ExtrusionEntity *extrusion : layer_region->perimeters().flatten().entities) { - - if (!extrusion->role().is_external_perimeter()) continue; - - Points extrusion_pts; - extrusion->collect_points(extrusion_pts); - float flow_width = get_flow_width(layer_region, extrusion->role()); - auto annotated_points = estimate_points_properties(extrusion_pts, prev_layer_lines, flow_width, - params.bridge_distance); - for (size_t i = 0; i < annotated_points.size(); ++i) { - ExtendedPoint &curr_point = annotated_points[i]; - float line_len = i > 0 ? ((annotated_points[i - 1].position - curr_point.position).norm()) : 0.0f; - ExtrusionLine line_out{i > 0 ? annotated_points[i - 1].position.cast() : curr_point.position.cast(), - curr_point.position.cast(), line_len, extrusion}; - - const ExtrusionLine nearest_prev_layer_line = prev_layer_lines.get_lines().size() > 0 ? - prev_layer_lines.get_line(curr_point.nearest_prev_layer_line) : - ExtrusionLine{}; - - float sign = (prev_layer_boundary.distance_from_lines(curr_point.position) + 0.5f * flow_width) < 0.0f ? -1.0f : - 1.0f; - curr_point.distance *= sign; - - line_out.curled_up_height = estimate_curled_up_height(curr_point, layer_region->layer()->height, flow_width, - nearest_prev_layer_line.curled_up_height, params); - - current_layer_lines.push_back(line_out); - } - } - } - - for (const ExtrusionLine &line : current_layer_lines) { - if (line.curled_up_height > 0.3f) { - l->malformed_lines.push_back(Line{Point::new_scale(line.a), Point::new_scale(line.b)}); - } - } - -#ifdef DEBUG_FILES - for (const ExtrusionLine &line : current_layer_lines) { - if (line.curled_up_height > 0.3f) { - Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height); - fprintf(debug_file, "v %f %f %f %f %f %f\n", line.b[0], line.b[1], l->print_z, color[0], color[1], color[2]); - } - } - for (const ExtrusionLine &line : current_layer_lines) { - Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height); - fprintf(full_file, "v %f %f %f %f %f %f\n", line.b[0], line.b[1], l->print_z, color[0], color[1], color[2]); - } -#endif - - prev_layer_lines = LD{current_layer_lines}; - } - -#ifdef DEBUG_FILES - fclose(debug_file); - fclose(full_file); -#endif -} std::vector> gather_issues(const SupportPoints &support_points, PartialObjects &partial_objects) { @@ -1262,6 +1270,7 @@ std::vector> gather_issues(const SupportPoint return result; } +*/ + } // namespace SupportSpotsGenerator } // namespace Slic3r -*/ \ No newline at end of file diff --git a/src/libslic3r/SupportSpotsGenerator.hpp b/src/libslic3r/SupportSpotsGenerator.hpp index c3fde4d6ae..c15a061f38 100644 --- a/src/libslic3r/SupportSpotsGenerator.hpp +++ b/src/libslic3r/SupportSpotsGenerator.hpp @@ -1,6 +1,6 @@ #ifndef SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_ #define SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_ -/* + #include "Layer.hpp" #include "Line.hpp" #include "PrintBase.hpp" @@ -9,6 +9,7 @@ #include #include + namespace Slic3r { namespace SupportSpotsGenerator { @@ -44,6 +45,7 @@ struct Params const std::pair malformation_distance_factors = std::pair { 0.5, 1.1 }; const float max_curled_height_factor = 10.0f; + const float curling_tolerance_limit = 0.1f; const float min_distance_between_support_points = 3.0f; //mm const float support_points_interface_radius = 1.5f; // mm @@ -77,6 +79,9 @@ struct Params } }; +void estimate_malformations(std::vector &layers, const Params ¶ms); + + enum class SupportPointCause { LongBridge, // point generated on bridge and straight perimeter extrusion longer than the allowed length FloatingBridgeAnchor, // point generated on unsupported bridge endpoint @@ -97,7 +102,7 @@ enum class SupportPointCause { // between forces that destabilize the object (extruder conflicts with curled filament, weight if instable center of mass, bed movements etc) // and forces that stabilize the object (bed adhesion, other support spots adhesion, weight if stable center of mass). // Note that the force is only the difference - the amount needed to stabilize the object again. -struct SupportPoint +/*struct SupportPoint { SupportPoint(SupportPointCause cause, const Vec3f &position, float force, float spot_radius, const Vec2f &direction) : cause(cause), position(position), force(force), spot_radius(spot_radius), direction(direction) @@ -147,13 +152,12 @@ using PartialObjects = std::vector; std::tuple full_search(const PrintObject *po, const PrintTryCancel& cancel_func, const Params ¶ms); void estimate_supports_malformations(std::vector &layers, float supports_flow_width, const Params ¶ms); -void estimate_malformations(std::vector &layers, const Params ¶ms); // NOTE: the boolean marks if the issue is critical or not for now. std::vector> gather_issues(const SupportPoints &support_points, PartialObjects &partial_objects); - -}} // namespace Slic3r::SupportSpotsGenerator */ +}} // namespace Slic3r::SupportSpotsGenerator + #endif /* SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_ */