diff --git a/resources/ui_layout/filament.ui b/resources/ui_layout/filament.ui index 6ee4794fc..dcf4d8291 100644 --- a/resources/ui_layout/filament.ui +++ b/resources/ui_layout/filament.ui @@ -21,7 +21,6 @@ group:Filament properties setting:filament_soluble setting:filament_shrink group:Print speed override - setting:filament_max_wipe_tower_speed setting:filament_max_volumetric_speed volumetric_speed_description @@ -59,6 +58,7 @@ group:Multimaterial toolchange string reduction setting:filament_dip_extraction_speed group:Wipe tower parameters setting:filament_minimal_purge_on_wipe_tower + setting:filament_max_wipe_tower_speed group:Toolchange parameters with single extruder MM printers setting:filament_loading_speed_start setting:filament_loading_speed diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 710008ca7..f5613c26f 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -417,6 +417,7 @@ int CLI::run(int argc, char **argv) PrintBase *print = (printer_technology == ptFFF) ? static_cast(&fff_print) : static_cast(&sla_print); if (! m_config.opt_bool("dont_arrange")) { //FIXME make the min_object_distance configurable. + print->apply(model, m_print_config); // arrange_objects needs that the print has the config model.arrange_objects(print); model.center_instances_around_point((! user_center_specified && m_print_config.has("bed_shape")) ? BoundingBoxf(m_print_config.opt("bed_shape")->values).center() : diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 07661246a..613c00dfa 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -420,6 +420,10 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T gcode += tcr_gcode; check_add_eol(toolchange_gcode_str); + if (gcodegen.writer().tool() && gcodegen.m_config.filament_enable_toolchange_part_fan.values[gcodegen.writer().tool()->id()]) { + //if the fan may ahve been changed silently by the wipetower, recover it. + gcode += gcodegen.m_writer.set_fan(gcodegen.m_writer.get_fan(), true); + } // A phony move to the end position at the wipe tower. gcodegen.writer().travel_to_xy(end_pos.cast()); @@ -428,19 +432,17 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T gcode += gcodegen.writer().retract(); gcode += gcodegen.writer().travel_to_z(current_z, "Travel back up to the topmost object layer."); gcode += gcodegen.writer().unretract(); - } - - else { - // Prepare a future wipe. - gcodegen.m_wipe.path.points.clear(); - if (new_extruder_id >= 0) { - // Start the wipe at the current position. - gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, end_pos)); - // Wipe end point: Wipe direction away from the closer tower edge to the further tower edge. - gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, - Vec2f((std::abs(m_left - end_pos.x()) < std::abs(m_right - end_pos.x())) ? m_right : m_left, - end_pos.y()))); - } + } else { + // Prepare a future wipe. + gcodegen.m_wipe.path.points.clear(); + if (new_extruder_id >= 0) { + // Start the wipe at the current position. + gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, end_pos)); + // Wipe end point: Wipe direction away from the closer tower edge to the further tower edge. + gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, + Vec2f((std::abs(m_left - end_pos.x()) < std::abs(m_right - end_pos.x())) ? m_right : m_left, + end_pos.y()))); + } } // Let the planner know we are traveling between objects. @@ -845,7 +847,8 @@ namespace DoExport { // If the following block is enabled for other firmwares than the Marlin, then the function // this->print_machine_envelope(file, print); // shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor. - if (config.gcode_flavor.value == gcfMarlin || config.gcode_flavor.value == gcfLerdge) { + // supermerill: done + if (true) { normal_time_estimator.set_max_acceleration((float)config.machine_max_acceleration_extruding.values[0]); normal_time_estimator.set_retract_acceleration((float)config.machine_max_acceleration_retracting.values[0]); normal_time_estimator.set_max_travel_acceleration((float)config.machine_max_acceleration_travel.values[0]); @@ -1073,9 +1076,9 @@ namespace DoExport { print_statistics.clear(); print_statistics.estimated_normal_print_time = normal_time_estimator.get_time_dhm/*s*/(); print_statistics.estimated_silent_print_time = silent_time_estimator_enabled ? silent_time_estimator.get_time_dhm/*s*/() : "N/A"; - print_statistics.estimated_normal_custom_gcode_print_times = normal_time_estimator.get_custom_gcode_times_dhm(true); + print_statistics.estimated_normal_custom_gcode_print_times = normal_time_estimator.get_custom_gcode_times(); if (silent_time_estimator_enabled) - print_statistics.estimated_silent_custom_gcode_print_times = silent_time_estimator.get_custom_gcode_times_dhm(true); + print_statistics.estimated_silent_custom_gcode_print_times = silent_time_estimator.get_custom_gcode_times(); print_statistics.total_toolchanges = std::max(0, wipe_tower_data.number_of_toolchanges); if (! extruders.empty()) { std::pair out_filament_used_mm ("; filament used [mm] = ", 0); @@ -1205,34 +1208,6 @@ static void init_multiextruders(FILE *file, Print &print, GCodeWriter & writer, int(print.config().temperature.get_at(tool_id))); } } - //activate first extruder is multi-extruder and not in start-gcode - if (writer.multiple_extruders) { - if (std::set{gcfRepRap}.count(print.config().gcode_flavor.value) > 0) { - //if not in gcode - bool find = false; - if (!custom_gcode.empty()) { - const char *ptr = custom_gcode.data(); - while (*ptr != 0) { - // Skip whitespaces. - for (; *ptr == ' ' || *ptr == '\t'; ++ptr); - if (*ptr == 'T') { - find = true; - break; - } else if (*ptr == 'A') { - //TODO: ACTIVATE_EXTRUDER for klipper (if used) - } - // Skip the rest of the line. - for (; *ptr != 0 && *ptr != '\r' && *ptr != '\n'; ++ptr); - // Skip the end of line indicators. - for (; *ptr == '\r' || *ptr == '\n'; ++ptr); - } - } - if (!find) { - fprintf(file, writer.toolchange(tool_ordering.first_extruder()).c_str()); - } - } - writer.toolchange(tool_ordering.first_extruder()); - } } @@ -1462,7 +1437,7 @@ void GCode::_do_export(Print &print, FILE *file) this->print_machine_envelope(file, print); // Disable fan. - if ( (! print.config().cooling.get_at(initial_extruder_id) || print.config().disable_fan_first_layers.get_at(initial_extruder_id)) + if ( print.config().disable_fan_first_layers.get_at(initial_extruder_id) && config().gcode_flavor != gcfKlipper) _write(file, m_writer.set_fan(0, true)); @@ -1521,10 +1496,47 @@ void GCode::_do_export(Print &print, FILE *file) // Calculate wiping points if needed DoExport::init_ooze_prevention(print, m_ooze_prevention); print.throw_if_canceled(); - - if (! (has_wipe_tower && print.config().single_extruder_multi_material_priming)) { - // Set initial extruder only after custom start G-code. - // Ugly hack: Do not set the initial extruder if the extruder is primed using the MMU priming towers at the edge of the print bed. + + //activate first extruder is multi-extruder and not in start-gcode + if (m_writer.multiple_extruders) { + //if not in gcode + bool find = false; + if (!start_gcode.empty()) { + const char *ptr = start_gcode.data(); + while (*ptr != 0) { + // Skip whitespaces. + for (; *ptr == ' ' || *ptr == '\t'; ++ptr); + if (*ptr == 'T') { + // TX for most of the firmwares + find = true; + break; + } else if (*ptr == 'A' && print.config().gcode_flavor.value == gcfKlipper) { + // ACTIVATE_EXTRUDER for klipper (if used) + if (std::string::npos != start_gcode.find("ACTIVATE_EXTRUDER", size_t(ptr - start_gcode.data()))) { + find = true; + break; + } + } + // Skip the rest of the line. + for (; *ptr != 0 && *ptr != '\r' && *ptr != '\n'; ++ptr); + // Skip the end of line indicators. + for (; *ptr == '\r' || *ptr == '\n'; ++ptr); + } + } + if (!find) { + // Set initial extruder only after custom start G-code. + // Ugly hack: Do not set the initial extruder if the extruder is primed using the MMU priming towers at the edge of the print bed. + if (!(has_wipe_tower && print.config().single_extruder_multi_material_priming)) { + _write(file, this->set_extruder(initial_extruder_id, 0.)); + } else { + m_writer.toolchange(initial_extruder_id); + } + } else { + // set writer to the tool as should be set in the start_gcode. + _write(file, this->set_extruder(initial_extruder_id, 0., true)); + } + } else { + // if we are running a single-extruder setup, just set the extruder and "return nothing" _write(file, this->set_extruder(initial_extruder_id, 0.)); } @@ -1693,6 +1705,18 @@ void GCode::_do_export(Print &print, FILE *file) if (m_silent_time_estimator_enabled) m_silent_time_estimator.scale_time(config().time_estimation_compensation.get_abs_value(1)); } + //try to compensate fora random bug #364 + if (m_normal_time_estimator.get_time() < 0) { + std::cerr << "error, negative time estimation : " << m_normal_time_estimator.get_time() << ", retry.\n"; + m_normal_time_estimator.calculate_time(true); + if (m_silent_time_estimator_enabled) + m_silent_time_estimator.calculate_time(true); + if (config().time_estimation_compensation.get_abs_value(1) != 1) { + m_normal_time_estimator.scale_time(config().time_estimation_compensation.get_abs_value(1)); + if (m_silent_time_estimator_enabled) + m_silent_time_estimator.scale_time(config().time_estimation_compensation.get_abs_value(1)); + } + } // Get filament stats. _write(file, DoExport::update_print_stats_and_format_filament_stats( @@ -1915,7 +1939,7 @@ void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, c if (temp_by_gcode >= 0 && temp_by_gcode < 1000) temp = temp_by_gcode; m_writer.set_temperature(temp, wait, first_printing_extruder_id); - } else if(this->config().gcode_flavor != gcfKlipper){ + } else if(this->config().gcode_flavor != gcfKlipper || print.config().start_gcode.value.empty()){ // Custom G-code does not set the extruder temperature. Do it now. if (print.config().single_extruder_multi_material.value) { // Set temperature of the first printing extruder only. @@ -4339,7 +4363,7 @@ std::string GCode::retract(bool toolchange) return gcode; } -std::string GCode::set_extruder(unsigned int extruder_id, double print_z) +std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool no_toolchange /*=false*/) { if (!m_writer.need_toolchange(extruder_id)) return ""; @@ -4410,7 +4434,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z) // We inform the writer about what is happening, but we may not use the resulting gcode. std::string toolchange_command = m_writer.toolchange(extruder_id); - if (! custom_gcode_changes_tool(toolchange_gcode_parsed, m_writer.toolchange_prefix(), extruder_id)) + if (! custom_gcode_changes_tool(toolchange_gcode_parsed, m_writer.toolchange_prefix(), extruder_id) && !no_toolchange) gcode += toolchange_command; else { // user provided his own toolchange gcode, no need to do anything diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index ded150a69..6cf524490 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -334,7 +334,7 @@ private: bool needs_retraction(const Polyline &travel, ExtrusionRole role = erNone); std::string retract(bool toolchange = false); std::string unretract() { return m_writer.unlift() + m_writer.unretract(); } - std::string set_extruder(unsigned int extruder_id, double print_z); + std::string set_extruder(unsigned int extruder_id, double print_z, bool no_toolchange = false); /* Origin of print coordinates expressed in unscaled G-code coordinates. This affects the input arguments supplied to the extrude*() and travel_to() diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index 236941e26..faef66485 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -312,7 +312,7 @@ std::vector CoolingBuffer::parse_layer_gcode(const std:: PerExtruderAdjustments &adj = per_extruder_adjustments[i]; uint16_t extruder_id = extruders[i].id(); adj.extruder_id = extruder_id; - adj.cooling_slow_down_enabled = config.cooling.get_at(extruder_id); + adj.cooling_slow_down_enabled = config.slowdown_below_layer_time.get_at(extruder_id) > 0; adj.slowdown_below_layer_time = float(config.slowdown_below_layer_time.get_at(extruder_id)); adj.min_print_speed = float(config.min_print_speed.get_at(extruder_id)); adj.max_speed_reduction = float(config.max_speed_reduction.get_at(extruder_id) / 100); diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 7c3dd05cf..3b8f1e0ac 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -440,6 +440,8 @@ public: { if (m_gcode_flavor == gcfMarlin) m_gcode += "M220 R\n"; + else + m_gcode += "M220 S100\n"; return *this; } @@ -715,7 +717,8 @@ std::vector WipeTower::prime( uint16_t tool = tools[idx_tool]; m_left_to_right = true; - toolchange_Change(writer, tool, m_filpar[tool].material); // Select the tool, set a speed override for soluble and flex materials. + toolchange_Change(writer, tool); // Select the tool, set a speed override for soluble and flex materials. + writer.speed_override(int(100 * get_speed_reduction())); toolchange_Load(writer, cleaning_box); // Prime the tool. if (idx_tool + 1 == tools.size()) { // Last tool should not be unloaded, but it should be wiped enough to become of a pure color. @@ -726,7 +729,7 @@ std::vector WipeTower::prime( toolchange_Wipe(writer, cleaning_box , 20.f); box_coordinates box = cleaning_box; box.translate(0.f, writer.y() - cleaning_box.ld.y() + m_perimeter_width); - toolchange_Unload(writer, box , m_filpar[m_current_tool].material, m_filpar[tools[idx_tool + 1]].first_layer_temperature, idx_tool + 1); + toolchange_Unload(writer, box , m_filpar[tools[idx_tool + 1]].first_layer_temperature, idx_tool + 1); cleaning_box.translate(prime_section_width, 0.f); writer.travel(cleaning_box.ld, 7200); } @@ -833,15 +836,17 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool last_in_lay // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. if (tool != (unsigned int)-1){ // This is not the last change. - toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, + toolchange_Unload(writer, cleaning_box, m_is_first_layer ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature, tool); - toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials. + toolchange_Change(writer, tool); // Change the tool, set a speed override for soluble and flex materials. + writer.speed_override(int(100 * get_speed_reduction())); toolchange_Load(writer, cleaning_box); writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road + writer.speed_override(int(100 * get_speed_reduction())); toolchange_Wipe(writer, cleaning_box, wipe_volume); // Wipe the newly loaded filament until the end of the assigned wipe area. ++ m_num_tool_changes; } else - toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].temperature, m_current_tool); + toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].temperature, m_current_tool); m_depth_traversed += wipe_area; @@ -952,7 +957,6 @@ WipeTower::ToolChangeResult WipeTower::toolchange_Brim(bool sideOnly, float y_of void WipeTower::toolchange_Unload( WipeTowerWriter &writer, const box_coordinates &cleaning_box, - const std::string& current_material, const int new_temperature, const size_t next_tool) { @@ -1184,8 +1188,7 @@ void WipeTower::toolchange_Unload( // Change the tool, set a speed override for soluble and flex materials. void WipeTower::toolchange_Change( WipeTowerWriter &writer, - const size_t new_tool, - const std::string& new_material) + const size_t new_tool) { // Ask the writer about how much of the old filament we consumed: if (m_current_tool < m_used_filament_length.size()) @@ -1244,6 +1247,19 @@ void WipeTower::toolchange_Load( } } +float WipeTower::get_speed_reduction() const +{ + float speed_override = m_config->filament_max_wipe_tower_speed.get_at(m_current_tool) / 100.f; + if (speed_override <= 0) { + speed_override = 1; + std::string material_upp = boost::algorithm::to_upper_copy(m_filpar[m_current_tool].material); + if (material_upp == "PVA") speed_override = (m_z_pos < 0.80f) ? 0.60 : 0.80; + if (material_upp == "SCAFF") speed_override = 0.35; + if (material_upp == "FLEX") speed_override = 0.35; + } + return speed_override; +} + // Wipe the newly loaded filament until the end of the assigned wipe area. void WipeTower::toolchange_Wipe( WipeTowerWriter &writer, @@ -1257,6 +1273,9 @@ void WipeTower::toolchange_Wipe( const float& xl = cleaning_box.ld.x(); const float& xr = cleaning_box.rd.x(); + // Speed override for the material. Go slow for flex and soluble materials. + wipe_coeff *= get_speed_reduction(); + // Variables x_to_wipe and traversed_x are here to be able to make sure it always wipes at least // the ordered volume, even if it means violating the box. This can later be removed and simply // wipe until the end of the assigned area. @@ -1332,6 +1351,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer() // Slow down on the 1st layer. float speed_factor = m_is_first_layer ? 0.5f : 1.f; + speed_factor *= get_speed_reduction(); float current_depth = m_layer_info->depth - m_layer_info->toolchanges_depth(); box_coordinates fill_box(Vec2f(m_perimeter_width, m_depth_traversed + m_perimeter_width), m_wipe_tower_width - 2 * m_perimeter_width, current_depth-m_perimeter_width); diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index 08d4c2c58..a6e87473a 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -135,11 +135,13 @@ public: } // Return the wipe tower position. - const Vec2f& position() const { return m_wipe_tower_pos; } + const Vec2f& position() const { return m_wipe_tower_pos; } // Return the wipe tower width. - float width() const { return m_wipe_tower_width; } + float width() const { return m_wipe_tower_width; } // The wipe tower is finished, there should be no more tool changes or wipe tower prints. - bool finished() const { return m_max_color_changes == 0; } + bool finished() const { return m_max_color_changes == 0; } + // get the speed reduction from the current filament material + float get_speed_reduction() const; // Returns gcode to prime the nozzles at the front edge of the print bed. std::vector prime( @@ -366,14 +368,12 @@ private: void toolchange_Unload( WipeTowerWriter &writer, const box_coordinates &cleaning_box, - const std::string& current_material, const int new_temperature, const size_t temp_tool); void toolchange_Change( WipeTowerWriter &writer, - const size_t new_tool, - const std::string& new_material); + const size_t new_tool); void toolchange_Load( WipeTowerWriter &writer, diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index 229441b6c..f01300d4f 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -794,27 +794,6 @@ namespace Slic3r { return ret; } - std::vector> GCodeTimeEstimator::get_custom_gcode_times_dhm(bool include_remaining) const - { - std::vector> ret; - - float total_time = 0.0f; - for (const std::pair &t : m_custom_gcode_times) - { - std::string time = _get_time_dhm(t.second); - if (include_remaining) - { - time += " ("; - time += _get_time_dhm(m_time - total_time); - time += ")"; - } - total_time += t.second; - ret.push_back({t.first, time}); - } - - return ret; - } - // Return an estimate of the memory consumed by the time estimator. size_t GCodeTimeEstimator::memory_used() const { diff --git a/src/libslic3r/GCodeTimeEstimator.hpp b/src/libslic3r/GCodeTimeEstimator.hpp index a2ad52aa3..0bf03e4c3 100644 --- a/src/libslic3r/GCodeTimeEstimator.hpp +++ b/src/libslic3r/GCodeTimeEstimator.hpp @@ -417,10 +417,6 @@ namespace Slic3r { // If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)" std::vector get_color_times_minutes(bool include_remaining) const; - // Returns the estimated time, in format DDd HHh MMm, for each custom_gcode - // If include_remaining==true the strings will be formatted as: "time for custom_gcode (remaining time at color start)" - std::vector> get_custom_gcode_times_dhm(bool include_remaining) const; - // Return an estimate of the memory consumed by the time estimator. size_t memory_used() const; diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 15019b30f..b4aac60dc 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -67,6 +67,7 @@ public: std::string postamble() const; std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1); std::string set_bed_temperature(unsigned int temperature, bool wait = false); + unsigned int get_fan() { return m_last_fan_speed; } std::string set_fan(unsigned int speed, bool dont_save = false); void set_acceleration(unsigned int acceleration); std::string write_acceleration(); diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index df094a92c..dd858250b 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -525,19 +525,19 @@ void PerimeterGenerator::process() +(float)(min_spacing / 2 - 1)); ExPolygons no_thin_onion = offset_ex(last, double(-good_spacing)); - float div = 2; - while (no_thin_onion.size() > 0 && next_onion.size() > no_thin_onion.size() && no_thin_onion.size() + next_onion.size() > 3) { - div -= 0.3; - if (div == 2) div -= 0.3; + std::vector divs { 1.8, 1.6 }; //don't over-extrude, so don't use divider >2 + size_t idx_div = 0; + while (next_onion.size() > no_thin_onion.size() && idx_div < divs.size()) { + float div = divs[idx_div]; //use a sightly bigger spacing to try to drastically improve the split, that can lead to very thick gapfill ExPolygons next_onion_secondTry = offset2_ex( last, - -(float)(good_spacing + min_spacing / div - 1), - +(float)(min_spacing / div - 1)); - if (next_onion.size() > next_onion_secondTry.size() * 1.1) { + -(float)(good_spacing + (min_spacing / div) - 1), + +(float)((min_spacing / div) - 1)); + if (next_onion.size() > next_onion_secondTry.size() * 1.2 && next_onion.size() > next_onion_secondTry.size() + 2) { next_onion = next_onion_secondTry; } - if (div > 3 || div < 1.2) break; + idx_div++; } } else { @@ -752,7 +752,11 @@ void PerimeterGenerator::process() coll2.entities.push_back(loop); } } - entities = coll2; + //note: this hacky thing is possible because coll2.entities contains in fact entities's entities + //if you does entities = coll2, you'll delete entities's entities and then you have nothing. + entities.entities = coll2.entities; + //and you have to empty coll2 or it will delete his content, hence crashing our hack + coll2.entities.clear(); } } else if (this->config->external_perimeters_hole.value) { //reverse the hole, and put them in first place. @@ -768,13 +772,19 @@ void PerimeterGenerator::process() coll2.entities.push_back(loop); } } - entities = coll2; + //note: this hacky thing is possible because coll2.entities contains in fact entities's entities + //if you does entities = coll2, you'll delete entities's entities and then you have nothing. + entities.entities = coll2.entities; + //and you have to empty coll2 or it will delete his content, hence crashing our hack + coll2.entities.clear(); } } // append perimeters for this slice as a collection - if (!entities.empty()) - this->loops->append(entities); + if (!entities.empty()) { + //move it, to avoid to clone evrything and then delete it + this->loops->entities.emplace_back( new ExtrusionEntityCollection(std::move(entities))); + } } // for each loop of an island // fill gaps diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index a9cee4fb1..58b53edb9 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -319,8 +319,8 @@ struct PrintStatistics PrintStatistics() { clear(); } std::string estimated_normal_print_time; std::string estimated_silent_print_time; - std::vector> estimated_normal_custom_gcode_print_times; - std::vector> estimated_silent_custom_gcode_print_times; + std::vector> estimated_normal_custom_gcode_print_times; + std::vector> estimated_silent_custom_gcode_print_times; double total_used_filament; std::vector> color_extruderid_to_used_filament; double total_extruded_volume; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index bdc05ae78..034a21185 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1095,8 +1095,16 @@ void PrintConfigDef::init_fff_params() def = this->add("filament_max_wipe_tower_speed", coFloats); def->label = L("Max speed on the wipe tower"); - def->tooltip = L("This setting is used to set the maximum speed when extruding inside the wipe tower (use M220). In %, set 0 to disable and use the Filament type instead."); - def->sidetext = L("% of mm/s"); + def->tooltip = L("This setting is used to set the maximum speed when extruding inside the wipe tower (use M220)." + " In %, set 0 to disable and use the Filament type instead." + "\nIf disabled, these filament types will have a defaut value of:" + "\n - PVA: 80% to 60%" + "\n - SCAFF: 35%" + "\n - FLEX: 35%" + "\n - OTHERS: 100%" + "\nNote that the wipe tower reset the speed at 100% for the unretract in any case." + "\nIf using marlin, M220 B/R is used to save the speed override before the wipe tower print."); + def->sidetext = L("%"); def->min = 0; def->max = 200; def->mode = comExpert; @@ -1304,7 +1312,7 @@ void PrintConfigDef::init_fff_params() " Only the filament used for the perimeter is taken into account." "\nBe sure to let enough space between objects, as this compensation is done after the checks."); def->sidetext = L("%"); - def->min = 0; + def->min = 10; def->mode = comExpert; def->set_default_value(new ConfigOptionPercents{ 100 }); diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 5cdf75037..283741a86 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -337,6 +337,30 @@ inline std::string get_time_dhms(float time_in_secs) return buffer; } +// Returns the given time is seconds in format DDd HHh MMm +inline std::string get_time_dhm(float time_in_secs) +{ + char buffer[64]; + + int minutes = std::round(time_in_secs / 60.); + if (minutes <= 0) { + ::sprintf(buffer, "%ds", (int)time_in_secs); + } else { + int days = minutes / 1440; + minutes -= days * 1440; + int hours = minutes / 60; + minutes -= hours * 60; + if (days > 0) + ::sprintf(buffer, "%dd %dh %dm", days, hours, minutes); + else if (hours > 0) + ::sprintf(buffer, "%dh %dm", hours, minutes); + else + ::sprintf(buffer, "%dm", minutes); + } + + return buffer; +} + } // namespace Slic3r #if WIN32 diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 1453fa5bf..de205f5cb 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -95,7 +95,30 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); DynamicPrintConfig new_conf = *config; auto answer = dialog.ShowModal(); - if (!is_global_config || answer == wxID_YES) { + + if (!is_global_config) { + if (this->local_config->optptr("spiral_vase")) + new_conf.set_key_value("spiral_vase", new ConfigOptionBool(false)); + else if (this->local_config->optptr("perimeters")) + new_conf.set_key_value("perimeters", new ConfigOptionInt(1)); + else if (this->local_config->optptr("top_solid_layers")) + new_conf.set_key_value("top_solid_layers", new ConfigOptionInt(0)); + else if (this->local_config->optptr("fill_density")) + new_conf.set_key_value("fill_density", new ConfigOptionPercent(0)); + else if (this->local_config->optptr("support_material")) + new_conf.set_key_value("support_material", new ConfigOptionBool(false)); + else if (this->local_config->optptr("support_material_enforce_layers")) + new_conf.set_key_value("support_material_enforce_layers", new ConfigOptionInt(0)); + else if (this->local_config->optptr("exact_last_layer_height")) + new_conf.set_key_value("exact_last_layer_height", new ConfigOptionBool(false)); + else if (this->local_config->optptr("ensure_vertical_shell_thickness")) + new_conf.set_key_value("ensure_vertical_shell_thickness", new ConfigOptionBool(false)); + else if (this->local_config->optptr("infill_dense")) + new_conf.set_key_value("infill_dense", new ConfigOptionBool(false)); + else if (this->local_config->optptr("extra_perimeters")) + new_conf.set_key_value("extra_perimeters", new ConfigOptionBool(false)); + this->local_config->apply_only(new_conf, this->local_config->keys(), true); + } else if (answer == wxID_YES) { new_conf.set_key_value("perimeters", new ConfigOptionInt(1)); new_conf.set_key_value("top_solid_layers", new ConfigOptionInt(0)); new_conf.set_key_value("fill_density", new ConfigOptionPercent(0)); @@ -114,7 +137,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con if (cb_value_change) cb_value_change("fill_density", fill_density); } - + if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && ((ConfigOptionEnumGeneric*)config->option("support_material_contact_distance_type"))->value != zdNone && (config->opt_int("support_material_extruder") != 0 || config->opt_int("support_material_interface_extruder") != 0)) { @@ -127,7 +150,19 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); DynamicPrintConfig new_conf = *config; auto answer = dialog.ShowModal(); - if (!is_global_config || answer == wxID_YES) { + if (!is_global_config) { + if (this->local_config->optptr("wipe_tower")) + new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); + else if (this->local_config->optptr("support_material_extruder")) + new_conf.set_key_value("support_material_extruder", new ConfigOptionInt(0)); + else if (this->local_config->optptr("support_material_interface_extruder")) + new_conf.set_key_value("support_material_interface_extruder", new ConfigOptionInt(0)); + else if (this->local_config->optptr("support_material_contact_distance_type")) + new_conf.set_key_value("support_material_contact_distance_type", new ConfigOptionEnum(zdNone)); + else if (this->local_config->optptr("support_material")) + new_conf.set_key_value("support_material", new ConfigOptionBool(false)); + this->local_config->apply_only(new_conf, this->local_config->keys(), true); + } else if (answer == wxID_YES) { new_conf.set_key_value("support_material_extruder", new ConfigOptionInt(0)); new_conf.set_key_value("support_material_interface_extruder", new ConfigOptionInt(0)); } @@ -137,7 +172,7 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con } if (config->opt_bool("wipe_tower") && config->opt_bool("support_material") && - ((ConfigOptionEnumGeneric*)config->option("support_material_contact_distance_type"))->value != zdNone && + ((ConfigOptionEnumGeneric*)config->option("support_material_contact_distance_type"))->value == zdNone && !config->opt_bool("support_material_synchronize_layers")) { wxString msg_text = _(L("For the Wipe Tower to work with the soluble supports, the support layers\n" "need to be synchronized with the object layers.")); @@ -147,11 +182,21 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); DynamicPrintConfig new_conf = *config; auto answer = dialog.ShowModal(); - if (!is_global_config || answer == wxID_YES) { + if (!is_global_config) { + if (this->local_config->optptr("wipe_tower")) + new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); + else if (this->local_config->optptr("support_material_synchronize_layers")) + new_conf.set_key_value("support_material_synchronize_layers", new ConfigOptionBool(true)); + else if (this->local_config->optptr("support_material_contact_distance_type")) + new_conf.set_key_value("support_material_contact_distance_type", new ConfigOptionEnum(zdFilament)); + else if (this->local_config->optptr("support_material")) + new_conf.set_key_value("support_material", new ConfigOptionBool(false)); + this->local_config->apply_only(new_conf, this->local_config->keys(), true); + } else if (answer == wxID_YES) { new_conf.set_key_value("support_material_synchronize_layers", new ConfigOptionBool(true)); - } - else + } else { new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false)); + } apply(config, &new_conf); } @@ -177,15 +222,16 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con if ( (!opts[i].opt->percent) && (opts[i].opt->get_abs_value(diameter) < opts[i].min || opts[i].opt->get_abs_value(diameter) > opts[i].max) ) { wxString msg_text = _(L("Did you forgot to put a '%' in the "+opts[i].name+" field? " "it's currently set to "+std::to_string(opts[i].opt->get_abs_value(diameter)) + " mm.")); - if (is_global_config) + if (is_global_config) { msg_text += "\n\n" + _(L("Shall I add the '%'?")); - wxMessageDialog dialog(nullptr, msg_text, _(L("Wipe Tower")), - wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); - DynamicPrintConfig new_conf = *config; - auto answer = dialog.ShowModal(); - if (!is_global_config || answer == wxID_YES) { - new_conf.set_key_value(opts[i].name, new ConfigOptionFloatOrPercent(opts[i].opt->value*100, true)); - apply(config, &new_conf); + wxMessageDialog dialog(nullptr, msg_text, _(L("Wipe Tower")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); + DynamicPrintConfig new_conf = *config; + auto answer = dialog.ShowModal(); + if (answer == wxID_YES) { + new_conf.set_key_value(opts[i].name, new ConfigOptionFloatOrPercent(opts[i].opt->value * 100, true)); + apply(config, &new_conf); + } } } } @@ -211,15 +257,16 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con if (config->opt_float("brim_width") > 0 && config->opt_float("brim_offset") >= config->opt_float("brim_width")) { wxString msg_text = _(L("It's not possible to use a bigger value for the brim offset than the brim width, as it won't extrude anything." " Brim offset have to be lower than the brim width.")); - if (is_global_config) + if (is_global_config) { msg_text += "\n\n" + _(L("Shall I switch the brim offset to 0?")); - wxMessageDialog dialog(nullptr, msg_text, _(L("Brim configuration")), - wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); - auto answer = dialog.ShowModal(); - if (!is_global_config || answer == wxID_YES) { - DynamicPrintConfig new_conf = *config; - new_conf.set_key_value("brim_offset", new ConfigOptionFloat(0)); - apply(config, &new_conf); + wxMessageDialog dialog(nullptr, msg_text, _(L("Brim configuration")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); + auto answer = dialog.ShowModal(); + if (!is_global_config || answer == wxID_YES) { + DynamicPrintConfig new_conf = *config; + new_conf.set_key_value("brim_offset", new ConfigOptionFloat(0)); + apply(config, &new_conf); + } } } @@ -231,26 +278,25 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con support_material_overhangs_queried = true; if (!config->opt_bool("overhangs")/* != 1*/) { wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n" - "- Detect bridging perimeters")); - if (is_global_config) + "- Detect bridging perimeters")); + if (is_global_config) { msg_text += "\n\n" + _(L("Shall I adjust those settings for supports?")); - wxMessageDialog dialog(nullptr, msg_text, _(L("Support Generator")), - wxICON_WARNING | (is_global_config ? wxYES | wxNO | wxCANCEL : wxOK)); - DynamicPrintConfig new_conf = *config; - auto answer = dialog.ShowModal(); - if (!is_global_config || answer == wxID_YES) { - // Enable "detect bridging perimeters". - new_conf.set_key_value("overhangs", new ConfigOptionBool(true)); + wxMessageDialog dialog(nullptr, msg_text, _(L("Support Generator")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO | wxCANCEL : wxOK)); + DynamicPrintConfig new_conf = *config; + auto answer = dialog.ShowModal(); + if (!is_global_config || answer == wxID_YES) { + // Enable "detect bridging perimeters". + new_conf.set_key_value("overhangs", new ConfigOptionBool(true)); + } else if (answer == wxID_NO) { + // Do nothing, leave supports on and "detect bridging perimeters" off. + } else if (answer == wxID_CANCEL) { + // Disable supports. + new_conf.set_key_value("support_material", new ConfigOptionBool(false)); + support_material_overhangs_queried = false; + } + apply(config, &new_conf); } - else if (answer == wxID_NO) { - // Do nothing, leave supports on and "detect bridging perimeters" off. - } - else if (answer == wxID_CANCEL) { - // Disable supports. - new_conf.set_key_value("support_material", new ConfigOptionBool(false)); - support_material_overhangs_queried = false; - } - apply(config, &new_conf); } } } @@ -285,22 +331,22 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con str_fill_pattern = _utf8(config->def()->get("fill_pattern")->enum_labels[fill_pattern]); if (!correct_100p_fill) { wxString msg_text = GUI::from_u8((boost::format(_utf8(L("The %1% infill pattern is not supposed to work at 100%% density."))) % str_fill_pattern).str()); - if (is_global_config) + if (is_global_config) { msg_text += "\n\n" + _(L("Shall I switch to rectilinear fill pattern?")); - wxMessageDialog dialog(nullptr, msg_text, _(L("Infill")), - wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK) ); - DynamicPrintConfig new_conf = *config; - auto answer = dialog.ShowModal(); - if (!is_global_config || answer == wxID_YES) { - new_conf.set_key_value("fill_pattern", new ConfigOptionEnum(ipRectilinear)); - fill_density = 100; + wxMessageDialog dialog(nullptr, msg_text, _(L("Infill")), + wxICON_WARNING | (is_global_config ? wxYES | wxNO : wxOK)); + DynamicPrintConfig new_conf = *config; + auto answer = dialog.ShowModal(); + if (!is_global_config || answer == wxID_YES) { + new_conf.set_key_value("fill_pattern", new ConfigOptionEnum(ipRectilinear)); + fill_density = 100; + } else + fill_density = wxGetApp().preset_bundle->prints.get_selected_preset().config.option("fill_density")->value; + new_conf.set_key_value("fill_density", new ConfigOptionPercent(fill_density)); + apply(config, &new_conf); + if (cb_value_change) + cb_value_change("fill_density", fill_density); } - else - fill_density = wxGetApp().preset_bundle->prints.get_selected_preset().config.option("fill_density")->value; - new_conf.set_key_value("fill_density", new ConfigOptionPercent(fill_density)); - apply(config, &new_conf); - if (cb_value_change) - cb_value_change("fill_density", fill_density); } } } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e2a316454..e7fabed3a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1244,7 +1244,7 @@ void Sidebar::update_sliced_info_sizer() if (ps.color_extruderid_to_used_filament.size() > 0) { double total_length = 0; for (int i = 0; i < ps.color_extruderid_to_used_filament.size(); i++) { - new_label+= from_u8((boost::format("\n - %1% %2%") % _utf8(L("Color")) % i ).str()); + new_label+= from_u8((boost::format("\n - %1% %2%") % _utf8(L("Color")) % (i+1) ).str()); total_length += ps.color_extruderid_to_used_filament[i].second; info_text += wxString::Format("\n%.2f (%.2f)", ps.color_extruderid_to_used_filament[i].second / 1000, total_length / 1000); } @@ -1260,7 +1260,7 @@ void Sidebar::update_sliced_info_sizer() info_text = wxString::Format("%.2f", ps.total_weight); double total_weight = 0; for (int i = 0; i < ps.color_extruderid_to_used_weight.size(); i++) { - new_label += from_u8((boost::format("\n - %1% %2%") % _utf8(L("Color")) % i).str()); + new_label += from_u8((boost::format("\n - %1% %2%") % _utf8(L("Color")) % (i + 1)).str()); total_weight += ps.color_extruderid_to_used_weight[i].second; info_text += (ps.color_extruderid_to_used_weight[i].second == 0 ? "\nN/A": wxString::Format("\n%.2f", ps.color_extruderid_to_used_weight[i].second / 1000)) + (total_weight == 0 ? " (N/A)" : wxString::Format(" (%.2f)", total_weight / 1000)); @@ -1292,25 +1292,23 @@ void Sidebar::update_sliced_info_sizer() wxString str_color = _(L("Color")); wxString str_pause = _(L("Pause")); - auto fill_labels = [str_color, str_pause](const std::vector>& times, + auto fill_labels = [str_color, str_pause](const std::vector>& times, wxString& new_label, wxString& info_text) { - int color_change_count = 0; - for (auto time : times) - if (time.first == cgtColorChange) - color_change_count++; - - for (int i = (int)times.size() - 1; i >= 0; --i) + int color_change_count = 1; + float time_from_beginning = 0; + for (size_t i = 0; i < times.size(); ++i) { - if (i == 0 || times[i - 1].first == cgtPausePrint) + if (times[i].first == cgtPausePrint) new_label += from_u8((boost::format("\n - %1%%2%") % (std::string(str_color.ToUTF8()) + " ") % color_change_count).str()); - else if (times[i - 1].first == cgtColorChange) - new_label += from_u8((boost::format("\n - %1%%2%") % (std::string(str_color.ToUTF8()) + " ") % color_change_count--).str()); + else if (times[i].first == cgtColorChange) + new_label += from_u8((boost::format("\n - %1%%2%") % (std::string(str_color.ToUTF8()) + " ") % color_change_count++).str()); if (i != (int)times.size() - 1 && times[i].first == cgtPausePrint) new_label += from_u8((boost::format(" -> %1%") % std::string(str_pause.ToUTF8())).str()); - info_text += from_u8((boost::format("\n%1%") % times[i].second).str()); + time_from_beginning += times[i].second; + info_text += from_u8((boost::format("\n%1% (%2%)") % get_time_dhm(times[i].second) % get_time_dhm(time_from_beginning)).str()); } }; diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index e89c6a15b..b2d8f3371 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -574,11 +574,15 @@ const std::vector& Preset::filament_options() "filament_toolchange_part_fan_speed", "filament_dip_insertion_speed", "filament_dip_extraction_speed", //skinnydip params end - "temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", - "max_fan_speed", "bridge_fan_speed" - , "top_fan_speed" - , "disable_fan_first_layers" - , "fan_below_layer_time", + "temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", + "cooling", + "fan_always_on", + "min_fan_speed", + "max_fan_speed", + "bridge_fan_speed", + "top_fan_speed", + "disable_fan_first_layers", + "fan_below_layer_time", "slowdown_below_layer_time", "max_speed_reduction", "min_print_speed", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 146ae66ce..1d3dc0efb 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1889,8 +1889,7 @@ void TabFilament::update() this->update_volumetric_flow_preset_hints(); Layout(); - bool cooling = m_config->opt_bool("cooling", 0); - bool fan_always_on = cooling || m_config->opt_bool("fan_always_on", 0); + bool fan_always_on = m_config->opt_bool("fan_always_on", 0); //get_field("max_fan_speed")->toggle(m_config->opt_int("fan_below_layer_time", 0) > 0); Field* min_print_speed_field = get_field("min_print_speed");