diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index d47d185a09..208363f351 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -12,6 +12,7 @@ #include "Utils.hpp" #include "ClipperUtils.hpp" #include "libslic3r.h" +#include "LocalesUtils.hpp" #include #include @@ -750,6 +751,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re std::string path_tmp(path); path_tmp += ".tmp"; + CNumericLocalesSetter c_locales_setter; FILE *file = boost::nowide::fopen(path_tmp.c_str(), "wb"); if (file == nullptr) throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n"); @@ -981,6 +983,7 @@ namespace DoExport { double filament_weight = extruded_volume * extruder.filament_density() * 0.001; double filament_cost = filament_weight * extruder.filament_cost() * 0.001; auto append = [&extruder](std::pair &dst, const char *tmpl, double value) { + assert(is_decimal_separator_point()); while (dst.second < extruder.id()) { // Fill in the non-printing extruders with zeros. dst.first += (dst.second > 0) ? ", 0" : "0"; @@ -1620,7 +1623,7 @@ void GCode::print_machine_envelope(FILE *file, Print &print) int(print.config().machine_max_acceleration_retracting.values.front() + 0.5), travel_acc); - + assert(is_decimal_separator_point()); fprintf(file, "M205 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n", print.config().machine_max_jerk_x.values.front(), print.config().machine_max_jerk_y.values.front(), @@ -1984,6 +1987,7 @@ void GCode::process_layer( } std::string gcode; + assert(is_decimal_separator_point()); // for the sprintfs // add tag for processor #if ENABLE_VALIDATE_CUSTOM_GCODE @@ -2826,6 +2830,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, // so, if the last role was erWipeTower we force export of GCodeProcessor::Height_Tag lines bool last_was_wipe_tower = (m_last_processor_extrusion_role == erWipeTower); char buf[64]; + assert(is_decimal_separator_point()); if (path.role() != m_last_processor_extrusion_role) { m_last_processor_extrusion_role = path.role(); diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 917f84f40b..61c835a4b1 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -1,6 +1,7 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/Utils.hpp" #include "libslic3r/Print.hpp" +#include "libslic3r/LocalesUtils.hpp" #include "GCodeProcessor.hpp" #include @@ -465,9 +466,7 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) }; auto format_time_float = [](float time) { - char time_str[64]; - sprintf(time_str, "%.2f", time); - return std::string(time_str); + return Slic3r::float_to_string_decimal_point(time, 2); }; auto format_line_M73_stop_float = [format_time_float](const std::string& mask, float time) { diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index fc6a15b656..5e1937ad84 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -4,9 +4,12 @@ #include #include #include +#include +#include #include "GCodeProcessor.hpp" #include "BoundingBox.hpp" +#include "LocalesUtils.hpp" namespace Slic3r @@ -30,29 +33,27 @@ public: m_filpar(filament_parameters) { // adds tag for analyzer: - char buf[64]; + std::ostringstream str; #if ENABLE_VALIDATE_CUSTOM_GCODE - sprintf(buf, ";%s%f\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height).c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming - m_gcode += buf; - sprintf(buf, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erWipeTower).c_str()); + str << ";" << GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) << m_layer_height << "\n"; // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming + str << ";" << GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role) << ExtrusionEntity::role_to_string(erWipeTower) << "\n"; #else - sprintf(buf, ";%s%f\n", GCodeProcessor::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming - m_gcode += buf; - sprintf(buf, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erWipeTower).c_str()); + str << ";" << GCodeProcessor::Height_Tag << m_layer_height << "\n"; // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming + str << ";" << GCodeProcessor::Extrusion_Role_Tag << ExtrusionEntity::role_to_string(erWipeTower) << "\n"; #endif // ENABLE_VALIDATE_CUSTOM_GCODE - m_gcode += buf; + m_gcode += str.str(); change_analyzer_line_width(line_width); } WipeTowerWriter& change_analyzer_line_width(float line_width) { // adds tag for analyzer: - char buf[64]; + std::stringstream str; #if ENABLE_VALIDATE_CUSTOM_GCODE - sprintf(buf, ";%s%f\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width).c_str(), line_width); + str << ";" << GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width) << line_width << "\n"; #else - sprintf(buf, ";%s%f\n", GCodeProcessor::Width_Tag.c_str(), line_width); + str << ";" << GCodeProcessor::Width_Tag << line_width << "\n"; #endif // ENABLE_VALIDATE_CUSTOM_GCODE - m_gcode += buf; + m_gcode += str.str(); return *this; } @@ -61,9 +62,9 @@ public: static const float area = float(M_PI) * 1.75f * 1.75f / 4.f; float mm3_per_mm = (len == 0.f ? 0.f : area * e / len); // adds tag for processor: - char buf[64]; - sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), mm3_per_mm); - m_gcode += buf; + std::stringstream str; + str << ";" << GCodeProcessor::Mm3_Per_Mm_Tag << mm3_per_mm << "\n"; + m_gcode += str.str(); return *this; } #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING @@ -325,9 +326,7 @@ public: { if (time==0.f) return *this; - char buf[128]; - sprintf(buf, "G4 S%.3f\n", time); - m_gcode += buf; + m_gcode += "G4 S" + Slic3r::float_to_string_decimal_point(time, 3) + "\n"; return *this; } @@ -443,37 +442,29 @@ private: const std::vector& m_filpar; std::string set_format_X(float x) - { - char buf[64]; - sprintf(buf, " X%.3f", x); - m_current_pos.x() = x; - return buf; + { + m_current_pos.x() = x; + return " X" + Slic3r::float_to_string_decimal_point(x, 3); } std::string set_format_Y(float y) { - char buf[64]; - sprintf(buf, " Y%.3f", y); - m_current_pos.y() = y; - return buf; + m_current_pos.y() = y; + return " Y" + Slic3r::float_to_string_decimal_point(y, 3); } std::string set_format_Z(float z) { - char buf[64]; - sprintf(buf, " Z%.3f", z); - return buf; + return " Z" + Slic3r::float_to_string_decimal_point(z, 3); } std::string set_format_E(float e) { - char buf[64]; - sprintf(buf, " E%.4f", e); - return buf; + return " E" + Slic3r::float_to_string_decimal_point(e, 4); } std::string set_format_F(float f) { - char buf[64]; - sprintf(buf, " F%d", int(floor(f + 0.5f))); - m_current_feedrate = f; - return buf; + char buf[64]; + sprintf(buf, " F%d", int(floor(f + 0.5f))); + m_current_feedrate = f; + return buf; } WipeTowerWriter& operator=(const WipeTowerWriter &rhs); @@ -959,8 +950,8 @@ void WipeTower::toolchange_Change( // postprocessor that we absolutely want to have this in the gcode, even if it thought it is the same as before. Vec2f current_pos = writer.pos_rotated(); writer.feedrate(m_travel_speed * 60.f) // see https://github.com/prusa3d/PrusaSlicer/issues/5483 - .append(std::string("G1 X") + std::to_string(current_pos.x()) - + " Y" + std::to_string(current_pos.y()) + .append(std::string("G1 X") + Slic3r::float_to_string_decimal_point(current_pos.x()) + + " Y" + Slic3r::float_to_string_decimal_point(current_pos.y()) + never_skip_tag() + "\n"); // The toolchange Tn command will be inserted later, only in case that the user does @@ -1310,11 +1301,10 @@ static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult& first, { assert(first.new_tool == second.initial_tool); WipeTower::ToolChangeResult out = first; - if (first.end_pos != second.start_pos) { - char buf[2048]; // Add a travel move from tc1.end_pos to tc2.start_pos. - sprintf(buf, "G1 X%.3f Y%.3f F7200\n", second.start_pos.x(), second.start_pos.y()); - out.gcode += buf; - } + if (first.end_pos != second.start_pos) + out.gcode += "G1 X" + Slic3r::float_to_string_decimal_point(second.start_pos.x(), 3) + + " Y" + Slic3r::float_to_string_decimal_point(second.start_pos.y(), 3) + + " F7200\n"; out.gcode += second.gcode; out.extrusions.insert(out.extrusions.end(), second.extrusions.begin(), second.extrusions.end()); out.end_pos = second.end_pos; diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 52df39fd5f..c35172752b 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1457,7 +1457,7 @@ void PageDiameters::apply_custom_config(DynamicPrintConfig &config) config.set_key_value("filament_diameter", opt_filam); auto set_extrusion_width = [&config, opt_nozzle](const char *key, double dmr) { - char buf[64]; + char buf[64]; // locales don't matter here (sprintf/atof) sprintf(buf, "%.2lf", dmr * opt_nozzle->values.front() / 0.4); config.set_key_value(key, new ConfigOptionFloatOrPercent(atof(buf), false)); }; diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 209679c0fc..f71921becd 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -5,6 +5,7 @@ #include "libslic3r/Geometry.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/Utils.hpp" +#include "libslic3r/LocalesUtils.hpp" #include "GUI_App.hpp" #include "MainFrame.hpp" #include "Plater.hpp" @@ -78,6 +79,7 @@ static float round_to_nearest(float value, unsigned int decimals) res = std::round(value); else { char buf[64]; + // locales should not matter, both sprintf and stof are sensitive, so... sprintf(buf, "%.*g", decimals, value); res = std::stof(buf); } @@ -3465,18 +3467,16 @@ void GCodeViewer::render_statistics() const ImGuiWrapper& imgui = *wxGetApp().imgui(); auto add_time = [this, &imgui](const std::string& label, int64_t time) { - char buf[1024]; - sprintf(buf, "%lld ms (%s)", time, get_time_dhms(static_cast(time) * 0.001f).c_str()); imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); ImGui::SameLine(offset); - imgui.text(buf); + imgui.text(std::to_string(time) + " ms (" + get_time_dhms(static_cast(time) * 0.001f) + ")"); }; auto add_memory = [this, &imgui](const std::string& label, int64_t memory) { - auto format_string = [memory](const std::string& units, float value) { - char buf[1024]; - sprintf(buf, "%lld bytes (%.3f %s)", memory, static_cast(memory) * value, units.c_str()); - return std::string(buf); + auto format_string = [memory](const std::string& units, float value) { + return std::to_string(memory) + " bytes (" + + Slic3r::float_to_string_decimal_point(float(memory) * value, 3) + + " " + units + ")"; }; static const float kb = 1024.0f; @@ -3496,11 +3496,9 @@ void GCodeViewer::render_statistics() const }; auto add_counter = [this, &imgui](const std::string& label, int64_t counter) { - char buf[1024]; - sprintf(buf, "%lld", counter); imgui.text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, label); ImGui::SameLine(offset); - imgui.text(buf); + imgui.text(std::to_string(counter)); }; imgui.set_next_window_pos(0.5f * wxGetApp().plater()->get_current_canvas3D()->get_canvas_size().get_width(), 0.0f, ImGuiCond_Once, 0.5f, 0.0f); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 803ab5a143..d6520335bc 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1586,7 +1586,7 @@ bool GUI_App::load_language(wxString language, bool initial) m_wxLocale->AddCatalog(SLIC3R_APP_KEY); m_imgui->set_language(into_u8(language_info->CanonicalName)); //FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only. - wxSetlocale(LC_NUMERIC, "C"); + //wxSetlocale(LC_NUMERIC, "C"); Preset::update_suffix_modified((" (" + _L("modified") + ")").ToUTF8().data()); return true; }