GCodeWriter: published GCodeFormatter, made it more generic, so
it could be used outside of GCodeWriter. Ported the GCodeWriter::retract/deretract to GCodeFormatter.
This commit is contained in:
parent
fda8ef6fce
commit
e7591e6aa6
@ -1,7 +1,6 @@
|
||||
#include "GCodeWriter.hpp"
|
||||
#include "CustomGCode.hpp"
|
||||
#include <algorithm>
|
||||
#include <charconv>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
@ -11,15 +10,8 @@
|
||||
#include <boost/spirit/include/karma.hpp>
|
||||
#endif
|
||||
|
||||
#define XYZF_EXPORT_DIGITS 3
|
||||
#define E_EXPORT_DIGITS 5
|
||||
|
||||
#define FLAVOR_IS(val) this->config.gcode_flavor == val
|
||||
#define FLAVOR_IS_NOT(val) this->config.gcode_flavor != val
|
||||
#define COMMENT(comment) if (this->config.gcode_comments && !comment.empty()) gcode << " ; " << comment;
|
||||
#define PRECISION(val, precision) std::fixed << std::setprecision(precision) << (val)
|
||||
#define XYZF_NUM(val) PRECISION(val, XYZF_EXPORT_DIGITS)
|
||||
#define E_NUM(val) PRECISION(val, E_EXPORT_DIGITS)
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -261,115 +253,12 @@ std::string GCodeWriter::toolchange(unsigned int extruder_id)
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
class G1Writer {
|
||||
private:
|
||||
static constexpr const size_t buflen = 256;
|
||||
char buf[buflen];
|
||||
char *buf_end;
|
||||
std::to_chars_result ptr_err;
|
||||
|
||||
public:
|
||||
G1Writer() {
|
||||
this->buf[0] = 'G';
|
||||
this->buf[1] = '1';
|
||||
this->buf_end = this->buf + buflen;
|
||||
this->ptr_err.ptr = this->buf + 2;
|
||||
}
|
||||
|
||||
void emit_axis(const char axis, const double v, size_t digits) {
|
||||
assert(digits <= 6);
|
||||
static constexpr const std::array<int, 7> pow_10{1, 10, 100, 1000, 10000, 100000, 1000000};
|
||||
*ptr_err.ptr++ = ' '; *ptr_err.ptr++ = axis;
|
||||
|
||||
char *base_ptr = this->ptr_err.ptr;
|
||||
auto v_int = int64_t(std::round(v * pow_10[digits]));
|
||||
// Older stdlib on macOS doesn't support std::from_chars at all, so it is used boost::spirit::karma::generate instead of it.
|
||||
// That is a little bit slower than std::to_chars but not much.
|
||||
#ifdef __APPLE__
|
||||
boost::spirit::karma::generate(this->ptr_err.ptr, boost::spirit::karma::int_generator<int64_t>(), v_int);
|
||||
#else
|
||||
// this->buf_end minus 1 because we need space for adding the extra decimal point.
|
||||
this->ptr_err = std::to_chars(this->ptr_err.ptr, this->buf_end - 1, v_int);
|
||||
#endif
|
||||
size_t writen_digits = (this->ptr_err.ptr - base_ptr) - (v_int < 0 ? 1 : 0);
|
||||
if (writen_digits < digits) {
|
||||
// Number is smaller than 10^digits, so that we will pad it with zeros.
|
||||
size_t remaining_digits = digits - writen_digits;
|
||||
// Move all newly inserted chars by remaining_digits to allocate space for padding with zeros.
|
||||
for (char *from_ptr = this->ptr_err.ptr - 1, *to_ptr = from_ptr + remaining_digits; from_ptr >= this->ptr_err.ptr - writen_digits; --to_ptr, --from_ptr)
|
||||
*to_ptr = *from_ptr;
|
||||
|
||||
memset(this->ptr_err.ptr - writen_digits, '0', remaining_digits);
|
||||
this->ptr_err.ptr += remaining_digits;
|
||||
}
|
||||
|
||||
// Move all newly inserted chars by one to allocate space for a decimal point.
|
||||
for (char *to_ptr = this->ptr_err.ptr, *from_ptr = to_ptr - 1; from_ptr >= this->ptr_err.ptr - digits; --to_ptr, --from_ptr)
|
||||
*to_ptr = *from_ptr;
|
||||
|
||||
*(this->ptr_err.ptr - digits) = '.';
|
||||
for (size_t i = 0; i < digits; ++i) {
|
||||
if (*this->ptr_err.ptr != '0')
|
||||
break;
|
||||
this->ptr_err.ptr--;
|
||||
}
|
||||
if (*this->ptr_err.ptr == '.')
|
||||
this->ptr_err.ptr--;
|
||||
if ((this->ptr_err.ptr + 1) == base_ptr || *this->ptr_err.ptr == '-')
|
||||
*(++this->ptr_err.ptr) = '0';
|
||||
this->ptr_err.ptr++;
|
||||
}
|
||||
|
||||
void emit_xy(const Vec2d &point) {
|
||||
this->emit_axis('X', point.x(), XYZF_EXPORT_DIGITS);
|
||||
this->emit_axis('Y', point.y(), XYZF_EXPORT_DIGITS);
|
||||
}
|
||||
|
||||
void emit_xyz(const Vec3d &point) {
|
||||
this->emit_axis('X', point.x(), XYZF_EXPORT_DIGITS);
|
||||
this->emit_axis('Y', point.y(), XYZF_EXPORT_DIGITS);
|
||||
this->emit_z(point.z());
|
||||
}
|
||||
|
||||
void emit_z(const double z) {
|
||||
this->emit_axis('Z', z, XYZF_EXPORT_DIGITS);
|
||||
}
|
||||
|
||||
void emit_e(const std::string &axis, double v) {
|
||||
if (! axis.empty()) {
|
||||
// not gcfNoExtrusion
|
||||
this->emit_axis(axis[0], v, E_EXPORT_DIGITS);
|
||||
}
|
||||
}
|
||||
|
||||
void emit_f(double speed) {
|
||||
this->emit_axis('F', speed, XYZF_EXPORT_DIGITS);
|
||||
}
|
||||
|
||||
void emit_string(const std::string &s) {
|
||||
strncpy(ptr_err.ptr, s.c_str(), s.size());
|
||||
ptr_err.ptr += s.size();
|
||||
}
|
||||
|
||||
void emit_comment(bool allow_comments, const std::string &comment) {
|
||||
if (allow_comments && ! comment.empty()) {
|
||||
*ptr_err.ptr ++ = ' '; *ptr_err.ptr ++ = ';'; *ptr_err.ptr ++ = ' ';
|
||||
this->emit_string(comment);
|
||||
}
|
||||
}
|
||||
|
||||
std::string string() {
|
||||
*ptr_err.ptr ++ = '\n';
|
||||
return std::string(this->buf, ptr_err.ptr - buf);
|
||||
}
|
||||
};
|
||||
|
||||
std::string GCodeWriter::set_speed(double F, const std::string &comment, const std::string &cooling_marker) const
|
||||
{
|
||||
assert(F > 0.);
|
||||
assert(F < 100000.);
|
||||
|
||||
G1Writer w;
|
||||
auto w = GCodeFormatter::G1();
|
||||
w.emit_f(F);
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
w.emit_string(cooling_marker);
|
||||
@ -381,7 +270,7 @@ std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string &com
|
||||
m_pos(0) = point(0);
|
||||
m_pos(1) = point(1);
|
||||
|
||||
G1Writer w;
|
||||
auto w = GCodeFormatter::G1();
|
||||
w.emit_xy(point);
|
||||
w.emit_f(this->config.travel_speed.value * 60.0);
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
@ -414,7 +303,7 @@ std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &co
|
||||
m_lifted = 0;
|
||||
m_pos = point;
|
||||
|
||||
G1Writer w;
|
||||
auto w = GCodeFormatter::G1();
|
||||
w.emit_xyz(point);
|
||||
w.emit_f(this->config.travel_speed.value * 60.0);
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
@ -448,7 +337,7 @@ std::string GCodeWriter::_travel_to_z(double z, const std::string &comment)
|
||||
if (speed == 0.)
|
||||
speed = this->config.travel_speed.value;
|
||||
|
||||
G1Writer w;
|
||||
auto w = GCodeFormatter::G1();
|
||||
w.emit_z(z);
|
||||
w.emit_f(speed * 60.0);
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
@ -473,7 +362,7 @@ std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std:
|
||||
m_pos(1) = point(1);
|
||||
m_extruder->extrude(dE);
|
||||
|
||||
G1Writer w;
|
||||
auto w = GCodeFormatter::G1();
|
||||
w.emit_xy(point);
|
||||
w.emit_e(m_extrusion_axis, m_extruder->E());
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
@ -486,7 +375,7 @@ std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std
|
||||
m_lifted = 0;
|
||||
m_extruder->extrude(dE);
|
||||
|
||||
G1Writer w;
|
||||
auto w = GCodeFormatter::G1();
|
||||
w.emit_xyz(point);
|
||||
w.emit_e(m_extrusion_axis, m_extruder->E());
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
@ -517,12 +406,11 @@ std::string GCodeWriter::retract_for_toolchange(bool before_wipe)
|
||||
|
||||
std::string GCodeWriter::_retract(double length, double restart_extra, const std::string &comment)
|
||||
{
|
||||
std::ostringstream gcode;
|
||||
|
||||
/* If firmware retraction is enabled, we use a fake value of 1
|
||||
since we ignore the actual configured retract_length which
|
||||
might be 0, in which case the retraction logic gets skipped. */
|
||||
if (this->config.use_firmware_retraction) length = 1;
|
||||
if (this->config.use_firmware_retraction)
|
||||
length = 1;
|
||||
|
||||
// If we use volumetric E values we turn lengths into volumes */
|
||||
if (this->config.use_volumetric_e) {
|
||||
@ -532,52 +420,48 @@ std::string GCodeWriter::_retract(double length, double restart_extra, const std
|
||||
restart_extra = restart_extra * area;
|
||||
}
|
||||
|
||||
double dE = m_extruder->retract(length, restart_extra);
|
||||
if (dE != 0) {
|
||||
|
||||
std::string gcode;
|
||||
if (double dE = m_extruder->retract(length, restart_extra); dE != 0) {
|
||||
if (this->config.use_firmware_retraction) {
|
||||
if (FLAVOR_IS(gcfMachinekit))
|
||||
gcode << "G22 ; retract\n";
|
||||
else
|
||||
gcode << "G10 ; retract\n";
|
||||
gcode = FLAVOR_IS(gcfMachinekit) ? "G22 ; retract\n" : "G10 ; retract\n";
|
||||
} else if (! m_extrusion_axis.empty()) {
|
||||
gcode << "G1 " << m_extrusion_axis << E_NUM(m_extruder->E())
|
||||
<< " F" << XYZF_NUM(m_extruder->retract_speed() * 60.);
|
||||
COMMENT(comment);
|
||||
gcode << "\n";
|
||||
auto w = GCodeFormatter::G1();
|
||||
w.emit_e(m_extrusion_axis, m_extruder->E());
|
||||
w.emit_f(m_extruder->retract_speed() * 60.);
|
||||
w.emit_comment(this->config.gcode_comments, comment);
|
||||
gcode = w.string();
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAVOR_IS(gcfMakerWare))
|
||||
gcode << "M103 ; extruder off\n";
|
||||
|
||||
return gcode.str();
|
||||
gcode += "M103 ; extruder off\n";
|
||||
|
||||
return gcode;
|
||||
}
|
||||
|
||||
std::string GCodeWriter::unretract()
|
||||
{
|
||||
std::ostringstream gcode;
|
||||
std::string gcode;
|
||||
|
||||
if (FLAVOR_IS(gcfMakerWare))
|
||||
gcode << "M101 ; extruder on\n";
|
||||
gcode = "M101 ; extruder on\n";
|
||||
|
||||
double dE = m_extruder->unretract();
|
||||
if (dE != 0) {
|
||||
if (double dE = m_extruder->unretract(); dE != 0) {
|
||||
if (this->config.use_firmware_retraction) {
|
||||
if (FLAVOR_IS(gcfMachinekit))
|
||||
gcode << "G23 ; unretract\n";
|
||||
else
|
||||
gcode << "G11 ; unretract\n";
|
||||
gcode << this->reset_e();
|
||||
gcode += FLAVOR_IS(gcfMachinekit) ? "G23 ; unretract\n" : "G11 ; unretract\n";
|
||||
gcode += this->reset_e();
|
||||
} else if (! m_extrusion_axis.empty()) {
|
||||
// use G1 instead of G0 because G0 will blend the restart with the previous travel move
|
||||
gcode << "G1 " << m_extrusion_axis << E_NUM(m_extruder->E())
|
||||
<< " F" << XYZF_NUM(m_extruder->deretract_speed() * 60.);
|
||||
if (this->config.gcode_comments) gcode << " ; unretract";
|
||||
gcode << "\n";
|
||||
auto w = GCodeFormatter::G1();
|
||||
w.emit_e(m_extrusion_axis, m_extruder->E());
|
||||
w.emit_f(m_extruder->deretract_speed() * 60.);
|
||||
w.emit_comment(this->config.gcode_comments, " ; unretract");
|
||||
gcode += w.string();
|
||||
}
|
||||
}
|
||||
|
||||
return gcode.str();
|
||||
return gcode;
|
||||
}
|
||||
|
||||
/* If this method is called more than once before calling unlift(),
|
||||
@ -649,4 +533,49 @@ std::string GCodeWriter::set_fan(unsigned int speed) const
|
||||
return GCodeWriter::set_fan(this->config.gcode_flavor, this->config.gcode_comments, speed);
|
||||
}
|
||||
|
||||
|
||||
void GCodeFormatter::emit_axis(const char axis, const double v, size_t digits) {
|
||||
assert(digits <= 6);
|
||||
static constexpr const std::array<int, 7> pow_10{1, 10, 100, 1000, 10000, 100000, 1000000};
|
||||
*ptr_err.ptr++ = ' '; *ptr_err.ptr++ = axis;
|
||||
|
||||
char *base_ptr = this->ptr_err.ptr;
|
||||
auto v_int = int64_t(std::round(v * pow_10[digits]));
|
||||
// Older stdlib on macOS doesn't support std::from_chars at all, so it is used boost::spirit::karma::generate instead of it.
|
||||
// That is a little bit slower than std::to_chars but not much.
|
||||
#ifdef __APPLE__
|
||||
boost::spirit::karma::generate(this->ptr_err.ptr, boost::spirit::karma::int_generator<int64_t>(), v_int);
|
||||
#else
|
||||
// this->buf_end minus 1 because we need space for adding the extra decimal point.
|
||||
this->ptr_err = std::to_chars(this->ptr_err.ptr, this->buf_end - 1, v_int);
|
||||
#endif
|
||||
size_t writen_digits = (this->ptr_err.ptr - base_ptr) - (v_int < 0 ? 1 : 0);
|
||||
if (writen_digits < digits) {
|
||||
// Number is smaller than 10^digits, so that we will pad it with zeros.
|
||||
size_t remaining_digits = digits - writen_digits;
|
||||
// Move all newly inserted chars by remaining_digits to allocate space for padding with zeros.
|
||||
for (char *from_ptr = this->ptr_err.ptr - 1, *to_ptr = from_ptr + remaining_digits; from_ptr >= this->ptr_err.ptr - writen_digits; --to_ptr, --from_ptr)
|
||||
*to_ptr = *from_ptr;
|
||||
|
||||
memset(this->ptr_err.ptr - writen_digits, '0', remaining_digits);
|
||||
this->ptr_err.ptr += remaining_digits;
|
||||
}
|
||||
|
||||
// Move all newly inserted chars by one to allocate space for a decimal point.
|
||||
for (char *to_ptr = this->ptr_err.ptr, *from_ptr = to_ptr - 1; from_ptr >= this->ptr_err.ptr - digits; --to_ptr, --from_ptr)
|
||||
*to_ptr = *from_ptr;
|
||||
|
||||
*(this->ptr_err.ptr - digits) = '.';
|
||||
for (size_t i = 0; i < digits; ++i) {
|
||||
if (*this->ptr_err.ptr != '0')
|
||||
break;
|
||||
this->ptr_err.ptr--;
|
||||
}
|
||||
if (*this->ptr_err.ptr == '.')
|
||||
this->ptr_err.ptr--;
|
||||
if ((this->ptr_err.ptr + 1) == base_ptr || *this->ptr_err.ptr == '-')
|
||||
*(++this->ptr_err.ptr) = '0';
|
||||
this->ptr_err.ptr++;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "libslic3r.h"
|
||||
#include <string>
|
||||
#include <charconv>
|
||||
#include "Extruder.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
@ -93,6 +94,79 @@ private:
|
||||
std::string _retract(double length, double restart_extra, const std::string &comment);
|
||||
};
|
||||
|
||||
class GCodeFormatter {
|
||||
private:
|
||||
static constexpr const size_t buflen = 256;
|
||||
char buf[buflen];
|
||||
char *buf_end;
|
||||
std::to_chars_result ptr_err;
|
||||
|
||||
GCodeFormatter() {
|
||||
this->buf_end = buf + buflen;
|
||||
this->ptr_err.ptr = this->buf;
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr const int XYZF_EXPORT_DIGITS = 3;
|
||||
static constexpr const int E_EXPORT_DIGITS = 5;
|
||||
|
||||
static GCodeFormatter empty() {
|
||||
return {};
|
||||
}
|
||||
static GCodeFormatter G1() {
|
||||
GCodeFormatter out;
|
||||
out.buf[0] = 'G';
|
||||
out.buf[1] = '1';
|
||||
out.ptr_err.ptr += 2;
|
||||
return out;
|
||||
}
|
||||
|
||||
void emit_axis(const char axis, const double v, size_t digits);
|
||||
|
||||
void emit_xy(const Vec2d &point) {
|
||||
this->emit_axis('X', point.x(), XYZF_EXPORT_DIGITS);
|
||||
this->emit_axis('Y', point.y(), XYZF_EXPORT_DIGITS);
|
||||
}
|
||||
|
||||
void emit_xyz(const Vec3d &point) {
|
||||
this->emit_axis('X', point.x(), XYZF_EXPORT_DIGITS);
|
||||
this->emit_axis('Y', point.y(), XYZF_EXPORT_DIGITS);
|
||||
this->emit_z(point.z());
|
||||
}
|
||||
|
||||
void emit_z(const double z) {
|
||||
this->emit_axis('Z', z, XYZF_EXPORT_DIGITS);
|
||||
}
|
||||
|
||||
void emit_e(const std::string &axis, double v) {
|
||||
if (! axis.empty()) {
|
||||
// not gcfNoExtrusion
|
||||
this->emit_axis(axis[0], v, E_EXPORT_DIGITS);
|
||||
}
|
||||
}
|
||||
|
||||
void emit_f(double speed) {
|
||||
this->emit_axis('F', speed, XYZF_EXPORT_DIGITS);
|
||||
}
|
||||
|
||||
void emit_string(const std::string &s) {
|
||||
strncpy(ptr_err.ptr, s.c_str(), s.size());
|
||||
ptr_err.ptr += s.size();
|
||||
}
|
||||
|
||||
void emit_comment(bool allow_comments, const std::string &comment) {
|
||||
if (allow_comments && ! comment.empty()) {
|
||||
*ptr_err.ptr ++ = ' '; *ptr_err.ptr ++ = ';'; *ptr_err.ptr ++ = ' ';
|
||||
this->emit_string(comment);
|
||||
}
|
||||
}
|
||||
|
||||
std::string string() {
|
||||
*ptr_err.ptr ++ = '\n';
|
||||
return std::string(this->buf, ptr_err.ptr - buf);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace Slic3r */
|
||||
|
||||
#endif /* slic3r_GCodeWriter_hpp_ */
|
||||
|
Loading…
Reference in New Issue
Block a user