diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 793a666752..eb45e95c1f 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -7,6 +7,10 @@ #include #include +#ifdef __APPLE__ + #include +#endif + #define XYZF_EXPORT_DIGITS 3 #define E_EXPORT_DIGITS 5 @@ -273,17 +277,47 @@ public: } void emit_axis(const char axis, const double v, size_t digits) { - *ptr_err.ptr ++ = ' '; *ptr_err.ptr ++ = axis; -#ifdef WIN32 - this->ptr_err = std::to_chars(this->ptr_err.ptr, this->buf_end, v, std::chars_format::fixed, digits); + assert(digits <= 6); + static constexpr const std::array 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(), v_int); #else - int buf_capacity = int(this->buf_end - this->ptr_err.ptr); - int ret = snprintf(this->ptr_err.ptr, buf_capacity, "%.*lf", int(digits), v); - if (ret <= 0 || ret > buf_capacity) - ptr_err.ec = std::errc::value_too_large; - else - this->ptr_err.ptr = this->ptr_err.ptr + ret; + // 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) {