Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/xs
diff options
context:
space:
mode:
authorbubnikv <bubnikv@gmail.com>2018-01-06 17:04:57 +0300
committerbubnikv <bubnikv@gmail.com>2018-01-06 17:04:57 +0300
commiteaac587467793f465ba839bb76677b6bc18d69af (patch)
treed3aa2a959fb2bea1f9e46eca0f306d1a0d791c7d /xs
parent696d420dc8017422b4a7b5b1c3c1b34f408c887d (diff)
parentae0688f351752525a6acdacfbe2c85461b1ba45e (diff)
Merge remote-tracking branch 'origin/time_estimate'
Diffstat (limited to 'xs')
-rw-r--r--xs/src/libslic3r/GCodeTimeEstimator.cpp1732
-rw-r--r--xs/src/libslic3r/GCodeTimeEstimator.hpp507
2 files changed, 1149 insertions, 1090 deletions
diff --git a/xs/src/libslic3r/GCodeTimeEstimator.cpp b/xs/src/libslic3r/GCodeTimeEstimator.cpp
index ef0d65d7c..2ebeb9fd2 100644
--- a/xs/src/libslic3r/GCodeTimeEstimator.cpp
+++ b/xs/src/libslic3r/GCodeTimeEstimator.cpp
@@ -15,993 +15,1039 @@ static const float DEFAULT_AXIS_MAX_ACCELERATION[] = { 9000.0f, 9000.0f, 500.0f,
static const float DEFAULT_AXIS_MAX_JERK[] = { 10.0f, 10.0f, 0.2f, 2.5f }; // from Prusa Firmware (Configuration.h)
static const float DEFAULT_MINIMUM_FEEDRATE = 0.0f; // from Prusa Firmware (Configuration_adv.h)
static const float DEFAULT_MINIMUM_TRAVEL_FEEDRATE = 0.0f; // from Prusa Firmware (Configuration_adv.h)
+static const float DEFAULT_EXTRUDE_FACTOR_OVERRIDE_PERCENTAGE = 1.0f; // 100 percent
static const float PREVIOUS_FEEDRATE_THRESHOLD = 0.0001f;
namespace Slic3r {
- void GCodeTimeEstimator::Feedrates::reset()
- {
- feedrate = 0.0f;
- safe_feedrate = 0.0f;
- ::memset(axis_feedrate, 0, Num_Axis * sizeof(float));
- ::memset(abs_axis_feedrate, 0, Num_Axis * sizeof(float));
- }
-
- float GCodeTimeEstimator::Block::Trapezoid::acceleration_time(float acceleration) const
- {
- return acceleration_time_from_distance(feedrate.entry, accelerate_until, acceleration);
- }
-
- float GCodeTimeEstimator::Block::Trapezoid::cruise_time() const
- {
- return (feedrate.cruise != 0.0f) ? cruise_distance() / feedrate.cruise : 0.0f;
- }
-
- float GCodeTimeEstimator::Block::Trapezoid::deceleration_time(float acceleration) const
- {
- return acceleration_time_from_distance(feedrate.cruise, (distance - decelerate_after), -acceleration);
- }
-
- float GCodeTimeEstimator::Block::Trapezoid::cruise_distance() const
- {
- return decelerate_after - accelerate_until;
- }
-
- float GCodeTimeEstimator::Block::Trapezoid::acceleration_time_from_distance(float initial_feedrate, float distance, float acceleration)
- {
- return (acceleration != 0.0f) ? (speed_from_distance(initial_feedrate, distance, acceleration) - initial_feedrate) / acceleration : 0.0f;
- }
-
- float GCodeTimeEstimator::Block::Trapezoid::speed_from_distance(float initial_feedrate, float distance, float acceleration)
- {
- return ::sqrt(sqr(initial_feedrate) + 2.0f * acceleration * distance);
- }
-
- float GCodeTimeEstimator::Block::move_length() const
- {
- float length = ::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]));
- return (length > 0.0f) ? length : std::abs(delta_pos[E]);
- }
-
- float GCodeTimeEstimator::Block::is_extruder_only_move() const
- {
- return (delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f) && (delta_pos[E] != 0.0f);
- }
-
- float GCodeTimeEstimator::Block::is_travel_move() const
- {
- return delta_pos[E] == 0.0f;
- }
-
- float GCodeTimeEstimator::Block::acceleration_time() const
- {
- return trapezoid.acceleration_time(acceleration);
- }
-
- float GCodeTimeEstimator::Block::cruise_time() const
- {
- return trapezoid.cruise_time();
- }
-
- float GCodeTimeEstimator::Block::deceleration_time() const
- {
- return trapezoid.deceleration_time(acceleration);
- }
-
- float GCodeTimeEstimator::Block::cruise_distance() const
- {
- return trapezoid.cruise_distance();
- }
-
- void GCodeTimeEstimator::Block::calculate_trapezoid()
- {
- float distance = move_length();
-
- trapezoid.distance = distance;
- trapezoid.feedrate = feedrate;
-
- float accelerate_distance = estimate_acceleration_distance(feedrate.entry, feedrate.cruise, acceleration);
- float decelerate_distance = estimate_acceleration_distance(feedrate.cruise, feedrate.exit, -acceleration);
- float cruise_distance = distance - accelerate_distance - decelerate_distance;
-
- // Not enough space to reach the nominal feedrate.
- // This means no cruising, and we'll have to use intersection_distance() to calculate when to abort acceleration
- // and start braking in order to reach the exit_feedrate exactly at the end of this block.
- if (cruise_distance < 0.0f)
- {
- accelerate_distance = clamp(0.0f, distance, intersection_distance(feedrate.entry, feedrate.exit, acceleration, distance));
- cruise_distance = 0.0f;
- trapezoid.feedrate.cruise = Trapezoid::speed_from_distance(feedrate.entry, accelerate_distance, acceleration);
- }
-
- trapezoid.accelerate_until = accelerate_distance;
- trapezoid.decelerate_after = accelerate_distance + cruise_distance;
- }
-
- float GCodeTimeEstimator::Block::max_allowable_speed(float acceleration, float target_velocity, float distance)
- {
- return ::sqrt(sqr(target_velocity) - 2.0f * acceleration * distance);
- }
-
- float GCodeTimeEstimator::Block::estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration)
- {
- return (acceleration == 0.0f) ? 0.0f : (sqr(target_rate) - sqr(initial_rate)) / (2.0f * acceleration);
- }
-
- float GCodeTimeEstimator::Block::intersection_distance(float initial_rate, float final_rate, float acceleration, float distance)
- {
- return (acceleration == 0.0f) ? 0.0f : (2.0f * acceleration * distance - sqr(initial_rate) + sqr(final_rate)) / (4.0f * acceleration);
- }
-
- GCodeTimeEstimator::GCodeTimeEstimator()
- {
- reset();
- set_default();
- }
-
- void GCodeTimeEstimator::calculate_time_from_text(const std::string& gcode)
- {
- _parser.parse_buffer(gcode,
- [this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
- { this->_process_gcode_line(reader, line); });
- _calculate_time();
- reset();
- }
-
- void GCodeTimeEstimator::calculate_time_from_file(const std::string& file)
- {
- _parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
- _calculate_time();
- reset();
- }
-
- void GCodeTimeEstimator::calculate_time_from_lines(const std::vector<std::string>& gcode_lines)
- {
- auto action = [this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
- { this->_process_gcode_line(reader, line); };
- for (const std::string& line : gcode_lines)
- _parser.parse_line(line, action);
- _calculate_time();
- reset();
- }
-
- void GCodeTimeEstimator::add_gcode_line(const std::string& gcode_line)
- {
- PROFILE_FUNC();
- _parser.parse_line(gcode_line,
- [this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
- { this->_process_gcode_line(reader, line); });
- }
-
- void GCodeTimeEstimator::add_gcode_block(const char *ptr)
- {
- PROFILE_FUNC();
- GCodeReader::GCodeLine gline;
- auto action = [this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
- { this->_process_gcode_line(reader, line); };
- for (; *ptr != 0;) {
- gline.reset();
- ptr = _parser.parse_line(ptr, gline, action);
- }
- }
-
- void GCodeTimeEstimator::calculate_time()
- {
- PROFILE_FUNC();
- _calculate_time();
- _reset();
- }
-
- void GCodeTimeEstimator::set_axis_position(EAxis axis, float position)
- {
- _state.axis[axis].position = position;
- }
-
- void GCodeTimeEstimator::set_axis_max_feedrate(EAxis axis, float feedrate_mm_sec)
- {
- _state.axis[axis].max_feedrate = feedrate_mm_sec;
- }
-
- void GCodeTimeEstimator::set_axis_max_acceleration(EAxis axis, float acceleration)
- {
- _state.axis[axis].max_acceleration = acceleration;
- }
-
- void GCodeTimeEstimator::set_axis_max_jerk(EAxis axis, float jerk)
- {
- _state.axis[axis].max_jerk = jerk;
- }
-
- float GCodeTimeEstimator::get_axis_position(EAxis axis) const
- {
- return _state.axis[axis].position;
- }
-
- float GCodeTimeEstimator::get_axis_max_feedrate(EAxis axis) const
- {
- return _state.axis[axis].max_feedrate;
- }
-
- float GCodeTimeEstimator::get_axis_max_acceleration(EAxis axis) const
- {
- return _state.axis[axis].max_acceleration;
- }
-
- float GCodeTimeEstimator::get_axis_max_jerk(EAxis axis) const
- {
- return _state.axis[axis].max_jerk;
- }
-
- void GCodeTimeEstimator::set_feedrate(float feedrate_mm_sec)
- {
- _state.feedrate = feedrate_mm_sec;
- }
-
- float GCodeTimeEstimator::get_feedrate() const
- {
- return _state.feedrate;
- }
-
- void GCodeTimeEstimator::set_acceleration(float acceleration_mm_sec2)
- {
- _state.acceleration = acceleration_mm_sec2;
- }
-
- float GCodeTimeEstimator::get_acceleration() const
- {
- return _state.acceleration;
- }
-
- void GCodeTimeEstimator::set_retract_acceleration(float acceleration_mm_sec2)
- {
- _state.retract_acceleration = acceleration_mm_sec2;
- }
-
- float GCodeTimeEstimator::get_retract_acceleration() const
- {
- return _state.retract_acceleration;
- }
-
- void GCodeTimeEstimator::set_minimum_feedrate(float feedrate_mm_sec)
- {
- _state.minimum_feedrate = feedrate_mm_sec;
- }
-
- float GCodeTimeEstimator::get_minimum_feedrate() const
- {
- return _state.minimum_feedrate;
- }
-
- void GCodeTimeEstimator::set_minimum_travel_feedrate(float feedrate_mm_sec)
- {
- _state.minimum_travel_feedrate = feedrate_mm_sec;
- }
-
- float GCodeTimeEstimator::get_minimum_travel_feedrate() const
- {
- return _state.minimum_travel_feedrate;
- }
-
- void GCodeTimeEstimator::set_dialect(GCodeTimeEstimator::EDialect dialect)
- {
- _state.dialect = dialect;
- }
-
- GCodeTimeEstimator::EDialect GCodeTimeEstimator::get_dialect() const
- {
- return _state.dialect;
- }
-
- void GCodeTimeEstimator::set_units(GCodeTimeEstimator::EUnits units)
- {
- _state.units = units;
- }
-
- GCodeTimeEstimator::EUnits GCodeTimeEstimator::get_units() const
- {
- return _state.units;
- }
-
- void GCodeTimeEstimator::set_positioning_xyz_type(GCodeTimeEstimator::EPositioningType type)
- {
- _state.positioning_xyz_type = type;
- }
-
- GCodeTimeEstimator::EPositioningType GCodeTimeEstimator::get_positioning_xyz_type() const
- {
- return _state.positioning_xyz_type;
- }
-
- void GCodeTimeEstimator::set_positioning_e_type(GCodeTimeEstimator::EPositioningType type)
- {
- _state.positioning_e_type = type;
- }
-
- GCodeTimeEstimator::EPositioningType GCodeTimeEstimator::get_positioning_e_type() const
- {
- return _state.positioning_e_type;
- }
-
- void GCodeTimeEstimator::add_additional_time(float timeSec)
- {
- _state.additional_time += timeSec;
- }
-
- void GCodeTimeEstimator::set_additional_time(float timeSec)
- {
- _state.additional_time = timeSec;
- }
-
- float GCodeTimeEstimator::get_additional_time() const
- {
- return _state.additional_time;
- }
-
- void GCodeTimeEstimator::set_default()
- {
- set_units(Millimeters);
- set_dialect(Unknown);
- set_positioning_xyz_type(Absolute);
- set_positioning_e_type(Relative);
-
- set_feedrate(DEFAULT_FEEDRATE);
- set_acceleration(DEFAULT_ACCELERATION);
- set_retract_acceleration(DEFAULT_RETRACT_ACCELERATION);
- set_minimum_feedrate(DEFAULT_MINIMUM_FEEDRATE);
- set_minimum_travel_feedrate(DEFAULT_MINIMUM_TRAVEL_FEEDRATE);
-
- for (unsigned char a = X; a < Num_Axis; ++a)
- {
- EAxis axis = (EAxis)a;
- set_axis_max_feedrate(axis, DEFAULT_AXIS_MAX_FEEDRATE[a]);
- set_axis_max_acceleration(axis, DEFAULT_AXIS_MAX_ACCELERATION[a]);
- set_axis_max_jerk(axis, DEFAULT_AXIS_MAX_JERK[a]);
- }
- }
-
- void GCodeTimeEstimator::reset()
- {
- _blocks.clear();
- _reset();
- }
-
- float GCodeTimeEstimator::get_time() const
- {
- return _time;
- }
-
- std::string GCodeTimeEstimator::get_time_hms() const
- {
- float timeinsecs = get_time();
- int hours = (int)(timeinsecs / 3600.0f);
- timeinsecs -= (float)hours * 3600.0f;
- int minutes = (int)(timeinsecs / 60.0f);
- timeinsecs -= (float)minutes * 60.0f;
-
- char buffer[64];
- if (hours > 0)
- ::sprintf(buffer, "%dh %dm %ds", hours, minutes, (int)timeinsecs);
- else if (minutes > 0)
- ::sprintf(buffer, "%dm %ds", minutes, (int)timeinsecs);
- else
- ::sprintf(buffer, "%ds", (int)timeinsecs);
-
- return buffer;
- }
-
- void GCodeTimeEstimator::_reset()
- {
- _curr.reset();
- _prev.reset();
-
- set_axis_position(X, 0.0f);
- set_axis_position(Y, 0.0f);
- set_axis_position(Z, 0.0f);
-
- set_additional_time(0.0f);
- }
-
- void GCodeTimeEstimator::_calculate_time()
- {
- _forward_pass();
- _reverse_pass();
- _recalculate_trapezoids();
-
- _time = get_additional_time();
-
- for (const Block& block : _blocks)
- {
- _time += block.acceleration_time();
- _time += block.cruise_time();
- _time += block.deceleration_time();
- }
- }
-
- void GCodeTimeEstimator::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line)
- {
- PROFILE_FUNC();
- std::string cmd = line.cmd();
- if (cmd.length() > 1)
- {
- switch (::toupper(cmd[0]))
- {
- case 'G':
- {
- switch (::atoi(&cmd[1]))
- {
- case 1: // Move
- {
- _processG1(line);
- break;
- }
- case 4: // Dwell
- {
- _processG4(line);
- break;
- }
- case 20: // Set Units to Inches
- {
- _processG20(line);
- break;
- }
- case 21: // Set Units to Millimeters
- {
- _processG21(line);
- break;
- }
- case 28: // Move to Origin (Home)
- {
- _processG28(line);
- break;
- }
- case 90: // Set to Absolute Positioning
- {
- _processG90(line);
- break;
- }
- case 91: // Set to Relative Positioning
- {
- _processG91(line);
- break;
- }
- case 92: // Set Position
- {
- _processG92(line);
- break;
- }
- }
+ void GCodeTimeEstimator::Feedrates::reset()
+ {
+ feedrate = 0.0f;
+ safe_feedrate = 0.0f;
+ ::memset(axis_feedrate, 0, Num_Axis * sizeof(float));
+ ::memset(abs_axis_feedrate, 0, Num_Axis * sizeof(float));
+ }
- break;
- }
- case 'M':
- {
- switch (::atoi(&cmd[1]))
- {
- case 82: // Set extruder to absolute mode
- {
- _processM82(line);
- break;
- }
- case 83: // Set extruder to relative mode
- {
- _processM83(line);
- break;
- }
- case 109: // Set Extruder Temperature and Wait
- {
- _processM109(line);
- break;
- }
- case 201: // Set max printing acceleration
- {
- _processM201(line);
- break;
- }
- case 203: // Set maximum feedrate
- {
- _processM203(line);
- break;
- }
- case 204: // Set default acceleration
- {
- _processM204(line);
- break;
- }
- case 205: // Advanced settings
- {
- _processM205(line);
- break;
- }
- case 566: // Set allowable instantaneous speed change
- {
- _processM566(line);
- break;
- }
- }
+ float GCodeTimeEstimator::Block::Trapezoid::acceleration_time(float acceleration) const
+ {
+ return acceleration_time_from_distance(feedrate.entry, accelerate_until, acceleration);
+ }
- break;
- }
- }
+ float GCodeTimeEstimator::Block::Trapezoid::cruise_time() const
+ {
+ return (feedrate.cruise != 0.0f) ? cruise_distance() / feedrate.cruise : 0.0f;
}
- }
- // Returns the new absolute position on the given axis in dependence of the given parameters
- float axis_absolute_position_from_G1_line(GCodeTimeEstimator::EAxis axis, const GCodeReader::GCodeLine& lineG1, GCodeTimeEstimator::EUnits units, GCodeTimeEstimator::EPositioningType type, float current_absolute_position)
- {
- float lengthsScaleFactor = (units == GCodeTimeEstimator::Inches) ? INCHES_TO_MM : 1.0f;
- if (lineG1.has(Slic3r::Axis(axis)))
+ float GCodeTimeEstimator::Block::Trapezoid::deceleration_time(float acceleration) const
{
- float ret = lineG1.value(Slic3r::Axis(axis)) * lengthsScaleFactor;
- return (type == GCodeTimeEstimator::Absolute) ? ret : current_absolute_position + ret;
+ return acceleration_time_from_distance(feedrate.cruise, (distance - decelerate_after), -acceleration);
}
- else
- return current_absolute_position;
- }
- void GCodeTimeEstimator::_processG1(const GCodeReader::GCodeLine& line)
- {
- // updates axes positions from line
- EUnits units = get_units();
- float new_pos[Num_Axis];
- for (unsigned char a = X; a < Num_Axis; ++a)
+ float GCodeTimeEstimator::Block::Trapezoid::cruise_distance() const
{
- new_pos[a] = axis_absolute_position_from_G1_line((EAxis)a, line, units, (a == E) ? get_positioning_e_type() : get_positioning_xyz_type(), get_axis_position((EAxis)a));
+ return decelerate_after - accelerate_until;
}
- // updates feedrate from line, if present
- if (line.has_f())
- set_feedrate(std::max(line.f() * MMMIN_TO_MMSEC, get_minimum_feedrate()));
+ float GCodeTimeEstimator::Block::Trapezoid::acceleration_time_from_distance(float initial_feedrate, float distance, float acceleration)
+ {
+ return (acceleration != 0.0f) ? (speed_from_distance(initial_feedrate, distance, acceleration) - initial_feedrate) / acceleration : 0.0f;
+ }
- // fills block data
- Block block;
+ float GCodeTimeEstimator::Block::Trapezoid::speed_from_distance(float initial_feedrate, float distance, float acceleration)
+ {
+ return ::sqrt(sqr(initial_feedrate) + 2.0f * acceleration * distance);
+ }
- // calculates block movement deltas
- float max_abs_delta = 0.0f;
- for (unsigned char a = X; a < Num_Axis; ++a)
+ float GCodeTimeEstimator::Block::move_length() const
{
- block.delta_pos[a] = new_pos[a] - get_axis_position((EAxis)a);
- max_abs_delta = std::max(max_abs_delta, std::abs(block.delta_pos[a]));
+ float length = ::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]));
+ return (length > 0.0f) ? length : std::abs(delta_pos[E]);
}
- // is it a move ?
- if (max_abs_delta == 0.0f)
- return;
+ float GCodeTimeEstimator::Block::is_extruder_only_move() const
+ {
+ return (delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f) && (delta_pos[E] != 0.0f);
+ }
- // calculates block feedrate
- _curr.feedrate = std::max(get_feedrate(), block.is_travel_move() ? get_minimum_travel_feedrate() : get_minimum_feedrate());
+ float GCodeTimeEstimator::Block::is_travel_move() const
+ {
+ return delta_pos[E] == 0.0f;
+ }
- float distance = block.move_length();
- float invDistance = 1.0f / distance;
+ float GCodeTimeEstimator::Block::acceleration_time() const
+ {
+ return trapezoid.acceleration_time(acceleration);
+ }
- float min_feedrate_factor = 1.0f;
- for (unsigned char a = X; a < Num_Axis; ++a)
+ float GCodeTimeEstimator::Block::cruise_time() const
{
- _curr.axis_feedrate[a] = _curr.feedrate * block.delta_pos[a] * invDistance;
- _curr.abs_axis_feedrate[a] = std::abs(_curr.axis_feedrate[a]);
- if (_curr.abs_axis_feedrate[a] > 0.0f)
- min_feedrate_factor = std::min(min_feedrate_factor, get_axis_max_feedrate((EAxis)a) / _curr.abs_axis_feedrate[a]);
+ return trapezoid.cruise_time();
}
-
- block.feedrate.cruise = min_feedrate_factor * _curr.feedrate;
- for (unsigned char a = X; a < Num_Axis; ++a)
+ float GCodeTimeEstimator::Block::deceleration_time() const
{
- _curr.axis_feedrate[a] *= min_feedrate_factor;
- _curr.abs_axis_feedrate[a] *= min_feedrate_factor;
+ return trapezoid.deceleration_time(acceleration);
}
- // calculates block acceleration
- float acceleration = block.is_extruder_only_move() ? get_retract_acceleration() : get_acceleration();
+ float GCodeTimeEstimator::Block::cruise_distance() const
+ {
+ return trapezoid.cruise_distance();
+ }
- for (unsigned char a = X; a < Num_Axis; ++a)
+ void GCodeTimeEstimator::Block::calculate_trapezoid()
{
- float axis_max_acceleration = get_axis_max_acceleration((EAxis)a);
- if (acceleration * std::abs(block.delta_pos[a]) * invDistance > axis_max_acceleration)
- acceleration = axis_max_acceleration;
+ float distance = move_length();
+
+ trapezoid.distance = distance;
+ trapezoid.feedrate = feedrate;
+
+ float accelerate_distance = estimate_acceleration_distance(feedrate.entry, feedrate.cruise, acceleration);
+ float decelerate_distance = estimate_acceleration_distance(feedrate.cruise, feedrate.exit, -acceleration);
+ float cruise_distance = distance - accelerate_distance - decelerate_distance;
+
+ // Not enough space to reach the nominal feedrate.
+ // This means no cruising, and we'll have to use intersection_distance() to calculate when to abort acceleration
+ // and start braking in order to reach the exit_feedrate exactly at the end of this block.
+ if (cruise_distance < 0.0f)
+ {
+ accelerate_distance = clamp(0.0f, distance, intersection_distance(feedrate.entry, feedrate.exit, acceleration, distance));
+ cruise_distance = 0.0f;
+ trapezoid.feedrate.cruise = Trapezoid::speed_from_distance(feedrate.entry, accelerate_distance, acceleration);
+ }
+
+ trapezoid.accelerate_until = accelerate_distance;
+ trapezoid.decelerate_after = accelerate_distance + cruise_distance;
}
- block.acceleration = acceleration;
+ float GCodeTimeEstimator::Block::max_allowable_speed(float acceleration, float target_velocity, float distance)
+ {
+ return ::sqrt(sqr(target_velocity) - 2.0f * acceleration * distance);
+ }
- // calculates block exit feedrate
- _curr.safe_feedrate = block.feedrate.cruise;
+ float GCodeTimeEstimator::Block::estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration)
+ {
+ return (acceleration == 0.0f) ? 0.0f : (sqr(target_rate) - sqr(initial_rate)) / (2.0f * acceleration);
+ }
- for (unsigned char a = X; a < Num_Axis; ++a)
+ float GCodeTimeEstimator::Block::intersection_distance(float initial_rate, float final_rate, float acceleration, float distance)
{
- float axis_max_jerk = get_axis_max_jerk((EAxis)a);
- if (_curr.abs_axis_feedrate[a] > axis_max_jerk)
- _curr.safe_feedrate = std::min(_curr.safe_feedrate, axis_max_jerk);
+ return (acceleration == 0.0f) ? 0.0f : (2.0f * acceleration * distance - sqr(initial_rate) + sqr(final_rate)) / (4.0f * acceleration);
}
- block.feedrate.exit = _curr.safe_feedrate;
+ GCodeTimeEstimator::GCodeTimeEstimator()
+ {
+ reset();
+ set_default();
+ }
- // calculates block entry feedrate
- float vmax_junction = _curr.safe_feedrate;
- if (!_blocks.empty() && (_prev.feedrate > PREVIOUS_FEEDRATE_THRESHOLD))
+ void GCodeTimeEstimator::calculate_time_from_text(const std::string& gcode)
{
- bool prev_speed_larger = _prev.feedrate > block.feedrate.cruise;
- float smaller_speed_factor = prev_speed_larger ? (block.feedrate.cruise / _prev.feedrate) : (_prev.feedrate / block.feedrate.cruise);
- // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting.
- vmax_junction = prev_speed_larger ? block.feedrate.cruise : _prev.feedrate;
+ reset();
- float v_factor = 1.0f;
- bool limited = false;
+ _parser.parse_buffer(gcode,
+ [this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
+ { this->_process_gcode_line(reader, line); });
- for (unsigned char a = X; a < Num_Axis; ++a)
- {
- // Limit an axis. We have to differentiate coasting from the reversal of an axis movement, or a full stop.
- float v_exit = _prev.axis_feedrate[a];
- float v_entry = _curr.axis_feedrate[a];
+ _reset();
+ }
- if (prev_speed_larger)
- v_exit *= smaller_speed_factor;
+ void GCodeTimeEstimator::calculate_time_from_file(const std::string& file)
+ {
+ reset();
- if (limited)
- {
- v_exit *= v_factor;
- v_entry *= v_factor;
- }
+ _parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
+ _calculate_time();
- // Calculate the jerk depending on whether the axis is coasting in the same direction or reversing a direction.
- float jerk =
- (v_exit > v_entry) ?
- (((v_entry > 0.0f) || (v_exit < 0.0f)) ?
- // coasting
- (v_exit - v_entry) :
- // axis reversal
- std::max(v_exit, -v_entry)) :
- // v_exit <= v_entry
- (((v_entry < 0.0f) || (v_exit > 0.0f)) ?
- // coasting
- (v_entry - v_exit) :
- // axis reversal
- std::max(-v_exit, v_entry));
-
- float axis_max_jerk = get_axis_max_jerk((EAxis)a);
- if (jerk > axis_max_jerk)
- {
- v_factor *= axis_max_jerk / jerk;
- limited = true;
+ _reset();
+ }
+
+ void GCodeTimeEstimator::calculate_time_from_lines(const std::vector<std::string>& gcode_lines)
+ {
+ reset();
+
+ auto action = [this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
+ { this->_process_gcode_line(reader, line); };
+ for (const std::string& line : gcode_lines)
+ _parser.parse_line(line, action);
+ _calculate_time();
+
+ _reset();
+ }
+
+ void GCodeTimeEstimator::add_gcode_line(const std::string& gcode_line)
+ {
+ PROFILE_FUNC();
+ _parser.parse_line(gcode_line,
+ [this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
+ { this->_process_gcode_line(reader, line); });
+ }
+
+ void GCodeTimeEstimator::add_gcode_block(const char *ptr)
+ {
+ PROFILE_FUNC();
+ GCodeReader::GCodeLine gline;
+ auto action = [this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
+ { this->_process_gcode_line(reader, line); };
+ for (; *ptr != 0;) {
+ gline.reset();
+ ptr = _parser.parse_line(ptr, gline, action);
}
- }
+ }
- if (limited)
- vmax_junction *= v_factor;
+ void GCodeTimeEstimator::calculate_time()
+ {
+ PROFILE_FUNC();
+ _calculate_time();
+ _reset();
+ }
- // Now the transition velocity is known, which maximizes the shared exit / entry velocity while
- // respecting the jerk factors, it may be possible, that applying separate safe exit / entry velocities will achieve faster prints.
- float vmax_junction_threshold = vmax_junction * 0.99f;
+ void GCodeTimeEstimator::set_axis_position(EAxis axis, float position)
+ {
+ _state.axis[axis].position = position;
+ }
- // Not coasting. The machine will stop and start the movements anyway, better to start the segment from start.
- if ((_prev.safe_feedrate > vmax_junction_threshold) && (_curr.safe_feedrate > vmax_junction_threshold))
- vmax_junction = _curr.safe_feedrate;
+ void GCodeTimeEstimator::set_axis_max_feedrate(EAxis axis, float feedrate_mm_sec)
+ {
+ _state.axis[axis].max_feedrate = feedrate_mm_sec;
}
- float v_allowable = Block::max_allowable_speed(-acceleration, _curr.safe_feedrate, distance);
- block.feedrate.entry = std::min(vmax_junction, v_allowable);
+ void GCodeTimeEstimator::set_axis_max_acceleration(EAxis axis, float acceleration)
+ {
+ _state.axis[axis].max_acceleration = acceleration;
+ }
- block.max_entry_speed = vmax_junction;
- block.flags.nominal_length = (block.feedrate.cruise <= v_allowable);
- block.flags.recalculate = true;
- block.safe_feedrate = _curr.safe_feedrate;
+ void GCodeTimeEstimator::set_axis_max_jerk(EAxis axis, float jerk)
+ {
+ _state.axis[axis].max_jerk = jerk;
+ }
- // calculates block trapezoid
- block.calculate_trapezoid();
+ float GCodeTimeEstimator::get_axis_position(EAxis axis) const
+ {
+ return _state.axis[axis].position;
+ }
- // updates previous
- _prev = _curr;
+ float GCodeTimeEstimator::get_axis_max_feedrate(EAxis axis) const
+ {
+ return _state.axis[axis].max_feedrate;
+ }
- // updates axis positions
- for (unsigned char a = X; a < Num_Axis; ++a)
+ float GCodeTimeEstimator::get_axis_max_acceleration(EAxis axis) const
{
- set_axis_position((EAxis)a, new_pos[a]);
+ return _state.axis[axis].max_acceleration;
}
- // adds block to blocks list
- _blocks.emplace_back(block);
- }
+ float GCodeTimeEstimator::get_axis_max_jerk(EAxis axis) const
+ {
+ return _state.axis[axis].max_jerk;
+ }
- void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line)
- {
- EDialect dialect = get_dialect();
+ void GCodeTimeEstimator::set_feedrate(float feedrate_mm_sec)
+ {
+ _state.feedrate = feedrate_mm_sec;
+ }
- float value;
- if (line.has_value('P', value))
- add_additional_time(value * MILLISEC_TO_SEC);
+ float GCodeTimeEstimator::get_feedrate() const
+ {
+ return _state.feedrate;
+ }
- // see: http://reprap.org/wiki/G-code#G4:_Dwell
- if ((dialect == Repetier) ||
- (dialect == Marlin) ||
- (dialect == Smoothieware) ||
- (dialect == RepRapFirmware))
+ void GCodeTimeEstimator::set_acceleration(float acceleration_mm_sec2)
{
- if (line.has_value('S', value))
- add_additional_time(value);
+ _state.acceleration = acceleration_mm_sec2;
}
- }
- void GCodeTimeEstimator::_processG20(const GCodeReader::GCodeLine& line)
- {
- set_units(Inches);
- }
+ float GCodeTimeEstimator::get_acceleration() const
+ {
+ return _state.acceleration;
+ }
- void GCodeTimeEstimator::_processG21(const GCodeReader::GCodeLine& line)
- {
- set_units(Millimeters);
- }
+ void GCodeTimeEstimator::set_retract_acceleration(float acceleration_mm_sec2)
+ {
+ _state.retract_acceleration = acceleration_mm_sec2;
+ }
+
+ float GCodeTimeEstimator::get_retract_acceleration() const
+ {
+ return _state.retract_acceleration;
+ }
+
+ void GCodeTimeEstimator::set_minimum_feedrate(float feedrate_mm_sec)
+ {
+ _state.minimum_feedrate = feedrate_mm_sec;
+ }
- void GCodeTimeEstimator::_processG28(const GCodeReader::GCodeLine& line)
- {
- // TODO
- }
+ float GCodeTimeEstimator::get_minimum_feedrate() const
+ {
+ return _state.minimum_feedrate;
+ }
+
+ void GCodeTimeEstimator::set_minimum_travel_feedrate(float feedrate_mm_sec)
+ {
+ _state.minimum_travel_feedrate = feedrate_mm_sec;
+ }
+
+ float GCodeTimeEstimator::get_minimum_travel_feedrate() const
+ {
+ return _state.minimum_travel_feedrate;
+ }
+
+ void GCodeTimeEstimator::set_extrude_factor_override_percentage(float percentage)
+ {
+ _state.extrude_factor_override_percentage = percentage;
+ }
+
+ float GCodeTimeEstimator::get_extrude_factor_override_percentage() const
+ {
+ return _state.extrude_factor_override_percentage;
+ }
+
+ void GCodeTimeEstimator::set_dialect(GCodeTimeEstimator::EDialect dialect)
+ {
+ _state.dialect = dialect;
+ }
+
+ GCodeTimeEstimator::EDialect GCodeTimeEstimator::get_dialect() const
+ {
+ return _state.dialect;
+ }
+
+ void GCodeTimeEstimator::set_units(GCodeTimeEstimator::EUnits units)
+ {
+ _state.units = units;
+ }
+
+ GCodeTimeEstimator::EUnits GCodeTimeEstimator::get_units() const
+ {
+ return _state.units;
+ }
+
+ void GCodeTimeEstimator::set_positioning_xyz_type(GCodeTimeEstimator::EPositioningType type)
+ {
+ _state.positioning_xyz_type = type;
+ }
+
+ GCodeTimeEstimator::EPositioningType GCodeTimeEstimator::get_positioning_xyz_type() const
+ {
+ return _state.positioning_xyz_type;
+ }
+
+ void GCodeTimeEstimator::set_positioning_e_type(GCodeTimeEstimator::EPositioningType type)
+ {
+ _state.positioning_e_type = type;
+ }
+
+ GCodeTimeEstimator::EPositioningType GCodeTimeEstimator::get_positioning_e_type() const
+ {
+ return _state.positioning_e_type;
+ }
- void GCodeTimeEstimator::_processG90(const GCodeReader::GCodeLine& line)
- {
- set_positioning_xyz_type(Absolute);
- }
+ void GCodeTimeEstimator::add_additional_time(float timeSec)
+ {
+ _state.additional_time += timeSec;
+ }
- void GCodeTimeEstimator::_processG91(const GCodeReader::GCodeLine& line)
- {
- // TODO: THERE ARE DIALECT VARIANTS
+ void GCodeTimeEstimator::set_additional_time(float timeSec)
+ {
+ _state.additional_time = timeSec;
+ }
- set_positioning_xyz_type(Relative);
- }
+ float GCodeTimeEstimator::get_additional_time() const
+ {
+ return _state.additional_time;
+ }
- void GCodeTimeEstimator::_processM82(const GCodeReader::GCodeLine& line)
- {
- set_positioning_e_type(Absolute);
- }
+ void GCodeTimeEstimator::set_default()
+ {
+ set_units(Millimeters);
+ set_dialect(Unknown);
+ set_positioning_xyz_type(Absolute);
+ set_positioning_e_type(Relative);
+
+ set_feedrate(DEFAULT_FEEDRATE);
+ set_acceleration(DEFAULT_ACCELERATION);
+ set_retract_acceleration(DEFAULT_RETRACT_ACCELERATION);
+ set_minimum_feedrate(DEFAULT_MINIMUM_FEEDRATE);
+ set_minimum_travel_feedrate(DEFAULT_MINIMUM_TRAVEL_FEEDRATE);
+ set_extrude_factor_override_percentage(DEFAULT_EXTRUDE_FACTOR_OVERRIDE_PERCENTAGE);
+
+ for (unsigned char a = X; a < Num_Axis; ++a)
+ {
+ EAxis axis = (EAxis)a;
+ set_axis_max_feedrate(axis, DEFAULT_AXIS_MAX_FEEDRATE[a]);
+ set_axis_max_acceleration(axis, DEFAULT_AXIS_MAX_ACCELERATION[a]);
+ set_axis_max_jerk(axis, DEFAULT_AXIS_MAX_JERK[a]);
+ }
+ }
- void GCodeTimeEstimator::_processM83(const GCodeReader::GCodeLine& line)
- {
- set_positioning_e_type(Relative);
- }
+ void GCodeTimeEstimator::reset()
+ {
+ _time = 0.0f;
+ _reset();
+ }
- void GCodeTimeEstimator::_processG92(const GCodeReader::GCodeLine& line)
- {
- float lengthsScaleFactor = (get_units() == Inches) ? INCHES_TO_MM : 1.0f;
- bool anyFound = false;
+ float GCodeTimeEstimator::get_time() const
+ {
+ return _time;
+ }
- if (line.has_x())
+ std::string GCodeTimeEstimator::get_time_hms() const
{
- set_axis_position(X, line.x() * lengthsScaleFactor);
- anyFound = true;
+ float timeinsecs = get_time();
+ int hours = (int)(timeinsecs / 3600.0f);
+ timeinsecs -= (float)hours * 3600.0f;
+ int minutes = (int)(timeinsecs / 60.0f);
+ timeinsecs -= (float)minutes * 60.0f;
+
+ char buffer[64];
+ if (hours > 0)
+ ::sprintf(buffer, "%dh %dm %ds", hours, minutes, (int)timeinsecs);
+ else if (minutes > 0)
+ ::sprintf(buffer, "%dm %ds", minutes, (int)timeinsecs);
+ else
+ ::sprintf(buffer, "%ds", (int)timeinsecs);
+
+ return buffer;
}
- if (line.has_y())
+ void GCodeTimeEstimator::_reset()
{
- set_axis_position(Y, line.y() * lengthsScaleFactor);
- anyFound = true;
+ _blocks.clear();
+
+ _curr.reset();
+ _prev.reset();
+
+ set_axis_position(X, 0.0f);
+ set_axis_position(Y, 0.0f);
+ set_axis_position(Z, 0.0f);
+
+ set_additional_time(0.0f);
}
- if (line.has_z())
+ void GCodeTimeEstimator::_calculate_time()
{
- set_axis_position(Z, line.z() * lengthsScaleFactor);
- anyFound = true;
+ _forward_pass();
+ _reverse_pass();
+ _recalculate_trapezoids();
+
+ _time += get_additional_time();
+
+ for (const Block& block : _blocks)
+ {
+ _time += block.acceleration_time();
+ _time += block.cruise_time();
+ _time += block.deceleration_time();
+ }
}
- if (line.has_e())
+ void GCodeTimeEstimator::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line)
{
- set_axis_position(E, line.e() * lengthsScaleFactor);
- anyFound = true;
+ PROFILE_FUNC();
+ std::string cmd = line.cmd();
+ if (cmd.length() > 1)
+ {
+ switch (::toupper(cmd[0]))
+ {
+ case 'G':
+ {
+ switch (::atoi(&cmd[1]))
+ {
+ case 1: // Move
+ {
+ _processG1(line);
+ break;
+ }
+ case 4: // Dwell
+ {
+ _processG4(line);
+ break;
+ }
+ case 20: // Set Units to Inches
+ {
+ _processG20(line);
+ break;
+ }
+ case 21: // Set Units to Millimeters
+ {
+ _processG21(line);
+ break;
+ }
+ case 28: // Move to Origin (Home)
+ {
+ _processG28(line);
+ break;
+ }
+ case 90: // Set to Absolute Positioning
+ {
+ _processG90(line);
+ break;
+ }
+ case 91: // Set to Relative Positioning
+ {
+ _processG91(line);
+ break;
+ }
+ case 92: // Set Position
+ {
+ _processG92(line);
+ break;
+ }
+ }
+
+ break;
+ }
+ case 'M':
+ {
+ switch (::atoi(&cmd[1]))
+ {
+ case 1: // Sleep or Conditional stop
+ {
+ _processM1(line);
+ break;
+ }
+ case 82: // Set extruder to absolute mode
+ {
+ _processM82(line);
+ break;
+ }
+ case 83: // Set extruder to relative mode
+ {
+ _processM83(line);
+ break;
+ }
+ case 109: // Set Extruder Temperature and Wait
+ {
+ _processM109(line);
+ break;
+ }
+ case 201: // Set max printing acceleration
+ {
+ _processM201(line);
+ break;
+ }
+ case 203: // Set maximum feedrate
+ {
+ _processM203(line);
+ break;
+ }
+ case 204: // Set default acceleration
+ {
+ _processM204(line);
+ break;
+ }
+ case 205: // Advanced settings
+ {
+ _processM205(line);
+ break;
+ }
+ case 221: // Set extrude factor override percentage
+ {
+ _processM221(line);
+ break;
+ }
+ case 566: // Set allowable instantaneous speed change
+ {
+ _processM566(line);
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+ }
}
- if (!anyFound)
+ // Returns the new absolute position on the given axis in dependence of the given parameters
+ float axis_absolute_position_from_G1_line(GCodeTimeEstimator::EAxis axis, const GCodeReader::GCodeLine& lineG1, GCodeTimeEstimator::EUnits units, GCodeTimeEstimator::EPositioningType type, float current_absolute_position)
{
- for (unsigned char a = X; a < Num_Axis; ++a)
- {
- set_axis_position((EAxis)a, 0.0f);
- }
+ float lengthsScaleFactor = (units == GCodeTimeEstimator::Inches) ? INCHES_TO_MM : 1.0f;
+ if (lineG1.has(Slic3r::Axis(axis)))
+ {
+ float ret = lineG1.value(Slic3r::Axis(axis)) * lengthsScaleFactor;
+ return (type == GCodeTimeEstimator::Absolute) ? ret : current_absolute_position + ret;
+ }
+ else
+ return current_absolute_position;
}
- }
- void GCodeTimeEstimator::_processM109(const GCodeReader::GCodeLine& line)
- {
- // TODO
- }
+ void GCodeTimeEstimator::_processG1(const GCodeReader::GCodeLine& line)
+ {
+ // updates axes positions from line
+ EUnits units = get_units();
+ float new_pos[Num_Axis];
+ for (unsigned char a = X; a < Num_Axis; ++a)
+ {
+ new_pos[a] = axis_absolute_position_from_G1_line((EAxis)a, line, units, (a == E) ? get_positioning_e_type() : get_positioning_xyz_type(), get_axis_position((EAxis)a));
+ }
- void GCodeTimeEstimator::_processM201(const GCodeReader::GCodeLine& line)
- {
- EDialect dialect = get_dialect();
+ // updates feedrate from line, if present
+ if (line.has_f())
+ set_feedrate(std::max(line.f() * MMMIN_TO_MMSEC, get_minimum_feedrate()));
- // see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration
- float factor = ((dialect != RepRapFirmware) && (get_units() == GCodeTimeEstimator::Inches)) ? INCHES_TO_MM : 1.0f;
+ // fills block data
+ Block block;
- if (line.has_x())
- set_axis_max_acceleration(X, line.x() * factor);
+ // calculates block movement deltas
+ float max_abs_delta = 0.0f;
+ for (unsigned char a = X; a < Num_Axis; ++a)
+ {
+ block.delta_pos[a] = new_pos[a] - get_axis_position((EAxis)a);
+ max_abs_delta = std::max(max_abs_delta, std::abs(block.delta_pos[a]));
+ }
- if (line.has_y())
- set_axis_max_acceleration(Y, line.y() * factor);
+ // is it a move ?
+ if (max_abs_delta == 0.0f)
+ return;
- if (line.has_z())
- set_axis_max_acceleration(Z, line.z() * factor);
+ // calculates block feedrate
+ _curr.feedrate = std::max(get_feedrate(), block.is_travel_move() ? get_minimum_travel_feedrate() : get_minimum_feedrate());
- if (line.has_e())
- set_axis_max_acceleration(E, line.e() * factor);
- }
+ float distance = block.move_length();
+ float invDistance = 1.0f / distance;
- void GCodeTimeEstimator::_processM203(const GCodeReader::GCodeLine& line)
- {
- EDialect dialect = get_dialect();
+ float min_feedrate_factor = 1.0f;
+ for (unsigned char a = X; a < Num_Axis; ++a)
+ {
+ _curr.axis_feedrate[a] = _curr.feedrate * block.delta_pos[a] * invDistance;
+ if (a == E)
+ _curr.axis_feedrate[a] *= get_extrude_factor_override_percentage();
- // see http://reprap.org/wiki/G-code#M203:_Set_maximum_feedrate
- if (dialect == Repetier)
- return;
+ _curr.abs_axis_feedrate[a] = std::abs(_curr.axis_feedrate[a]);
+ if (_curr.abs_axis_feedrate[a] > 0.0f)
+ min_feedrate_factor = std::min(min_feedrate_factor, get_axis_max_feedrate((EAxis)a) / _curr.abs_axis_feedrate[a]);
+ }
+
+ block.feedrate.cruise = min_feedrate_factor * _curr.feedrate;
- // see http://reprap.org/wiki/G-code#M203:_Set_maximum_feedrate
- float factor = (dialect == Marlin) ? 1.0f : MMMIN_TO_MMSEC;
+ for (unsigned char a = X; a < Num_Axis; ++a)
+ {
+ _curr.axis_feedrate[a] *= min_feedrate_factor;
+ _curr.abs_axis_feedrate[a] *= min_feedrate_factor;
+ }
- if (line.has_x())
- set_axis_max_feedrate(X, line.x() * factor);
+ // calculates block acceleration
+ float acceleration = block.is_extruder_only_move() ? get_retract_acceleration() : get_acceleration();
- if (line.has_y())
- set_axis_max_feedrate(Y, line.y() * factor);
+ for (unsigned char a = X; a < Num_Axis; ++a)
+ {
+ float axis_max_acceleration = get_axis_max_acceleration((EAxis)a);
+ if (acceleration * std::abs(block.delta_pos[a]) * invDistance > axis_max_acceleration)
+ acceleration = axis_max_acceleration;
+ }
- if (line.has_z())
- set_axis_max_feedrate(Z, line.z() * factor);
+ block.acceleration = acceleration;
- if (line.has_e())
- set_axis_max_feedrate(E, line.e() * factor);
- }
+ // calculates block exit feedrate
+ _curr.safe_feedrate = block.feedrate.cruise;
- void GCodeTimeEstimator::_processM204(const GCodeReader::GCodeLine& line)
- {
- float value;
- if (line.has_value('S', value))
- set_acceleration(value);
+ for (unsigned char a = X; a < Num_Axis; ++a)
+ {
+ float axis_max_jerk = get_axis_max_jerk((EAxis)a);
+ if (_curr.abs_axis_feedrate[a] > axis_max_jerk)
+ _curr.safe_feedrate = std::min(_curr.safe_feedrate, axis_max_jerk);
+ }
+
+ block.feedrate.exit = _curr.safe_feedrate;
+
+ // calculates block entry feedrate
+ float vmax_junction = _curr.safe_feedrate;
+ if (!_blocks.empty() && (_prev.feedrate > PREVIOUS_FEEDRATE_THRESHOLD))
+ {
+ bool prev_speed_larger = _prev.feedrate > block.feedrate.cruise;
+ float smaller_speed_factor = prev_speed_larger ? (block.feedrate.cruise / _prev.feedrate) : (_prev.feedrate / block.feedrate.cruise);
+ // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting.
+ vmax_junction = prev_speed_larger ? block.feedrate.cruise : _prev.feedrate;
+
+ float v_factor = 1.0f;
+ bool limited = false;
+
+ for (unsigned char a = X; a < Num_Axis; ++a)
+ {
+ // Limit an axis. We have to differentiate coasting from the reversal of an axis movement, or a full stop.
+ float v_exit = _prev.axis_feedrate[a];
+ float v_entry = _curr.axis_feedrate[a];
+
+ if (prev_speed_larger)
+ v_exit *= smaller_speed_factor;
+
+ if (limited)
+ {
+ v_exit *= v_factor;
+ v_entry *= v_factor;
+ }
+
+ // Calculate the jerk depending on whether the axis is coasting in the same direction or reversing a direction.
+ float jerk =
+ (v_exit > v_entry) ?
+ (((v_entry > 0.0f) || (v_exit < 0.0f)) ?
+ // coasting
+ (v_exit - v_entry) :
+ // axis reversal
+ std::max(v_exit, -v_entry)) :
+ // v_exit <= v_entry
+ (((v_entry < 0.0f) || (v_exit > 0.0f)) ?
+ // coasting
+ (v_entry - v_exit) :
+ // axis reversal
+ std::max(-v_exit, v_entry));
+
+ float axis_max_jerk = get_axis_max_jerk((EAxis)a);
+ if (jerk > axis_max_jerk)
+ {
+ v_factor *= axis_max_jerk / jerk;
+ limited = true;
+ }
+ }
+
+ if (limited)
+ vmax_junction *= v_factor;
+
+ // Now the transition velocity is known, which maximizes the shared exit / entry velocity while
+ // respecting the jerk factors, it may be possible, that applying separate safe exit / entry velocities will achieve faster prints.
+ float vmax_junction_threshold = vmax_junction * 0.99f;
+
+ // Not coasting. The machine will stop and start the movements anyway, better to start the segment from start.
+ if ((_prev.safe_feedrate > vmax_junction_threshold) && (_curr.safe_feedrate > vmax_junction_threshold))
+ vmax_junction = _curr.safe_feedrate;
+ }
+
+ float v_allowable = Block::max_allowable_speed(-acceleration, _curr.safe_feedrate, distance);
+ block.feedrate.entry = std::min(vmax_junction, v_allowable);
+
+ block.max_entry_speed = vmax_junction;
+ block.flags.nominal_length = (block.feedrate.cruise <= v_allowable);
+ block.flags.recalculate = true;
+ block.safe_feedrate = _curr.safe_feedrate;
+
+ // calculates block trapezoid
+ block.calculate_trapezoid();
+
+ // updates previous
+ _prev = _curr;
+
+ // updates axis positions
+ for (unsigned char a = X; a < Num_Axis; ++a)
+ {
+ set_axis_position((EAxis)a, new_pos[a]);
+ }
- if (line.has_value('T', value))
- set_retract_acceleration(value);
- }
+ // adds block to blocks list
+ _blocks.emplace_back(block);
+ }
- void GCodeTimeEstimator::_processM205(const GCodeReader::GCodeLine& line)
- {
- if (line.has_x())
+ void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line)
{
- float max_jerk = line.x();
- set_axis_max_jerk(X, max_jerk);
- set_axis_max_jerk(Y, max_jerk);
+ EDialect dialect = get_dialect();
+
+ float value;
+ if (line.has_value('P', value))
+ add_additional_time(value * MILLISEC_TO_SEC);
+
+ // see: http://reprap.org/wiki/G-code#G4:_Dwell
+ if ((dialect == Repetier) ||
+ (dialect == Marlin) ||
+ (dialect == Smoothieware) ||
+ (dialect == RepRapFirmware))
+ {
+ if (line.has_value('S', value))
+ add_additional_time(value);
+ }
+
+ _simulate_st_synchronize();
}
- if (line.has_y())
- set_axis_max_jerk(Y, line.y());
+ void GCodeTimeEstimator::_processG20(const GCodeReader::GCodeLine& line)
+ {
+ set_units(Inches);
+ }
- if (line.has_z())
- set_axis_max_jerk(Z, line.z());
+ void GCodeTimeEstimator::_processG21(const GCodeReader::GCodeLine& line)
+ {
+ set_units(Millimeters);
+ }
+
+ void GCodeTimeEstimator::_processG28(const GCodeReader::GCodeLine& line)
+ {
+ // TODO
+ }
+
+ void GCodeTimeEstimator::_processG90(const GCodeReader::GCodeLine& line)
+ {
+ set_positioning_xyz_type(Absolute);
+ }
+
+ void GCodeTimeEstimator::_processG91(const GCodeReader::GCodeLine& line)
+ {
+ // TODO: THERE ARE DIALECT VARIANTS
- if (line.has_e())
- set_axis_max_jerk(E, line.e());
+ set_positioning_xyz_type(Relative);
+ }
- float value;
- if (line.has_value('S', value))
- set_minimum_feedrate(value);
+ void GCodeTimeEstimator::_processG92(const GCodeReader::GCodeLine& line)
+ {
+ float lengthsScaleFactor = (get_units() == Inches) ? INCHES_TO_MM : 1.0f;
+ bool anyFound = false;
- if (line.has_value('T', value))
- set_minimum_travel_feedrate(value);
- }
+ if (line.has_x())
+ {
+ set_axis_position(X, line.x() * lengthsScaleFactor);
+ anyFound = true;
+ }
- void GCodeTimeEstimator::_processM566(const GCodeReader::GCodeLine& line)
- {
- if (line.has_x())
- set_axis_max_jerk(X, line.x() * MMMIN_TO_MMSEC);
+ if (line.has_y())
+ {
+ set_axis_position(Y, line.y() * lengthsScaleFactor);
+ anyFound = true;
+ }
- if (line.has_y())
- set_axis_max_jerk(Y, line.y() * MMMIN_TO_MMSEC);
+ if (line.has_z())
+ {
+ set_axis_position(Z, line.z() * lengthsScaleFactor);
+ anyFound = true;
+ }
- if (line.has_z())
- set_axis_max_jerk(Z, line.z() * MMMIN_TO_MMSEC);
+ if (line.has_e())
+ {
+ set_axis_position(E, line.e() * lengthsScaleFactor);
+ anyFound = true;
+ }
+ else
+ _simulate_st_synchronize();
- if (line.has_e())
- set_axis_max_jerk(E, line.e() * MMMIN_TO_MMSEC);
- }
+ if (!anyFound)
+ {
+ for (unsigned char a = X; a < Num_Axis; ++a)
+ {
+ set_axis_position((EAxis)a, 0.0f);
+ }
+ }
+ }
- void GCodeTimeEstimator::_forward_pass()
- {
- Block* block[2] = { nullptr, nullptr };
+ void GCodeTimeEstimator::_processM1(const GCodeReader::GCodeLine& line)
+ {
+ _simulate_st_synchronize();
+ }
- for (Block& b : _blocks)
+ void GCodeTimeEstimator::_processM82(const GCodeReader::GCodeLine& line)
{
- block[0] = block[1];
- block[1] = &b;
- _planner_forward_pass_kernel(block[0], block[1]);
+ set_positioning_e_type(Absolute);
}
- _planner_forward_pass_kernel(block[1], nullptr);
- }
+ void GCodeTimeEstimator::_processM83(const GCodeReader::GCodeLine& line)
+ {
+ set_positioning_e_type(Relative);
+ }
- void GCodeTimeEstimator::_reverse_pass()
- {
- Block* block[2] = { nullptr, nullptr };
+ void GCodeTimeEstimator::_processM109(const GCodeReader::GCodeLine& line)
+ {
+ // TODO
+ }
- for (int i = (int)_blocks.size() - 1; i >= 0; --i)
+ void GCodeTimeEstimator::_processM201(const GCodeReader::GCodeLine& line)
{
- block[1] = block[0];
- block[0] = &_blocks[i];
- _planner_reverse_pass_kernel(block[0], block[1]);
+ EDialect dialect = get_dialect();
+
+ // see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration
+ float factor = ((dialect != RepRapFirmware) && (get_units() == GCodeTimeEstimator::Inches)) ? INCHES_TO_MM : 1.0f;
+
+ if (line.has_x())
+ set_axis_max_acceleration(X, line.x() * factor);
+
+ if (line.has_y())
+ set_axis_max_acceleration(Y, line.y() * factor);
+
+ if (line.has_z())
+ set_axis_max_acceleration(Z, line.z() * factor);
+
+ if (line.has_e())
+ set_axis_max_acceleration(E, line.e() * factor);
}
- }
- void GCodeTimeEstimator::_planner_forward_pass_kernel(Block* prev, Block* curr)
- {
- if (prev == nullptr || curr == nullptr)
-//FIXME something is fishy here. Review and compare with the firmware.
-// if (prev == nullptr)
- return;
+ void GCodeTimeEstimator::_processM203(const GCodeReader::GCodeLine& line)
+ {
+ EDialect dialect = get_dialect();
+
+ // see http://reprap.org/wiki/G-code#M203:_Set_maximum_feedrate
+ if (dialect == Repetier)
+ return;
+
+ // see http://reprap.org/wiki/G-code#M203:_Set_maximum_feedrate
+ float factor = (dialect == Marlin) ? 1.0f : MMMIN_TO_MMSEC;
+
+ if (line.has_x())
+ set_axis_max_feedrate(X, line.x() * factor);
- // If the previous block is an acceleration block, but it is not long enough to complete the
- // full speed change within the block, we need to adjust the entry speed accordingly. Entry
- // speeds have already been reset, maximized, and reverse planned by reverse planner.
- // If nominal length is true, max junction speed is guaranteed to be reached. No need to recheck.
- if (!prev->flags.nominal_length)
+ if (line.has_y())
+ set_axis_max_feedrate(Y, line.y() * factor);
+
+ if (line.has_z())
+ set_axis_max_feedrate(Z, line.z() * factor);
+
+ if (line.has_e())
+ set_axis_max_feedrate(E, line.e() * factor);
+ }
+
+ void GCodeTimeEstimator::_processM204(const GCodeReader::GCodeLine& line)
{
- if (prev->feedrate.entry < curr->feedrate.entry)
- {
- float entry_speed = std::min(curr->feedrate.entry, Block::max_allowable_speed(-prev->acceleration, prev->feedrate.entry, prev->move_length()));
+ float value;
+ if (line.has_value('S', value))
+ set_acceleration(value);
- // Check for junction speed change
- if (curr->feedrate.entry != entry_speed)
+ if (line.has_value('T', value))
+ set_retract_acceleration(value);
+ }
+
+ void GCodeTimeEstimator::_processM205(const GCodeReader::GCodeLine& line)
+ {
+ if (line.has_x())
{
- curr->feedrate.entry = entry_speed;
- curr->flags.recalculate = true;
+ float max_jerk = line.x();
+ set_axis_max_jerk(X, max_jerk);
+ set_axis_max_jerk(Y, max_jerk);
}
- }
+
+ if (line.has_y())
+ set_axis_max_jerk(Y, line.y());
+
+ if (line.has_z())
+ set_axis_max_jerk(Z, line.z());
+
+ if (line.has_e())
+ set_axis_max_jerk(E, line.e());
+
+ float value;
+ if (line.has_value('S', value))
+ set_minimum_feedrate(value);
+
+ if (line.has_value('T', value))
+ set_minimum_travel_feedrate(value);
}
- }
- void GCodeTimeEstimator::_planner_reverse_pass_kernel(Block* curr, Block* next)
- {
- if ((curr == nullptr) || (next == nullptr))
- return;
+ void GCodeTimeEstimator::_processM221(const GCodeReader::GCodeLine& line)
+ {
+ float value_s;
+ float value_t;
+ if (line.has_value('S', value_s) && !line.has_value('T', value_t))
+ set_extrude_factor_override_percentage(value_s * 0.01f);
+ }
- // If entry speed is already at the maximum entry speed, no need to recheck. Block is cruising.
- // If not, block in state of acceleration or deceleration. Reset entry speed to maximum and
- // check for maximum allowable speed reductions to ensure maximum possible planned speed.
- if (curr->feedrate.entry != curr->max_entry_speed)
+ void GCodeTimeEstimator::_processM566(const GCodeReader::GCodeLine& line)
{
- // If nominal length true, max junction speed is guaranteed to be reached. Only compute
- // for max allowable speed if block is decelerating and nominal length is false.
- if (!curr->flags.nominal_length && (curr->max_entry_speed > next->feedrate.entry))
- curr->feedrate.entry = std::min(curr->max_entry_speed, Block::max_allowable_speed(-curr->acceleration, next->feedrate.entry, curr->move_length()));
- else
- curr->feedrate.entry = curr->max_entry_speed;
+ if (line.has_x())
+ set_axis_max_jerk(X, line.x() * MMMIN_TO_MMSEC);
- curr->flags.recalculate = true;
+ if (line.has_y())
+ set_axis_max_jerk(Y, line.y() * MMMIN_TO_MMSEC);
+
+ if (line.has_z())
+ set_axis_max_jerk(Z, line.z() * MMMIN_TO_MMSEC);
+
+ if (line.has_e())
+ set_axis_max_jerk(E, line.e() * MMMIN_TO_MMSEC);
+ }
+
+ void GCodeTimeEstimator::_simulate_st_synchronize()
+ {
+ _calculate_time();
+ _reset();
}
- }
- void GCodeTimeEstimator::_recalculate_trapezoids()
- {
- Block* curr = nullptr;
- Block* next = nullptr;
+ void GCodeTimeEstimator::_forward_pass()
+ {
+ if (_blocks.size() > 1)
+ {
+ for (unsigned int i = 0; i < (unsigned int)_blocks.size() - 1; ++i)
+ {
+ _planner_forward_pass_kernel(_blocks[i], _blocks[i + 1]);
+ }
+ }
+ }
+
+ void GCodeTimeEstimator::_reverse_pass()
+ {
+ if (_blocks.size() > 1)
+ {
+ for (int i = (int)_blocks.size() - 1; i >= 1; --i)
+ {
+ _planner_reverse_pass_kernel(_blocks[i - 1], _blocks[i]);
+ }
+ }
+ }
- for (Block& b : _blocks)
+ void GCodeTimeEstimator::_planner_forward_pass_kernel(Block& prev, Block& curr)
{
- curr = next;
- next = &b;
+ // If the previous block is an acceleration block, but it is not long enough to complete the
+ // full speed change within the block, we need to adjust the entry speed accordingly. Entry
+ // speeds have already been reset, maximized, and reverse planned by reverse planner.
+ // If nominal length is true, max junction speed is guaranteed to be reached. No need to recheck.
+ if (!prev.flags.nominal_length)
+ {
+ if (prev.feedrate.entry < curr.feedrate.entry)
+ {
+ float entry_speed = std::min(curr.feedrate.entry, Block::max_allowable_speed(-prev.acceleration, prev.feedrate.entry, prev.move_length()));
+
+ // Check for junction speed change
+ if (curr.feedrate.entry != entry_speed)
+ {
+ curr.feedrate.entry = entry_speed;
+ curr.flags.recalculate = true;
+ }
+ }
+ }
+ }
- if (curr != nullptr)
- {
- // Recalculate if current block entry or exit junction speed has changed.
- if (curr->flags.recalculate || next->flags.recalculate)
+ void GCodeTimeEstimator::_planner_reverse_pass_kernel(Block& curr, Block& next)
+ {
+ // If entry speed is already at the maximum entry speed, no need to recheck. Block is cruising.
+ // If not, block in state of acceleration or deceleration. Reset entry speed to maximum and
+ // check for maximum allowable speed reductions to ensure maximum possible planned speed.
+ if (curr.feedrate.entry != curr.max_entry_speed)
{
- // NOTE: Entry and exit factors always > 0 by all previous logic operations.
- Block block = *curr;
- block.feedrate.exit = next->feedrate.entry;
- block.calculate_trapezoid();
- curr->trapezoid = block.trapezoid;
- curr->flags.recalculate = false; // Reset current only to ensure next trapezoid is computed
+ // If nominal length true, max junction speed is guaranteed to be reached. Only compute
+ // for max allowable speed if block is decelerating and nominal length is false.
+ if (!curr.flags.nominal_length && (curr.max_entry_speed > next.feedrate.entry))
+ curr.feedrate.entry = std::min(curr.max_entry_speed, Block::max_allowable_speed(-curr.acceleration, next.feedrate.entry, curr.move_length()));
+ else
+ curr.feedrate.entry = curr.max_entry_speed;
+
+ curr.flags.recalculate = true;
}
- }
}
- // Last/newest block in buffer. Always recalculated.
- if (next != nullptr)
+ void GCodeTimeEstimator::_recalculate_trapezoids()
{
- Block block = *next;
- block.feedrate.exit = next->safe_feedrate;
- block.calculate_trapezoid();
- next->trapezoid = block.trapezoid;
- next->flags.recalculate = false;
+ Block* curr = nullptr;
+ Block* next = nullptr;
+
+ for (Block& b : _blocks)
+ {
+ curr = next;
+ next = &b;
+
+ if (curr != nullptr)
+ {
+ // Recalculate if current block entry or exit junction speed has changed.
+ if (curr->flags.recalculate || next->flags.recalculate)
+ {
+ // NOTE: Entry and exit factors always > 0 by all previous logic operations.
+ Block block = *curr;
+ block.feedrate.exit = next->feedrate.entry;
+ block.calculate_trapezoid();
+ curr->trapezoid = block.trapezoid;
+ curr->flags.recalculate = false; // Reset current only to ensure next trapezoid is computed
+ }
+ }
+ }
+
+ // Last/newest block in buffer. Always recalculated.
+ if (next != nullptr)
+ {
+ Block block = *next;
+ block.feedrate.exit = next->safe_feedrate;
+ block.calculate_trapezoid();
+ next->trapezoid = block.trapezoid;
+ next->flags.recalculate = false;
+ }
}
- }
}
diff --git a/xs/src/libslic3r/GCodeTimeEstimator.hpp b/xs/src/libslic3r/GCodeTimeEstimator.hpp
index 84c6de5fc..46f866972 100644
--- a/xs/src/libslic3r/GCodeTimeEstimator.hpp
+++ b/xs/src/libslic3r/GCodeTimeEstimator.hpp
@@ -6,310 +6,323 @@
namespace Slic3r {
- class GCodeTimeEstimator
- {
- public:
- enum EUnits : unsigned char
+ class GCodeTimeEstimator
{
- Millimeters,
- Inches
- };
-
- enum EAxis : unsigned char
- {
- X,
- Y,
- Z,
- E,
- Num_Axis
- };
-
- enum EDialect : unsigned char
- {
- Unknown,
- Marlin,
- Repetier,
- Smoothieware,
- RepRapFirmware,
- Teacup,
- Num_Dialects
- };
-
- enum EPositioningType : unsigned char
- {
- Absolute,
- Relative
- };
-
- private:
- struct Axis
- {
- float position; // mm
- float max_feedrate; // mm/s
- float max_acceleration; // mm/s^2
- float max_jerk; // mm/s
- };
-
- struct Feedrates
- {
- float feedrate; // mm/s
- float axis_feedrate[Num_Axis]; // mm/s
- float abs_axis_feedrate[Num_Axis]; // mm/s
- float safe_feedrate; // mm/s
-
- void reset();
- };
-
- struct State
- {
- EDialect dialect;
- EUnits units;
- EPositioningType positioning_xyz_type;
- EPositioningType positioning_e_type;
- Axis axis[Num_Axis];
- float feedrate; // mm/s
- float acceleration; // mm/s^2
- float retract_acceleration; // mm/s^2
- float additional_time; // s
- float minimum_feedrate; // mm/s
- float minimum_travel_feedrate; // mm/s
- };
-
- public:
- struct Block
- {
- struct FeedrateProfile
- {
- float entry; // mm/s
- float cruise; // mm/s
- float exit; // mm/s
- };
-
- struct Trapezoid
- {
- float distance; // mm
- float accelerate_until; // mm
- float decelerate_after; // mm
- FeedrateProfile feedrate;
-
- float acceleration_time(float acceleration) const;
- float cruise_time() const;
- float deceleration_time(float acceleration) const;
- float cruise_distance() const;
-
- // This function gives the time needed to accelerate from an initial speed to reach a final distance.
- static float acceleration_time_from_distance(float initial_feedrate, float distance, float acceleration);
-
- // This function gives the final speed while accelerating at the given constant acceleration from the given initial speed along the given distance.
- static float speed_from_distance(float initial_feedrate, float distance, float acceleration);
- };
-
- struct Flags
- {
- bool recalculate;
- bool nominal_length;
- };
+ public:
+ enum EUnits : unsigned char
+ {
+ Millimeters,
+ Inches
+ };
+
+ enum EAxis : unsigned char
+ {
+ X,
+ Y,
+ Z,
+ E,
+ Num_Axis
+ };
+
+ enum EDialect : unsigned char
+ {
+ Unknown,
+ Marlin,
+ Repetier,
+ Smoothieware,
+ RepRapFirmware,
+ Teacup,
+ Num_Dialects
+ };
+
+ enum EPositioningType : unsigned char
+ {
+ Absolute,
+ Relative
+ };
+
+ private:
+ struct Axis
+ {
+ float position; // mm
+ float max_feedrate; // mm/s
+ float max_acceleration; // mm/s^2
+ float max_jerk; // mm/s
+ };
+
+ struct Feedrates
+ {
+ float feedrate; // mm/s
+ float axis_feedrate[Num_Axis]; // mm/s
+ float abs_axis_feedrate[Num_Axis]; // mm/s
+ float safe_feedrate; // mm/s
+
+ void reset();
+ };
+
+ struct State
+ {
+ EDialect dialect;
+ EUnits units;
+ EPositioningType positioning_xyz_type;
+ EPositioningType positioning_e_type;
+ Axis axis[Num_Axis];
+ float feedrate; // mm/s
+ float acceleration; // mm/s^2
+ float retract_acceleration; // mm/s^2
+ float additional_time; // s
+ float minimum_feedrate; // mm/s
+ float minimum_travel_feedrate; // mm/s
+ float extrude_factor_override_percentage;
+ };
+
+ public:
+ struct Block
+ {
+ struct FeedrateProfile
+ {
+ float entry; // mm/s
+ float cruise; // mm/s
+ float exit; // mm/s
+ };
+
+ struct Trapezoid
+ {
+ float distance; // mm
+ float accelerate_until; // mm
+ float decelerate_after; // mm
+ FeedrateProfile feedrate;
+
+ float acceleration_time(float acceleration) const;
+ float cruise_time() const;
+ float deceleration_time(float acceleration) const;
+ float cruise_distance() const;
+
+ // This function gives the time needed to accelerate from an initial speed to reach a final distance.
+ static float acceleration_time_from_distance(float initial_feedrate, float distance, float acceleration);
+
+ // This function gives the final speed while accelerating at the given constant acceleration from the given initial speed along the given distance.
+ static float speed_from_distance(float initial_feedrate, float distance, float acceleration);
+ };
+
+ struct Flags
+ {
+ bool recalculate;
+ bool nominal_length;
+ };
+
+ Flags flags;
+
+ float delta_pos[Num_Axis]; // mm
+ float acceleration; // mm/s^2
+ float max_entry_speed; // mm/s
+ float safe_feedrate; // mm/s
+
+ FeedrateProfile feedrate;
+ Trapezoid trapezoid;
+
+ // Returns the length of the move covered by this block, in mm
+ float move_length() const;
+
+ // Returns true if this block is a retract/unretract move only
+ float is_extruder_only_move() const;
+
+ // Returns true if this block is a move with no extrusion
+ float is_travel_move() const;
+
+ // Returns the time spent accelerating toward cruise speed, in seconds
+ float acceleration_time() const;
+
+ // Returns the time spent at cruise speed, in seconds
+ float cruise_time() const;
+
+ // Returns the time spent decelerating from cruise speed, in seconds
+ float deceleration_time() const;
+
+ // Returns the distance covered at cruise speed, in mm
+ float cruise_distance() const;
+
+ // Calculates this block's trapezoid
+ void calculate_trapezoid();
- Flags flags;
+ // Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the
+ // acceleration within the allotted distance.
+ static float max_allowable_speed(float acceleration, float target_velocity, float distance);
- float delta_pos[Num_Axis]; // mm
- float acceleration; // mm/s^2
- float max_entry_speed; // mm/s
- float safe_feedrate; // mm/s
+ // Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the given acceleration:
+ static float estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration);
- FeedrateProfile feedrate;
- Trapezoid trapezoid;
+ // This function gives you the point at which you must start braking (at the rate of -acceleration) if
+ // you started at speed initial_rate and accelerated until this point and want to end at the final_rate after
+ // a total travel of distance. This can be used to compute the intersection point between acceleration and
+ // deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed)
+ static float intersection_distance(float initial_rate, float final_rate, float acceleration, float distance);
+ };
- // Returns the length of the move covered by this block, in mm
- float move_length() const;
+ typedef std::vector<Block> BlocksList;
- // Returns true if this block is a retract/unretract move only
- float is_extruder_only_move() const;
+ private:
+ GCodeReader _parser;
+ State _state;
+ Feedrates _curr;
+ Feedrates _prev;
+ BlocksList _blocks;
+ float _time; // s
- // Returns true if this block is a move with no extrusion
- float is_travel_move() const;
+ public:
+ GCodeTimeEstimator();
- // Returns the time spent accelerating toward cruise speed, in seconds
- float acceleration_time() const;
+ // Calculates the time estimate from the given gcode in string format
+ void calculate_time_from_text(const std::string& gcode);
- // Returns the time spent at cruise speed, in seconds
- float cruise_time() const;
+ // Calculates the time estimate from the gcode contained in the file with the given filename
+ void calculate_time_from_file(const std::string& file);
- // Returns the time spent decelerating from cruise speed, in seconds
- float deceleration_time() const;
+ // Calculates the time estimate from the gcode contained in given list of gcode lines
+ void calculate_time_from_lines(const std::vector<std::string>& gcode_lines);
- // Returns the distance covered at cruise speed, in mm
- float cruise_distance() const;
+ // Adds the given gcode line
+ void add_gcode_line(const std::string& gcode_line);
- // Calculates this block's trapezoid
- void calculate_trapezoid();
+ void add_gcode_block(const char *ptr);
+ void add_gcode_block(const std::string &str) { this->add_gcode_block(str.c_str()); }
- // Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the
- // acceleration within the allotted distance.
- static float max_allowable_speed(float acceleration, float target_velocity, float distance);
+ // Calculates the time estimate from the gcode lines added using add_gcode_line()
+ void calculate_time();
- // Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the given acceleration:
- static float estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration);
+ // Set current position on the given axis with the given value
+ void set_axis_position(EAxis axis, float position);
- // This function gives you the point at which you must start braking (at the rate of -acceleration) if
- // you started at speed initial_rate and accelerated until this point and want to end at the final_rate after
- // a total travel of distance. This can be used to compute the intersection point between acceleration and
- // deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed)
- static float intersection_distance(float initial_rate, float final_rate, float acceleration, float distance);
- };
-
- typedef std::vector<Block> BlocksList;
-
- private:
- GCodeReader _parser;
- State _state;
- Feedrates _curr;
- Feedrates _prev;
- BlocksList _blocks;
- float _time; // s
-
- public:
- GCodeTimeEstimator();
-
- // Calculates the time estimate from the given gcode in string format
- void calculate_time_from_text(const std::string& gcode);
+ void set_axis_max_feedrate(EAxis axis, float feedrate_mm_sec);
+ void set_axis_max_acceleration(EAxis axis, float acceleration);
+ void set_axis_max_jerk(EAxis axis, float jerk);
- // Calculates the time estimate from the gcode contained in the file with the given filename
- void calculate_time_from_file(const std::string& file);
+ // Returns current position on the given axis
+ float get_axis_position(EAxis axis) const;
- // Calculates the time estimate from the gcode contained in given list of gcode lines
- void calculate_time_from_lines(const std::vector<std::string>& gcode_lines);
+ float get_axis_max_feedrate(EAxis axis) const;
+ float get_axis_max_acceleration(EAxis axis) const;
+ float get_axis_max_jerk(EAxis axis) const;
- // Adds the given gcode line
- void add_gcode_line(const std::string& gcode_line);
+ void set_feedrate(float feedrate_mm_sec);
+ float get_feedrate() const;
- void add_gcode_block(const char *ptr);
- void add_gcode_block(const std::string &str) { this->add_gcode_block(str.c_str()); }
+ void set_acceleration(float acceleration_mm_sec2);
+ float get_acceleration() const;
- // Calculates the time estimate from the gcode lines added using add_gcode_line()
- void calculate_time();
+ void set_retract_acceleration(float acceleration_mm_sec2);
+ float get_retract_acceleration() const;
- // Set current position on the given axis with the given value
- void set_axis_position(EAxis axis, float position);
+ void set_minimum_feedrate(float feedrate_mm_sec);
+ float get_minimum_feedrate() const;
- void set_axis_max_feedrate(EAxis axis, float feedrate_mm_sec);
- void set_axis_max_acceleration(EAxis axis, float acceleration);
- void set_axis_max_jerk(EAxis axis, float jerk);
+ void set_minimum_travel_feedrate(float feedrate_mm_sec);
+ float get_minimum_travel_feedrate() const;
- // Returns current position on the given axis
- float get_axis_position(EAxis axis) const;
+ void set_extrude_factor_override_percentage(float percentage);
+ float get_extrude_factor_override_percentage() const;
- float get_axis_max_feedrate(EAxis axis) const;
- float get_axis_max_acceleration(EAxis axis) const;
- float get_axis_max_jerk(EAxis axis) const;
+ void set_dialect(EDialect dialect);
+ EDialect get_dialect() const;
- void set_feedrate(float feedrate_mm_sec);
- float get_feedrate() const;
+ void set_units(EUnits units);
+ EUnits get_units() const;
- void set_acceleration(float acceleration_mm_sec2);
- float get_acceleration() const;
+ void set_positioning_xyz_type(EPositioningType type);
+ EPositioningType get_positioning_xyz_type() const;
- void set_retract_acceleration(float acceleration_mm_sec2);
- float get_retract_acceleration() const;
+ void set_positioning_e_type(EPositioningType type);
+ EPositioningType get_positioning_e_type() const;
- void set_minimum_feedrate(float feedrate_mm_sec);
- float get_minimum_feedrate() const;
+ void add_additional_time(float timeSec);
+ void set_additional_time(float timeSec);
+ float get_additional_time() const;
- void set_minimum_travel_feedrate(float feedrate_mm_sec);
- float get_minimum_travel_feedrate() const;
+ void set_default();
- void set_dialect(EDialect dialect);
- EDialect get_dialect() const;
+ // Call this method before to start adding lines using add_gcode_line() when reusing an instance of GCodeTimeEstimator
+ void reset();
- void set_units(EUnits units);
- EUnits get_units() const;
+ // Returns the estimated time, in seconds
+ float get_time() const;
- void set_positioning_xyz_type(EPositioningType type);
- EPositioningType get_positioning_xyz_type() const;
+ // Returns the estimated time, in format HHh MMm SSs
+ std::string get_time_hms() const;
- void set_positioning_e_type(EPositioningType type);
- EPositioningType get_positioning_e_type() const;
+ private:
+ void _reset();
- void add_additional_time(float timeSec);
- void set_additional_time(float timeSec);
- float get_additional_time() const;
+ // Calculates the time estimate
+ void _calculate_time();
- void set_default();
+ // Processes the given gcode line
+ void _process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line);
- // Call this method before to start adding lines using add_gcode_line() when reusing an instance of GCodeTimeEstimator
- void reset();
+ // Move
+ void _processG1(const GCodeReader::GCodeLine& line);
- // Returns the estimated time, in seconds
- float get_time() const;
+ // Dwell
+ void _processG4(const GCodeReader::GCodeLine& line);
- // Returns the estimated time, in format HHh MMm SSs
- std::string get_time_hms() const;
+ // Set Units to Inches
+ void _processG20(const GCodeReader::GCodeLine& line);
- private:
- void _reset();
+ // Set Units to Millimeters
+ void _processG21(const GCodeReader::GCodeLine& line);
- // Calculates the time estimate
- void _calculate_time();
+ // Move to Origin (Home)
+ void _processG28(const GCodeReader::GCodeLine& line);
- // Processes the given gcode line
- void _process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line);
+ // Set to Absolute Positioning
+ void _processG90(const GCodeReader::GCodeLine& line);
- // Move
- void _processG1(const GCodeReader::GCodeLine& line);
+ // Set to Relative Positioning
+ void _processG91(const GCodeReader::GCodeLine& line);
- // Dwell
- void _processG4(const GCodeReader::GCodeLine& line);
+ // Set Position
+ void _processG92(const GCodeReader::GCodeLine& line);
- // Set Units to Inches
- void _processG20(const GCodeReader::GCodeLine& line);
+ // Sleep or Conditional stop
+ void _processM1(const GCodeReader::GCodeLine& line);
- // Set Units to Millimeters
- void _processG21(const GCodeReader::GCodeLine& line);
+ // Set extruder to absolute mode
+ void _processM82(const GCodeReader::GCodeLine& line);
- // Move to Origin (Home)
- void _processG28(const GCodeReader::GCodeLine& line);
+ // Set extruder to relative mode
+ void _processM83(const GCodeReader::GCodeLine& line);
- // Set to Absolute Positioning
- void _processG90(const GCodeReader::GCodeLine& line);
+ // Set Extruder Temperature and Wait
+ void _processM109(const GCodeReader::GCodeLine& line);
- // Set to Relative Positioning
- void _processG91(const GCodeReader::GCodeLine& line);
+ // Set max printing acceleration
+ void _processM201(const GCodeReader::GCodeLine& line);
- // Set Position
- void _processG92(const GCodeReader::GCodeLine& line);
+ // Set maximum feedrate
+ void _processM203(const GCodeReader::GCodeLine& line);
- // Set extruder to absolute mode
- void _processM82(const GCodeReader::GCodeLine& line);
+ // Set default acceleration
+ void _processM204(const GCodeReader::GCodeLine& line);
- // Set extruder to relative mode
- void _processM83(const GCodeReader::GCodeLine& line);
+ // Advanced settings
+ void _processM205(const GCodeReader::GCodeLine& line);
- // Set Extruder Temperature and Wait
- void _processM109(const GCodeReader::GCodeLine& line);
+ // Set extrude factor override percentage
+ void _processM221(const GCodeReader::GCodeLine& line);
- // Set max printing acceleration
- void _processM201(const GCodeReader::GCodeLine& line);
+ // Set allowable instantaneous speed change
+ void _processM566(const GCodeReader::GCodeLine& line);
- // Set maximum feedrate
- void _processM203(const GCodeReader::GCodeLine& line);
+ // Simulates firmware st_synchronize() call
+ void _simulate_st_synchronize();
- // Set default acceleration
- void _processM204(const GCodeReader::GCodeLine& line);
+ void _forward_pass();
+ void _reverse_pass();
- // Advanced settings
- void _processM205(const GCodeReader::GCodeLine& line);
+ void _planner_forward_pass_kernel(Block& prev, Block& curr);
+ void _planner_reverse_pass_kernel(Block& curr, Block& next);
- // Set allowable instantaneous speed change
- void _processM566(const GCodeReader::GCodeLine& line);
-
- void _forward_pass();
- void _reverse_pass();
-
- void _planner_forward_pass_kernel(Block* prev, Block* curr);
- void _planner_reverse_pass_kernel(Block* curr, Block* next);
-
- void _recalculate_trapezoids();
- };
+ void _recalculate_trapezoids();
+ };
} /* namespace Slic3r */