Fix crash when opening a G-code file exported by OrcaSlicer (#16441)

This commit is contained in:
SoftFever
2026-10-14 00:39:09 +08:00
committed by GitHub
parent 7131dd30e7
commit 5d42ff6879
2 changed files with 75 additions and 1 deletions
+2 -1
View File
@@ -3752,7 +3752,8 @@ DynamicConfig GCodeProcessor::export_config_for_render() const
config.set_key_value("filament_is_support", new ConfigOptionBools(m_parser.get_config().filament_is_support.values));
config.set_key_value("filament_type", new ConfigOptionStrings(m_parser.get_config().filament_type.values));
config.set_key_value("filament_map", new ConfigOptionInts(m_parser.get_config().filament_map.values));
config.apply(m_belt_render_config);
// += clones the options; apply() would need a definition this config does not have.
config += m_belt_render_config;
return config;
}
+73
View File
@@ -2,14 +2,19 @@
#include "libslic3r/libslic3r.h"
#include "libslic3r/GCode/GCodeProcessor.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/Print.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "test_utils.hpp"
#include <cstddef>
#include <fstream>
#include <initializer_list>
#include <string>
#include <catch2/catch_message.hpp>
#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators.hpp>
#include <catch2/matchers/catch_matchers.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
@@ -49,6 +54,74 @@ TEST_CASE("The belt header's angle marks G-code as belt G-code", "[GCodeProcesso
CHECK_THAT(processed_belt_tilt(gcode), WithinAbs(45., 1e-6));
}
TEST_CASE("A loaded G-code's belt settings and bed replace the selected printer's in the preview", "[GCodeProcessor][belt][Regression]")
{
// Loading a G-code applies the selected printer's config to the Print, then the file's render
// config on top, so the preview's belt view and back-transform follow the file. The selected
// printer is always the other kind, and every belt and bed key differs between the two.
const bool file_is_belt = GENERATE(false, true);
CAPTURE(file_is_belt);
DynamicPrintConfig file = DynamicPrintConfig::full_print_config();
file.set_deserialize_strict({
{ "belt_printer", file_is_belt },
{ "belt_slice_rotation", "y" },
{ "belt_slice_rotation_angle", -30 },
{ "gcode_remap_x", "rev_x" },
{ "gcode_remap_y", "pos_z" },
{ "gcode_remap_z", "pos_y" },
{ "belt_frame_tilt_decouple", 1 },
{ "belt_frame_tilt_angle", 35 },
{ "printable_area", "0x0,300x0,300x250,0x250" },
{ "printable_height", 123 },
});
DynamicPrintConfig selected = DynamicPrintConfig::full_print_config();
selected.set_deserialize_strict({
{ "belt_printer", !file_is_belt },
{ "belt_slice_rotation", "x" },
{ "belt_slice_rotation_angle", 45 },
{ "gcode_remap_x", "pos_x" },
{ "gcode_remap_y", "pos_y" },
{ "gcode_remap_z", "pos_z" },
{ "belt_frame_tilt_decouple", 0 },
{ "belt_frame_tilt_angle", 50 },
{ "printable_area", "0x0,180x0,180x180,0x180" },
{ "printable_height", 200 },
});
ScopedTemporaryFile temp(".gcode");
{
std::ofstream os(temp.string());
REQUIRE(os.is_open());
// A full config block, as the loader rejects one with fewer than 80 values.
os << "; generated by OrcaSlicer\n" << body << "; CONFIG_BLOCK_START\n";
for (const std::string &key : file.keys())
os << "; " << key << " = " << file.opt_serialize(key) << '\n';
os << "; CONFIG_BLOCK_END\n";
REQUIRE(os.good());
}
GCodeProcessor processor;
REQUIRE_NOTHROW(processor.process_file(temp.string()));
Model model;
Print print;
print.apply(model, selected);
REQUIRE_NOTHROW(print.apply_config_for_render(processor.export_config_for_render()));
// The file's belt settings win either way, so a non-belt file turns a selected belt printer's view off.
for (const char *key : { "belt_printer", "belt_slice_rotation", "belt_slice_rotation_angle", "gcode_remap_x",
"gcode_remap_y", "gcode_remap_z", "belt_frame_tilt_decouple", "belt_frame_tilt_angle" }) {
CAPTURE(key);
CHECK(print.config().opt_serialize(key) == file.opt_serialize(key));
}
// Only a belt file brings the bed it was sliced for.
const DynamicPrintConfig &bed_source = file_is_belt ? file : selected;
for (const char *key : { "printable_area", "printable_height" }) {
CAPTURE(key);
CHECK(print.config().opt_serialize(key) == bed_source.opt_serialize(key));
}
}
TEST_CASE("Non-belt start G-code moves keep the first-layer Z in the processor", "[GCodeProcessor]")
{
// The belt path (GCodeWriter tests: "start-gcode prepare-stage moves keep their real Z")