Compare commits

...
Author SHA1 Message Date
Hanif Koh ebbf27147e Keep a Decimal Point in the Wipe Tower's Travel Feedrate
merge_tcr formatted the feedrate of the travel that joins two wipe tower
blocks with std::to_string, which follows the numeric locale. The GUI slices
on a thread that keeps the user's locale, so a comma-decimal locale wrote
moves such as 'G1 Y249.463 F5400,000000', which Klipper rejects. Format it
with float_to_string_decimal_point like the X and Y beside it; the output in
the C locale is unchanged.

The comma-locale test helper moves to the shared test header so the wipe
tower test can use it.
2026-10-21 13:28:48 +08:00
4 changed files with 60 additions and 40 deletions

No files matched your search

+1 -1
View File
@@ -3349,7 +3349,7 @@ WipeTower::ToolChangeResult WipeTower::merge_tcr(ToolChangeResult &first, ToolCh
WipeTower::ToolChangeResult out = first;
if ((first.end_pos - second.start_pos).norm() > (float)EPSILON) {
std::string travel_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) + " F" + std::to_string(m_max_speed) + "\n";
Slic3r::float_to_string_decimal_point(second.start_pos.y(), 3) + " F" + Slic3r::float_to_string_decimal_point(m_max_speed, 6) + "\n";
bool need_insert_travel = true;
if (second.is_tool_change
&& is_approx(second.start_pos.x(), second.tool_change_start_pos.x())
+22
View File
@@ -8,6 +8,7 @@
#include <cstddef>
#include "libslic3r/Model.hpp"
#include "libslic3r/Print.hpp"
#include <sstream>
#include <string>
#include <vector>
@@ -22,9 +23,11 @@
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/GCode/GCodeProcessor.hpp"
#include "libslic3r/GCode/WipeTower.hpp"
#include "libslic3r/LocalesUtils.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "test_helpers.hpp"
#include "test_utils.hpp"
#include "libslic3r/PrintBase.hpp"
#include "libslic3r/TriangleMesh.hpp"
@@ -219,6 +222,24 @@ TEST_CASE("The wipe tower sets Klipper's acceleration and accel_to_decel on one
!Catch::Matchers::ContainsSubstring("M204"));
}
TEST_CASE("The wipe tower's G-code moves keep a decimal point in a comma-decimal locale", "[WipeTower]")
{
// The GUI slices on a thread that keeps the user's numeric locale.
CommaNumericLocale comma;
CNumericLocalesSetter restore;
if (! comma.apply())
SKIP("no locale with a comma decimal separator is installed");
DynamicPrintConfig config = wipe_tower_toolchange_config("klipper");
// Type 1 towers join their toolchange blocks with a travel move of their own.
config.set_deserialize_strict({ { "wipe_tower_type", "type1" } });
const std::string gcode = slice_with_prime_tower(config);
REQUIRE_FALSE(wipe_tower_regions(gcode).empty());
std::istringstream lines(gcode);
for (std::string line; std::getline(lines, line);)
if (! line.empty() && line.front() == 'G' && line.find(',') != std::string::npos)
FAIL_CHECK(line);
}
// What Print feeds the shared estimate. The libslic3r WipeTowerEstimate cases cannot see this:
// they call the estimator directly. The estimate counts the filaments the print really uses,
// so the two-filament shape gives the outer wall the second one.
@@ -476,3 +497,4 @@ TEST_CASE("A tower printed without a tool change is still validated against the
CHECK(print.wipe_tower_data(1).depth > 0.f);
CHECK_THAT(print.validate().string, Catch::Matchers::ContainsSubstring("printable area"));
}
+1 -39
View File
@@ -1,55 +1,17 @@
#include <catch2/catch_all.hpp>
#include <clocale>
#include <locale.h>
#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators.hpp>
#include <catch2/catch_message.hpp>
#include <catch2/matchers/catch_matchers.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include "libslic3r/LocalesUtils.hpp"
#include "test_utils.hpp"
#include <string>
using namespace Slic3r;
namespace {
// Switches this thread's numeric locale to one whose decimal separator is a comma,
// when the system has one installed.
struct CommaNumericLocale
{
#ifdef _WIN32
bool apply()
{
for (const char* name : { "de-DE", "German_Germany.1252" })
if (std::setlocale(LC_NUMERIC, name) != nullptr)
return true;
return false;
}
#else
locale_t locale { (locale_t) 0 };
bool apply()
{
for (const char* name : { "de_DE.UTF-8", "de_DE.utf8", "de_DE" })
if ((locale = newlocale(LC_NUMERIC_MASK, name, (locale_t) 0)) != (locale_t) 0) {
uselocale(locale);
return true;
}
return false;
}
// Freed once the setters around apply() have put the thread's own locale back.
~CommaNumericLocale()
{
if (locale != (locale_t) 0)
freelocale(locale);
}
#endif
};
} // namespace
TEST_CASE("Floats print as printf prints them in the C locale", "[LocalesUtils]")
{
const auto [value, precision, text] = GENERATE(table<double, int, std::string>({
+36
View File
@@ -12,12 +12,16 @@
#include <boost/filesystem.hpp>
#include <boost/nowide/cstdlib.hpp>
#include <clocale>
#include <cstdio>
#include <fstream>
#include <initializer_list>
#include <optional>
#include <string>
#include <utility>
#include <locale.h>
#if defined(WIN32) || defined(_WIN32)
#define PATH_SEPARATOR R"(\)"
#else
@@ -223,4 +227,36 @@ private:
std::optional<std::string> m_previous;
};
// Switches this thread's numeric locale to one whose decimal separator is a comma,
// when the system has one installed.
struct CommaNumericLocale
{
#ifdef _WIN32
bool apply()
{
for (const char* name : { "de-DE", "German_Germany.1252" })
if (std::setlocale(LC_NUMERIC, name) != nullptr)
return true;
return false;
}
#else
locale_t locale { (locale_t) 0 };
bool apply()
{
for (const char* name : { "de_DE.UTF-8", "de_DE.utf8", "de_DE" })
if ((locale = newlocale(LC_NUMERIC_MASK, name, (locale_t) 0)) != (locale_t) 0) {
uselocale(locale);
return true;
}
return false;
}
// Freed once the setters around apply() have put the thread's own locale back.
~CommaNumericLocale()
{
if (locale != (locale_t) 0)
freelocale(locale);
}
#endif
};
#endif // SLIC3R_TEST_UTILS