Optimized the GCodeReader.

Fixed the profiling build.
This commit is contained in:
bubnikv 2018-01-03 17:29:49 +01:00
parent 0e4ecfaf56
commit b292554fd8
11 changed files with 396 additions and 218 deletions

View File

@ -349,8 +349,8 @@ if(APPLE)
target_link_libraries(XS "-undefined dynamic_lookup")
endif()
target_link_libraries(XS libslic3r libslic3r_gui admesh clipper nowide polypartition poly2tri)
if(SLIC3R_DEBUG)
target_link_libraries(Shiny)
if(SLIC3R_PROFILE)
target_link_libraries(XS Shiny)
endif()
# Add the OpenGL and GLU libraries.
@ -393,7 +393,7 @@ endif ()
if (SLIC3R_PROFILE)
message("Slic3r will be built with a Shiny invasive profiler")
target_compile_definitions(XS PRIVATE -DSLIC3R_PROFILE)
add_definitions(-DSLIC3R_PROFILE)
endif ()
if (SLIC3R_HAS_BROKEN_CROAK)
@ -552,7 +552,7 @@ endif()
add_executable(slic3r ${PROJECT_SOURCE_DIR}/src/slic3r.cpp)
target_include_directories(XS PRIVATE src src/libslic3r)
target_link_libraries(slic3r libslic3r libslic3r_gui admesh ${Boost_LIBRARIES} clipper ${EXPAT_LIBRARIES} ${GLEW_LIBRARIES} polypartition poly2tri ${TBB_LIBRARIES} ${wxWidgets_LIBRARIES})
if(SLIC3R_DEBUG)
if(SLIC3R_PROFILE)
target_link_libraries(Shiny)
endif()
if (APPLE)

View File

