Merge branch 'main' into belt-printer

This commit is contained in:
Joseph Robertson authored and GitHub committed 2026-10-07 14:14:20 -05:00
commit e39d6cc089
241 files changed
+1047 -1771

No files matched your search

-1
View File
@@ -12,7 +12,6 @@
#include "libslic3r/Flow.hpp"
#include "libslic3r/libslic3r.h"
using namespace Slic3r::Test;
using namespace Slic3r;
/// Test the expected behavior for auto-width,
-2
View File
@@ -27,8 +27,6 @@
#include "test_utils.hpp"
using namespace std;
namespace Slic3r { namespace Test {
const std::unordered_map<TestMesh, const char*, TestMeshHash> mesh_names {
-1
View File
@@ -19,7 +19,6 @@
#include "libslic3r/Print.hpp"
using namespace Slic3r;
using namespace Slic3r::Test;
SCENARIO("Model construction", "[Model]") {
GIVEN("A Slic3r Model") {
-1
View File
@@ -21,7 +21,6 @@
//#include "test_options.hpp"
using namespace Slic3r;
using namespace std;
static inline TriangleMesh make_cube() { return make_cube(20., 20, 20); }
-1
View File
@@ -241,7 +241,6 @@ TEST_CASE("Arachne wall generation - 60% min_bead_width", "[Arachne]") {
// getTransitionThickness(1) = (1 + 0.619) * 0.42 = 0.68mm. A 0.5mm-thick wall therefore sits
// in the transition band: alpha produced 2 beads here, beta collapses it to 1 fat bead.
TEST_CASE("Arachne widening keeps two beads in transition band (#14376)", "[Arachne]") {
using namespace Slic3r::Arachne;
// Widths in mm; the scaled coord_t values and the thresholds below are both derived from
// these so a width change cannot silently desync the transition-band math.
-43
View File
@@ -992,7 +992,6 @@ TEST_CASE("tessellate tracks per-triangle face id", "[CadDocument]")
TEST_CASE("extrude two-sided + through-all + intersect", "[CadDocument]")
{
using namespace Slic3r;
SketchPlane xy = SketchPlane::XY();
// a 10x10 square wire centred on origin
SketchProfile sp;
@@ -1013,7 +1012,6 @@ TEST_CASE("extrude two-sided + through-all + intersect", "[CadDocument]")
TEST_CASE("extrude taper + up-to-face distance", "[CadDocument]")
{
using namespace Slic3r;
SketchPlane xy = SketchPlane::XY();
SketchProfile sp; sp.points = { Vec2d(-5,-5),Vec2d(5,-5),Vec2d(5,5),Vec2d(-5,5) }; sp.closed = true;
TopoDS_Wire w = sp.to_occt_wire(xy);
@@ -1047,7 +1045,6 @@ TEST_CASE("extrude taper + up-to-face distance", "[CadDocument]")
// asserting, because that is what "the thread actually cuts" means.
TEST_CASE("internal thread cuts a visible groove into the bore wall", "[CadDocument][thread]")
{
using namespace Slic3r;
SketchPlane xy = SketchPlane::XY();
// 40x40x20 box centred on the origin, extruded +Z.
@@ -1093,7 +1090,6 @@ TEST_CASE("internal thread cuts a visible groove into the bore wall", "[CadDocum
TEST_CASE("revolve builds a solid of revolution about an in-plane axis", "[CadDocument]")
{
using namespace Slic3r;
SketchPlane xy = SketchPlane::XY();
// Rectangle profile (10 wide x 10 tall, area 100) offset to +v so it lies entirely
@@ -1136,7 +1132,6 @@ TEST_CASE("revolve builds a solid of revolution about an in-plane axis", "[CadDo
TEST_CASE("sweep builds a solid by sweeping a profile along a path", "[CadDocument]")
{
using namespace Slic3r;
CadDocument doc;
// Profile: circle r=5 on the XY plane at the origin (area = 25*pi).
@@ -1172,7 +1167,6 @@ TEST_CASE("sweep builds a solid by sweeping a profile along a path", "[CadDocume
TEST_CASE("pattern replicates a body linearly and circularly", "[CadDocument]")
{
using namespace Slic3r;
// Linear: a 10x10x10 box (V=1000) repeated 3x at 20mm spacing along plane X.
// 20 > 10 so the copies are disjoint -> total V = 3*1000 = 3000.
@@ -1221,8 +1215,6 @@ TEST_CASE("pattern replicates a body linearly and circularly", "[CadDocument]")
TEST_CASE("pattern-on-curve: copies land on a line and bbox spans the curve length", "[CadDocument][pattern]")
{
using Catch::Matchers::WithinAbs;
using Catch::Matchers::WithinRel;
using namespace Slic3r;
CadDocument doc;
@@ -1250,7 +1242,6 @@ TEST_CASE("pattern-on-curve: copies land on a line and bbox spans the curve leng
TEST_CASE("pattern-on-curve: bad refs are safe", "[CadDocument][pattern]")
{
using namespace Slic3r;
CadDocument doc;
int s0 = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 4, 4, 0, "Seed");
@@ -1266,7 +1257,6 @@ TEST_CASE("pattern-on-curve: bad refs are safe", "[CadDocument][pattern]")
TEST_CASE("pattern-on-curve: round-trip through serialize/deserialize", "[CadDocument][pattern]")
{
using Catch::Matchers::WithinRel;
using namespace Slic3r;
CadDocument doc;
int s0 = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 4, 4, 0, "Seed");
@@ -1312,7 +1302,6 @@ TEST_CASE("pattern-on-curve: round-trip through serialize/deserialize", "[CadDoc
TEST_CASE("thread standards table carries correct ISO/UTS measures", "[CadDocument]")
{
using namespace Slic3r;
// Table is non-empty and every entry is self-consistent.
const auto& table = thread_standards();
@@ -1459,7 +1448,6 @@ TEST_CASE("loft builds a solid skinning two profiles on parallel planes", "[CadD
TEST_CASE("draft tapers a solid face about the body base", "[CadDocument]")
{
using namespace Slic3r;
// 10x10x10 box from z=0..10 (V=1000). Drafting a vertical side face by +10deg about
// the bottom (neutral) plane tilts its top edge inward, removing material so V<1000.
@@ -1740,7 +1728,6 @@ TEST_CASE("split by face keep upper only", "[CadDocument][cut]")
TEST_CASE("split by face round-trip serialization", "[CadDocument][cut]")
{
using Catch::Matchers::WithinRel;
using Catch::Matchers::WithinAbs;
CadDocument doc;
@@ -1808,7 +1795,6 @@ TEST_CASE("split by face round-trip serialization", "[CadDocument][cut]")
TEST_CASE("mirror reflects a body about a plane", "[CadDocument]")
{
using Catch::Matchers::WithinRel;
using Catch::Matchers::WithinAbs;
auto make_box = [](CadDocument& doc, double w, double h, double d) {
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), w, h, 0, "Box");
@@ -1939,7 +1925,6 @@ TEST_CASE("mirror reflects a body about a plane", "[CadDocument]")
TEST_CASE("mirror serialization round-trip", "[CadDocument]")
{
using Catch::Matchers::WithinRel;
CadDocument doc;
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 20, 20, 0, "Box");
@@ -2453,7 +2438,6 @@ TEST_CASE("a v3 recipe is refused with a message naming the version", "[CadDocum
TEST_CASE("re-edit: editing a mid-timeline feature rebuilds downstream", "[CadDocument]")
{
using Catch::Matchers::WithinRel;
CadDocument doc;
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(),
@@ -2486,7 +2470,6 @@ TEST_CASE("re-edit: editing a mid-timeline feature rebuilds downstream", "[CadDo
TEST_CASE("re-edit survives serialize -> deserialize", "[CadDocument]")
{
using Catch::Matchers::WithinRel;
CadDocument doc;
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(),
@@ -2519,7 +2502,6 @@ TEST_CASE("re-edit survives serialize -> deserialize", "[CadDocument]")
TEST_CASE("re-edit: multi-type timeline replays all downstream features", "[CadDocument]")
{
using Catch::Matchers::WithinRel;
CadDocument doc;
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(),
@@ -2994,7 +2976,6 @@ TEST_CASE("datum coordinate system: point_world gives world axes", "[CadDocument
TEST_CASE("helix curve: arc length, bounding box, left-handed, conical", "[CadDocument]")
{
using Catch::Matchers::WithinRel;
using Catch::Matchers::WithinAbs;
// --- Cylindrical helix r=5, pitch=2, height=10 (5 turns) ---
// One turn arc length = sqrt((2*pi*r)^2 + pitch^2) = sqrt((10*pi)^2 + 4).
@@ -3386,7 +3367,6 @@ TEST_CASE("transform degenerate axis errors", "[CadDocument]")
TEST_CASE("transform moved body participates in later boolean at its new position", "[CadDocument]")
{
using Catch::Matchers::WithinAbs;
CadDocument doc;
// Two boxes that do NOT overlap
@@ -3516,7 +3496,6 @@ TEST_CASE("thicken a planar face to a plate", "[CadDocument]")
TEST_CASE("thicken flip offsets against face normal", "[CadDocument]")
{
using Catch::Matchers::WithinAbs;
CadDocument doc;
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 20, 20, 0, "BoxSketch");
@@ -3615,7 +3594,6 @@ TEST_CASE("thicken zero thickness returns error", "[CadDocument]")
TEST_CASE("thickened plate fuses with source", "[CadDocument]")
{
using Catch::Matchers::WithinRel;
CadDocument doc;
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 20, 20, 0, "Box");
@@ -3649,7 +3627,6 @@ TEST_CASE("thickened plate fuses with source", "[CadDocument]")
TEST_CASE("thicken round-trip serialization", "[CadDocument]")
{
using Catch::Matchers::WithinAbs;
using Catch::Matchers::WithinRel;
CadDocument doc;
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 20, 20, 0, "Box");
@@ -3833,7 +3810,6 @@ TEST_CASE("project bad face id returns error", "[CadDocument][project]")
TEST_CASE("project round-trip serialization", "[CadDocument][project]")
{
using Catch::Matchers::WithinAbs;
using Catch::Matchers::WithinRel;
CadDocument doc;
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 20, 20, 10, "Box");
@@ -4609,8 +4585,6 @@ TEST_CASE("golden recipe v1 still deserialises", "[CadDocument]")
TEST_CASE("rib adds material to a box", "[CadDocument][rib]")
{
using Catch::Matchers::WithinRel;
using Catch::Matchers::WithinAbs;
CadDocument doc;
@@ -4763,7 +4737,6 @@ TEST_CASE("bridge two collinear lines", "[CadDocument][bridge]")
TEST_CASE("bridge closes a C profile and extrudes", "[CadDocument][bridge]")
{
using Catch::Matchers::WithinAbs;
using Catch::Matchers::WithinRel;
CadDocument doc;
@@ -4861,8 +4834,6 @@ TEST_CASE("bridge round-trip serialization", "[CadDocument][bridge]")
TEST_CASE("delete_face removes a fillet face and restores volume", "[CadDocument][deleteface]")
{
using Catch::Matchers::WithinRel;
using Catch::Matchers::WithinAbs;
CadDocument doc;
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 20, 20, 10, "Box");
@@ -4912,7 +4883,6 @@ TEST_CASE("delete_face with bad face index fails safely", "[CadDocument][deletef
TEST_CASE("delete_face round-trip serialization", "[CadDocument][deleteface]")
{
using Catch::Matchers::WithinRel;
using Catch::Matchers::WithinAbs;
CadDocument doc;
@@ -4970,7 +4940,6 @@ TEST_CASE("delete_face round-trip serialization", "[CadDocument][deleteface]")
TEST_CASE("hole: counterbore removes more material than a simple bore", "[CadDocument][hole]")
{
using Catch::Matchers::WithinAbs;
auto make_box_hole = [](int style, double cbore_d, double cbore_depth,
double csink_d, double csink_angle, const std::string& desig) {
CadDocument doc;
@@ -4998,7 +4967,6 @@ TEST_CASE("hole: counterbore removes more material than a simple bore", "[CadDoc
TEST_CASE("hole: countersink removes more material than a simple bore", "[CadDocument][hole]")
{
using Catch::Matchers::WithinAbs;
auto make_box = []() {
CadDocument doc;
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 30, 30, 0, "Box");
@@ -5301,7 +5269,6 @@ TEST_CASE("parametric recipe round-trips through serialize/deserialize", "[CadDo
TEST_CASE("surface-extrude makes an open shell", "[CadDocument][surface]")
{
using Catch::Matchers::WithinRel;
CadDocument doc;
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 20, 20, 0, "Rect");
@@ -5324,7 +5291,6 @@ TEST_CASE("surface-extrude makes an open shell", "[CadDocument][surface]")
TEST_CASE("surface-revolve makes an open shell", "[CadDocument][surface]")
{
using Catch::Matchers::WithinRel;
CadDocument doc;
// A small rectangle offset from the axis: u=10..15, v=0..5.
@@ -5395,7 +5361,6 @@ TEST_CASE("surface round-trip serialize/deserialize", "[CadDocument][surface]")
TEST_CASE("thicken-surface makes a solid from a sheet", "[CadDocument][surface]")
{
using Catch::Matchers::WithinRel;
using Catch::Matchers::WithinAbs;
CadDocument doc;
@@ -5519,7 +5484,6 @@ TEST_CASE("thicken surface fills the corners of a closed-loop wall", "[CadDocume
TEST_CASE("surface-offset creates another sheet shifted outward", "[CadDocument][surface]")
{
using Catch::Matchers::WithinAbs;
CadDocument doc;
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 20, 20, 0, "Rect");
@@ -5568,7 +5532,6 @@ TEST_CASE("thicken-surface on non-sheet fails", "[CadDocument][surface]")
TEST_CASE("thicken-surface round-trip serialize/deserialize", "[CadDocument][surface]")
{
using Catch::Matchers::WithinAbs;
using Catch::Matchers::WithinRel;
CadDocument doc;
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 20, 20, 0, "Rect");
@@ -5608,7 +5571,6 @@ TEST_CASE("thicken-surface round-trip serialize/deserialize", "[CadDocument][sur
TEST_CASE("surface-loft makes an open shell", "[CadDocument][surface]")
{
using Catch::Matchers::WithinAbs;
CadDocument doc;
SketchProfile bot;
@@ -6315,7 +6277,6 @@ TEST_CASE("mate conflicts: a broken mate is left to apply_mate", "[CadDocument][
TEST_CASE("ordering: fillet after mate resolves face ids", "[CadDocument][mate]")
{
using Catch::Matchers::WithinAbs;
CadDocument doc;
int sk_a = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 10, 10, 0, "BoxA");
@@ -7846,7 +7807,6 @@ TEST_CASE("plane_of_face gives a sketchable plane for a planar face only", "[Cad
// that asserts a state the code cannot reach is exactly what the contract forbids.
TEST_CASE("recompute on a healthy box + fillet leaves no body null and no error (positive contract)", "[CadDocument]")
{
using namespace Slic3r;
CadDocument doc;
SketchProfile sp;
sp.points.push_back(Vec2d(0, 0));
@@ -8758,7 +8718,6 @@ TEST_CASE("a body carries its own name, through recompute and the recipe", "[Cad
TEST_CASE("deleting a feature remaps the references of every consumer, not just Extrude",
"[CadDocument]")
{
using namespace Slic3r;
const SketchPlane xy = SketchPlane::XY();
// A rectangle 10x10 centred at v = 15, revolved 360 deg about the plane X axis.
@@ -9098,7 +9057,6 @@ namespace {
// centerline x = 0 from (0,0) to (0,20): the half-profile of a tube, drawn the usual way.
Slic3r::CadFeature tube_half_profile()
{
using namespace Slic3r;
CadFeature sk;
sk.type = CadFeatureType::Sketch;
sk.plane = SketchPlane::XY();
@@ -9113,7 +9071,6 @@ Slic3r::CadFeature tube_half_profile()
TEST_CASE("revolve about a line of the sketch", "[CadDocument][revolve]")
{
using namespace Slic3r;
SECTION("a construction centerline: the profile sweeps into a tube around it") {
CadDocument doc;
+104 -3
View File
@@ -16,7 +16,6 @@
#include <cereal/types/vector.hpp>
#include <cereal/archives/binary.hpp>
#include <boost/filesystem.hpp>
#include <boost/nowide/fstream.hpp>
#include "libslic3r/Config.hpp"
#include <cstddef>
@@ -32,8 +31,6 @@
#include <utility>
#include <catch2/matchers/catch_matchers_vector.hpp>
namespace fs = boost::filesystem;
using namespace Slic3r;
SCENARIO("Generic config validation performs as expected.", "[Config]") {
@@ -541,6 +538,110 @@ SCENARIO("update_diff_values_to_child_config keeps a child's values on variants
}
}
SCENARIO("update_non_diff_values_to_base_config keeps a project's changed values on variants it does not list",
"[Config][Variant]") {
std::set<std::string> no_keys;
auto variants = [](std::initializer_list<std::string> names) { return new Slic3r::ConfigOptionStrings(names); };
GIVEN("A filament base with three variants") {
Slic3r::DynamicPrintConfig base;
base.set_key_value("filament_extruder_variant",
variants({"Direct Drive Standard", "Bowden Standard", "Direct Drive High Flow"}));
base.set_deserialize_strict("nozzle_temperature", "220,220,220");
WHEN("the project was saved when the base had only its first variant") {
Slic3r::DynamicPrintConfig project;
project.set_key_value("filament_extruder_variant", variants({"Direct Drive Standard"}));
project.set_deserialize_strict("nozzle_temperature", "199");
AND_WHEN("the project lists the value as changed") {
project.update_non_diff_values_to_base_config(base, project.keys(), {"nozzle_temperature"}, "", "filament_extruder_variant",
Slic3r::filament_options_with_variant, no_keys);
THEN("the project's value applies to every variant") {
REQUIRE(project.opt_serialize("nozzle_temperature") == "199,199,199");
}
}
AND_WHEN("the project does not list the value as changed") {
project.update_non_diff_values_to_base_config(base, project.keys(), {}, "", "filament_extruder_variant",
Slic3r::filament_options_with_variant, no_keys);
THEN("the base's values replace it") {
REQUIRE(project.opt_serialize("nozzle_temperature") == "220,220,220");
}
}
}
WHEN("the project lists every variant, in another order") {
Slic3r::DynamicPrintConfig project;
project.set_key_value("filament_extruder_variant",
variants({"Bowden Standard", "Direct Drive High Flow", "Direct Drive Standard"}));
project.set_deserialize_strict("nozzle_temperature", "190,205,199");
project.update_non_diff_values_to_base_config(base, project.keys(), {"nozzle_temperature"}, "", "filament_extruder_variant",
Slic3r::filament_options_with_variant, no_keys);
THEN("each variant keeps its own value") {
REQUIRE(project.opt_serialize("nozzle_temperature") == "199,190,205");
}
}
WHEN("the project lists no variants") {
Slic3r::DynamicPrintConfig project;
project.set_deserialize_strict("nozzle_temperature", "199");
project.update_non_diff_values_to_base_config(base, project.keys(), {"nozzle_temperature"}, "", "filament_extruder_variant",
Slic3r::filament_options_with_variant, no_keys);
THEN("the project's value applies to every variant") {
REQUIRE(project.opt_serialize("nozzle_temperature") == "199,199,199");
}
}
}
GIVEN("A two-extruder printer base with two variants per extruder") {
Slic3r::DynamicPrintConfig base;
base.set_key_value("printer_extruder_variant",
variants({"Direct Drive Standard", "Direct Drive High Flow", "Direct Drive Standard", "Direct Drive High Flow"}));
base.set_key_value("printer_extruder_id", new Slic3r::ConfigOptionInts({1, 1, 2, 2}));
base.set_deserialize_strict("retraction_length", "0.8,0.8,0.8,0.8");
WHEN("the project lists only the Standard variant of each extruder") {
Slic3r::DynamicPrintConfig project;
project.set_key_value("printer_extruder_variant", variants({"Direct Drive Standard", "Direct Drive Standard"}));
project.set_key_value("printer_extruder_id", new Slic3r::ConfigOptionInts({1, 2}));
project.set_deserialize_strict("retraction_length", "1.1,2.2");
project.update_non_diff_values_to_base_config(base, project.keys(), {"retraction_length"}, "printer_extruder_id", "printer_extruder_variant",
Slic3r::printer_options_with_variant_1,
Slic3r::printer_options_with_variant_2);
THEN("each extruder's High Flow variant takes that extruder's value") {
REQUIRE(project.opt_serialize("retraction_length") == "1.1,1.1,2.2,2.2");
}
}
WHEN("the project lists only the Standard variant of each extruder, and the variant lists as changed") {
Slic3r::DynamicPrintConfig project;
project.set_key_value("printer_extruder_variant", variants({"Direct Drive Standard", "Direct Drive Standard"}));
project.set_key_value("printer_extruder_id", new Slic3r::ConfigOptionInts({1, 2}));
project.set_deserialize_strict("machine_max_speed_x", "300,100,400,150");
base.set_deserialize_strict("machine_max_speed_x", "500,200,500,200,500,200,500,200");
project.update_non_diff_values_to_base_config(base, project.keys(),
{"machine_max_speed_x", "printer_extruder_id", "printer_extruder_variant"},
"printer_extruder_id", "printer_extruder_variant",
Slic3r::printer_options_with_variant_1,
Slic3r::printer_options_with_variant_2);
THEN("the variant lists are the base's") {
REQUIRE(project.opt_serialize("printer_extruder_variant") == base.opt_serialize("printer_extruder_variant"));
REQUIRE(project.opt_serialize("printer_extruder_id") == "1,1,2,2");
}
THEN("each extruder's High Flow variant takes that extruder's pair of limits") {
REQUIRE(project.opt_serialize("machine_max_speed_x") == "300,100,300,100,400,150,400,150");
}
}
WHEN("the project lists no variants") {
Slic3r::DynamicPrintConfig project;
project.set_deserialize_strict("retraction_length", "1.1");
project.update_non_diff_values_to_base_config(base, project.keys(), {"retraction_length"}, "printer_extruder_id", "printer_extruder_variant",
Slic3r::printer_options_with_variant_1,
Slic3r::printer_options_with_variant_2);
THEN("only the first extruder's variants take the project's value") {
REQUIRE(project.opt_serialize("retraction_length") == "1.1,1.1,0.8,0.8");
}
}
}
}
// SCENARIO("DynamicPrintConfig JSON serialization", "[Config]") {
// WHEN("DynamicPrintConfig is serialized and deserialized") {
// auto now = std::chrono::high_resolution_clock::now();
@@ -799,3 +799,67 @@ TEST_CASE("A per-variant filament option read with a single value gives it to ev
config.load_from_ini_string("pressure_advance = 0.021", ForwardCompatibilitySubstitutionRule::Disable);
REQUIRE(config.option<ConfigOptionFloats>("pressure_advance")->values == std::vector<double>({0.021, 0.021, 0.021}));
}
// Machine limits (printer_options_with_variant_2) hold a (normal, silent) pair per printer variant, so the
// printer Tab's Motion ability page can edit each extruder's own limits.
TEST_CASE("set_num_extruders gives every printer variant its own pair of machine limits", "[Config]")
{
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
auto speed_x = [&config]() { return config.option<ConfigOptionFloats>("machine_max_speed_x")->values; };
SECTION("a new extruder's pair is padded with the first value, like the other variant keys") {
config.option<ConfigOptionFloats>("machine_max_speed_x")->values = {500., 200.};
config.set_num_extruders(3);
REQUIRE(config.option<ConfigOptionStrings>("printer_extruder_variant")->size() == 3);
REQUIRE(speed_x() == std::vector<double>({500., 200., 500., 500., 500., 500.}));
}
SECTION("per-extruder pairs are kept, and removing an extruder removes its pair") {
config.option<ConfigOptionFloats>("machine_max_speed_x")->values = {500., 200., 400., 150., 300., 100.};
config.set_num_extruders(3);
REQUIRE(speed_x() == std::vector<double>({500., 200., 400., 150., 300., 100.}));
config.set_num_extruders(2);
REQUIRE(speed_x() == std::vector<double>({500., 200., 400., 150.}));
}
SECTION("a printer with nozzle variants gets a pair per variant") {
// 2 extruders x 2 variants each = 4 variants
config.option<ConfigOptionStrings>("extruder_variant_list", true)->values = {"Direct Drive Standard,Direct Drive High Flow",
"Direct Drive Standard,Direct Drive High Flow"};
const std::vector<double> per_variant = {500., 200., 510., 210., 520., 220., 530., 230.};
config.option<ConfigOptionFloats>("machine_max_speed_x")->values = per_variant;
config.set_num_extruders(2);
REQUIRE(speed_x() == per_variant);
config.option<ConfigOptionFloats>("machine_max_speed_x")->values = {500., 200.};
config.set_num_extruders(2);
REQUIRE(speed_x() == std::vector<double>({500., 200., 500., 500., 500., 500., 500., 500.}));
}
}
// The device drying options hold several values per filament, as many as each filament preset gives.
TEST_CASE("The device drying options are rebuilt as each filament's values in slot order", "[Config]")
{
DynamicPrintConfig two_values, one_value, no_value;
two_values.option<ConfigOptionStrings>("filament_dev_ams_drying_ams_limitations", true)->values = {"1", "0"};
two_values.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature", true)->values = {45., 45., 55., 55.};
one_value.option<ConfigOptionStrings>("filament_dev_ams_drying_ams_limitations", true)->values = {"1"};
one_value.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature", true)->values = {65., 65., 75., 75.};
// values a project stored for three other filaments
DynamicPrintConfig config;
config.option<ConfigOptionStrings>("filament_dev_ams_drying_ams_limitations", true)->values = {"0", "0", "0"};
config.option<ConfigOptionFloats>("filament_dev_chamber_drying_time", true)->values = {12., 8., 12.};
set_filament_dev_options(config, {&two_values, &one_value, &two_values});
REQUIRE(config.option<ConfigOptionStrings>("filament_dev_ams_drying_ams_limitations")->values ==
std::vector<std::string>({"1", "0", "1", "1", "0"}));
REQUIRE(config.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature")->values ==
std::vector<double>({45., 45., 55., 55., 65., 65., 75., 75., 45., 45., 55., 55.}));
// an option no filament defines keeps the stored values
REQUIRE(config.option<ConfigOptionFloats>("filament_dev_chamber_drying_time")->values == std::vector<double>({12., 8., 12.}));
// a filament without the option takes the option's default
set_filament_dev_options(config, {&two_values, &no_value});
REQUIRE(config.option<ConfigOptionStrings>("filament_dev_ams_drying_ams_limitations")->values == std::vector<std::string>({"1", "0", ""}));
}
@@ -19,7 +19,6 @@
using namespace Slic3r;
TEST_CASE("Split empty mesh", "[its_split][its]") {
using namespace Slic3r;
indexed_triangle_set its;
@@ -29,7 +28,6 @@ TEST_CASE("Split empty mesh", "[its_split][its]") {
}
TEST_CASE("Split simple mesh consisting of one part", "[its_split][its]") {
using namespace Slic3r;
auto cube = its_make_cube(10., 10., 10.);
@@ -53,7 +51,6 @@ void debug_write_obj(const std::vector<indexed_triangle_set> &res, const std::st
}
TEST_CASE("Split two non-watertight mesh", "[its_split][its]") {
using namespace Slic3r;
auto cube1 = its_make_cube(10., 10., 10.);
cube1.indices.pop_back();
@@ -76,7 +73,6 @@ TEST_CASE("Split two non-watertight mesh", "[its_split][its]") {
}
TEST_CASE("Split non-manifold mesh", "[its_split][its]") {
using namespace Slic3r;
auto cube = its_make_cube(10., 10., 10.), cube_low = cube;
@@ -96,7 +92,6 @@ TEST_CASE("Split non-manifold mesh", "[its_split][its]") {
}
TEST_CASE("Split two watertight meshes", "[its_split][its]") {
using namespace Slic3r;
auto sphere1 = its_make_sphere(10., 2 * PI / 200.), sphere2 = sphere1;
-2
View File
@@ -377,7 +377,6 @@ TEST_CASE("10x10 raster with two rings", "[MarchingSquares]")
TEST_CASE("Square with hole in the middle", "[MarchingSquares]")
{
using namespace Slic3r;
ExPolygons inp = {square_with_hole(50.)};
@@ -434,7 +433,6 @@ TEST_CASE("Square with hole in the middle", "[MarchingSquares]")
TEST_CASE("Circle with hole in the middle", "[MarchingSquares]")
{
using namespace Slic3r;
test_expolys(create_raster({1000, 1000}), circle_with_hole(25.), W1x1, "circle_with_hole");
}
@@ -6228,8 +6228,9 @@ TEST_CASE("A per-variant project value maps onto its base preset's variant layou
base_finder(&base, calls));
CHECK(config.option<ConfigOptionStrings>("print_extruder_variant")->values ==
std::vector<std::string>{"Direct Drive Standard", "Direct Drive High Flow"});
// The listed key keeps the project's Standard value and takes High Flow from the base.
check_double_vector(config.option<ConfigOptionFloats>("outer_wall_speed")->values, {100., 300.});
// The listed key keeps the project's Standard value, and High Flow, which the project does not
// list, takes it too, as a user preset's value does.
check_double_vector(config.option<ConfigOptionFloats>("outer_wall_speed")->values, {100., 100.});
check_double_vector(config.option<ConfigOptionFloats>("inner_wall_speed")->values, {250., 350.});
}
-2
View File
@@ -9,8 +9,6 @@
#include <locale>
#include <string>
using namespace Slic3r;
static void test_time_fmt(Slic3r::Utils::TimeFormat fmt) {
using namespace Slic3r::Utils;
time_t t = get_current_time_utc();
-4
View File
@@ -29,10 +29,6 @@
#include <libslic3r/VoronoiVisualUtils.hpp>
#endif
using boost::polygon::voronoi_builder;
using boost::polygon::voronoi_diagram;
using boost::polygon::construct_voronoi;
using namespace Slic3r;
using VD = Geometry::VoronoiDiagram;
+36 -29
View File
@@ -78,31 +78,34 @@ TEST_CASE("Series and managed classification", "[NetworkVersions]")
TEST_CASE_METHOD(PluginFolderFixture, "Managed builds fold into the series; customs are surfaced", "[NetworkVersions]")
{
add_plugin("02.08.01.55"); // managed, same series -> folded into the 02.08.01 row
add_plugin("02.08.04.60"); // managed, same series -> folded into the 02.08.04 row
add_plugin("02.09.00.10"); // managed, unknown series -> not listed
add_plugin("02.08.01.55"); // managed, series this build no longer has an ABI for -> not listed
add_plugin("02.03.00.62"); // managed, older whitelisted series -> folded into 02.03.00
add_plugin("02.01.01.52"); // managed, series with no ABI in this build -> not listed
add_plugin("02.08.01_custom"); // custom, whitelisted series -> listed under it
add_plugin("02.08.01.52-dev"); // custom (dash-suffixed), whitelisted series -> listed
add_plugin("02.08.04_custom"); // custom, whitelisted series -> listed under it
add_plugin("02.08.04.52-dev"); // custom (dash-suffixed), whitelisted series -> listed
auto versions = get_all_available_versions();
// The specific managed build never gets its own row - the series represents it.
REQUIRE(count_version(versions, "02.08.01.55") == 0);
REQUIRE(count_version(versions, "02.08.01") == 1);
REQUIRE(count_version(versions, "02.08.04.60") == 0);
REQUIRE(count_version(versions, "02.08.04") == 1);
REQUIRE(count_version(versions, "02.09.00.10") == 0);
REQUIRE(count_version(versions, "02.08.01.55") == 0);
REQUIRE(count_version(versions, "02.08.01") == 0);
REQUIRE(count_version(versions, "02.03.00.62") == 0);
REQUIRE(count_version(versions, "02.03.00") == 1);
REQUIRE(count_version(versions, "02.01.01.52") == 0);
// Custom-named builds are distinct files kept under their own name.
REQUIRE(count_version(versions, "02.08.01_custom") == 1);
REQUIRE(count_version(versions, "02.08.01.52-dev") == 1);
REQUIRE(count_version(versions, "02.08.04_custom") == 1);
REQUIRE(count_version(versions, "02.08.04.52-dev") == 1);
// Newest series first, its customs nested under it (suffix sort: "" < ".52-dev" < "_custom"),
// then older series, legacy last.
REQUIRE(versions[0].version == "02.08.01");
REQUIRE(versions[1].version == "02.08.01.52-dev");
REQUIRE(versions[2].version == "02.08.01_custom");
REQUIRE(versions[0].version == "02.08.04");
REQUIRE(versions[1].version == "02.08.04.52-dev");
REQUIRE(versions[2].version == "02.08.04_custom");
REQUIRE(versions[3].version == "02.03.00");
REQUIRE(versions.back().version == BAMBU_NETWORK_AGENT_VERSION_LEGACY);
@@ -111,9 +114,9 @@ TEST_CASE_METHOD(PluginFolderFixture, "Managed builds fold into the series; cust
REQUIRE_FALSE(versions[3].is_latest);
// Customs sort/render nested under their series (non-empty suffix, base = the series).
REQUIRE(versions[1].base_version == "02.08.01");
REQUIRE(versions[1].base_version == "02.08.04");
REQUIRE_FALSE(versions[1].suffix.empty());
REQUIRE(versions[2].base_version == "02.08.01");
REQUIRE(versions[2].base_version == "02.08.04");
REQUIRE_FALSE(versions[2].suffix.empty());
// "(Latest)" is the series row, never a nested custom build.
@@ -123,20 +126,20 @@ TEST_CASE_METHOD(PluginFolderFixture, "Managed builds fold into the series; cust
REQUIRE_FALSE(versions[2].is_latest);
// The stored default that drives download and update-check decisions is now the series.
REQUIRE(std::string(get_latest_network_version()) == "02.08.01");
REQUIRE(std::string(get_latest_network_version()) == "02.08.04");
}
TEST_CASE_METHOD(PluginFolderFixture, "Only the loaded series is marked installed", "[NetworkVersions]")
{
add_plugin("02.08.01.55");
add_plugin("02.08.01_custom");
add_plugin("02.08.04.60");
add_plugin("02.08.04_custom");
// The loaded plug-in reports its full build (02.08.01.55); the series row is what gets marked.
// The loaded plug-in reports its full build (02.08.04.60); the series row is what gets marked.
{
auto versions = get_all_available_versions("02.08.01.55");
auto versions = get_all_available_versions("02.08.04.60");
int marked = 0;
for (const auto& info : versions)
if (info.is_loaded) { ++marked; REQUIRE(info.version == "02.08.01"); }
if (info.is_loaded) { ++marked; REQUIRE(info.version == "02.08.04"); }
REQUIRE(marked == 1);
}
@@ -152,10 +155,10 @@ TEST_CASE_METHOD(PluginFolderFixture, "Only the loaded series is marked installe
// A loaded custom build matches its own row, never the bare series.
{
auto versions = get_all_available_versions("02.08.01_custom");
auto versions = get_all_available_versions("02.08.04_custom");
int marked = 0;
for (const auto& info : versions)
if (info.is_loaded) { ++marked; REQUIRE(info.version == "02.08.01_custom"); }
if (info.is_loaded) { ++marked; REQUIRE(info.version == "02.08.04_custom"); }
REQUIRE(marked == 1);
}
@@ -167,11 +170,11 @@ TEST_CASE_METHOD(PluginFolderFixture, "Only the loaded series is marked installe
TEST_CASE("Only whitelisted series pass the load gate", "[NetworkVersions]")
{
// Each whitelisted series, its builds, and custom-named builds of that series.
REQUIRE(is_supported_network_version("02.08.01"));
REQUIRE(is_supported_network_version("02.08.01.52"));
REQUIRE(is_supported_network_version("02.08.01.55"));
REQUIRE(is_supported_network_version("02.08.01_custom"));
REQUIRE(is_supported_network_version("02.08.01.52-dev"));
REQUIRE(is_supported_network_version("02.08.04"));
REQUIRE(is_supported_network_version("02.08.04.52"));
REQUIRE(is_supported_network_version("02.08.04.60"));
REQUIRE(is_supported_network_version("02.08.04_custom"));
REQUIRE(is_supported_network_version("02.08.04.52-dev"));
REQUIRE(is_supported_network_version("02.03.00"));
REQUIRE(is_supported_network_version("02.03.00.62"));
REQUIRE(is_supported_network_version("02.03.00.70"));
@@ -179,6 +182,9 @@ TEST_CASE("Only whitelisted series pass the load gate", "[NetworkVersions]")
REQUIRE(is_supported_network_version(BAMBU_NETWORK_AGENT_VERSION_LEGACY));
// Series whitelisted by previous Orca releases that no generation here can call.
REQUIRE_FALSE(is_supported_network_version("02.08.01"));
REQUIRE_FALSE(is_supported_network_version("02.08.01.55"));
REQUIRE_FALSE(is_supported_network_version("02.08.01_custom"));
REQUIRE_FALSE(is_supported_network_version("02.01.01.52"));
REQUIRE_FALSE(is_supported_network_version("02.00.02.50"));
@@ -198,9 +204,9 @@ TEST_CASE("Each version resolves to the ABI generation that can call it", "[Netw
{
// The generation is keyed on the series, so every build of a series - including the
// custom-named ones - resolves to the same one.
CHECK(network_plugin_abi("02.08.01") == NetworkAbi::Current);
CHECK(network_plugin_abi("02.08.01.55") == NetworkAbi::Current);
CHECK(network_plugin_abi("02.08.01.52-dev") == NetworkAbi::Current);
CHECK(network_plugin_abi("02.08.04") == NetworkAbi::Current);
CHECK(network_plugin_abi("02.08.04.60") == NetworkAbi::Current);
CHECK(network_plugin_abi("02.08.04.52-dev") == NetworkAbi::Current);
CHECK(network_plugin_abi("02.03.00") == NetworkAbi::V0203);
CHECK(network_plugin_abi("02.03.00.62") == NetworkAbi::V0203);
CHECK(network_plugin_abi("02.03.00_custom") == NetworkAbi::V0203);
@@ -208,6 +214,7 @@ TEST_CASE("Each version resolves to the ABI generation that can call it", "[Netw
// Anything the load gate rejects must dispatch through nothing at all, rather than
// defaulting to a layout it does not share.
CHECK(network_plugin_abi("02.08.01.55") == NetworkAbi::Unsupported);
CHECK(network_plugin_abi("02.01.01.52") == NetworkAbi::Unsupported);
CHECK(network_plugin_abi("02.00.02.50") == NetworkAbi::Unsupported);
CHECK(network_plugin_abi("02.09.00.10") == NetworkAbi::Unsupported);
@@ -234,7 +241,7 @@ TEST_CASE_METHOD(PluginFolderFixture, "Legacy series never adopts discovered bui
// With nothing else on disk, the series holds "(Latest)" even though its library is
// not installed.
for (const auto& info : versions) {
if (info.version == "02.08.01") {
if (info.version == "02.08.04") {
REQUIRE(info.is_latest);
REQUIRE_FALSE(info.is_loaded);
}
-3
View File
@@ -13,9 +13,6 @@ using Slic3r::GUI::PluginSortKey;
using Slic3r::GUI::PluginSortOrder;
using Slic3r::GUI::PluginSource;
using Slic3r::GUI::PluginStatus;
using Slic3r::GUI::plugin_sort_key_from_string;
using Slic3r::GUI::plugin_sort_order_from_string;
using Slic3r::GUI::sort_plugin_items_for_dialog;
namespace {
@@ -144,7 +144,6 @@ TEST_CASE("orca.slicing is workflow-only: context exposes raw print/object; view
}
#include "libslic3r/PrintConfig.hpp" // DynamicPrintConfig for the psGCodePostProcess context
#include <boost/filesystem.hpp>
#include <boost/nowide/fstream.hpp>
#include <sstream>
#include "libslic3r/BoundingBox.hpp"
@@ -157,7 +156,6 @@ TEST_CASE("orca.slicing is workflow-only: context exposes raw print/object; view
// the export path handed in. Exercising the real bindings by calling the Python execute() directly
// (not the C++ audit trampoline) keeps this a pure binding-surface test.
TEST_CASE("orca.slicing psGCodePostProcess context: file edit in place + config fallback", "[slicing_pipeline]") {
namespace fs = boost::filesystem;
ensure_python_initialized();
import_orca_module();
py::gil_scoped_acquire gil;
@@ -237,7 +235,6 @@ struct TestLayerRegion : Slic3r::LayerRegion {
// decomposition of an ExtrusionLoop into its contained ExtrusionPath (flatten()
// does NOT decompose loops, hence the hand-rolled recursive walk).
static void build_nested_perimeters(TestLayerRegion& region) {
using namespace Slic3r;
ExtrusionPath pathA(erExternalPerimeter); // -> "Outer wall"
pathA.mm3_per_mm = 0.05; pathA.width = 0.45f; pathA.height = 0.20f;
pathA.polyline.points = { Point3(0, 0, 0), Point3(10, 0, 0), Point3(10, 10, 0) };
@@ -434,7 +431,6 @@ namespace {
// Nested collection: outer -> inner -> [ ExtrusionLoop(pathA), ExtrusionPath(pathB) ].
// Exercises polymorphic downcast of .entities and loop decomposition in flatten_paths().
static Slic3r::ExtrusionEntityCollection build_nested_collection() {
using namespace Slic3r;
ExtrusionPath pathA(erExternalPerimeter); // -> "Outer wall"
pathA.mm3_per_mm = 0.05; pathA.width = 0.45f; pathA.height = 0.20f;
pathA.polyline.points = { Point3(0, 0, 0), Point3(10, 0, 0), Point3(10, 10, 0) };