diff options
Diffstat (limited to 'xs/src/libslic3r/GCodeReader.cpp')
-rw-r--r-- | xs/src/libslic3r/GCodeReader.cpp | 221 |
1 files changed, 164 insertions, 57 deletions
diff --git a/xs/src/libslic3r/GCodeReader.cpp b/xs/src/libslic3r/GCodeReader.cpp index 453cc9f94..86009fb0f 100644 --- a/xs/src/libslic3r/GCodeReader.cpp +++ b/xs/src/libslic3r/GCodeReader.cpp @@ -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); + } + 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()); } - this->args[arg] = value; + m_axis[axis] = new_value; + m_mask |= 1 << int(axis); } } |