Files
OrcaSlicer/tests/fff_print/test_cooling.cpp
T
HanifKoh 84657ff11e Add Missing Includes Across the Remaining Sources and Tests (#16071)
* Ignore Clipper, libpng, mcut and Boost.Polygon Internals in clang-tidy

Each only works through a wrapper or umbrella header: libslic3r/clipper.hpp or clipper_z.hpp configure Clipper before including it, png.h pulls in libpng's config headers, and Boost.Polygon's headers only compile through polygon.hpp or voronoi.hpp.

* Ignore minilzo's Config Headers in clang-tidy

lzoconf.h and lzodefs.h are internal to minilzo.h, which is what the code includes.

* Add Missing Includes Across the Remaining Sources and Tests

Covers src/slic3r/Utils, src/slic3r/plugin, src/slic3r/Config, src/libvgcode, src/dev-utils, src/OrcaSlicer.cpp and tests/, the directories left after src/slic3r/GUI and src/libslic3r. Generated with clang-tidy misc-include-cleaner. libvgcode's own headers are included by relative path as in the rest of that library, and Catch2 and pybind11 with angle brackets as elsewhere in the repo.

* Make the GUI and Test Headers Compile on Their Own

Each now includes, or forward-declares, what it uses instead of relying on what its includers happened to include first. Headers that only compile on one platform, or that nothing built includes, are left alone.

* Keep Windows and nanosvg Setup Ahead of the Added Includes

OrcaSlicer.cpp and several tests set _WIN32_WINNT, WIN32_LEAN_AND_MEAN or NOMINMAX before including Windows.h, and the profile validator defines NANOSVG_IMPLEMENTATION before any libslic3r header. The added includes had landed above those blocks, which broke the Windows build.

* Add the GUI Includes the First Pass Missed

Covers headers that only became editable once they compiled on their own, and wx symbols whose suggested header changed as the clang-tidy ignore list grew after the src/slic3r/GUI pass.

* Keep the Added Test Includes Below the NOMINMAX Guard

test_marchingsquares.cpp and test_texture_displacement.cpp had includes inside #ifndef NOMINMAX, which the tests inherit as defined on Windows from libslic3r, so those were skipped there. .clang-tidy also ignores the MSVC STL and UCRT internals, Boost.Multiprecision's fwd.hpp and CPython's Windows include directory, as in #16068.
2026-10-03 13:45:21 +08:00

102 lines
4.2 KiB
C++

#include <catch2/catch_all.hpp>
#include <catch2/catch_test_macros.hpp>
#include "test_helpers.hpp"
#include <algorithm>
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/Config.hpp"
#include "libslic3r/TriangleMesh.hpp"
#include "libslic3r/libslic3r.h"
#include <sstream>
#include <string>
#include <utility>
#include <vector>
using namespace Slic3r;
using namespace Slic3r::Test;
// The fan is held off for the first close_fan_the_first_x_layers layers, so an explicit
// fan-off command is emitted.
TEST_CASE("Fan is held off for the initial layers", "[Cooling]")
{
const std::string gcode = slice({ cube(20) }, {
{ "cooling", true },
{ "close_fan_the_first_x_layers", 5 },
});
CHECK(gcode.find("M106 S0") != std::string::npos);
}
// The cooling pass resolves and strips its internal speed placeholders; none leak into
// the final G-code.
TEST_CASE("Cooling consumes its internal speed markers", "[Cooling]")
{
const std::string gcode = slice({ cube(20) }, { { "layer_height", 0.2 } });
CHECK(gcode.find(";_EXTRUDE_SET_SPEED") == std::string::npos);
}
TEST_CASE("Overhang fan transitions do not depend on overhang speed", "[Cooling][Regression]")
{
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
config.set_deserialize_strict({
{ "bridge_speed", 2.0 },
{ "enable_arc_fitting", false },
{ "enable_overhang_bridge_fan", true },
{ "enable_overhang_speed", false },
{ "initial_layer_print_height", 0.3 },
{ "inner_wall_speed", 30.0 },
{ "layer_height", 0.3 },
{ "outer_wall_speed", 30.0 },
{ "overhang_1_4_speed", "30" },
{ "overhang_2_4_speed", "29" },
{ "overhang_3_4_speed", "6" },
{ "overhang_4_4_speed", "3" },
{ "slow_down_for_layer_cooling", false },
{ "slowdown_for_curled_perimeters", false },
});
config.set_key_value("fan_max_speed", new ConfigOptionFloats{20.0});
config.set_key_value("fan_min_speed", new ConfigOptionFloats{20.0});
config.set_key_value("overhang_fan_speed", new ConfigOptionInts{100});
config.set_key_value("overhang_fan_threshold", new ConfigOptionEnumsGeneric{Overhang_threshold_2_4});
config.set_key_value("layer_change_gcode", new ConfigOptionString{";TEST_LAYER_Z=[layer_z]"});
const auto fan_commands = [](const std::string &gcode) {
std::vector<std::pair<std::string, std::string>> commands;
std::istringstream input(gcode);
std::string layer;
std::string line;
while (std::getline(input, line)) {
if (line.rfind(";TEST_LAYER_Z=", 0) == 0)
layer = line;
else if (!layer.empty() && (line.rfind("M106", 0) == 0 || line.rfind("M107", 0) == 0))
commands.emplace_back(layer, line);
}
return commands;
};
const auto feedrates = [](const std::string &gcode) {
std::vector<std::string> values;
std::istringstream input(gcode);
std::string word;
while (input >> word)
if (!word.empty() && word.front() == 'F')
values.push_back(word);
return values;
};
constexpr double sphere_radius = 50.0; // 100 mm diameter.
const std::string without_speed_gcode = slice({make_sphere(sphere_radius, PI / 24.0)}, config);
config.set_deserialize_strict({{"enable_overhang_speed", true}});
const std::string with_speed_gcode = slice({make_sphere(sphere_radius, PI / 24.0)}, config);
const auto without_speed_fan = fan_commands(without_speed_gcode);
const auto with_speed_fan = fan_commands(with_speed_gcode);
const auto without_speed_feedrates = feedrates(without_speed_gcode);
const auto with_speed_feedrates = feedrates(with_speed_gcode);
REQUIRE_FALSE(without_speed_fan.empty());
REQUIRE(std::any_of(without_speed_fan.begin(), without_speed_fan.end(),
[](const auto &command) { return command.second.find("S255") != std::string::npos; }));
REQUIRE(with_speed_feedrates != without_speed_feedrates);
CHECK(with_speed_fan == without_speed_fan);
}