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

View File

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

View File

@ -20,6 +20,8 @@
#include "SVG.hpp" #include "SVG.hpp"
#include <Shiny/Shiny.h>
#if 0 #if 0
// Enable debugging and asserts, even in the release build. // Enable debugging and asserts, even in the release build.
#define DEBUG #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) void GCode::do_export(Print *print, const char *path)
{ {
PROFILE_CLEAR();
// Remove the old g-code if it exists. // Remove the old g-code if it exists.
boost::nowide::remove(path); boost::nowide::remove(path);
@ -384,10 +388,16 @@ void GCode::do_export(Print *print, const char *path)
throw std::runtime_error( throw std::runtime_error(
std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' + std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' +
"Is " + path_tmp + " locked?" + '\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) void GCode::_do_export(Print &print, FILE *file)
{ {
PROFILE_FUNC();
// resets time estimator // resets time estimator
m_time_estimator.reset(); m_time_estimator.reset();
@ -1987,44 +1997,41 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
return gcode; 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 // writes string to file
fwrite(what.data(), 1, what.size(), file); fwrite(what, 1, size, file);
// updates time estimator and gcode lines vector // updates time estimator and gcode lines vector
const char endLine = '\n'; m_time_estimator.add_gcode_block(what);
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);
}
} }
} }
void GCode::_writeln(FILE* file, const std::string &what) void GCode::_writeln(FILE* file, const std::string &what)
{ {
if (!what.empty()) { if (! what.empty())
if (what.back() != '\n') _write(file, (what.back() == '\n') ? what : (what + '\n'));
_write_format(file, "%s\n", what.c_str());
else
_write(file, what);
}
} }
void GCode::_write_format(FILE* file, const char* format, ...) void GCode::_write_format(FILE* file, const char* format, ...)
{ {
char buffer[1024];
va_list args; va_list args;
va_start(args, format); 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); va_end(args);
if (buffer_dynamic)
if (res >= 0) free(bufptr);
_writeln(file, buffer);
} }
std::string GCode::_extrude(const ExtrusionPath &path, std::string description, double speed) std::string GCode::_extrude(const ExtrusionPath &path, std::string description, double speed)

View File

@ -278,7 +278,8 @@ protected:
GCodeTimeEstimator m_time_estimator; GCodeTimeEstimator m_time_estimator;
// Write a string into a file. // 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. // Write a string into a file.
// Add a newline, if the string does not end with a newline already. // Add a newline, if the string does not end with a newline already.

View File

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

View File

@ -13,7 +13,7 @@ class SpiralVase {
SpiralVase(const PrintConfig &config) SpiralVase(const PrintConfig &config)
: enable(false), _config(&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); this->_reader.apply_config(*this->_config);
}; };
std::string process_layer(const std::string &gcode); std::string process_layer(const std::string &gcode);

View File

