mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-08 09:46:55 +00:00
126 lines
4.7 KiB
C++
126 lines
4.7 KiB
C++
#include <catch2/catch_all.hpp>
|
|
|
|
#include "libslic3r/Layer.hpp"
|
|
#include "libslic3r/TriangleMesh.hpp"
|
|
|
|
#include "test_helpers.hpp"
|
|
|
|
using namespace Slic3r::Test;
|
|
using namespace Slic3r;
|
|
|
|
namespace {
|
|
|
|
// The upper plate overhangs both the lower plate and open air, so branches land on the model and on
|
|
// the bed in the same slice.
|
|
TriangleMesh two_tier_mesh()
|
|
{
|
|
TriangleMesh lower = make_cube(30, 30, 3);
|
|
TriangleMesh column = make_cube(8, 8, 15);
|
|
TriangleMesh upper = make_cube(50, 50, 3);
|
|
// Each part overlaps the one below rather than resting on it; a coplanar join slices ambiguously.
|
|
column.translate(11.f, 11.f, 2.f);
|
|
upper.translate(-10.f, -10.f, 16.f);
|
|
TriangleMesh mesh = lower;
|
|
mesh.merge(column);
|
|
mesh.merge(upper);
|
|
return mesh;
|
|
}
|
|
|
|
TriangleMesh scaled(TestMesh id, float scale)
|
|
{
|
|
TriangleMesh mesh = Slic3r::Test::mesh(id);
|
|
mesh.scale(scale);
|
|
return mesh;
|
|
}
|
|
|
|
void slice_with_tree_support(const TriangleMesh &mesh, Slic3r::Print &print, const char *style,
|
|
int threshold_angle = 30, int build_plate_only = 0, int raft_layers = 0)
|
|
{
|
|
Slic3r::Test::init_and_process_print({ mesh }, print, {
|
|
{ "enable_support", 1 },
|
|
{ "support_type", "tree(auto)" },
|
|
{ "support_style", style },
|
|
{ "support_on_build_plate_only", build_plate_only },
|
|
{ "support_threshold_angle", threshold_angle },
|
|
{ "raft_layers", raft_layers },
|
|
{ "layer_height", 0.2 },
|
|
});
|
|
}
|
|
|
|
Points support_points(const Slic3r::Print &print)
|
|
{
|
|
Points points;
|
|
for (const SupportLayer *layer : print.objects().front()->support_layers())
|
|
layer->support_fills.collect_points(points);
|
|
return points;
|
|
}
|
|
|
|
size_t support_point_count(const TriangleMesh &mesh, const char *style, int threshold_angle = 30,
|
|
int build_plate_only = 0)
|
|
{
|
|
Slic3r::Print print;
|
|
slice_with_tree_support(mesh, print, style, threshold_angle, build_plate_only);
|
|
return support_points(print).size();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_CASE("Tree support is generated for an overhang and not for a plain cube", "[TreeSupport]")
|
|
{
|
|
REQUIRE(support_point_count(scaled(TestMesh::overhang, 2.f), "tree_slim") > 1000);
|
|
REQUIRE(support_point_count(Slic3r::Test::cube(20), "tree_slim") == 0);
|
|
}
|
|
|
|
TEST_CASE("Restricting tree support to the build plate changes what is generated", "[TreeSupport]")
|
|
{
|
|
const TriangleMesh mesh = two_tier_mesh();
|
|
const size_t anywhere = support_point_count(mesh, "tree_slim", 30, 0);
|
|
const size_t plate_only = support_point_count(mesh, "tree_slim", 30, 1);
|
|
REQUIRE(anywhere > 1000);
|
|
REQUIRE(plate_only > 1000);
|
|
// The upper plate overhangs the lower one, so some branches would land on the model.
|
|
REQUIRE(plate_only != anywhere);
|
|
}
|
|
|
|
TEST_CASE("Tree support layers rise monotonically within the layer height limits", "[TreeSupport]")
|
|
{
|
|
Slic3r::Print print;
|
|
slice_with_tree_support(scaled(TestMesh::overhang, 2.f), print, "tree_slim");
|
|
const double nozzle = print.config().nozzle_diameter.values.front();
|
|
|
|
size_t checked = 0;
|
|
double previous = 0;
|
|
bool previous_was_adjacent = false;
|
|
for (const SupportLayer *layer : print.objects().front()->support_layers()) {
|
|
if (layer->print_z <= 0 || layer->height <= 0) {
|
|
// Layers with no nodes are left at zero. Skipping one leaves a hole, so the next pair
|
|
// spans more than one layer and its gap says nothing about the layer height limit.
|
|
previous_was_adjacent = false;
|
|
continue;
|
|
}
|
|
if (previous > 0) {
|
|
CAPTURE(previous, layer->print_z);
|
|
REQUIRE(layer->print_z > previous);
|
|
if (previous_was_adjacent)
|
|
REQUIRE(layer->print_z - previous <= nozzle + EPSILON);
|
|
}
|
|
previous = layer->print_z;
|
|
previous_was_adjacent = true;
|
|
++checked;
|
|
}
|
|
REQUIRE(checked > 10);
|
|
}
|
|
|
|
TEST_CASE("A raft is still generated under tree support", "[TreeSupport]")
|
|
{
|
|
// The mesh supports itself, so a layer count alone passes with no raft at all.
|
|
Slic3r::Print rafted, unrafted;
|
|
slice_with_tree_support(scaled(TestMesh::overhang, 2.f), rafted, "tree_slim", 30, 0, 3);
|
|
slice_with_tree_support(scaled(TestMesh::overhang, 2.f), unrafted, "tree_slim", 30, 0, 0);
|
|
const PrintObject *rafted_object = rafted.objects().front();
|
|
const PrintObject *unrafted_object = unrafted.objects().front();
|
|
REQUIRE(rafted_object->support_layers().size() > unrafted_object->support_layers().size());
|
|
// The raft goes under the object.
|
|
REQUIRE(rafted_object->layers().front()->print_z > unrafted_object->layers().front()->print_z);
|
|
}
|