From 3942cf958c3d9248eace446f7608c3f094c65fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Wed, 25 May 2022 16:17:57 +0200 Subject: [PATCH] Updated Arachne with Cura master. --- .../Arachne/SkeletalTrapezoidation.cpp | 57 +++++++++---------- .../Arachne/SkeletalTrapezoidation.hpp | 8 ++- .../Arachne/SkeletalTrapezoidationEdge.hpp | 4 +- src/libslic3r/Arachne/WallToolPaths.cpp | 51 +++++++---------- src/libslic3r/Arachne/WallToolPaths.hpp | 1 + src/libslic3r/Arachne/utils/ExtrusionLine.cpp | 2 +- .../Arachne/utils/PolylineStitcher.hpp | 2 +- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 28 ++++----- src/libslic3r/PrintConfig.hpp | 2 +- src/libslic3r/PrintObject.cpp | 2 +- src/slic3r/GUI/ConfigManipulation.cpp | 2 +- src/slic3r/GUI/Tab.cpp | 2 +- 13 files changed, 77 insertions(+), 86 deletions(-) diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp b/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp index 6d1a67513..2852d242c 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidation.cpp @@ -368,10 +368,12 @@ void SkeletalTrapezoidation::computeSegmentCellRange(vd_t::cell_type& cell, Poin SkeletalTrapezoidation::SkeletalTrapezoidation(const Polygons& polys, const BeadingStrategy& beading_strategy, double transitioning_angle, coord_t discretization_step_size, - coord_t transition_filter_dist, coord_t beading_propagation_transition_dist - ): transitioning_angle(transitioning_angle), + coord_t transition_filter_dist, coord_t allowed_filter_deviation, + coord_t beading_propagation_transition_dist + ): transitioning_angle(transitioning_angle), discretization_step_size(discretization_step_size), transition_filter_dist(transition_filter_dist), + allowed_filter_deviation(allowed_filter_deviation), beading_propagation_transition_dist(beading_propagation_transition_dist), beading_strategy(beading_strategy) { @@ -918,7 +920,7 @@ void SkeletalTrapezoidation::generateTransitionMids(ptr_vector_templace_back(mid_pos, transition_lower_bead_count); + transitions->emplace_back(mid_pos, transition_lower_bead_count, mid_R); } assert((edge.from->data.bead_count == edge.to->data.bead_count) || edge.data.hasTransitions()); } @@ -997,17 +999,13 @@ std::list SkeletalTrapezoidation::diss { std::list to_be_dissolved; if (traveled_dist > max_dist) - { return to_be_dissolved; - } + bool should_dissolve = true; - for (edge_t* edge = edge_to_start->next; edge && edge != edge_to_start->twin; edge = edge->twin->next) - { + for (edge_t* edge = edge_to_start->next; edge && edge != edge_to_start->twin; edge = edge->twin->next){ if (!edge->data.isCentral()) - { continue; - } - + Point a = edge->from->p; Point b = edge->to->p; Point ab = b - a; @@ -1015,19 +1013,22 @@ std::list SkeletalTrapezoidation::diss bool is_aligned = edge->isUpward(); edge_t* aligned_edge = is_aligned? edge : edge->twin; bool seen_transition_on_this_edge = false; - - if (aligned_edge->data.hasTransitions()) - { + + const coord_t origin_radius = origin_transition.feature_radius; + const coord_t radius_here = edge->from->data.distance_to_boundary; + const bool dissolve_result_is_odd = bool(origin_transition.lower_bead_count % 2) == going_up; + const coord_t width_deviation = std::abs(origin_radius - radius_here) * 2; // times by two because the deviation happens at both sides of the significant edge + const coord_t line_width_deviation = dissolve_result_is_odd ? width_deviation : width_deviation / 2; // assume the deviation will be split over either 1 or 2 lines, i.e. assume wall_distribution_count = 1 + if (line_width_deviation > allowed_filter_deviation) + should_dissolve = false; + + if (should_dissolve && aligned_edge->data.hasTransitions()) { auto& transitions = *aligned_edge->data.getTransitions(); - for (auto transition_it = transitions.begin(); transition_it != transitions.end(); ++ transition_it) - { // Note: this is not necessarily iterating in the traveling direction! + for (auto transition_it = transitions.begin(); transition_it != transitions.end(); ++ transition_it) { // Note: this is not necessarily iterating in the traveling direction! // Check whether we should dissolve coord_t pos = is_aligned? transition_it->pos : ab_size - transition_it->pos; - if (traveled_dist + pos < max_dist - && transition_it->lower_bead_count == origin_transition.lower_bead_count) // Only dissolve local optima - { - if (traveled_dist + pos < beading_strategy.getTransitioningLength(transition_it->lower_bead_count)) - { + if (traveled_dist + pos < max_dist && transition_it->lower_bead_count == origin_transition.lower_bead_count) { // Only dissolve local optima + if (traveled_dist + pos < beading_strategy.getTransitioningLength(transition_it->lower_bead_count)) { // Consecutive transitions both in/decreasing in bead count should never be closer together than the transition distance assert(going_up != is_aligned || transition_it->lower_bead_count == 0); } @@ -1036,11 +1037,9 @@ std::list SkeletalTrapezoidation::diss } } } - if (!seen_transition_on_this_edge) - { + if (should_dissolve && !seen_transition_on_this_edge) { std::list to_be_dissolved_here = dissolveNearbyTransitions(edge, origin_transition, traveled_dist + ab_size, max_dist, going_up); - if (to_be_dissolved_here.empty()) - { // The region is too long to be dissolved in this direction, so it cannot be dissolved in any direction. + if (to_be_dissolved_here.empty()) { // The region is too long to be dissolved in this direction, so it cannot be dissolved in any direction. to_be_dissolved.clear(); return to_be_dissolved; } @@ -1048,12 +1047,10 @@ std::list SkeletalTrapezoidation::diss should_dissolve = should_dissolve && !to_be_dissolved.empty(); } } - + if (!should_dissolve) - { to_be_dissolved.clear(); - } - + return to_be_dissolved; } @@ -1062,10 +1059,8 @@ void SkeletalTrapezoidation::dissolveBeadCountRegion(edge_t* edge_to_start, coor { assert(from_bead_count != to_bead_count); if (edge_to_start->to->data.bead_count != from_bead_count) - { return; - } - + edge_to_start->to->data.bead_count = to_bead_count; for (edge_t* edge = edge_to_start->next; edge && edge != edge_to_start->twin; edge = edge->twin->next) { diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp b/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp index f9b619c26..51b24bbcd 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidation.hpp @@ -59,6 +59,7 @@ class SkeletalTrapezoidation double transitioning_angle; //!< How pointy a region should be before we apply the method. Equals 180* - limit_bisector_angle coord_t discretization_step_size; //!< approximate size of segments when parabolic VD edges get discretized (and vertex-vertex edges) coord_t transition_filter_dist; //!< Filter transition mids (i.e. anchors) closer together than this + coord_t allowed_filter_deviation; //!< The allowed line width deviation induced by filtering coord_t beading_propagation_transition_dist; //!< When there are different beadings propagated from below and from above, use this transitioning distance static constexpr coord_t central_filter_dist = scaled(0.02); //!< Filter areas marked as 'central' smaller than this static constexpr coord_t snap_dist = scaled(0.02); //!< Generic arithmatic inaccuracy. Only used to determine whether a transition really needs to insert an extra edge. @@ -96,9 +97,10 @@ public: SkeletalTrapezoidation(const Polygons& polys, const BeadingStrategy& beading_strategy, double transitioning_angle - , coord_t discretization_step_size = scaled(0.0008) - , coord_t transition_filter_dist = scaled(0.001) - , coord_t beading_propagation_transition_dist = scaled(0.0004)); + , coord_t discretization_step_size + , coord_t transition_filter_dist + , coord_t allowed_filter_deviation + , coord_t beading_propagation_transition_dist); /*! * A skeletal graph through the polygons that we need to fill with beads. diff --git a/src/libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp b/src/libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp index ddc1c3ce8..e0d3fe81d 100644 --- a/src/libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp +++ b/src/libslic3r/Arachne/SkeletalTrapezoidationEdge.hpp @@ -26,8 +26,10 @@ public: { coord_t pos; // Position along edge as measure from edge.from.p int lower_bead_count; - TransitionMiddle(coord_t pos, int lower_bead_count) + coord_t feature_radius; // The feature radius at which this transition is placed + TransitionMiddle(coord_t pos, int lower_bead_count, coord_t feature_radius) : pos(pos), lower_bead_count(lower_bead_count) + , feature_radius(feature_radius) {} }; diff --git a/src/libslic3r/Arachne/WallToolPaths.cpp b/src/libslic3r/Arachne/WallToolPaths.cpp index e27c12390..14c5b9c03 100644 --- a/src/libslic3r/Arachne/WallToolPaths.cpp +++ b/src/libslic3r/Arachne/WallToolPaths.cpp @@ -38,21 +38,24 @@ WallToolPaths::WallToolPaths(const Polygons& outline, const coord_t bead_width_0 if (const auto &min_bead_width_opt = print_object_config.min_bead_width; min_bead_width_opt.percent) { assert(!print_config.nozzle_diameter.empty()); double min_nozzle_diameter = *std::min_element(print_config.nozzle_diameter.values.begin(), print_config.nozzle_diameter.values.end()); - min_bead_width = scaled(min_bead_width_opt.value * 0.01 * min_nozzle_diameter); + this->min_bead_width = scaled(min_bead_width_opt.value * 0.01 * min_nozzle_diameter); + } + + if (const auto &wall_transition_filter_deviation_opt = print_object_config.wall_transition_filter_deviation; wall_transition_filter_deviation_opt.percent) { + assert(!print_config.nozzle_diameter.empty()); + double min_nozzle_diameter = *std::min_element(print_config.nozzle_diameter.values.begin(), print_config.nozzle_diameter.values.end()); + this->wall_transition_filter_deviation = scaled(wall_transition_filter_deviation_opt.value * 0.01 * min_nozzle_diameter); } } void simplify(Polygon &thiss, const int64_t smallest_line_segment_squared, const int64_t allowed_error_distance_squared) { - if (thiss.size() < 3) - { + if (thiss.size() < 3) { thiss.points.clear(); return; } if (thiss.size() == 3) - { return; - } Polygon new_path; Point previous = thiss.points.back(); @@ -76,22 +79,16 @@ void simplify(Polygon &thiss, const int64_t smallest_line_segment_squared, const */ int64_t accumulated_area_removed = int64_t(previous.x()) * int64_t(current.y()) - int64_t(previous.y()) * int64_t(current.x()); // Twice the Shoelace formula for area of polygon per line segment. - for (size_t point_idx = 0; point_idx < thiss.points.size(); point_idx++) - { + for (size_t point_idx = 0; point_idx < thiss.points.size(); point_idx++) { current = thiss.points.at(point_idx % thiss.points.size()); //Check if the accumulated area doesn't exceed the maximum. Point next; - if (point_idx + 1 < thiss.points.size()) - { + if (point_idx + 1 < thiss.points.size()) { next = thiss.points.at(point_idx + 1); - } - else if (point_idx + 1 == thiss.points.size() && new_path.size() > 1) - { // don't spill over if the [next] vertex will then be equal to [previous] + } else if (point_idx + 1 == thiss.points.size() && new_path.size() > 1) { // don't spill over if the [next] vertex will then be equal to [previous] next = new_path[0]; //Spill over to new polygon for checking removed area. - } - else - { + } else { next = thiss.points.at((point_idx + 1) % thiss.points.size()); } const int64_t removed_area_next = int64_t(current.x()) * int64_t(next.y()) - int64_t(current.y()) * int64_t(next.x()); // Twice the Shoelace formula for area of polygon per line segment. @@ -99,8 +96,7 @@ void simplify(Polygon &thiss, const int64_t smallest_line_segment_squared, const accumulated_area_removed += removed_area_next; const int64_t length2 = (current - previous).cast().squaredNorm(); - if (length2 < scaled(25.)) - { + if (length2 < scaled(25.)) { // We're allowed to always delete segments of less than 5 micron. continue; } @@ -109,9 +105,7 @@ void simplify(Polygon &thiss, const int64_t smallest_line_segment_squared, const const int64_t base_length_2 = (next - previous).cast().squaredNorm(); if (base_length_2 == 0) //Two line segments form a line back and forth with no area. - { continue; //Remove the vertex. - } //We want to check if the height of the triangle formed by previous, current and next vertices is less than allowed_error_distance_squared. //1/2 L = A [actual area is half of the computed shoelace value] // Shoelace formula is .5*(...) , but we simplify the computation and take out the .5 //A = 1/2 * b * h [triangle area formula] @@ -122,16 +116,13 @@ void simplify(Polygon &thiss, const int64_t smallest_line_segment_squared, const const int64_t height_2 = double(area_removed_so_far) * double(area_removed_so_far) / double(base_length_2); if ((height_2 <= Slic3r::sqr(scaled(0.005)) //Almost exactly colinear (barring rounding errors). && Line::distance_to_infinite(current, previous, next) <= scaled(0.005))) // make sure that height_2 is not small because of cancellation of positive and negative areas - { continue; - } if (length2 < smallest_line_segment_squared && height_2 <= allowed_error_distance_squared) // removing the vertex doesn't introduce too much error.) { const int64_t next_length2 = (current - next).cast().squaredNorm(); - if (next_length2 > smallest_line_segment_squared) - { + if (next_length2 > 4 * smallest_line_segment_squared) { // Special case; The next line is long. If we were to remove this, it could happen that we get quite noticeable artifacts. // We should instead move this point to a location where both edges are kept and then remove the previous point that we wanted to keep. // By taking the intersection of these two lines, we get a point that preserves the direction (so it makes the corner a bit more pointy). @@ -146,20 +137,16 @@ void simplify(Polygon &thiss, const int64_t smallest_line_segment_squared, const // We can't find a better spot for it, but the size of the line is more than 5 micron. // So the only thing we can do here is leave it in... } - else - { + else { // New point seems like a valid one. current = intersection_point; // If there was a previous point added, remove it. - if(!new_path.empty()) - { + if(!new_path.empty()) { new_path.points.pop_back(); previous = previous_previous; } } - } - else - { + } else { continue; //Remove the vertex. } } @@ -517,7 +504,8 @@ const std::vector &WallToolPaths::generate() wall_0_inset, wall_distribution_count ); - const coord_t transition_filter_dist = scaled(this->print_object_config.wall_transition_filter_distance.value); + const coord_t transition_filter_dist = scaled(100.f); + const coord_t allowed_filter_deviation = wall_transition_filter_deviation; SkeletalTrapezoidation wall_maker ( prepared_outline, @@ -525,6 +513,7 @@ const std::vector &WallToolPaths::generate() beading_strat->getTransitioningAngle(), discretization_step_size, transition_filter_dist, + allowed_filter_deviation, wall_transition_length ); wall_maker.generateToolpaths(toolpaths); diff --git a/src/libslic3r/Arachne/WallToolPaths.hpp b/src/libslic3r/Arachne/WallToolPaths.hpp index 733db1400..698f84115 100644 --- a/src/libslic3r/Arachne/WallToolPaths.hpp +++ b/src/libslic3r/Arachne/WallToolPaths.hpp @@ -117,6 +117,7 @@ private: bool toolpaths_generated; // toolpaths; //().squaredNorm(); - if (next_length2 > smallest_line_segment_squared) + if (next_length2 > 4 * smallest_line_segment_squared) { // Special case; The next line is long. If we were to remove this, it could happen that we get quite noticeable artifacts. // We should instead move this point to a location where both edges are kept and then remove the previous point that we wanted to keep. diff --git a/src/libslic3r/Arachne/utils/PolylineStitcher.hpp b/src/libslic3r/Arachne/utils/PolylineStitcher.hpp index 14bdec0d4..2ab770a3e 100644 --- a/src/libslic3r/Arachne/utils/PolylineStitcher.hpp +++ b/src/libslic3r/Arachne/utils/PolylineStitcher.hpp @@ -178,7 +178,7 @@ public: { ++start_pos; } - chain.insert(chain.end(), (*closest.polygons)[closest.poly_idx].rbegin(), (*closest.polygons)[closest.poly_idx].rend()); + chain.insert(chain.end(), start_pos, (*closest.polygons)[closest.poly_idx].rend()); } for(size_t i = old_size; i < chain.size(); ++i) //Update chain length. { diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 11e51a734..8d166d41c 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -449,7 +449,7 @@ static std::vector s_Preset_print_options { "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "gcode_resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width", "wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits", - "slicing_engine", "wall_transition_length", "wall_transition_filter_distance", "wall_transition_angle", + "slicing_engine", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", "wall_distribution_count", "wall_split_middle_threshold", "wall_add_middle_threshold", "min_feature_size", "min_bead_width" }; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index b5bb9b340..bc79f4951 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3067,24 +3067,28 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->set_default_value(new ConfigOptionFloat(0.4)); - def = this->add("wall_transition_filter_distance", coFloat); - def->label = L("Wall Transition Distance Filter"); + def = this->add("wall_transition_filter_deviation", coFloatOrPercent); + def->label = L("Wall Transitioning Filter Margin"); def->category = L("Advanced"); - def->tooltip = L("If it would be transitioning back and forth between different numbers of walls in " - "quick succession, don't transition at all. Remove transitions if they are closer " - "together than this distance."); + def->tooltip = L("Prevent transitioning back and forth between one extra wall and one less. This " + "margin extends the range of line widths which follow to [Minimum Wall Line " + "Width - Margin, 2 * Minimum Wall Line Width + Margin]. Increasing this margin " + "reduces the number of transitions, which reduces the number of extrusion " + "starts/stops and travel time. However, large line width variation can lead to " + "under- or overextrusion problems." + "If expressed as percentage (for example 25%), it will be computed over nozzle diameter."); def->sidetext = L("mm"); def->mode = comExpert; def->min = 0; - def->set_default_value(new ConfigOptionFloat(1.4)); + def->set_default_value(new ConfigOptionFloatOrPercent(25, true)); def = this->add("wall_transition_angle", coFloat); - def->label = L("Wall Transition Angle"); + def->label = L("Wall Transitioning Threshold Angle"); def->category = L("Advanced"); - def->tooltip = L("When transitioning between different numbers of walls as the part becomes thinner, " - "two adjacent walls will join together at this angle. This can make the walls come " - "together faster than what the Wall Transition Length indicates, filling the space " - "better."); + def->tooltip = L("When to create transitions between even and odd numbers of walls. A wedge shape with" + " an angle greater than this setting will not have transitions and no walls will be " + "printed in the center to fill the remaining space. Reducing this setting reduces " + "the number and length of these center walls, but may leave gaps or overextrude."); def->sidetext = L("°"); def->mode = comExpert; def->min = 1.; @@ -4089,8 +4093,6 @@ void DynamicPrintConfig::normalize_fdm() opt_min_bead_width->value = std::max(opt_min_bead_width->value, 0.001); if (auto *opt_wall_transition_length = this->opt("wall_transition_length", false); opt_wall_transition_length) opt_wall_transition_length->value = std::max(opt_wall_transition_length->value, 0.001); - if (auto *opt_wall_transition_filter_distance = this->opt("wall_transition_filter_distance", false); opt_wall_transition_filter_distance) - opt_wall_transition_filter_distance->value = std::max(opt_wall_transition_filter_distance->value, 0.001); } void handle_legacy_sla(DynamicPrintConfig &config) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 0e829086c..ef7d27388 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -489,7 +489,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionEnum, slicing_mode)) ((ConfigOptionEnum, slicing_engine)) ((ConfigOptionFloat, wall_transition_length)) - ((ConfigOptionFloat, wall_transition_filter_distance)) + ((ConfigOptionFloatOrPercent, wall_transition_filter_deviation)) ((ConfigOptionFloat, wall_transition_angle)) ((ConfigOptionInt, wall_distribution_count)) ((ConfigOptionPercent, wall_split_middle_threshold)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 7360fb9ea..2b31a7957 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -664,7 +664,7 @@ bool PrintObject::invalidate_state_by_config_options( } else if ( opt_key == "slicing_engine" || opt_key == "wall_transition_length" - || opt_key == "wall_transition_filter_distance" + || opt_key == "wall_transition_filter_deviation" || opt_key == "wall_transition_angle" || opt_key == "wall_distribution_count" || opt_key == "wall_split_middle_threshold" diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 595182c7f..16b8e5b48 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -320,7 +320,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) bool have_arachne = config->opt_enum("slicing_engine") == SlicingEngine::Arachne; toggle_field("wall_transition_length", have_arachne); - toggle_field("wall_transition_filter_distance", have_arachne); + toggle_field("wall_transition_filter_deviation", have_arachne); toggle_field("wall_transition_angle", have_arachne); toggle_field("wall_distribution_count", have_arachne); toggle_field("wall_split_middle_threshold", have_arachne); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 643feb5ba..088d96d29 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1673,7 +1673,7 @@ void TabPrint::build() optgroup = page->new_optgroup(L("Experimental")); optgroup->append_single_option_line("slicing_engine"); optgroup->append_single_option_line("wall_transition_length"); - optgroup->append_single_option_line("wall_transition_filter_distance"); + optgroup->append_single_option_line("wall_transition_filter_deviation"); optgroup->append_single_option_line("wall_transition_angle"); optgroup->append_single_option_line("wall_distribution_count"); optgroup->append_single_option_line("wall_split_middle_threshold");