169 lines
7.1 KiB
C++
169 lines
7.1 KiB
C++
#ifndef slic3r_GCodeReader_hpp_
|
|
#define slic3r_GCodeReader_hpp_
|
|
|
|
#include "libslic3r.h"
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
#include <functional>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include "PrintConfig.hpp"
|
|
|
|
namespace Slic3r {
|
|
|
|
class GCodeReader {
|
|
public:
|
|
class GCodeLine {
|
|
public:
|
|
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_view cmd() const {
|
|
const char *cmd = GCodeReader::skip_whitespaces(m_raw.c_str());
|
|
return std::string_view(cmd, GCodeReader::skip_word(cmd) - cmd);
|
|
}
|
|
const std::string_view comment() const
|
|
{ size_t pos = m_raw.find(';'); return (pos == std::string::npos) ? std::string_view() : std::string_view(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(char axis) const;
|
|
bool has_value(char axis, float &value) const;
|
|
float new_X(const GCodeReader &reader) const { return this->has(X) ? this->x() : reader.x(); }
|
|
float new_Y(const GCodeReader &reader) const { return this->has(Y) ? this->y() : reader.y(); }
|
|
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 {
|
|
const char *cmd = GCodeReader::skip_whitespaces(m_raw.c_str());
|
|
size_t len = strlen(cmd_test);
|
|
return strncmp(cmd, cmd_test, len) == 0 && GCodeReader::is_end_of_word(cmd[len]);
|
|
}
|
|
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); }
|
|
bool has_unknown_axis() const { return this->has(UNKNOWN_AXIS); }
|
|
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;
|
|
|
|
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);
|
|
|
|
template<typename Callback>
|
|
void parse_buffer(const std::string &buffer, Callback callback)
|
|
{
|
|
const char *ptr = buffer.c_str();
|
|
GCodeLine gline;
|
|
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
|
m_parsing = true;
|
|
while (m_parsing && *ptr != 0) {
|
|
#else
|
|
while (*ptr != 0) {
|
|
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
|
gline.reset();
|
|
ptr = this->parse_line(ptr, gline, callback);
|
|
}
|
|
}
|
|
|
|
void parse_buffer(const std::string &buffer)
|
|
{ this->parse_buffer(buffer, [](GCodeReader&, const GCodeReader::GCodeLine&){}); }
|
|
|
|
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);
|
|
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
|
void quit_parsing() { m_parsing = false; }
|
|
#else
|
|
void quit_parsing_file() { m_parsing_file = false; }
|
|
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
|
|
|
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; }
|
|
void set_extrusion_axis(char axis) { m_extrusion_axis = 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);
|
|
|
|
static bool is_whitespace(char c) { return c == ' ' || c == '\t'; }
|
|
static bool is_end_of_line(char c) { return c == '\r' || c == '\n' || c == 0; }
|
|
static bool is_end_of_gcode_line(char c) { return c == ';' || is_end_of_line(c); }
|
|
static bool is_end_of_word(char c) { return is_whitespace(c) || is_end_of_gcode_line(c); }
|
|
static const char* skip_whitespaces(const char *c) {
|
|
for (; is_whitespace(*c); ++ c)
|
|
; // silence -Wempty-body
|
|
return c;
|
|
}
|
|
static const char* skip_word(const char *c) {
|
|
for (; ! is_end_of_word(*c); ++ c)
|
|
; // silence -Wempty-body
|
|
return c;
|
|
}
|
|
|
|
GCodeConfig m_config;
|
|
char m_extrusion_axis;
|
|
float m_position[NUM_AXES];
|
|
bool m_verbose;
|
|
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
|
bool m_parsing{ false };
|
|
#else
|
|
bool m_parsing_file{ false };
|
|
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
|
};
|
|
|
|
} /* namespace Slic3r */
|
|
|
|
#endif /* slic3r_GCodeReader_hpp_ */
|