@ -90,8 +90,8 @@ ShinyNode* _ShinyManager_dummyNodeTable[] = { NULL };
/* primary hash function */
SHINY_INLINE uint32_t hash_value(void* a_pParent, void* a_pZone) {
// uint32_t a = (uint32_t) a_pParent + (uint32_t) a_pZone;
uint32_t a = *reinterpret_cast<uint32_t*>(&a_pParent) + *reinterpret_cast<uint32_t*>(&a_pZone);
uint32_t a = (uint32_t) a_pParent + (uint32_t) a_pZone;
// uint32_t a = *reinterpret_cast<uint32_t*>(&a_pParent) + *reinterpret_cast<uint32_t*>(&a_pZone);
a = (a+0x7ed55d16) + (a<<12);
a = (a^0xc761c23c) ^ (a>>19);

View File

@ -20,6 +20,8 @@
#include "SVG.hpp"
#include <Shiny/Shiny.h>
#if 0
// Enable debugging and asserts, even in the release build.
#define DEBUG
@ -348,6 +350,8 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
void GCode::do_export(Print *print, const char *path)
{
PROFILE_CLEAR();
// Remove the old g-code if it exists.
boost::nowide::remove(path);
@ -384,10 +388,16 @@ void GCode::do_export(Print *print, const char *path)
throw std::runtime_error(
std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' +
"Is " + path_tmp + " locked?" + '\n');
// Write the profiler measurements to file
PROFILE_UPDATE();
PROFILE_OUTPUT(debug_out_path("gcode-export-profile.txt").c_str());
}
void GCode::_do_export(Print &print, FILE *file)
{
PROFILE_FUNC();
// resets time estimator
m_time_estimator.reset();
@ -1987,44 +1997,41 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
return gcode;
}
void GCode::_write(FILE* file, const std::string& what)
void GCode::_write(FILE* file, const char *what, size_t size)
{
if (!what.empty()) {
if (size > 0) {
// writes string to file
fwrite(what.data(), 1, what.size(), file);
fwrite(what, 1, size, file);
// updates time estimator and gcode lines vector
const char endLine = '\n';
std::string::size_type beginPos = 0;
std::string::size_type endPos = what.find_first_of(endLine, beginPos);
while (endPos != std::string::npos) {
std::string line = what.substr(beginPos, endPos - beginPos + 1);
m_time_estimator.add_gcode_line(line);
beginPos = endPos + 1;
endPos = what.find_first_of(endLine, beginPos);
}
m_time_estimator.add_gcode_block(what);
}
}
void GCode::_writeln(FILE* file, const std::string& what)
void GCode::_writeln(FILE* file, const std::string &what)
{
if (!what.empty()) {
if (what.back() != '\n')
_write_format(file, "%s\n", what.c_str());
else
_write(file, what);
}
if (! what.empty())
_write(file, (what.back() == '\n') ? what : (what + '\n'));
}
void GCode::_write_format(FILE* file, const char* format, ...)
{
char buffer[1024];
va_list args;
va_start(args, format);
int res = ::vsnprintf(buffer, 1024, format, args);
int buflen =
#ifdef _MSC_VER
_vscprintf(format, args);
#else
vsnprintf(nullptr, 0, format, args);
#endif
char buffer[1024];
bool buffer_dynamic = buflen > 1024;
char *bufptr = buffer_dynamic ? (char*)malloc(buflen) : buffer;
int res = ::vsnprintf(bufptr, buflen, format, args);
if (res >= 0 && bufptr[0] != 0)
_write(file, bufptr, buflen);
va_end(args);
if (res >= 0)
_writeln(file, buffer);
if (buffer_dynamic)
free(bufptr);
}
std::string GCode::_extrude(const ExtrusionPath &path, std::string description, double speed)

View File

@ -278,7 +278,8 @@ protected:
GCodeTimeEstimator m_time_estimator;
// Write a string into a file.
void _write(FILE* file, const std::string& what);
void _write(FILE* file, const std::string& what) { this->_write(file, what.c_str(), what.size()); }
void _write(FILE* file, const char *what, size_t size);
// Write a string into a file.
// Add a newline, if the string does not end with a newline already.

View File

@ -4,17 +4,7 @@
namespace Slic3r {
std::string
_format_z(float z)
{
std::ostringstream ss;
ss << std::fixed << std::setprecision(3)
<< z;
return ss.str();
}
std::string
SpiralVase::process_layer(const std::string &gcode)
std::string SpiralVase::process_layer(const std::string &gcode)
{
/* This post-processor relies on several assumptions:
- all layers are processed through it, including those that are not supposed
@ -38,16 +28,17 @@ SpiralVase::process_layer(const std::string &gcode)
bool set_z = false;
{
//FIXME Performance warning: This copies the GCodeConfig of the reader.
GCodeReader r = this->_reader; // clone
r.parse(gcode, [&total_layer_length, &layer_height, &z, &set_z]
(GCodeReader &, const GCodeReader::GCodeLine &line) {
if (line.cmd == "G1") {
if (line.extruding()) {
total_layer_length += line.dist_XY();
} else if (line.has('Z')) {
layer_height += line.dist_Z();
(GCodeReader &reader, const GCodeReader::GCodeLine &line) {
if (line.cmd_is("G1")) {
if (line.extruding(reader)) {
total_layer_length += line.dist_XY(reader);
} else if (line.has(Z)) {
layer_height += line.dist_Z(reader);
if (!set_z) {
z = line.new_Z();
z = line.new_Z(reader);
set_z = true;
}
}
@ -60,22 +51,22 @@ SpiralVase::process_layer(const std::string &gcode)
std::string new_gcode;
this->_reader.parse(gcode, [&new_gcode, &z, &layer_height, &total_layer_length]
(GCodeReader &, GCodeReader::GCodeLine line) {
if (line.cmd == "G1") {
if (line.has('Z')) {
(GCodeReader &reader, GCodeReader::GCodeLine line) {
if (line.cmd_is("G1")) {
if (line.has_z()) {
// If this is the initial Z move of the layer, replace it with a
// (redundant) move to the last Z of previous layer.
line.set('Z', _format_z(z));
new_gcode += line.raw + '\n';
line.set(reader, Z, z);
new_gcode += line.raw() + '\n';
return;
} else {
float dist_XY = line.dist_XY();
float dist_XY = line.dist_XY(reader);
if (dist_XY > 0) {
// horizontal move
if (line.extruding()) {
if (line.extruding(reader)) {
z += dist_XY * layer_height / total_layer_length;
line.set('Z', _format_z(z));
new_gcode += line.raw + '\n';
line.set(reader, Z, z);
new_gcode += line.raw() + '\n';
}
return;
@ -87,7 +78,7 @@ SpiralVase::process_layer(const std::string &gcode)
}
}
}
new_gcode += line.raw + '\n';
new_gcode += line.raw() + '\n';
});
return new_gcode;

View File

@ -13,7 +13,7 @@ class SpiralVase {
SpiralVase(const PrintConfig &config)
: enable(false), _config(&config)
{
this->_reader.Z = this->_config->z_offset;
this->_reader.z() = this->_config->z_offset;
this->_reader.apply_config(*this->_config);
};
std::string process_layer(const std::string &gcode);

View File

@ -4,6 +4,8 @@
#include <fstream>
#include <iostream>
#include <Shiny/Shiny.h>
namespace Slic3r {
void GCodeReader::apply_config(const GCodeConfig &config)
@ -26,58 +28,121 @@ void GCodeReader::parse(const std::string &gcode, callback_t callback)
this->parse_line(line, callback);
}
void GCodeReader::parse_line(std::string line, callback_t callback)
static inline bool is_whitespace(char c)
{
GCodeLine gline(this);
gline.raw = line;
if (this->verbose)
std::cout << line << std::endl;
// strip comment
{
size_t pos = line.find(';');
if (pos != std::string::npos) {
gline.comment = line.substr(pos+1);
line.erase(pos);
}
}
return c == ' ' || c == '\t';
}
static inline bool is_end_of_line(char c)
{
return c == '\r' || c == '\n' || c == 0;
}
static inline bool is_end_of_gcode_line(char c)
{
return c == ';' || is_end_of_line(c);
}
static inline bool is_end_of_word(char c)
{
return is_whitespace(c) || is_end_of_gcode_line(c);
}
static inline const char* skip_whitespaces(const char *c)
{
for (; is_whitespace(*c); ++ c);
return c;
}
static inline const char* skip_word(const char *c)
{
for (; ! is_end_of_word(*c); ++ c);
return c;
}
const char* GCodeReader::parse_line_internal(const char *ptr, GCodeLine &gline, std::pair<const char*, const char*> &command)
{
PROFILE_FUNC();
// command and args
const char *c = ptr;
{
std::vector<std::string> args;
boost::split(args, line, boost::is_any_of(" "));
// first one is cmd
gline.cmd = args.front();
args.erase(args.begin());
for (std::string &arg : args) {
if (arg.size() < 2) continue;
gline.args.insert(std::make_pair(arg[0], arg.substr(1)));
PROFILE_BLOCK(command_and_args);
// Skip the whitespaces.
command.first = skip_whitespaces(c);
// Skip the command.
c = command.second = skip_word(command.first);
// Up to the end of line or comment.
while (! is_end_of_gcode_line(*c)) {
// Skip whitespaces.
c = skip_whitespaces(c);
if (is_end_of_gcode_line(*c))
break;
// Check the name of the axis.
Axis axis = NUM_AXES;
switch (*c) {
case 'X': axis = X; break;
case 'Y': axis = Y; break;
case 'Z': axis = Z; break;
case 'F': axis = F; break;
default:
if (*c == m_extrusion_axis)
axis = E;
break;
}
if (axis != NUM_AXES) {
// Try to parse the numeric value.
char *pend = nullptr;
double v = strtod(++ c, &pend);
if (pend != nullptr && is_end_of_word(*pend)) {
// The axis value has been parsed correctly.
gline.m_axis[int(axis)] = float(v);
gline.m_mask |= 1 << int(axis);
c = pend;
} else
// Skip the rest of the word.
c = skip_word(c);
} else
// Skip the rest of the word.
c = skip_word(c);
}
}
// convert extrusion axis
if (m_extrusion_axis != 'E') {
const auto it = gline.args.find(m_extrusion_axis);
if (it != gline.args.end()) {
std::swap(gline.args['E'], it->second);
gline.args.erase(it);
}
if (gline.has(E) && m_config.use_relative_e_distances)
m_position[E] = 0;
// Skip the rest of the line.
for (; ! is_end_of_line(*c); ++ c);
// Copy the raw string including the comment, without the trailing newlines.
if (c > ptr) {
PROFILE_BLOCK(copy_raw_string);
gline.m_raw.assign(ptr, c);
}
if (gline.has('E') && m_config.use_relative_e_distances)
this->E = 0;
if (callback) callback(*this, gline);
// update coordinates
if (gline.cmd == "G0" || gline.cmd == "G1" || gline.cmd == "G92") {
this->X = gline.new_X();
this->Y = gline.new_Y();
this->Z = gline.new_Z();
this->E = gline.new_E();
this->F = gline.new_F();
// Skip the trailing newlines.
if (*c == '\r')
++ c;
if (*c == '\n')
++ c;
if (m_verbose)
std::cout << gline.m_raw << std::endl;
return c;
}
void GCodeReader::update_coordinates(GCodeLine &gline, std::pair<const char*, const char*> &command)
{
PROFILE_FUNC();
if (*command.first == 'G') {
int cmd_len = int(command.second - command.first);
if ((cmd_len == 2 && (command.first[1] == '0' || command.first[1] == '1')) ||
(cmd_len == 3 && command.first[1] == '9' && command.first[2] == '2')) {
for (size_t i = 0; i < NUM_AXES; ++ i)
if (gline.has(Axis(i)))
this->m_position[i] = gline.value(Axis(i));
}
}
}
@ -89,22 +154,64 @@ void GCodeReader::parse_file(const std::string &file, callback_t callback)
this->parse_line(line, callback);
}
void GCodeReader::GCodeLine::set(char arg, std::string value)
bool GCodeReader::GCodeLine::has_value(char axis, float &value) const
{
const std::string space(" ");
if (this->has(arg)) {
size_t pos = this->raw.find(space + arg)+2;
size_t end = this->raw.find(' ', pos+1);
this->raw = this->raw.replace(pos, end-pos, value);
} else {
size_t pos = this->raw.find(' ');
if (pos == std::string::npos) {
this->raw += space + arg + value;
} else {
this->raw = this->raw.replace(pos, 0, space + arg + value);
const char *c = m_raw.c_str();
// Skip the whitespaces.
c = skip_whitespaces(c);
// Skip the command.
c = skip_word(c);
// Up to the end of line or comment.
while (! is_end_of_gcode_line(*c)) {
// Skip whitespaces.
c = skip_whitespaces(c);
if (is_end_of_gcode_line(*c))
break;
// Check the name of the axis.
if (*c == axis) {
// Try to parse the numeric value.
char *pend = nullptr;
double v = strtod(++ c, &pend);
if (pend != nullptr && is_end_of_word(*pend)) {
// The axis value has been parsed correctly.
value = float(v);
return true;
}
}
// Skip the rest of the word.
c = skip_word(c);
}
this->args[arg] = value;
return false;
}
void GCodeReader::GCodeLine::set(const GCodeReader &reader, const Axis 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";
if (int(axis) < 3)
match[1] += int(axis);
else if (axis == F)
match[1] = 'F';
else {
assert(axis == E);
match[1] = reader.extrusion_axis();
}
if (this->has(axis)) {
size_t pos = m_raw.find(match)+2;
size_t end = m_raw.find(' ', pos+1);
m_raw = m_raw.replace(pos, end-pos, ss.str());
} else {
size_t pos = m_raw.find(' ');
if (pos == std::string::npos)
m_raw += std::string(match) + ss.str();
else
m_raw = m_raw.replace(pos, 0, std::string(match) + ss.str());
}
m_axis[axis] = new_value;
m_mask |= 1 << int(axis);
}
}

View File

@ -11,54 +11,104 @@
namespace Slic3r {
class GCodeReader {
public:
public:
class GCodeLine {
public:
GCodeReader* reader;
std::string raw;
std::string cmd;
std::string comment;
std::map<char,std::string> args;
GCodeLine(GCodeReader* _reader) : reader(_reader) {};
bool has(char arg) const { return this->args.count(arg) > 0; };
float get_float(char arg) const { return float(atof(this->args.at(arg).c_str())); };
float new_X() const { return this->has('X') ? float(atof(this->args.at('X').c_str())) : this->reader->X; };
float new_Y() const { return this->has('Y') ? float(atof(this->args.at('Y').c_str())) : this->reader->Y; };
float new_Z() const { return this->has('Z') ? float(atof(this->args.at('Z').c_str())) : this->reader->Z; };
float new_E() const { return this->has('E') ? float(atof(this->args.at('E').c_str())) : this->reader->E; };
float new_F() const { return this->has('F') ? float(atof(this->args.at('F').c_str())) : this->reader->F; };
float dist_X() const { return this->new_X() - this->reader->X; };
float dist_Y() const { return this->new_Y() - this->reader->Y; };
float dist_Z() const { return this->new_Z() - this->reader->Z; };
float dist_E() const { return this->new_E() - this->reader->E; };
float dist_XY() const {
float x = this->dist_X();
float y = this->dist_Y();
GCodeLine() { reset(); }
void reset() { m_mask = 0; memset(m_axis, 0, sizeof(m_axis)); m_raw.clear(); }
const std::string& raw() const { return m_raw; }
const std::string cmd() const
{ size_t pos = m_raw.find_first_of(" \t\n;"); return (pos == std::string::npos) ? m_raw : m_raw.substr(0, pos); }
const std::string comment() const
{ size_t pos = m_raw.find(';'); return (pos == std::string::npos) ? "" : m_raw.substr(pos + 1); }
bool has(Axis axis) const { return (m_mask & (1 << int(axis))) != 0; }
float value(Axis axis) const { return m_axis[axis]; }
bool has_value(char axis, float &value) const;
float new_Z(const GCodeReader &reader) const { return this->has(Z) ? this->z() : reader.z(); }
float new_E(const GCodeReader &reader) const { return this->has(E) ? this->e() : reader.e(); }
float new_F(const GCodeReader &reader) const { return this->has(F) ? this->f() : reader.f(); }
float dist_X(const GCodeReader &reader) const { return this->has(X) ? (this->x() - reader.x()) : 0; }
float dist_Y(const GCodeReader &reader) const { return this->has(Y) ? (this->y() - reader.y()) : 0; }
float dist_Z(const GCodeReader &reader) const { return this->has(Z) ? (this->z() - reader.z()) : 0; }
float dist_E(const GCodeReader &reader) const { return this->has(E) ? (this->e() - reader.e()) : 0; }
float dist_XY(const GCodeReader &reader) const {
float x = this->has(X) ? (this->x() - reader.x()) : 0;
float y = this->has(Y) ? (this->y() - reader.y()) : 0;
return sqrt(x*x + y*y);
};
bool extruding() const { return this->cmd == "G1" && this->dist_E() > 0; };
bool retracting() const { return this->cmd == "G1" && this->dist_E() < 0; };
bool travel() const { return this->cmd == "G1" && ! this->has('E'); };
void set(char arg, std::string value);
}
bool cmd_is(const char *cmd_test) const {
int len = strlen(cmd_test);
if (strncmp(m_raw.c_str(), cmd_test, len))
return false;
char c = m_raw.c_str()[len];
return c == 0 || c == ' ' || c == '\t' || c == ';';
}
bool extruding(const GCodeReader &reader) const { return this->cmd_is("G1") && this->dist_E(reader) > 0; }
bool retracting(const GCodeReader &reader) const { return this->cmd_is("G1") && this->dist_E(reader) < 0; }
bool travel() const { return this->cmd_is("G1") && ! this->has(E); }
void set(const GCodeReader &reader, const Axis axis, const float new_value, const int decimal_digits = 3);
bool has_x() const { return this->has(X); }
bool has_y() const { return this->has(Y); }
bool has_z() const { return this->has(Z); }
bool has_e() const { return this->has(E); }
bool has_f() const { return this->has(F); }
float x() const { return m_axis[X]; }
float y() const { return m_axis[Y]; }
float z() const { return m_axis[Z]; }
float e() const { return m_axis[E]; }
float f() const { return m_axis[F]; }
private:
std::string m_raw;
float m_axis[NUM_AXES];
uint32_t m_mask;
friend class GCodeReader;
};
typedef std::function<void(GCodeReader&, const GCodeLine&)> callback_t;
float X, Y, Z, E, F;
bool verbose;
callback_t callback;
GCodeReader() : X(0), Y(0), Z(0), E(0), F(0), verbose(false), m_extrusion_axis('E') {};
GCodeReader() : m_verbose(false), m_extrusion_axis('E') { memset(m_position, 0, sizeof(m_position)); }
void apply_config(const GCodeConfig &config);
void apply_config(const DynamicPrintConfig &config);
void parse(const std::string &gcode, callback_t callback);
void parse_line(std::string line, callback_t callback);
template<typename Callback>
const char* parse_line(const char *ptr, GCodeLine &gline, Callback &callback)
{
std::pair<const char*, const char*> cmd;
const char *end = parse_line_internal(ptr, gline, cmd);
callback(*this, gline);
update_coordinates(gline, cmd);
return end;
}
template<typename Callback>
void parse_line(const std::string &line, Callback &callback)
{ GCodeLine gline; this->parse_line(line.c_str(), gline, callback); }
void parse_file(const std::string &file, callback_t callback);
float& x() { return m_position[X]; }
float x() const { return m_position[X]; }
float& y() { return m_position[Y]; }
float y() const { return m_position[Y]; }
float& z() { return m_position[Z]; }
float z() const { return m_position[Z]; }
float& e() { return m_position[E]; }
float e() const { return m_position[E]; }
float& f() { return m_position[F]; }
float f() const { return m_position[F]; }
char extrusion_axis() const { return m_extrusion_axis; }
private:
const char* parse_line_internal(const char *ptr, GCodeLine &gline, std::pair<const char*, const char*> &command);
void update_coordinates(GCodeLine &gline, std::pair<const char*, const char*> &command);
GCodeConfig m_config;
char m_extrusion_axis;
char m_extrusion_axis;
float m_position[NUM_AXES];
bool m_verbose;
};
} /* namespace Slic3r */

View File

@ -4,7 +4,6 @@
#include <Shiny/Shiny.h>
static const std::string AXIS_STR = "XYZE";
static const float MMMIN_TO_MMSEC = 1.0f / 60.0f;
static const float MILLISEC_TO_SEC = 0.001f;
static const float INCHES_TO_MM = 25.4f;
@ -159,7 +158,9 @@ namespace Slic3r {
{
for (const std::string& line : gcode_lines)
{
_parser.parse_line(line, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
_parser.parse_line(line,
[this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
{ this->_process_gcode_line(reader, line); });
}
_calculate_time();
reset();
@ -168,7 +169,21 @@ namespace Slic3r {
void GCodeTimeEstimator::add_gcode_line(const std::string& gcode_line)
{
PROFILE_FUNC();
_parser.parse_line(gcode_line, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
_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;
for (; *ptr != 0;) {
gline.reset();
ptr = _parser.parse_line(ptr, gline,
[this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
{ this->_process_gcode_line(reader, line); });
}
}
void GCodeTimeEstimator::calculate_time()
@ -406,13 +421,14 @@ namespace Slic3r {
void GCodeTimeEstimator::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line)
{
PROFILE_FUNC();
if (line.cmd.length() > 1)
std::string cmd = line.cmd();
if (cmd.length() > 1)
{
switch (::toupper(line.cmd[0]))
switch (::toupper(cmd[0]))
{
case 'G':
{
switch (::atoi(&line.cmd[1]))
switch (::atoi(&cmd[1]))
{
case 1: // Move
{
@ -460,7 +476,7 @@ namespace Slic3r {
}
case 'M':
{
switch (::atoi(&line.cmd[1]))
switch (::atoi(&cmd[1]))
{
case 82: // Set extruder to absolute mode
{
@ -514,9 +530,9 @@ namespace Slic3r {
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(AXIS_STR[axis]))
if (lineG1.has(Slic3r::Axis(axis)))
{
float ret = lineG1.get_float(AXIS_STR[axis]) * lengthsScaleFactor;
float ret = lineG1.value(Slic3r::Axis(axis)) * lengthsScaleFactor;
return (type == GCodeTimeEstimator::Absolute) ? ret : current_absolute_position + ret;
}
else
@ -534,8 +550,8 @@ namespace Slic3r {
}
// updates feedrate from line, if present
if (line.has('F'))
set_feedrate(std::max(line.get_float('F') * MMMIN_TO_MMSEC, get_minimum_feedrate()));
if (line.has_f())
set_feedrate(std::max(line.f() * MMMIN_TO_MMSEC, get_minimum_feedrate()));
// fills block data
Block block;
@ -682,15 +698,16 @@ namespace Slic3r {
}
// adds block to blocks list
_blocks.push_back(block);
_blocks.emplace_back(block);
}
void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line)
{
EDialect dialect = get_dialect();
if (line.has('P'))
add_additional_time(line.get_float('P') * MILLISEC_TO_SEC);
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) ||
@ -698,8 +715,8 @@ namespace Slic3r {
(dialect == Smoothieware) ||
(dialect == RepRapFirmware))
{
if (line.has('S'))
add_additional_time(line.get_float('S'));
if (line.has_value('S', value))
add_additional_time(value);
}
}
@ -745,27 +762,27 @@ namespace Slic3r {
float lengthsScaleFactor = (get_units() == Inches) ? INCHES_TO_MM : 1.0f;
bool anyFound = false;
if (line.has('X'))
if (line.has_x())
{
set_axis_position(X, line.get_float('X') * lengthsScaleFactor);
set_axis_position(X, line.x() * lengthsScaleFactor);
anyFound = true;
}
if (line.has('Y'))
if (line.has_y())
{
set_axis_position(Y, line.get_float('Y') * lengthsScaleFactor);
set_axis_position(Y, line.y() * lengthsScaleFactor);
anyFound = true;
}
if (line.has('Z'))
if (line.has_z())
{
set_axis_position(Z, line.get_float('Z') * lengthsScaleFactor);
set_axis_position(Z, line.z() * lengthsScaleFactor);
anyFound = true;
}
if (line.has('E'))
if (line.has_e())
{
set_axis_position(E, line.get_float('E') * lengthsScaleFactor);
set_axis_position(E, line.e() * lengthsScaleFactor);
anyFound = true;
}
@ -790,17 +807,17 @@ namespace Slic3r {
// 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.get_float('X') * factor);
if (line.has_x())
set_axis_max_acceleration(X, line.x() * factor);
if (line.has('Y'))
set_axis_max_acceleration(Y, line.get_float('Y') * factor);
if (line.has_y())
set_axis_max_acceleration(Y, line.y() * factor);
if (line.has('Z'))
set_axis_max_acceleration(Z, line.get_float('Z') * factor);
if (line.has_z())
set_axis_max_acceleration(Z, line.z() * factor);
if (line.has('E'))
set_axis_max_acceleration(E, line.get_float('E') * factor);
if (line.has_e())
set_axis_max_acceleration(E, line.e() * factor);
}
void GCodeTimeEstimator::_processM203(const GCodeReader::GCodeLine& line)
@ -814,66 +831,68 @@ namespace Slic3r {
// 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.get_float('X') * factor);
if (line.has_x())
set_axis_max_feedrate(X, line.x() * factor);
if (line.has('Y'))
set_axis_max_feedrate(Y, line.get_float('Y') * factor);
if (line.has_y())
set_axis_max_feedrate(Y, line.y() * factor);
if (line.has('Z'))
set_axis_max_feedrate(Z, line.get_float('Z') * factor);
if (line.has_z())
set_axis_max_feedrate(Z, line.z() * factor);
if (line.has('E'))
set_axis_max_feedrate(E, line.get_float('E') * factor);
if (line.has_e())
set_axis_max_feedrate(E, line.e() * factor);
}
void GCodeTimeEstimator::_processM204(const GCodeReader::GCodeLine& line)
{
if (line.has('S'))
set_acceleration(line.get_float('S'));
float value;
if (line.has_value('S', value))
set_acceleration(value);
if (line.has('T'))
set_retract_acceleration(line.get_float('T'));
if (line.has_value('T', value))
set_retract_acceleration(value);
}
void GCodeTimeEstimator::_processM205(const GCodeReader::GCodeLine& line)
{
if (line.has('X'))
if (line.has_x())
{
float max_jerk = line.get_float('X');
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.get_float('Y'));
if (line.has_y())
set_axis_max_jerk(Y, line.y());
if (line.has('Z'))
set_axis_max_jerk(Z, line.get_float('Z'));
if (line.has_z())
set_axis_max_jerk(Z, line.z());
if (line.has('E'))
set_axis_max_jerk(E, line.get_float('E'));
if (line.has_e())
set_axis_max_jerk(E, line.e());
if (line.has('S'))
set_minimum_feedrate(line.get_float('S'));
float value;
if (line.has_value('S', value))
set_minimum_feedrate(value);
if (line.has('T'))
set_minimum_travel_feedrate(line.get_float('T'));
if (line.has_value('T', value))
set_minimum_travel_feedrate(value);
}
void GCodeTimeEstimator::_processM566(const GCodeReader::GCodeLine& line)
{
if (line.has('X'))
set_axis_max_jerk(X, line.get_float('X') * MMMIN_TO_MMSEC);
if (line.has_x())
set_axis_max_jerk(X, line.x() * MMMIN_TO_MMSEC);
if (line.has('Y'))
set_axis_max_jerk(Y, line.get_float('Y') * MMMIN_TO_MMSEC);
if (line.has_y())
set_axis_max_jerk(Y, line.y() * MMMIN_TO_MMSEC);
if (line.has('Z'))
set_axis_max_jerk(Z, line.get_float('Z') * 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.get_float('E') * MMMIN_TO_MMSEC);
if (line.has_e())
set_axis_max_jerk(E, line.e() * MMMIN_TO_MMSEC);
}
void GCodeTimeEstimator::_forward_pass()

View File

@ -183,6 +183,9 @@ namespace Slic3r {
// Adds the given gcode line
void add_gcode_line(const std::string& gcode_line);
void add_gcode_block(const char *ptr);
void add_gcode_block(const std::string &str) { this->add_gcode_block(str.c_str()); }
// Calculates the time estimate from the gcode lines added using add_gcode_line()
void calculate_time();

View File

@ -102,7 +102,7 @@ inline std::string debug_out_path(const char *name, ...)
namespace Slic3r {
enum Axis { X=0, Y, Z };
enum Axis { X=0, Y, Z, E, F, NUM_AXES };
template <class T>
inline void append_to(std::vector<T> &dst, const std::vector<T> &src)