From 3466946cc267946c90202a3984508f68481b2e69 Mon Sep 17 00:00:00 2001 From: supermerill Date: Fri, 9 Sep 2022 21:58:40 +0200 Subject: [PATCH] Fix milling post-process supermerill/SuperSlicer#2739 supermerill/SuperSlicer#2786 --- src/libslic3r/GCode.cpp | 60 +++++------ src/libslic3r/GCode/SpiralVase.cpp | 149 +++++++++++++++------------ src/libslic3r/PerimeterGenerator.cpp | 3 + src/slic3r/GUI/Tab.cpp | 32 ++++-- 4 files changed, 139 insertions(+), 105 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index e2d8388655d..d6c83b25767 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2054,14 +2054,14 @@ void GCode::process_layers( // The pipeline elements are joined using const references, thus no copying is performed. output_stream.find_replace_supress(); - if (m_spiral_vase && m_find_replace) - tbb::parallel_pipeline(12, generator & spiral_vase & cooling & fan_mover & find_replace & output); - else if (m_spiral_vase) - tbb::parallel_pipeline(12, generator & spiral_vase & cooling & fan_mover & output); - else if (m_find_replace) - tbb::parallel_pipeline(12, generator & cooling & fan_mover & find_replace & output); - else - tbb::parallel_pipeline(12, generator & cooling & fan_mover & output); + tbb::filter pipeline_to_layerresult = generator; + if (m_spiral_vase) + pipeline_to_layerresult = pipeline_to_layerresult & spiral_vase; + tbb::filter pipeline_to_string = pipeline_to_layerresult & cooling & fan_mover; + if (m_find_replace) + pipeline_to_string = pipeline_to_string & find_replace; + tbb::filter full_pipeline = pipeline_to_string & output; + tbb::parallel_pipeline(12, full_pipeline); output_stream.find_replace_enable(); } @@ -2091,9 +2091,9 @@ void GCode::process_layers( }); const auto spiral_vase = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, [&spiral_vase = *this->m_spiral_vase.get()](GCode::LayerResult in)->GCode::LayerResult { - spiral_vase.enable(in.spiral_vase_enable); - return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush }; - }); + spiral_vase.enable(in.spiral_vase_enable); + return { spiral_vase.process_layer(std::move(in.gcode)), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush }; + }); const auto cooling = tbb::make_filter(slic3r_tbb_filtermode::serial_in_order, [&cooling_buffer = *this->m_cooling_buffer.get()](GCode::LayerResult in)->std::string { return cooling_buffer.process_layer(std::move(in.gcode), in.layer_id, in.cooling_buffer_flush); @@ -2128,14 +2128,14 @@ void GCode::process_layers( // The pipeline elements are joined using const references, thus no copying is performed. output_stream.find_replace_supress(); - if (m_spiral_vase && m_find_replace) - tbb::parallel_pipeline(12, generator & spiral_vase & cooling & fan_mover & find_replace & output); - else if (m_spiral_vase) - tbb::parallel_pipeline(12, generator & spiral_vase & cooling & fan_mover & output); - else if (m_find_replace) - tbb::parallel_pipeline(12, generator & cooling & fan_mover & find_replace & output); - else - tbb::parallel_pipeline(12, generator & cooling & fan_mover & output); + tbb::filter pipeline_to_layerresult = generator; + if (m_spiral_vase) + pipeline_to_layerresult = pipeline_to_layerresult & spiral_vase; + tbb::filter pipeline_to_string = pipeline_to_layerresult & cooling & fan_mover; + if (m_find_replace) + pipeline_to_string = pipeline_to_string & find_replace; + tbb::filter full_pipeline = pipeline_to_string & output; + tbb::parallel_pipeline(12, full_pipeline); output_stream.find_replace_enable(); } @@ -3162,14 +3162,6 @@ GCode::LayerResult GCode::process_layer( } } -#if 0 - // Apply spiral vase post-processing if this layer contains suitable geometry - // (we must feed all the G-code into the post-processor, including the first - // bottom non-spiral layers otherwise it will mess with positions) - // we apply spiral vase at this stage because it requires a full layer. - // Just a reminder: A spiral vase mode is allowed for a single object per layer, single material print only. - if (m_spiral_vase) - gcode = m_spiral_vase->process_layer(std::move(gcode)); //add milling post-process if enabled @@ -3210,10 +3202,10 @@ GCode::LayerResult GCode::process_layer( check_add_eol(gcode); } - gcode += "\n; began print:"; + gcode += "\n; began milling:\n"; for (const LayerToPrint& ltp : layers) { if (ltp.object_layer != nullptr) { - for (const PrintInstance& print_instance : ltp.object()->instances()){ + for (const PrintInstance& print_instance : ltp.object()->instances()) { this->set_origin(unscale(print_instance.shift)); for (const LayerRegion* lr : ltp.object_layer->regions()) { if (!lr->milling.empty()) { @@ -3227,7 +3219,7 @@ GCode::LayerResult GCode::process_layer( } //switch to extruder - m_placeholder_parser.set("current_extruder", milling_extruder_id); + m_placeholder_parser.set("current_extruder", current_extruder_filament); // Append the filament start G-code. const std::string& end_mill_gcode = m_config.milling_toolchange_end_gcode.get_at(0); if (!end_mill_gcode.empty()) { @@ -3250,6 +3242,14 @@ GCode::LayerResult GCode::process_layer( } } +#if 0 + // Apply spiral vase post-processing if this layer contains suitable geometry + // (we must feed all the G-code into the post-processor, including the first + // bottom non-spiral layers otherwise it will mess with positions) + // we apply spiral vase at this stage because it requires a full layer. + // Just a reminder: A spiral vase mode is allowed for a single object per layer, single material print only. + if (m_spiral_vase) + gcode = m_spiral_vase->process_layer(std::move(gcode)); // Apply cooling logic; this may alter speeds. if (m_cooling_buffer) diff --git a/src/libslic3r/GCode/SpiralVase.cpp b/src/libslic3r/GCode/SpiralVase.cpp index 482b6db3990..19401fb6c96 100644 --- a/src/libslic3r/GCode/SpiralVase.cpp +++ b/src/libslic3r/GCode/SpiralVase.cpp @@ -32,24 +32,29 @@ std::string SpiralVase::process_layer(const std::string &gcode) //FIXME Performance warning: This copies the GCodeConfig of the reader. GCodeReader r = m_reader; // clone bool set_z = false; - r.parse_buffer(gcode, [&total_layer_length, &layer_height, &z, &set_z, &height_str] + bool milling = false; + r.parse_buffer(gcode, [&total_layer_length, &layer_height, &z, &set_z, &height_str, &milling] (GCodeReader &reader, const GCodeReader::GCodeLine &line) { - if (line.cmd_is("G1")) { - if (line.extruding(reader)) { - total_layer_length += line.dist_XY(reader); - } else if (line.has(Z)) { - layer_height += line.dist_Z(reader); - if (!set_z) { - z = line.new_Z(reader); - set_z = true; + if (boost::starts_with(line.comment(), " milling")) + milling = true; + if (!milling) { + if (line.cmd_is("G1")) { + if (line.extruding(reader)) { + total_layer_length += line.dist_XY(reader); + } else if (line.has(Z)) { + layer_height += line.dist_Z(reader); + if (!set_z) { + z = line.new_Z(reader); + set_z = true; + } } - } - } else { - const std::string& comment = line.raw(); - if (comment.length() > 2 && comment.front() == ';') { - std::string comment_str = comment.substr(1); - if (boost::starts_with(comment_str, GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height))) { - height_str = comment_str.substr(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height).size()); + } else { + const std::string& comment = line.raw(); + if (comment.length() > 2 && comment.front() == ';') { + std::string comment_str = comment.substr(1); + if (boost::starts_with(comment_str, GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height))) { + height_str = comment_str.substr(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height).size()); + } } } } @@ -79,67 +84,83 @@ std::string SpiralVase::process_layer(const std::string &gcode) float len = 0.f; double E_accumulator = 0; double last_old_E = 0; - m_reader.parse_buffer(gcode, [this, &keep_first_travel , &new_gcode, &z, total_layer_length, layer_height_factor, &len, &E_accumulator, &last_old_E, &height_str] + bool is_milling = false; + GCodeReader::GCodeLine line_last_position; + m_reader.parse_buffer(gcode, [this, &keep_first_travel , &new_gcode, &z, total_layer_length, layer_height_factor, &len, &E_accumulator, &last_old_E, &height_str, &is_milling, &line_last_position] (GCodeReader &reader, GCodeReader::GCodeLine line) { - if (line.cmd_is("G1")) { - if (line.has_z()) { - // If this is the initial Z move of the layer, replace it with a - // (redundant) move to the last Z of previous layer. - line.set(reader, Z, z); - new_gcode += line.raw() + '\n'; - return; - } else { - float dist_XY = line.dist_XY(reader); - if (dist_XY > 0) { - // horizontal move - if (line.extruding(reader)) { - keep_first_travel = false; - len += dist_XY; - line.set(reader, Z, z + len * layer_height_factor); - if (m_transition_layer && line.has(E)) { - // Transition layer, modulate the amount of extrusion from zero to the final value. - if (m_config.use_relative_e_distances.value) { - line.set(reader, E, line.value(E) * len / total_layer_length); - } else { - last_old_E = line.value(E); - E_accumulator += line.dist_E(reader) * len / total_layer_length; - line.set(reader, E, E_accumulator); + if (boost::starts_with(line.comment()," milling")) + is_milling = true; + if (!is_milling) { + if (line.cmd_is("G1")) { + if (line.has_z()) { + // If this is the initial Z move of the layer, replace it with a + // (redundant) move to the last Z of previous layer. + line.set(reader, Z, z); + new_gcode += line.raw() + '\n'; + return; + } else { + float dist_XY = line.dist_XY(reader); + if (dist_XY > 0) { + // horizontal move + if (line.extruding(reader)) { + keep_first_travel = false; + len += dist_XY; + line.set(reader, Z, z + len * layer_height_factor); + if (m_transition_layer && line.has(E)) { + // Transition layer, modulate the amount of extrusion from zero to the final value. + if (m_config.use_relative_e_distances.value) { + line.set(reader, E, line.value(E) * len / total_layer_length); + } else { + last_old_E = line.value(E); + E_accumulator += line.dist_E(reader) * len / total_layer_length; + line.set(reader, E, E_accumulator); + } } + new_gcode += line.raw() + '\n'; + } else if (keep_first_travel) { + //we can travel until the first spiral extrusion + new_gcode += line.raw() + '\n'; } - new_gcode += line.raw() + '\n'; - } else if (keep_first_travel) { - //we can travel until the first spiral extrusion - new_gcode += line.raw() + '\n'; + line_last_position = line; + return; + + /* Skip travel moves: the move to first perimeter point will + cause a visible seam when loops are not aligned in XY; by skipping + it we blend the first loop move in the XY plane (although the smoothness + of such blend depend on how long the first segment is; maybe we should + enforce some minimum length?). */ } - return; - - /* Skip travel moves: the move to first perimeter point will - cause a visible seam when loops are not aligned in XY; by skipping - it we blend the first loop move in the XY plane (although the smoothness - of such blend depend on how long the first segment is; maybe we should - enforce some minimum length?). */ } - } - } else if (!height_str.empty()) { - const std::string& comment = line.raw(); - if (comment.length() > 2 && comment.front() == ';') { - std::string comment_str = comment.substr(1); - if (boost::starts_with(comment_str, GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height))) { - //do not write it on the gcode - return; + } else if (!height_str.empty()) { + const std::string& comment = line.raw(); + if (comment.length() > 2 && comment.front() == ';') { + std::string comment_str = comment.substr(1); + if (boost::starts_with(comment_str, GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height))) { + //do not write it on the gcode + return; + } } } + if (m_transition_layer && !m_config.use_relative_e_distances.value) { + new_gcode += "; End spiral transition layer\n"; + new_gcode += "G92 E" + to_string_nozero(last_old_E, m_config.gcode_precision_e.value) + "\n"; + } + new_gcode += line.raw() + '\n'; + } else { + //milling, just copy + new_gcode += line.raw() + '\n'; } - if (m_transition_layer && !m_config.use_relative_e_distances.value) { - new_gcode += "; End spiral transition layer\n"; - new_gcode += "G92 E"+ to_string_nozero(last_old_E, m_config.gcode_precision_e.value) + "\n"; - } - new_gcode += line.raw() + '\n'; }); if (m_transition_layer && !height_str.empty()) { //restore height/width new_gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + height_str +"\n"; } + if (is_milling) { + //travel back to last good position. + line_last_position.set(m_reader, Axis::E, 0); + new_gcode += "; return to spiral location\n"; + new_gcode += line_last_position.raw() + "\n"; + } return new_gcode; } diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 1248b889080..8df16a5cd0a 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -435,6 +435,9 @@ void PerimeterGenerator::process() if (unmillable.empty()) last = offset_ex(last, mill_extra_size); else { + //FIXME only work if mill_extra_size < mill_nozzle/2 (becasue it's the extra offset from unmillable) + //FIXME overhangs if mill_extra_size is too big + //FIXME merge with process_arachne? ExPolygons growth = diff_ex(offset_ex(last, mill_extra_size), unmillable, ApplySafetyOffset::Yes); last.insert(last.end(), growth.begin(), growth.end()); last = union_ex(last); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 0fdd89491ec..bccdefea101 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2989,16 +2989,16 @@ void TabPrinter::milling_count_changed(size_t milling_count) is_count_changed = true; } - /* This function should be call in any case because of correct updating/rebuilding - * of unregular pages of a Printer Settings - */ - build_unregular_pages(false); + if (is_count_changed) { + /* This function should be call in any case because of correct updating/rebuilding + * of unregular pages of a Printer Settings + */ + build_unregular_pages(false); - //no gui listing for now - //if (is_count_changed) { - // on_value_change("milling_count", milling_count); - // wxGetApp().sidebar().update_objects_list_milling_column(milling_count); - //} + //propagate change + on_value_change("milling_count", milling_count); + //wxGetApp().sidebar().update_objects_list_milling_column(milling_count); + } } void TabPrinter::append_option_line_kinematics(ConfigOptionsGroupShp optgroup, const std::string opt_key, const std::string override_sidetext) @@ -3287,8 +3287,10 @@ void TabPrinter::reload_config() // "extruders_count" doesn't update from the update_config(), // so update it implicitly - if (m_active_page && m_active_page->title() == "General") + if (m_active_page && m_active_page->get_field("extruders_count")) m_active_page->set_value("extruders_count", int(m_extruders_count)); + if (m_active_page && m_active_page->get_field("milling_count")) + m_active_page->set_value("milling_count", int(m_milling_count)); } void TabPrinter::activate_selected_page(std::function throw_if_canceled) @@ -3297,8 +3299,10 @@ void TabPrinter::activate_selected_page(std::function throw_if_canceled) // "extruders_count" doesn't update from the update_config(), // so update it implicitly - if (m_active_page && m_active_page->title() == "General") + if (m_active_page && m_active_page->get_field("extruders_count")) m_active_page->set_value("extruders_count", int(m_extruders_count)); + if (m_active_page && m_active_page->get_field("milling_count")) + m_active_page->set_value("milling_count", int(m_milling_count)); } void TabPrinter::clear_pages() @@ -4732,6 +4736,7 @@ void TabPrinter::cache_extruder_cnt() return; m_cache_extruder_count = m_extruders_count; + m_cache_milling_count = m_milling_count; } bool TabPrinter::apply_extruder_cnt_from_cache() @@ -4739,6 +4744,11 @@ bool TabPrinter::apply_extruder_cnt_from_cache() if (m_presets->get_edited_preset().printer_technology() == ptSLA) return false; + if (m_cache_milling_count > 0) { + m_presets->get_edited_preset().set_num_milling(m_cache_milling_count); + m_cache_milling_count = 0; + } + if (m_cache_extruder_count > 0) { m_presets->get_edited_preset().set_num_extruders(m_cache_extruder_count); m_cache_extruder_count = 0;