diff --git a/resources/icons/super_slicer_logo.svg b/resources/icons/super_slicer_logo.svg new file mode 100644 index 000000000..db75e6d93 --- /dev/null +++ b/resources/icons/super_slicer_logo.svg @@ -0,0 +1,68 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/resources/ui_layout/print.ui b/resources/ui_layout/print.ui index e6339ff27..f07e756c9 100644 --- a/resources/ui_layout/print.ui +++ b/resources/ui_layout/print.ui @@ -59,7 +59,7 @@ group:Advanced setting:label_width$10:width$3:sidetext_width$2:seam_angle_cost setting:label_width$10:width$3:sidetext_width$2:seam_travel_cost end_line - line:Looping perimeter + line:One-loop perimeters setting:perimeter_loop setting:perimeter_loop_seam end_line diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index cbe14bc02..5df62138e 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -89,6 +89,8 @@ add_library(libslic3r STATIC GCode/ThumbnailData.hpp GCode/CoolingBuffer.cpp GCode/CoolingBuffer.hpp + GCode/FanMover.cpp + GCode/FanMover.hpp GCode/PostProcessor.cpp GCode/PostProcessor.hpp # GCode/PressureEqualizer.cpp diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 0ad7c42ed..e6c496a1a 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -6,6 +6,7 @@ #include "EdgeGrid.hpp" #include "Geometry.hpp" #include "GCode/Analyzer.hpp" +#include "GCode/FanMover.hpp" #include "GCode/PrintExtents.hpp" #include "GCode/WipeTower.hpp" #include "ShortestPath.hpp" @@ -1262,6 +1263,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu m_last_mm3_per_mm = 0.0; m_last_width = 0.0f; #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING + m_fan_mover.release(); #else m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm; m_last_width = GCodeAnalyzer::Default_Width; @@ -1840,12 +1842,12 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu #endif // ENABLE_GCODE_VIEWER // Append full config. - _write(file, "\n"); + _write(file, "\n", true); { std::string full_config = ""; append_full_config(print, full_config); if (!full_config.empty()) - _write(file, full_config); + _write(file, full_config, true); } print.throw_if_canceled(); } @@ -3661,28 +3663,30 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill } -void GCode::_post_process(std::string& what) { - //TODO reactivate it by a way or another -#if !ENABLE_GCODE_VIEWER +void GCode::_post_process(std::string& what, bool flush) { + //if enabled, move the fan startup earlier. if (this->config().fan_speedup_time.value != 0) { - Slic3r::FanMover fen_post_process(std::abs(this->config().fan_speedup_time.value), this->config().fan_speedup_time.value>0); - what = fen_post_process.process_gcode(what); + if (this->m_fan_mover.get() == nullptr) + this->m_fan_mover.reset(new Slic3r::FanMover( + std::abs(this->config().fan_speedup_time.value), + this->config().fan_speedup_time.value > 0, + this->config().use_relative_e_distances.value)); + what = this->m_fan_mover->process_gcode(what, flush); } -#endif // !ENABLE_GCODE_VIEWER + } -void GCode::_write(FILE* file, const char *what) +void GCode::_write(FILE* file, const char *what, bool flush /*=false*/) { if (what != nullptr) { -#if ENABLE_GCODE_VIEWER - const char* gcode = what; -#else //const char * gcode_pp = _post_process(what).c_str(); std::string str_preproc{ what }; - _post_process(str_preproc); - + _post_process(str_preproc, flush); +#if ENABLE_GCODE_VIEWER + const char* gcode = str_preproc.c_str(); +#else const std::string str_ana = m_analyzer.process_gcode(str_preproc); // apply analyzer, if enabled diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 578c816d3..b990c5e50 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -12,6 +12,7 @@ #include "PlaceholderParser.hpp" #include "PrintConfig.hpp" #include "GCode/CoolingBuffer.hpp" +#include "GCode/FanMover.hpp" #include "GCode/SpiralVase.hpp" #include "GCode/ToolOrdering.hpp" #include "GCode/WipeTower.hpp" @@ -464,8 +465,8 @@ private: #endif // ENABLE_GCODE_VIEWER // Write a string into a file. - void _write(FILE* file, const std::string& what) { this->_write(file, what.c_str()); } - void _write(FILE* file, const char *what); + void _write(FILE* file, const std::string& what, bool flush = false) { this->_write(file, what.c_str()); } + void _write(FILE* file, const char *what, bool flush = false); // Write a string into a file. // Add a newline, if the string does not end with a newline already. @@ -475,8 +476,9 @@ private: // Formats and write into a file the given data. void _write_format(FILE* file, const char* format, ...); - //some post-processing on the file, before the analyzer - void _post_process(std::string& what); + //some post-processing on the file, with their data class + std::unique_ptr m_fan_mover; + void _post_process(std::string& what, bool flush = true); std::string _extrude(const ExtrusionPath &path, const std::string &description, double speed = -1); std::string _before_extrude(const ExtrusionPath &path, const std::string &description, double speed = -1); diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index faef66485..4afe65389 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -712,7 +712,7 @@ std::string CoolingBuffer::apply_layer_cooldown( float slowdown_below_layer_time = float(EXTRUDER_CONFIG(slowdown_below_layer_time)); float fan_below_layer_time = float(EXTRUDER_CONFIG(fan_below_layer_time)); //if (EXTRUDER_CONFIG(cooling)) { - if (layer_time < slowdown_below_layer_time) { + if (layer_time < slowdown_below_layer_time && fan_below_layer_time > 0) { // Layer time very short. Enable the fan to a full throttle. fan_speed_new = max_fan_speed; } else if (layer_time < fan_below_layer_time) { diff --git a/src/libslic3r/GCode/FanMover.cpp b/src/libslic3r/GCode/FanMover.cpp new file mode 100644 index 000000000..e34039319 --- /dev/null +++ b/src/libslic3r/GCode/FanMover.cpp @@ -0,0 +1,219 @@ +#include "FanMover.hpp" + +#include "GCodeReader.hpp" + +/* +#include +#include +#include + +#include "../libslic3r.h" +#include "../PrintConfig.hpp" +#include "../Utils.hpp" +#include "Print.hpp" + +#include +*/ + + +namespace Slic3r { + +const std::string& FanMover::process_gcode(const std::string& gcode, bool flush) +{ + m_process_output = ""; + + m_parser.parse_buffer(gcode, + [this](GCodeReader& reader, const GCodeReader::GCodeLine& line) { /*m_process_output += line.raw() + "\n";*/ this->_process_gcode_line(reader, line); }); + + if (flush) { + while (!buffer.empty()) { + m_process_output += buffer.back().raw + "\n"; + buffer.pop_back(); + } + } + + return m_process_output; +} + +bool is_end_of_word(char c) { + return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0; +} + +float get_axis_value(const std::string& line, char axis) +{ + char match[3] = " X"; + match[1] = axis; + + size_t pos = line.find(match) + 2; + size_t end = line.find(' ', pos + 1); + // Try to parse the numeric value. + const char* c = line.c_str(); + char* pend = nullptr; + double v = strtod(c+ pos, &pend); + if (pend != nullptr && is_end_of_word(*pend)) { + // The axis value has been parsed correctly. + return float(v); + } + return NAN; +} + +void change_axis_value(std::string& line, char axis, const float new_value, const int decimal_digits) +{ + + std::ostringstream ss; + ss << std::fixed << std::setprecision(decimal_digits) << new_value; + + char match[3] = " X"; + match[1] = axis; + + size_t pos = line.find(match) + 2; + size_t end = line.find(' ', pos + 1); + line = line.replace(pos, end - pos, ss.str()); +} + +void FanMover::_process_gcode_line(GCodeReader& reader, const GCodeReader::GCodeLine& line) +{ + // processes 'normal' gcode lines + std::string cmd = line.cmd(); + double time = 0; + float fan_speed = -1; + if (cmd.length() > 1) { + if (line.has_f()) + current_speed = line.f() / 60.0f; + switch (::toupper(cmd[0])) { + case 'G': + { + if (::atoi(&cmd[1]) == 1 || ::atoi(&cmd[1]) == 0) { + double distx = line.dist_X(reader); + double disty = line.dist_Y(reader); + double distz = line.dist_Z(reader); + double dist = distx * distx + disty * disty + distz * distz; + if (dist > 0) { + dist = std::sqrt(dist); + time = dist / current_speed; + } + } + break; + } + case 'M': + { + if (::atoi(&cmd[1]) == 106) { + if (line.has_value('S', fan_speed) ) { + int nb_M106_erased = 0; + if (fan_speed > expected_fan_speed) { + time = -1; // don't write! + buffer.emplace_front(BufferData("; erased: "+line.raw(), 0, -1)); + //erase M106 in the buffer -> don't slowdown if you are in the process of step-up. + auto it = buffer.begin(); + int i = 0; + while (it != buffer.end()) { + if (it->raw.compare(0, 4, "M106") == 0 && it->fan_speed < fan_speed) { + //found something that is lower than us -> change is speed by ours and delete us + it->fan_speed = fan_speed; + std::stringstream ss; ss << "S" << (int)fan_speed; + it->raw = std::regex_replace(it->raw, regex_fan_speed, ss.str()); + nb_M106_erased++; + } else { + ++it; + i++; + } + } + + if (nb_M106_erased == 0) { + //try to split the G1/G0 line to increae precision + if (!buffer.empty()) { + BufferData& backdata = buffer.back(); + if (buffer_time_size > nb_seconds_delay * 1.1f && backdata.raw.size() > 2 + && backdata.raw[0] == 'G' && backdata.raw[1] == '1' && backdata.raw[2] == ' ') { + float percent = (buffer_time_size - nb_seconds_delay) / backdata.time; + std::string before = backdata.raw; + std::string& after = backdata.raw; + if (backdata.dx != 0) { + change_axis_value(before, 'X', backdata.x + backdata.dx * percent, 3); + } + if (backdata.dy != 0) { + change_axis_value(before, 'Y', backdata.y + backdata.dy * percent, 3); + } + if (backdata.dz != 0) { + change_axis_value(before, 'Z', backdata.z + backdata.dz * percent, 3); + } + if (backdata.de != 0) { + if (relative_e) { + change_axis_value(before, 'E', backdata.de * percent, 5); + change_axis_value(after, 'E', backdata.de * (1 - percent), 5); + } else { + change_axis_value(before, 'E', backdata.e + backdata.de * percent, 5); + change_axis_value(after, 'E', backdata.e + backdata.de * (1 - percent), 5); + } + } + m_process_output += before + "\n"; + buffer_time_size -= backdata.time * percent; + backdata.time -= backdata.time * percent; + + } + } + + //print it + if (with_D_option) { + std::stringstream ss; + ss << " D" << (uint32_t)(buffer_time_size * 1000) << "\n"; + m_process_output += line.raw() + ss.str(); + } else { + m_process_output += line.raw() + "\n"; + } + current_fan_speed = fan_speed; + } + } + + //update + expected_fan_speed = fan_speed; + } + } + break; + } + } + } + + if (time >= 0) { + buffer.emplace_front(BufferData(line.raw(), time, fan_speed)); + BufferData& front = buffer.front(); + if (line.has(Axis::X)) { + front.x = reader.x(); + front.dx = line.dist_X(reader); + } + if (line.has(Axis::Y)) { + front.y = reader.y(); + front.dy = line.dist_Y(reader); + } + if (line.has(Axis::Z)) { + front.z = reader.z(); + front.dz = line.dist_Z(reader); + } + if (line.has(Axis::E)) { + front.e = reader.e(); + if(relative_e) + front.de = line.e(); + else + front.de = line.dist_E(reader); + } + buffer_time_size += time; + } + // puts the line back into the gcode + //if buffer too big, flush it. + if (time > 0) { + while (buffer_time_size - buffer.back().time > nb_seconds_delay) { + BufferData &backdata = buffer.back(); + if (backdata.fan_speed < 0 || (int)backdata.fan_speed != (int)current_fan_speed) { + buffer_time_size -= backdata.time; + m_process_output += backdata.raw + "\n"; + if (backdata.fan_speed >= 0) { + current_fan_speed = backdata.fan_speed; + } + } + buffer.pop_back(); + } + } +} + +} // namespace Slic3r + diff --git a/src/libslic3r/GCode/FanMover.hpp b/src/libslic3r/GCode/FanMover.hpp new file mode 100644 index 000000000..3cc43eddb --- /dev/null +++ b/src/libslic3r/GCode/FanMover.hpp @@ -0,0 +1,59 @@ +#ifndef slic3r_GCode_FanMover_hpp_ +#define slic3r_GCode_FanMover_hpp_ + + +#include "../libslic3r.h" +#include "../PrintConfig.hpp" +#include "../ExtrusionEntity.hpp" + +#include "../Point.hpp" +#include "../GCodeReader.hpp" +#include + +namespace Slic3r { + +class BufferData { +public: + std::string raw; + float time; + float fan_speed; + float x = 0, y = 0, z = 0, e = 0; + float dx = 0, dy = 0, dz = 0, de = 0; + BufferData(std::string line, float time = 0, float fan_speed = 0) : raw(line), time(time), fan_speed(fan_speed) {} +}; + +class FanMover +{ +private: + const std::regex regex_fan_speed; + const float nb_seconds_delay; + const bool with_D_option; + const bool relative_e; + + // in unit/second + double current_speed = 1000 / 60.0;; + float buffer_time_size = 0; + GCodeReader m_parser{}; + int expected_fan_speed = 0; + int current_fan_speed = 0; + + // The output of process_layer() + std::list buffer; + std::string m_process_output; + +public: + FanMover(const float nb_seconds_delay, const bool with_D_option, const bool relative_e) + : regex_fan_speed("S[0-9]+"), nb_seconds_delay(nb_seconds_delay), with_D_option(with_D_option), relative_e(relative_e){} + + // Adds the gcode contained in the given string to the analysis and returns it after removing the workcodes + const std::string& process_gcode(const std::string& gcode, bool flush); + +private: + // Processes the given gcode line + void _process_gcode_line(GCodeReader& reader, const GCodeReader::GCodeLine& line); +}; + +} // namespace Slic3r + + +#endif /* slic3r_GCode_FanMover_hpp_ */ diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index f452303da..00afa88e8 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2068,7 +2068,7 @@ void PrintConfigDef::init_fff_params() " It assume infinite acceleration for this time estimation, and only takes into account G1 and G0 moves. Use 0 to deactivate, negative to remove the 'D' option."); def->sidetext = L("s"); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloat(-1)); + def->set_default_value(new ConfigOptionFloat(-0.5)); def = this->add("machine_limits_usage", coEnum); def->label = L("How to apply"); @@ -3877,7 +3877,7 @@ void PrintConfigDef::init_fff_params() "\nPut 0 to disable."); def->cli = "z-step=f"; def->sidetext = L("mm"); - def->min = 0.0001; + def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0.005)); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index e45b2632f..a26d88bef 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -22,7 +22,7 @@ namespace Slic3r { namespace GUI { -wxString double_to_string(double const value, const int max_precision /*= 4*/) +wxString double_to_string(double const value, const int max_precision /*= 8*/) { // Style_NoTrailingZeroes does not work on OSX. It also does not work correctly with some locales on Windows. // return wxNumberFormatter::ToString(value, max_precision, wxNumberFormatter::Style_NoTrailingZeroes); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 3ee431637..10ab7f71c 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -134,7 +134,7 @@ public: memDC.SelectObject(bitmap); memDC.SetFont(m_action_font); - memDC.SetTextForeground(wxColour(237, 107, 33)); + memDC.SetTextForeground(wxColour(0, 102, 255)); memDC.DrawText(text, int(m_scale * 60), int(m_scale * 275)); memDC.SelectObject(wxNullBitmap); @@ -186,9 +186,9 @@ public: BitmapCache bmp_cache; int logo_size = lround(width * 0.25); #if ENABLE_GCODE_VIEWER - wxBitmap logo_bmp = *bmp_cache.load_svg(wxGetApp().is_editor() ? "prusa_slicer_logo" : "add_gcode", logo_size, logo_size); + wxBitmap logo_bmp = *bmp_cache.load_svg(wxGetApp().is_editor() ? "super_slicer_logo" : "add_gcode", logo_size, logo_size); #else - wxBitmap logo_bmp = *bmp_cache.load_svg("prusa_slicer_logo", logo_size, logo_size); + wxBitmap logo_bmp = *bmp_cache.load_svg("super_slicer_logo", logo_size, logo_size); #endif // ENABLE_GCODE_VIEWER wxCoord margin = int(m_scale * 20); @@ -761,7 +761,7 @@ bool GUI_App::on_init_inner() } // create splash screen with updated bmp - scrn = new SplashScreen(bmp.IsOk() ? bmp : create_scaled_bitmap("prusa_slicer_logo", nullptr, 400), + scrn = new SplashScreen(bmp.IsOk() ? bmp : create_scaled_bitmap("super_slicer_logo", nullptr, 400), wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT, 4000, splashscreen_pos); wxYield(); scrn->SetText(_L("Loading configuration..."));