Optimized the GCodeReader.
Fixed the profiling build.
This commit is contained in:
parent
0e4ecfaf56
commit
b292554fd8
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
return c == ' ' || c == '\t';
|
||||
}
|
||||
|
||||
// strip comment
|
||||
{
|
||||
size_t pos = line.find(';');
|
||||
if (pos != std::string::npos) {
|
||||
gline.comment = line.substr(pos+1);
|
||||
line.erase(pos);
|
||||
}
|
||||
}
|
||||
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;
|
||||
// Skip the trailing newlines.
|
||||
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
|
||||
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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,51 +14,101 @@ class GCodeReader {
|
||||
public:
|
||||
class GCodeLine {
|
||||
public:
|
||||
GCodeReader* reader;
|
||||
std::string raw;
|
||||
std::string cmd;
|
||||
std::string comment;
|
||||
std::map<char,std::string> args;
|
||||
GCodeLine() { reset(); }
|
||||
void reset() { m_mask = 0; memset(m_axis, 0, sizeof(m_axis)); m_raw.clear(); }
|
||||
|
||||
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; };
|
||||
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();
|
||||
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 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;
|
||||
|
||||
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;
|
||||
float m_position[NUM_AXES];
|
||||
bool m_verbose;
|
||||
};
|
||||
|
||||
} /* namespace Slic3r */
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user