diff --git a/src/libslic3r/GCode/FanMover.cpp b/src/libslic3r/GCode/FanMover.cpp index 87a658621..d4d50526a 100644 --- a/src/libslic3r/GCode/FanMover.cpp +++ b/src/libslic3r/GCode/FanMover.cpp @@ -50,12 +50,13 @@ float get_axis_value(const std::string& line, char axis) match[1] = axis; size_t pos = line.find(match) + 2; - size_t end = line.find(' ', pos + 1); + //size_t end = std::min(line.find(' ', pos + 1), 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)) { + errno = 0; + double v = strtod(c + pos, &pend); + if (pend != nullptr && errno == 0 && pend != c) { // The axis value has been parsed correctly. return float(v); } @@ -72,7 +73,7 @@ void change_axis_value(std::string& line, char axis, const float new_value, cons match[1] = axis; size_t pos = line.find(match) + 2; - size_t end = line.find(' ', pos + 1); + size_t end = std::min(line.find(' ', pos + 1), line.find(';', pos + 1)); line = line.replace(pos, end - pos, ss.str()); } @@ -93,19 +94,19 @@ int16_t get_fan_speed(const std::string &line, GCodeFlavor flavor) { } -void FanMover::_put_in_middle_G1(std::list::iterator item_to_split, float nb_sec, BufferData &&line_to_write) { +void FanMover::_put_in_middle_G1(std::list::iterator item_to_split, float nb_sec_since_itemtosplit_start, BufferData &&line_to_write) { //std::cout << "_put_in_middle_G1\n"; assert(item_to_split != m_buffer.end()); - if (nb_sec < item_to_split->time * 0.1) { + if (nb_sec_since_itemtosplit_start > item_to_split->time * 0.9) { // doesn't really need to be split, print it after m_buffer.insert(next(item_to_split), line_to_write); - } else if (nb_sec > item_to_split->time * 0.9) { + } else if (nb_sec_since_itemtosplit_start < item_to_split->time * 0.1) { // doesn't really need to be split, print it before //will also print before if line_to_split.time == 0 m_buffer.insert(item_to_split, line_to_write); } else if (item_to_split->raw.size() > 2 && item_to_split->raw[0] == 'G' && item_to_split->raw[1] == '1' && item_to_split->raw[2] == ' ') { - float percent = nb_sec / item_to_split->time; + float percent = nb_sec_since_itemtosplit_start / item_to_split->time; BufferData before = *item_to_split; before.time *= percent; item_to_split->time *= (1-percent); @@ -238,62 +239,106 @@ void FanMover::_process_gcode_line(GCodeReader& reader, const GCodeReader::GCode case 'M': { fan_speed = get_fan_speed(line.raw(), m_writer.config.gcode_flavor); - if (fan_speed > 0 && !m_is_custom_gcode) { - if (nb_seconds_delay > 0 && (!only_overhangs || current_role != ExtrusionRole::erOverhangPerimeter)) { - // this M106 need to go in the past - //check if we have !( kickstart and not in slowdown ) - if (kickstart <= 0 || fan_speed < m_current_fan_speed) { - // first erase everything lower that that value - _remove_slow_fan(fan_speed, m_buffer_time_size + 1); - // then write the fan command - if (std::abs(m_buffer_time_size - nb_seconds_delay) < EPSILON) { - _print_in_middle_G1(m_buffer.front(), m_buffer_time_size - nb_seconds_delay, line.raw()); - remove_from_buffer(m_buffer.begin()); - } else { - m_process_output += line.raw() + "\n"; - } - } else { - //if kickstart - // first erase everything lower that that value - _remove_slow_fan(fan_speed, m_buffer_time_size + 1); - // first erase everything lower that kickstart - _remove_slow_fan(255, kickstart); - // print me - if (m_buffer_time_size > nb_seconds_delay) { - _print_in_middle_G1(m_buffer.front(), m_buffer_time_size - nb_seconds_delay, m_writer.set_fan(100, true)); - remove_from_buffer(m_buffer.begin()); - } else { - m_process_output += m_writer.set_fan(100, true); - } - //write it in the queue if possible - float time_count = kickstart; - auto it = m_buffer.begin(); - while (it != m_buffer.end() && time_count > 0) { - if (time_count - it->time < 0) { - //found something that is lower than us - _put_in_middle_G1(it, time_count, BufferData( std::string(line.cmd()), 0, fan_speed )); - //found, stop - break; - } - time_count -= it->time; - ++it; - } - } - } else { - if (kickstart <= 0) { - //nothing to do - //we don't put time = -1; so it will printed in the buffer as other line are done - } else { - //if kickstart, write the M106 255 first - time = -1; - //set the target speed and set the kickstart flag - put_in_buffer(BufferData(m_writer.set_fan(100, true), 0, fan_speed, true)); - //add the normal speed line for the future - m_current_kickstart.fan_speed = fan_speed; - m_current_kickstart.time = kickstart; - m_current_kickstart.raw = line.raw(); - } + if (fan_speed >= 0) { + const auto fan_baseline = (m_writer.config.fan_percentage.value ? 100.0 : 255.0); + fan_speed = 100 * fan_speed / fan_baseline; + if (!m_is_custom_gcode) { + // if slow down => put in the queue. if not => + if (m_back_buffer_fan_speed < fan_speed) { + if (nb_seconds_delay > 0 && (!only_overhangs || current_role != ExtrusionRole::erOverhangPerimeter)) { + //don't put this command in the queue + time = -1; + // this M106 need to go in the past + //check if we have ( kickstart and not in slowdown ) + if (kickstart > 0 && fan_speed > m_front_buffer_fan_speed) { + //stop current kickstart , it's not relevant anymore + if (m_current_kickstart.time > 0) { + m_current_kickstart.time = (-1); + } + //if kickstart + // first erase everything lower that that value + _remove_slow_fan(fan_speed, m_buffer_time_size + 1); + // then erase everything lower that kickstart + _remove_slow_fan(fan_baseline, kickstart); + // print me + if (!m_buffer.empty() && (m_buffer_time_size - m_buffer.front().time * 0.1) > nb_seconds_delay) { + _print_in_middle_G1(m_buffer.front(), m_buffer_time_size - nb_seconds_delay, m_writer.set_fan(100, true)); + remove_from_buffer(m_buffer.begin()); + } else { + m_process_output += m_writer.set_fan(100, true); + } + //write it in the queue if possible + const float kickstart_duration = kickstart * float(fan_speed - m_front_buffer_fan_speed) / 100.f; + float time_count = kickstart_duration; + auto it = m_buffer.begin(); + while (it != m_buffer.end() && time_count > 0) { + time_count -= it->time; + if (time_count< 0) { + //found something that is lower than us + _put_in_middle_G1(it, it->time + time_count, BufferData(std::string(line.raw()), 0, fan_speed, true)); + //found, stop + break; + } + ++it; + } + if (time_count > 0) { + //can't place it in the buffer, use m_current_kickstart + m_current_kickstart.fan_speed = fan_speed; + m_current_kickstart.time = time_count; + m_current_kickstart.raw = line.raw(); + } + m_front_buffer_fan_speed = fan_speed; + } else { + // first erase everything lower that that value + _remove_slow_fan(fan_speed, m_buffer_time_size + 1); + // then write the fan command + if (!m_buffer.empty() && (m_buffer_time_size - m_buffer.front().time * 0.1) > nb_seconds_delay) { + _print_in_middle_G1(m_buffer.front(), m_buffer_time_size - nb_seconds_delay, line.raw()); + remove_from_buffer(m_buffer.begin()); + } else { + m_process_output += line.raw() + "\n"; + } + m_front_buffer_fan_speed = fan_speed; + } + } else { + if (kickstart <= 0) { + //nothing to do + //we don't put time = -1; so it will printed in the buffer as other line are done + } else if (m_current_kickstart.time > 0) { + //cherry-pick this one + if (m_back_buffer_fan_speed >= fan_speed) { + //stop kickstart + m_current_kickstart.time = -1; + //this will print me just after as time >=0 + } else { + // add some duration to the kickstart and use it for me. + float kickstart_duration = kickstart * float(fan_speed - m_back_buffer_fan_speed) / 100.f; + m_current_kickstart.fan_speed = fan_speed; + m_current_kickstart.time += kickstart_duration; + m_current_kickstart.raw = line.raw(); + //i'm printed by the m_current_kickstart + time = -1; + } + } else if(m_back_buffer_fan_speed < fan_speed - 10){ //only kickstart if more than 10% change + //don't write this line, as it will need to be delayed + time = -1; + //get the duration of kickstart + float kickstart_duration = kickstart * float(fan_speed - m_back_buffer_fan_speed) / 100.f; + //if kickstart, write the M106 S[fan_baseline] first + //set the target speed and set the kickstart flag + put_in_buffer(BufferData(m_writer.set_fan(100, true), 0, fan_speed, true)); + //kickstart! + //m_process_output += m_writer.set_fan(100, true); + //add the normal speed line for the future + m_current_kickstart.fan_speed = fan_speed; + m_current_kickstart.time = kickstart_duration; + m_current_kickstart.raw = line.raw(); + } + } + } + //update back buffer fan speed + m_back_buffer_fan_speed = fan_speed; } } break; @@ -335,30 +380,51 @@ void FanMover::_process_gcode_line(GCodeReader& reader, const GCodeReader::GCode new_data.de = line.dist_E(reader); } - if (m_current_kickstart.time > 0) { + if (m_current_kickstart.time > 0 && time > 0) { m_current_kickstart.time -= time; if (m_current_kickstart.time < 0) { //prev is possible because we just do a emplace_back. - _put_in_middle_G1(prev(m_buffer.end()), time + m_current_kickstart.time, BufferData{ m_current_kickstart.raw, 0, m_current_kickstart.fan_speed }); + _put_in_middle_G1(prev(m_buffer.end()), time + m_current_kickstart.time, BufferData{ m_current_kickstart.raw, 0, m_current_kickstart.fan_speed, true }); } } - } + }/* else { + BufferData& new_data = put_in_buffer(BufferData("; del? "+line.raw(), 0, fan_speed)); + if (line.has(Axis::X)) { + new_data.x = reader.x(); + new_data.dx = line.dist_X(reader); + } + if (line.has(Axis::Y)) { + new_data.y = reader.y(); + new_data.dy = line.dist_Y(reader); + } + if (line.has(Axis::Z)) { + new_data.z = reader.z(); + new_data.dz = line.dist_Z(reader); + } + if (line.has(Axis::E)) { + new_data.e = reader.e(); + if (relative_e) + new_data.de = line.e(); + else + new_data.de = line.dist_E(reader); + } + }*/ // puts the line back into the gcode //if buffer too big, flush it. - if (time > 0) { - while (!m_buffer.empty() && m_buffer_time_size - m_buffer.front().time > nb_seconds_delay) { - BufferData& backdata = m_buffer.front(); - if (backdata.fan_speed < 0 || backdata.fan_speed != m_current_fan_speed) { - if (backdata.is_kickstart && backdata.fan_speed < m_current_fan_speed) { + if (time >= 0) { + while (!m_buffer.empty() && m_buffer_time_size - m_buffer.front().time > nb_seconds_delay - EPSILON) { + BufferData& frontdata = m_buffer.front(); + if (frontdata.fan_speed < 0 || frontdata.fan_speed != m_front_buffer_fan_speed || frontdata.is_kickstart) { + if (frontdata.is_kickstart && frontdata.fan_speed < m_front_buffer_fan_speed) { //you have to slow down! not kickstart! rewrite the fan speed. - m_process_output += m_writer.set_fan(backdata.fan_speed,true); - m_current_fan_speed = backdata.fan_speed; + m_process_output += m_writer.set_fan(frontdata.fan_speed,true); + m_front_buffer_fan_speed = frontdata.fan_speed; } else { - m_process_output += backdata.raw + "\n"; - if (backdata.fan_speed >= 0) { - //note that this is the only plce where the fan_speed is set and we print from the buffer, as if the fan_speed >= 0 => time == 0 - //and as this flush all time == 0 lines fromt he back of the queue... - m_current_fan_speed = backdata.fan_speed; + m_process_output += frontdata.raw + "\n"; + if (frontdata.fan_speed >= 0) { + //note that this is the only place where the fan_speed is set and we print from the buffer, as if the fan_speed >= 0 => time == 0 + //and as this flush all time == 0 lines from the back of the queue... + m_front_buffer_fan_speed = frontdata.fan_speed; } } } diff --git a/src/libslic3r/GCode/FanMover.hpp b/src/libslic3r/GCode/FanMover.hpp index 6d31abdcf..12df81971 100644 --- a/src/libslic3r/GCode/FanMover.hpp +++ b/src/libslic3r/GCode/FanMover.hpp @@ -47,7 +47,8 @@ private: bool m_is_custom_gcode = false; // variable for when you add a line (front of the buffer) - int m_current_fan_speed = 0; + int m_front_buffer_fan_speed = 0; + int m_back_buffer_fan_speed = 0; BufferData m_current_kickstart{"",-1,0}; //buffer