From d54f20a12ca4bd424eb7c6213bef52e0fc6fb0bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Tue, 18 Jun 2024 21:09:51 +0200 Subject: [PATCH] failed arc welder in path ordering --- src/libslic3r/GCode.cpp | 133 +++++++++++++++++++------ src/libslic3r/GCode.hpp | 6 +- src/libslic3r/GCode/ExtrusionOrder.cpp | 126 ++++++++++------------- src/libslic3r/GCode/ExtrusionOrder.hpp | 40 +++----- 4 files changed, 171 insertions(+), 134 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 058e821986..2d6c40c805 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2299,24 +2299,59 @@ std::vector GCodeGenerator::get_sorte Skirt::make_skirt_loops_per_extruder_1st_layer(print, layer_tools, m_skirt_done) : Skirt::make_skirt_loops_per_extruder_other_layers(print, layer_tools, m_skirt_done)}; - const auto place_seam =[&]( - const Layer &layer, ExtrusionEntity *perimeter, const std::optional &previous_position - ) { - auto loop{dynamic_cast(perimeter)}; + const auto smooth_path{ + [&](const Layer *layer, const ExtrusionEntityReference &extrusion_reference, + const unsigned extruder_id, std::optional &previous_position) { + const ExtrusionEntity *extrusion_entity{&extrusion_reference.extrusion_entity()}; - Point seam_point{previous_position ? *previous_position : Point::Zero()}; - if (!this->m_config.spiral_vase && loop != nullptr) { - seam_point = this->m_seam_placer.place_seam(&layer, *loop, seam_point); - loop->seam = seam_point; - } + GCode::SmoothPath result; - auto path{dynamic_cast(perimeter)}; - if (path != nullptr) { - return path->last_point(); - } else { - return seam_point; - } - }; + if (auto loop = dynamic_cast(extrusion_entity)) { + Point seam_point = previous_position ? *previous_position : Point::Zero(); + if (loop->role().is_perimeter() && layer != nullptr) { + seam_point = this->m_seam_placer.place_seam(layer, *loop, seam_point); + } + + const GCode::SmoothPathCache &smooth_path_cache{loop->role().is_perimeter() ? smooth_path_caches.layer_local() : smooth_path_caches.global()}; + // Because the G-code export has 1um resolution, don't generate segments shorter + // than 1.5 microns, thus empty path segments will not be produced by G-code export. + GCode::SmoothPath smooth_path = + smooth_path_cache.resolve_or_fit_split_with_seam( + *loop, extrusion_reference.flipped(), m_scaled_resolution, seam_point, scaled(0.0015) + ); + + // Clip the path to avoid the extruder to get exactly on the first point of the + // loop; if polyline was shorter than the clipping distance we'd get a null + // polyline, so we discard it in that case. + const auto nozzle_diameter{m_config.nozzle_diameter.get_at(extruder_id)}; + if (m_enable_loop_clipping) { + clip_end( + smooth_path, + scale_(nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER, + scaled(GCode::ExtrusionOrder::min_gcode_segment_length) + ); + } + + assert(validate_smooth_path(smooth_path, !enable_loop_clipping)); + + + result = smooth_path; + } else if (auto multipath = dynamic_cast(extrusion_entity)) { + result = smooth_path_caches.layer_local().resolve_or_fit(*multipath, extrusion_reference.flipped(), m_scaled_resolution); + } else if (auto path = dynamic_cast(extrusion_entity)) { + result = smooth_path_caches.layer_local().resolve_or_fit(*path, extrusion_reference.flipped(), m_scaled_resolution); + } + + using GCode::SmoothPathElement; + for (const SmoothPathElement &element : result) { + if (!element.path.empty()) { + previous_position = element.path.back().point; + break; + } + } + + return result; + }}; using GCode::ExtrusionOrder::ExtruderExtrusions; using GCode::ExtrusionOrder::get_extrusions; @@ -2332,13 +2367,9 @@ std::vector GCodeGenerator::get_sorte first_layer, layer_tools, instances_to_print, - smooth_path_caches.global(), skirt_loops_per_extruder, - m_enable_loop_clipping, - m_config, - m_scaled_resolution, this->m_writer.extruder()->id(), - place_seam, + smooth_path, !this->m_brim_done, previous_position ) @@ -2894,6 +2925,38 @@ static inline bool validate_smooth_path(const GCode::SmoothPath &smooth_path, bo } #endif //NDEBUG +std::string GCodeGenerator::extrude_perimeter( + const GCode::ExtrusionOrder::Perimeter &perimeter, const std::string_view description +) { + double speed{-1}; + // Apply the small perimeter speed. + if (perimeter.extrusion_entity->length() <= SMALL_PERIMETER_LENGTH) + speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed); + + // Extrude along the smooth path. + std::string gcode; + for (const GCode::SmoothPathElement &el : perimeter.smooth_path) + gcode += this->_extrude(el.path_attributes, el.path, description, speed); + + // reset acceleration + gcode += m_writer.set_print_acceleration(fast_round_up(m_config.default_acceleration.value)); + + if (m_wipe.enabled()) { + // Wipe will hide the seam. + m_wipe.set_path(GCode::SmoothPath{perimeter.smooth_path}); + } else if (perimeter.extrusion_entity->role().is_external_perimeter() && m_layer != nullptr && m_config.perimeters.value > 1) { + // Only wipe inside if the wipe along the perimeter is disabled. + // Make a little move inwards before leaving loop. + if (std::optional pt = wipe_hide_seam(perimeter.smooth_path, perimeter.reversed, scale_(EXTRUDER_CONFIG(nozzle_diameter))); pt) { + // Generate the seam hiding travel move. + gcode += m_writer.travel_to_xy(this->point_to_gcode(*pt), "move inwards before travel"); + this->last_position = *pt; + } + } + + return gcode; +} + std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed) { // Extrude all loops CCW unless CW movements are prefered. @@ -2973,17 +3036,27 @@ std::string GCodeGenerator::extrude_skirt( } std::string GCodeGenerator::extrude_infill_range( - const std::vector &sorted_extrusions, + const std::vector &sorted_paths, const PrintRegion ®ion, const std::string &extrusion_name, const GCode::SmoothPathCache &smooth_path_cache ) { std::string gcode{}; - if (!sorted_extrusions.empty()) { + if (!sorted_paths.empty()) { this->m_config.apply(region.config()); - for (const ExtrusionEntityReference &ee : sorted_extrusions) { - gcode += this->extrude_entity(ee, smooth_path_cache, extrusion_name); + for (const GCode::SmoothPath &smooth_path : sorted_paths) { + // extrude along the path + std::string gcode; + for (const GCode::SmoothPathElement &el : smooth_path) + gcode += this->_extrude(el.path_attributes, el.path, extrusion_name); + + GCode::SmoothPath reversed_smooth_path{smooth_path}; + GCode::reverse(reversed_smooth_path); + m_wipe.set_path(std::move(reversed_smooth_path)); + + // reset acceleration + gcode += m_writer.set_print_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); } } return gcode; @@ -3006,7 +3079,7 @@ std::string GCodeGenerator::extrude_infill_ranges( std::string GCodeGenerator::extrude_perimeters( const Print &print, const PrintRegion ®ion, - const std::vector &perimeters, + const std::vector &perimeters, const InstanceToPrint &print_instance, const GCode::SmoothPathCache &smooth_path_cache ) { @@ -3016,13 +3089,11 @@ std::string GCodeGenerator::extrude_perimeters( std::string gcode{}; - for (const ExtrusionEntity *ee : perimeters) { + for (const GCode::ExtrusionOrder::Perimeter &perimeter : perimeters) { // Don't reorder, don't flip. - gcode += this->extrude_entity( - {*ee, false}, smooth_path_cache, comment_perimeter, -1. - ); + gcode += this->extrude_perimeter(perimeter, comment_perimeter); this->m_travel_obstacle_tracker.mark_extruded( - ee, print_instance.object_layer_to_print_id, print_instance.instance_id + perimeter.extrusion_entity, print_instance.object_layer_to_print_id, print_instance.instance_id ); } return gcode; diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index e9242d6e2d..2248a6461b 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -282,6 +282,8 @@ private: bool vase_mode ); std::string extrude_entity(const ExtrusionEntityReference &entity, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.); + + std::string extrude_perimeter(const GCode::ExtrusionOrder::Perimeter &perimeter, const std::string_view description); std::string extrude_loop(const ExtrusionLoop &loop, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.); std::string extrude_skirt(GCode::SmoothPath smooth_path, const ExtrusionFlow &extrusion_flow_override, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed); @@ -300,13 +302,13 @@ private: std::string extrude_perimeters( const Print &print, const PrintRegion ®ion, - const std::vector &perimeters, + const std::vector &perimeters, const InstanceToPrint &print_instance, const GCode::SmoothPathCache &smooth_path_cache ); std::string extrude_infill_range( - const std::vector &sorted_extrusions, + const std::vector &sorted_paths, const PrintRegion ®ion, const std::string &extrusion_name, const GCode::SmoothPathCache &smooth_path_cache diff --git a/src/libslic3r/GCode/ExtrusionOrder.cpp b/src/libslic3r/GCode/ExtrusionOrder.cpp index 0fd9768299..d609c71c59 100644 --- a/src/libslic3r/GCode/ExtrusionOrder.cpp +++ b/src/libslic3r/GCode/ExtrusionOrder.cpp @@ -106,13 +106,17 @@ ExtrusionEntitiesPtr extract_infill_extrusions( return result; } -std::vector extract_perimeter_extrusions( +std::vector extract_perimeter_extrusions( const Print &print, const Layer &layer, const LayerIsland &island, - const ExtractEntityPredicate &predicate + const ExtractEntityPredicate &predicate, + const unsigned extruder_id, + const Vec2d &offset, + std::optional &previous_position, + const PathSmoothingFunction &smooth_path ) { - std::vector result; + std::vector result; const LayerRegion &layerm = *layer.get_region(island.perimeters.region()); const PrintRegion ®ion = print.get_print_region(layerm.region().print_region_id()); @@ -127,7 +131,17 @@ std::vector extract_perimeter_extrusions( } for (ExtrusionEntity *ee : *eec) { - result.push_back(ee); + if (ee != nullptr) { + std::optional last_position{get_instance_point(previous_position, offset)}; + bool reverse_loop{false}; + if (auto loop = dynamic_cast(ee)) { + const bool is_hole = loop->is_clockwise(); + reverse_loop = print.config().prefer_clockwise_movements ? !is_hole : is_hole; + } + SmoothPath path{smooth_path(&layer, ExtrusionEntityReference{*ee, reverse_loop}, extruder_id, last_position)}; + previous_position = get_gcode_point(last_position, offset); + result.push_back(Perimeter{std::move(path), reverse_loop, ee}); + } } } @@ -158,7 +172,9 @@ std::vector extract_infill_ranges( const LayerIsland &island, const Vec2d &offset, std::optional &previous_position, - const ExtractEntityPredicate &predicate + const ExtractEntityPredicate &predicate, + const PathSmoothingFunction &smooth_path, + const unsigned extruder_id ) { std::vector result; for (auto it = island.fills.begin(); it != island.fills.end();) { @@ -182,12 +198,13 @@ std::vector extract_infill_ranges( const Point* start_near{previous_position_scaled ? &(*(previous_position_scaled)) : nullptr}; const ExtrusionEntityReferences sorted_extrusions{sort_fill_extrusions(extrusions, start_near)}; - if (!sorted_extrusions.empty()) { - result.push_back({sorted_extrusions, ®ion}); - } - if (const auto last_position = get_last_position(sorted_extrusions, offset)) { - previous_position = last_position; + std::vector paths; + for (const ExtrusionEntityReference &extrusion_reference : sorted_extrusions) { + std::optional last_position{get_instance_point(previous_position, offset)}; + paths.push_back(smooth_path(&layer, extrusion_reference, extruder_id, last_position)); + previous_position = get_gcode_point(previous_position, offset); } + result.push_back({std::move(paths), ®ion}); it = it_end; } return result; @@ -198,8 +215,9 @@ std::vector extract_island_extrusions( const Print &print, const Layer &layer, const ExtractEntityPredicate &predicate, - const SeamPlacingFunciton &place_seam, + const PathSmoothingFunction &smooth_path, const Vec2d &offset, + const unsigned extruder_id, std::optional &previous_position ) { std::vector result; @@ -217,31 +235,17 @@ std::vector extract_island_extrusions( result.push_back(IslandExtrusions{®ion}); IslandExtrusions &island_extrusions{result.back()}; - island_extrusions.perimeters = extract_perimeter_extrusions(print, layer, island, predicate); - if (print.config().infill_first) { island_extrusions.infill_ranges = extract_infill_ranges( - print, layer, island, offset, previous_position, infill_predicate + print, layer, island, offset, previous_position, infill_predicate, smooth_path, extruder_id ); - for (ExtrusionEntity* perimeter : island_extrusions.perimeters) { - std::optional instance_point{get_instance_point(previous_position, offset)}; - const std::optional seam_point{place_seam(layer, perimeter, instance_point)}; - if (seam_point) { - previous_position = get_gcode_point(*seam_point, offset); - } - } + island_extrusions.perimeters = extract_perimeter_extrusions(print, layer, island, predicate, extruder_id, offset, previous_position, smooth_path); } else { - for (ExtrusionEntity* perimeter : island_extrusions.perimeters) { - std::optional instance_point{get_instance_point(previous_position, offset)}; - const std::optional seam_point{place_seam(layer, perimeter, instance_point)}; - if (seam_point) { - previous_position = get_gcode_point(*seam_point, offset); - } - } + island_extrusions.perimeters = extract_perimeter_extrusions(print, layer, island, predicate, extruder_id, offset, previous_position, smooth_path); island_extrusions.infill_ranges = {extract_infill_ranges( - print, layer, island, offset, previous_position, infill_predicate + print, layer, island, offset, previous_position, infill_predicate, smooth_path, extruder_id )}; } } @@ -253,7 +257,9 @@ std::vector extract_ironing_extrusions( const Print &print, const Layer &layer, const ExtractEntityPredicate &predicate, + const PathSmoothingFunction &smooth_path, const Vec2d &offset, + const unsigned extruder_id, std::optional &previous_position ) { std::vector result; @@ -264,7 +270,7 @@ std::vector extract_ironing_extrusions( }; const std::vector ironing_ranges{extract_infill_ranges( - print, layer, island, offset, previous_position, ironing_predicate + print, layer, island, offset, previous_position, ironing_predicate, smooth_path, extruder_id )}; result.insert( result.end(), ironing_ranges.begin(), ironing_ranges.end() @@ -277,8 +283,9 @@ std::vector get_slices_extrusions( const Print &print, const Layer &layer, const ExtractEntityPredicate &predicate, - const SeamPlacingFunciton &place_seam, + const PathSmoothingFunction &smooth_path, const Vec2d &offset, + const unsigned extruder_id, std::optional &previous_position ) { // Note: ironing. @@ -293,9 +300,9 @@ std::vector get_slices_extrusions( const LayerSlice &lslice = layer.lslices_ex[idx]; result.emplace_back(SliceExtrusions{ extract_island_extrusions( - lslice, print, layer, predicate, place_seam, offset, previous_position + lslice, print, layer, predicate, smooth_path, offset, extruder_id, previous_position ), - extract_ironing_extrusions(lslice, print, layer, predicate, offset, previous_position) + extract_ironing_extrusions(lslice, print, layer, predicate, smooth_path, offset, extruder_id, previous_position) }); } return result; @@ -359,7 +366,7 @@ std::vector> get_overriden_extrusions( const LayerTools &layer_tools, const std::vector &instances_to_print, const unsigned int extruder_id, - const SeamPlacingFunciton &place_seam, + const PathSmoothingFunction &smooth_path, std::optional &previous_position ) { std::vector> result; @@ -384,7 +391,7 @@ std::vector> get_overriden_extrusions( const Vec2d &offset = unscale(print_object.instances()[instance.instance_id].shift); result.emplace_back(get_slices_extrusions( - print, *layer, predicate, place_seam, offset, previous_position + print, *layer, predicate, smooth_path, offset, extruder_id, previous_position )); } } @@ -397,7 +404,7 @@ std::vector get_normal_extrusions( const LayerTools &layer_tools, const std::vector &instances_to_print, const unsigned int extruder_id, - const SeamPlacingFunciton &place_seam, + const PathSmoothingFunction &smooth_path, std::optional &previous_position ) { std::vector result; @@ -438,8 +445,9 @@ std::vector get_normal_extrusions( print, *layer, predicate, - place_seam, + smooth_path, offset, + extruder_id, previous_position ); } @@ -454,13 +462,9 @@ std::vector get_extrusions( const bool is_first_layer, const LayerTools &layer_tools, const std::vector &instances_to_print, - const GCode::SmoothPathCache &smooth_path_cache, const std::map> &skirt_loops_per_extruder, - const bool enable_loop_clipping, - const FullPrintConfig &config, - const double scaled_resolution, unsigned current_extruder_id, - const SeamPlacingFunciton &place_seam, + const PathSmoothingFunction &smooth_path, bool get_brim, std::optional previous_position ) { @@ -482,35 +486,11 @@ std::vector get_extrusions( if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) { const std::pair loops = loops_it->second; for (std::size_t i = loops.first; i < loops.second; ++i) { - auto loop_src{dynamic_cast(print.skirt().entities[i])}; - if (loop_src != nullptr) { - const Point seam_point = previous_position ? get_instance_point(*previous_position, {0.0, 0.0}) : Point::Zero(); - const bool reverse_loop = config.prefer_clockwise_movements; - // Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns, - // thus empty path segments will not be produced by G-code export. - GCode::SmoothPath smooth_path = smooth_path_cache.resolve_or_fit_split_with_seam(*loop_src, reverse_loop, scaled_resolution, seam_point, scaled(0.0015)); - - // Clip the path to avoid the extruder to get exactly on the first point of the loop; - // if polyline was shorter than the clipping distance we'd get a null polyline, so - // we discard it in that case. - const auto nozzle_diameter{config.nozzle_diameter.get_at(extruder_id)}; - if (enable_loop_clipping) - clip_end(smooth_path, scale_(nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER, scaled(min_gcode_segment_length)); - - if (smooth_path.empty()) - continue; - - assert(validate_smooth_path(smooth_path, ! enable_loop_clipping)); - - for (const SmoothPathElement &element : smooth_path) { - if (!element.path.empty()) { - previous_position = get_gcode_point(element.path.back().point, {0.0, 0.0}); - break; - } - } - - extruder_extrusions.skirt.emplace_back(i, std::move(smooth_path)); - } + const ExtrusionEntityReference entity{*print.skirt().entities[i], false}; + std::optional last_position{get_instance_point(previous_position, {0.0, 0.0})}; + SmoothPath path{smooth_path(nullptr, entity, extruder_id, last_position)}; + previous_position = get_gcode_point(last_position, {0.0, 0.0}); + extruder_extrusions.skirt.emplace_back(i, std::move(path)); } } @@ -526,14 +506,14 @@ std::vector get_extrusions( bool is_anything_overridden = layer_tools.wiping_extrusions().is_anything_overridden(); if (is_anything_overridden) { extruder_extrusions.overriden_extrusions = get_overriden_extrusions( - print, layers, layer_tools, instances_to_print, extruder_id, place_seam, + print, layers, layer_tools, instances_to_print, extruder_id, smooth_path, previous_position ); } using GCode::ExtrusionOrder::get_normal_extrusions; extruder_extrusions.normal_extrusions = get_normal_extrusions( - print, layers, layer_tools, instances_to_print, extruder_id, place_seam, + print, layers, layer_tools, instances_to_print, extruder_id, smooth_path, previous_position ); extrusions.push_back(std::move(extruder_extrusions)); diff --git a/src/libslic3r/GCode/ExtrusionOrder.hpp b/src/libslic3r/GCode/ExtrusionOrder.hpp index b9e803c5ed..8594188c53 100644 --- a/src/libslic3r/GCode/ExtrusionOrder.hpp +++ b/src/libslic3r/GCode/ExtrusionOrder.hpp @@ -53,13 +53,19 @@ struct InstanceToPrint namespace Slic3r::GCode::ExtrusionOrder { struct InfillRange { - std::vector items; + std::vector items; const PrintRegion *region; }; +struct Perimeter { + GCode::SmoothPath smooth_path; + bool reversed; + const ExtrusionEntity *extrusion_entity; +}; + struct IslandExtrusions { const PrintRegion *region; - std::vector perimeters; + std::vector perimeters; std::vector infill_ranges; }; @@ -75,27 +81,9 @@ struct NormalExtrusions { std::optional get_last_position(const ExtrusionEntitiesPtr &extrusions, const Vec2d &offset); -using SeamPlacingFunciton = std::function(const Layer &layer, ExtrusionEntity* perimeter, const std::optional&)>; - -std::vector> get_overriden_extrusions( - const Print &print, - const GCode::ObjectsLayerToPrint &layers, - const LayerTools &layer_tools, - const std::vector &instances_to_print, - const unsigned int extruder_id, - const SeamPlacingFunciton &place_seam, - std::optional &previous_position -); - -std::vector get_normal_extrusions( - const Print &print, - const GCode::ObjectsLayerToPrint &layers, - const LayerTools &layer_tools, - const std::vector &instances_to_print, - const unsigned int extruder_id, - const SeamPlacingFunciton &place_seam, - std::optional &previous_position -); +using PathSmoothingFunction = std::function &previous_position +)>; struct ExtruderExtrusions { unsigned extruder_id; @@ -114,13 +102,9 @@ std::vector get_extrusions( const bool is_first_layer, const LayerTools &layer_tools, const std::vector &instances_to_print, - const GCode::SmoothPathCache &smooth_path_cache, const std::map> &skirt_loops_per_extruder, - const bool enable_loop_clipping, - const FullPrintConfig &config, - const double scaled_resolution, unsigned current_extruder_id, - const SeamPlacingFunciton &place_seam, + const PathSmoothingFunction &smooth_path, bool get_brim, std::optional previous_position );