@ -4,6 +4,8 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <Shiny/Shiny.h>
namespace Slic3r { namespace Slic3r {
void GCodeReader::apply_config(const GCodeConfig &config) 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); 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); return c == ' ' || c == '\t';
gline.raw = line; }
if (this->verbose)
std::cout << line << std::endl;
// strip comment static inline bool is_end_of_line(char c)
{ {
size_t pos = line.find(';'); return c == '\r' || c == '\n' || c == 0;
if (pos != std::string::npos) {
gline.comment = line.substr(pos+1);
line.erase(pos);
} }
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 // command and args
const char *c = ptr;
{ {
std::vector<std::string> args; PROFILE_BLOCK(command_and_args);
boost::split(args, line, boost::is_any_of(" ")); // Skip the whitespaces.
command.first = skip_whitespaces(c);
// first one is cmd // Skip the command.
gline.cmd = args.front(); c = command.second = skip_word(command.first);
args.erase(args.begin()); // Up to the end of line or comment.
while (! is_end_of_gcode_line(*c)) {
for (std::string &arg : args) { // Skip whitespaces.
if (arg.size() < 2) continue; c = skip_whitespaces(c);
gline.args.insert(std::make_pair(arg[0], arg.substr(1))); 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 (gline.has(E) && m_config.use_relative_e_distances)
if (m_extrusion_axis != 'E') { m_position[E] = 0;
const auto it = gline.args.find(m_extrusion_axis);
if (it != gline.args.end()) { // Skip the rest of the line.
std::swap(gline.args['E'], it->second); for (; ! is_end_of_line(*c); ++ c);
gline.args.erase(it);
} // 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) // Skip the trailing newlines.
this->E = 0; if (*c == '\r')
++ c;
if (*c == '\n')
++ c;
if (callback) callback(*this, gline); if (m_verbose)
std::cout << gline.m_raw << std::endl;
// update coordinates return c;
if (gline.cmd == "G0" || gline.cmd == "G1" || gline.cmd == "G92") { }
this->X = gline.new_X();
this->Y = gline.new_Y(); void GCodeReader::update_coordinates(GCodeLine &gline, std::pair<const char*, const char*> &command)
this->Z = gline.new_Z(); {
this->E = gline.new_E(); PROFILE_FUNC();
this->F = gline.new_F(); 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); 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(" "); const char *c = m_raw.c_str();
if (this->has(arg)) { // Skip the whitespaces.
size_t pos = this->raw.find(space + arg)+2; c = skip_whitespaces(c);
size_t end = this->raw.find(' ', pos+1); // Skip the command.
this->raw = this->raw.replace(pos, end-pos, value); c = skip_word(c);
} else { // Up to the end of line or comment.
size_t pos = this->raw.find(' '); while (! is_end_of_gcode_line(*c)) {
if (pos == std::string::npos) { // Skip whitespaces.
this->raw += space + arg + value; c = skip_whitespaces(c);
} else { if (is_end_of_gcode_line(*c))
this->raw = this->raw.replace(pos, 0, space + arg + value); 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;
} }
} }
this->args[arg] = value; // Skip the rest of the word.
c = skip_word(c);
}
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

@ -14,51 +14,101 @@ class GCodeReader {
public: public:
class GCodeLine { class GCodeLine {
public: public:
GCodeReader* reader; GCodeLine() { reset(); }
std::string raw; void reset() { m_mask = 0; memset(m_axis, 0, sizeof(m_axis)); m_raw.clear(); }
std::string cmd;
std::string comment;
std::map<char,std::string> args;
GCodeLine(GCodeReader* _reader) : reader(_reader) {}; 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(char arg) const { return this->args.count(arg) > 0; }; bool has(Axis axis) const { return (m_mask & (1 << int(axis))) != 0; }
float get_float(char arg) const { return float(atof(this->args.at(arg).c_str())); }; float value(Axis axis) const { return m_axis[axis]; }
float new_X() const { return this->has('X') ? float(atof(this->args.at('X').c_str())) : this->reader->X; }; bool has_value(char axis, float &value) const;
float new_Y() const { return this->has('Y') ? float(atof(this->args.at('Y').c_str())) : this->reader->Y; }; float new_Z(const GCodeReader &reader) const { return this->has(Z) ? this->z() : reader.z(); }
float new_Z() const { return this->has('Z') ? float(atof(this->args.at('Z').c_str())) : this->reader->Z; }; float new_E(const GCodeReader &reader) const { return this->has(E) ? this->e() : reader.e(); }
float new_E() const { return this->has('E') ? float(atof(this->args.at('E').c_str())) : this->reader->E; }; float new_F(const GCodeReader &reader) const { return this->has(F) ? this->f() : reader.f(); }
float new_F() const { return this->has('F') ? float(atof(this->args.at('F').c_str())) : this->reader->F; }; float dist_X(const GCodeReader &reader) const { return this->has(X) ? (this->x() - reader.x()) : 0; }
float dist_X() const { return this->new_X() - this->reader->X; }; float dist_Y(const GCodeReader &reader) const { return this->has(Y) ? (this->y() - reader.y()) : 0; }
float dist_Y() const { return this->new_Y() - this->reader->Y; }; float dist_Z(const GCodeReader &reader) const { return this->has(Z) ? (this->z() - reader.z()) : 0; }
float dist_Z() const { return this->new_Z() - this->reader->Z; }; float dist_E(const GCodeReader &reader) const { return this->has(E) ? (this->e() - reader.e()) : 0; }
float dist_E() const { return this->new_E() - this->reader->E; }; float dist_XY(const GCodeReader &reader) const {
float dist_XY() const { float x = this->has(X) ? (this->x() - reader.x()) : 0;
float x = this->dist_X(); float y = this->has(Y) ? (this->y() - reader.y()) : 0;
float y = this->dist_Y();
return sqrt(x*x + y*y); return sqrt(x*x + y*y);
}
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;
}; };
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);
};
typedef std::function<void(GCodeReader&, const GCodeLine&)> callback_t; typedef std::function<void(GCodeReader&, const GCodeLine&)> callback_t;
float X, Y, Z, E, F; GCodeReader() : m_verbose(false), m_extrusion_axis('E') { memset(m_position, 0, sizeof(m_position)); }
bool verbose;
callback_t callback;
GCodeReader() : X(0), Y(0), Z(0), E(0), F(0), verbose(false), m_extrusion_axis('E') {};
void apply_config(const GCodeConfig &config); void apply_config(const GCodeConfig &config);
void apply_config(const DynamicPrintConfig &config); void apply_config(const DynamicPrintConfig &config);
void parse(const std::string &gcode, callback_t callback); 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); 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: 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; GCodeConfig m_config;
char m_extrusion_axis; char m_extrusion_axis;
float m_position[NUM_AXES];
bool m_verbose;
}; };
} /* namespace Slic3r */ } /* namespace Slic3r */

View File

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

View File

@ -183,6 +183,9 @@ namespace Slic3r {
// Adds the given gcode line // Adds the given gcode line
void add_gcode_line(const std::string& 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() // Calculates the time estimate from the gcode lines added using add_gcode_line()
void calculate_time(); void calculate_time();

View File

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