mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-05 14:51:06 +00:00
Merge branch 'main' into feat/generic-n-extruders
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
#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;
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#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>
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
#include "libslic3r/AABBTreeLines.hpp"
|
||||
#include "libslic3r/GCode.hpp"
|
||||
#include "libslic3r/GCode/ExtrusionProcessor.hpp"
|
||||
#include "libslic3r/GCodeReader.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
@@ -9,7 +16,17 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include "libslic3r/Line.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <cstddef>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace Slic3r;
|
||||
@@ -524,6 +541,187 @@ TEST_CASE("A wall is left whole where neither its speed nor its cooling changes"
|
||||
REQUIRE(points.size() == 3);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// The caged overhang box, sliced, and a layer on its slope.
|
||||
struct SlicedCage
|
||||
{
|
||||
Print print;
|
||||
Model model;
|
||||
const PrintObject *object{nullptr};
|
||||
const Layer *layer{nullptr};
|
||||
|
||||
explicit SlicedCage(const DynamicPrintConfig &config = caged_overhang_config("classic"))
|
||||
{
|
||||
init_print(std::vector<TriangleMesh>{caged_overhang_mesh()}, print, model, config, nullptr, false);
|
||||
print.process();
|
||||
object = print.objects().front();
|
||||
layer = object->get_layer(int(std::lround((caged_slope_z_min + caged_slope_z_max) / 2. / caged_layer_height)));
|
||||
}
|
||||
};
|
||||
|
||||
using Walls = std::vector<std::vector<ProcessedPoint>>;
|
||||
|
||||
// Estimates every wall of `layer` against whatever layer `estimator` was last prepared with before it.
|
||||
Walls estimate_walls(ExtrusionQualityEstimator &estimator, const PrintObject *object, const Layer &layer)
|
||||
{
|
||||
const ConfigOptionPercents overlaps({90, 75, 50, 25, 13, 0});
|
||||
const ConfigOptionFloatsOrPercents speeds({FloatOrPercent{100, true}, FloatOrPercent{50, true}, FloatOrPercent{30, true},
|
||||
FloatOrPercent{20, true}, FloatOrPercent{10, true}, FloatOrPercent{5, true}});
|
||||
Walls walls;
|
||||
estimator.set_current_object(object);
|
||||
for (const LayerRegion *region : layer.regions())
|
||||
for_each_extrusion_path(region->perimeters, [&](const ExtrusionPath &path) {
|
||||
if (is_perimeter(path.role()))
|
||||
walls.push_back(estimator.estimate_extrusion_quality(path, overlaps, speeds, caged_outer_wall_speed, caged_outer_wall_speed,
|
||||
true, 0.5f));
|
||||
});
|
||||
return walls;
|
||||
}
|
||||
|
||||
uint32_t float_bits(float value)
|
||||
{
|
||||
uint32_t bits;
|
||||
std::memcpy(&bits, &value, sizeof(bits));
|
||||
return bits;
|
||||
}
|
||||
|
||||
bool same_point(const ProcessedPoint &a, const ProcessedPoint &b)
|
||||
{
|
||||
return a.p == b.p && float_bits(a.speed) == float_bits(b.speed) && float_bits(a.overlap) == float_bits(b.overlap);
|
||||
}
|
||||
|
||||
// Requires the walls to match point for point, bit for bit.
|
||||
void check_identical(const Walls &actual, const Walls &expected)
|
||||
{
|
||||
REQUIRE(actual.size() == expected.size());
|
||||
for (size_t wall = 0; wall < actual.size(); ++wall) {
|
||||
INFO("wall " << wall);
|
||||
REQUIRE(actual[wall].size() == expected[wall].size());
|
||||
for (size_t i = 0; i < actual[wall].size(); ++i) {
|
||||
const ProcessedPoint &a = actual[wall][i];
|
||||
const ProcessedPoint &e = expected[wall][i];
|
||||
INFO("point " << i << ": speed " << a.speed << " vs " << e.speed << ", overlap " << a.overlap << " vs " << e.overlap);
|
||||
CHECK(a.p == e.p);
|
||||
CHECK(float_bits(a.speed) == float_bits(e.speed));
|
||||
CHECK(float_bits(a.overlap) == float_bits(e.overlap));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool any_difference(const Walls &a, const Walls &b)
|
||||
{
|
||||
return !std::equal(a.begin(), a.end(), b.begin(), b.end(), [](const std::vector<ProcessedPoint> &wa, const std::vector<ProcessedPoint> &wb) {
|
||||
return std::equal(wa.begin(), wa.end(), wb.begin(), wb.end(), same_point);
|
||||
});
|
||||
}
|
||||
|
||||
bool any_slowed(const Walls &walls)
|
||||
{
|
||||
return std::any_of(walls.begin(), walls.end(), [](const std::vector<ProcessedPoint> &wall) {
|
||||
return std::any_of(wall.begin(), wall.end(), [](const ProcessedPoint &point) { return point.speed < caged_outer_wall_speed; });
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Overhang data computed ahead of the generator gives the same wall speeds", "[ExtrusionProcessor]")
|
||||
{
|
||||
const SlicedCage cage;
|
||||
REQUIRE(cage.layer->lower_layer != nullptr);
|
||||
|
||||
ExtrusionQualityEstimator queried;
|
||||
queried.prepare_for_new_layer(cage.object, cage.layer->lower_layer);
|
||||
queried.prepare_for_new_layer(cage.object, cage.layer);
|
||||
const Walls expected = estimate_walls(queried, cage.object, *cage.layer);
|
||||
REQUIRE(any_slowed(expected));
|
||||
|
||||
ExtrusionQualityEstimator precomputed;
|
||||
precomputed.prepare_for_new_layer(cage.object, cage.layer->lower_layer);
|
||||
precomputed.set_precomputed_layers({precompute_overhang_layer(cage.object, *cage.layer)});
|
||||
precomputed.prepare_for_new_layer(cage.object, cage.layer);
|
||||
check_identical(estimate_walls(precomputed, cage.object, *cage.layer), expected);
|
||||
}
|
||||
|
||||
TEST_CASE("Overhang distances measured against another layer than the previous one are not used", "[ExtrusionProcessor]")
|
||||
{
|
||||
const SlicedCage cage;
|
||||
const Layer *two_below = cage.layer->lower_layer->lower_layer;
|
||||
REQUIRE(two_below != nullptr);
|
||||
|
||||
ExtrusionQualityEstimator queried;
|
||||
queried.prepare_for_new_layer(cage.object, two_below);
|
||||
queried.prepare_for_new_layer(cage.object, cage.layer);
|
||||
const Walls expected = estimate_walls(queried, cage.object, *cage.layer);
|
||||
ExtrusionQualityEstimator one_below;
|
||||
one_below.prepare_for_new_layer(cage.object, cage.layer->lower_layer);
|
||||
one_below.prepare_for_new_layer(cage.object, cage.layer);
|
||||
REQUIRE(any_difference(estimate_walls(one_below, cage.object, *cage.layer), expected));
|
||||
|
||||
ExtrusionQualityEstimator precomputed;
|
||||
precomputed.prepare_for_new_layer(cage.object, two_below);
|
||||
precomputed.set_precomputed_layers({precompute_overhang_layer(cage.object, *cage.layer)});
|
||||
precomputed.prepare_for_new_layer(cage.object, cage.layer);
|
||||
check_identical(estimate_walls(precomputed, cage.object, *cage.layer), expected);
|
||||
}
|
||||
|
||||
TEST_CASE("Overhang data computed for another layer is not used", "[ExtrusionProcessor]")
|
||||
{
|
||||
const SlicedCage cage;
|
||||
const Layer *one_below = cage.layer->lower_layer;
|
||||
REQUIRE(one_below != nullptr);
|
||||
REQUIRE(one_below->lower_layer != nullptr);
|
||||
|
||||
ExtrusionQualityEstimator queried;
|
||||
queried.prepare_for_new_layer(cage.object, one_below);
|
||||
queried.prepare_for_new_layer(cage.object, cage.layer);
|
||||
const Walls expected = estimate_walls(queried, cage.object, *cage.layer);
|
||||
ExtrusionQualityEstimator two_below;
|
||||
two_below.prepare_for_new_layer(cage.object, one_below->lower_layer);
|
||||
two_below.prepare_for_new_layer(cage.object, cage.layer);
|
||||
REQUIRE(any_difference(estimate_walls(two_below, cage.object, *cage.layer), expected));
|
||||
|
||||
ExtrusionQualityEstimator precomputed;
|
||||
precomputed.set_precomputed_layers({precompute_overhang_layer(cage.object, *one_below)});
|
||||
precomputed.prepare_for_new_layer(cage.object, one_below);
|
||||
precomputed.prepare_for_new_layer(cage.object, cage.layer);
|
||||
check_identical(estimate_walls(precomputed, cage.object, *cage.layer), expected);
|
||||
}
|
||||
|
||||
TEST_CASE("Precomputed overhang data has the curled-line tree exactly when a region slows down for curled perimeters", "[ExtrusionProcessor]")
|
||||
{
|
||||
const bool slowdown = GENERATE(false, true);
|
||||
DynamicPrintConfig config = caged_overhang_config("classic");
|
||||
config.set_deserialize_strict("slowdown_for_curled_perimeters", slowdown ? "1" : "0");
|
||||
const SlicedCage cage(config);
|
||||
|
||||
GCode::LayerToPrint layer;
|
||||
layer.object_layer = cage.layer;
|
||||
layer.original_object = cage.object;
|
||||
const std::vector<PrecomputedOverhangLayer> precomputed = precompute_overhang_layers({layer}, false);
|
||||
REQUIRE(precomputed.size() == 1);
|
||||
CHECK((precomputed.front().lower_curled_lines != nullptr) == slowdown);
|
||||
}
|
||||
|
||||
TEST_CASE("Caged external overhangs are slowed when printed by object or through the pressure equalizer", "[ExtrusionProcessor]")
|
||||
{
|
||||
const auto [key, value] = GENERATE(table<const char *, const char *>({
|
||||
{"print_sequence", "by object"},
|
||||
{"max_volumetric_extrusion_rate_slope", "10"},
|
||||
}));
|
||||
INFO(key << " = " << value);
|
||||
DynamicPrintConfig config = caged_overhang_config("classic");
|
||||
config.set_deserialize_strict(key, value);
|
||||
Print print;
|
||||
Model model;
|
||||
init_print(std::vector<TriangleMesh>{caged_overhang_mesh()}, print, model, config, nullptr, false);
|
||||
|
||||
const std::vector<double> feed_rates = caged_slope_feed_rates(gcode(print));
|
||||
info_feed_rates("caged slope", feed_rates);
|
||||
REQUIRE_FALSE(feed_rates.empty());
|
||||
REQUIRE(*std::max_element(feed_rates.begin(), feed_rates.end()) < caged_slow_speed * MM_PER_MIN);
|
||||
}
|
||||
|
||||
TEST_CASE("Benchmark caged overhang interior sampling", "[ExtrusionProcessor][!benchmark]"){
|
||||
const char* wall_generator = GENERATE("classic", "arachne");
|
||||
|
||||
|
||||
@@ -2,13 +2,35 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include "libslic3r/Fill/FillBase.hpp"
|
||||
#include "libslic3r/Polyline.hpp"
|
||||
#include "libslic3r/Surface.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <iterator>
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/Line.hpp"
|
||||
#include "libslic3r/ExPolygon.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include <limits>
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <math.h>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/AABBTreeLines.hpp"
|
||||
#include "libslic3r/Fill/Fill.hpp"
|
||||
@@ -748,6 +770,61 @@ TEST_CASE("A region with ironing turned off is never ironed", "[Fill]")
|
||||
REQUIRE(Layer::choose_ironing_extruder(cfg, spiral_mode, /*is_topmost_layer=*/true) == -1);
|
||||
}
|
||||
|
||||
// Ironing path count and total length in mm, over the whole object.
|
||||
static std::pair<size_t, double> ironing_extent(const Print &print)
|
||||
{
|
||||
size_t paths = 0;
|
||||
double length = 0.;
|
||||
for (const Layer *layer : print.objects().front()->layers())
|
||||
for (const LayerRegion *region : layer->regions())
|
||||
for (const ExtrusionEntity *entity : region->fills.flatten().entities)
|
||||
if (ironing_role(entity->role())) {
|
||||
++paths;
|
||||
length += unscale<double>(entity->length());
|
||||
}
|
||||
return {paths, length};
|
||||
}
|
||||
|
||||
TEST_CASE("Ironing spacing below the minimum irons at the minimum spacing", "[Fill]")
|
||||
{
|
||||
const std::string pattern = GENERATE("rectilinear", "concentric");
|
||||
const bool via_filament = GENERATE(false, true);
|
||||
const double spacing = GENERATE(0., 0.001);
|
||||
CAPTURE(pattern, via_filament, spacing);
|
||||
|
||||
auto ironing_for = [&pattern, via_filament](double spacing) {
|
||||
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||
config.set_deserialize_strict({{"ironing_type", "top"},
|
||||
{"ironing_pattern", pattern},
|
||||
{"layer_height", 0.2}});
|
||||
// The filament override replaces the process spacing, which stays at a usable value.
|
||||
if (via_filament)
|
||||
config.set_deserialize_strict({{"ironing_spacing", 0.1}, {"filament_ironing_spacing", spacing}});
|
||||
else
|
||||
config.set_deserialize_strict({{"ironing_spacing", spacing}});
|
||||
Print print;
|
||||
Slic3r::Test::init_and_process_print({Slic3r::Test::cube(20)}, print, config);
|
||||
return ironing_extent(print);
|
||||
};
|
||||
|
||||
const std::pair<size_t, double> clamped = ironing_for(spacing);
|
||||
const std::pair<size_t, double> minimum = ironing_for(IRONING_SPACING_MIN);
|
||||
REQUIRE(minimum.first > 0);
|
||||
CHECK(clamped.first == minimum.first);
|
||||
CHECK_THAT(clamped.second, Catch::Matchers::WithinRel(minimum.second, 1e-9));
|
||||
}
|
||||
|
||||
TEST_CASE("Concentric fill at zero spacing returns without paths", "[Fill]")
|
||||
{
|
||||
std::unique_ptr<Fill> filler(Fill::new_from_type(ipConcentric));
|
||||
filler->spacing = 0.;
|
||||
filler->bounding_box = BoundingBox(Point(0, 0), Point::new_scale(10, 10));
|
||||
FillParams params;
|
||||
params.density = 1.f;
|
||||
Surface surface(stTop, ExPolygon({Point(0, 0), Point::new_scale(10, 0), Point::new_scale(10, 10), Point::new_scale(0, 10)}));
|
||||
CHECK(filler->fill_surface(&surface, params).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("Solid infill direction offsets every layer when no template is set", "[Fill]")
|
||||
{
|
||||
auto angles_for = [](int direction) {
|
||||
@@ -1616,24 +1693,32 @@ TEST_CASE("Smoothing multiline lightning infill keeps its outlines connected", "
|
||||
// and the outlines of branches that run close to each other merge into one. Rounding the branches
|
||||
// before those outlines are built moves them apart, which breaks the merged outlines up into
|
||||
// separate loops - many more of them, each needing its own travel move.
|
||||
// A micron change of the cube moves the loop count of a single slice by several percent, so the
|
||||
// shapes of a few nearly equal cubes are added up.
|
||||
auto shape_for = [](const std::string &smooth_factor) {
|
||||
Print print;
|
||||
Slic3r::Test::init_and_process_print({Slic3r::Test::cube(20)}, print,
|
||||
{{"sparse_infill_pattern", "lightning"},
|
||||
{"sparse_infill_density", "50%"},
|
||||
{"fill_multiline", 2},
|
||||
{"sparse_infill_smooth_factor", smooth_factor},
|
||||
{"layer_height", 0.2}});
|
||||
return sparse_infill_shape(print);
|
||||
SparseInfillShape sum;
|
||||
for (const double size : {20., 20.001, 20.002, 20.003}) {
|
||||
Print print;
|
||||
Slic3r::Test::init_and_process_print({Slic3r::Test::cube(size)}, print,
|
||||
{{"sparse_infill_pattern", "lightning"},
|
||||
{"sparse_infill_density", "50%"},
|
||||
{"fill_multiline", 2},
|
||||
{"sparse_infill_smooth_factor", smooth_factor},
|
||||
{"layer_height", 0.2}});
|
||||
const SparseInfillShape shape = sparse_infill_shape(print);
|
||||
sum.path_count += shape.path_count;
|
||||
sum.point_count += shape.point_count;
|
||||
sum.sharp_turns += shape.sharp_turns;
|
||||
}
|
||||
return sum;
|
||||
};
|
||||
|
||||
const SparseInfillShape sharp = shape_for("0%");
|
||||
const SparseInfillShape smooth = shape_for("100%");
|
||||
|
||||
REQUIRE(sharp.path_count > 0);
|
||||
// The loop count varies by a loop or two between platforms and between runs, so this is not an
|
||||
// exact comparison. Smoothing should leave it about where it was; uncapping the smoothing
|
||||
// reach, the regression this guards against, adds about 10%.
|
||||
// Smoothing should leave the loop count about where it was; uncapping the smoothing reach, the
|
||||
// regression this guards against, adds about 10%.
|
||||
const size_t allowed_extra = sharp.path_count / 50; // 2%
|
||||
REQUIRE(smooth.path_count <= sharp.path_count + allowed_extra);
|
||||
// The outlines are still rounded.
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include "test_helpers.hpp" // get access to init_print, etc
|
||||
|
||||
#include "libslic3r/Config.hpp"
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
||||
#include "libslic3r/MultiNozzleUtils.hpp"
|
||||
@@ -8,9 +12,13 @@
|
||||
#include "test_utils.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include <ios>
|
||||
#include <map>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
||||
|
||||
|
||||
@@ -1,21 +1,38 @@
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/Extruder.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include "libslic3r/GCodeReader.hpp"
|
||||
#include "libslic3r/GCodeWriter.hpp"
|
||||
#include "libslic3r/GCode.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/ModelArrange.hpp"
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "test_helpers.hpp"
|
||||
@@ -23,10 +40,7 @@
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::Test;
|
||||
|
||||
// Arrange on a finite bed, not an unbounded InfiniteBed: the latter places items
|
||||
// near INT64_MIN/4 (~2.3e18), which reaches ClipperLib's coordinate limit and throws
|
||||
// "Coordinate outside allowed range" on Windows/arm64. A 500x500 bed keeps coordinates
|
||||
// small while still covering large printers.
|
||||
// Arrange on a 500x500 bed, which keeps coordinates small while still covering large printers.
|
||||
static void arrange_objects_on_test_bed(Model &model, const DynamicPrintConfig &config)
|
||||
{
|
||||
const BoundingBox bed{Point::new_scale(0., 0.), Point::new_scale(500., 500.)};
|
||||
@@ -100,6 +114,22 @@ SCENARIO("Origin manipulation", "[GCodeWriter]") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("A cached config slot is looked up again whenever its key changes", "[GCodeWriter]")
|
||||
{
|
||||
GCode::ConfigIndexCache cache;
|
||||
int lookups = 0;
|
||||
auto slot = [&](int filament, size_t layer, size_t generation) {
|
||||
return cache.get(filament, layer, generation, [&] { ++lookups; return filament * 100 + int(layer) * 10 + int(generation); });
|
||||
};
|
||||
REQUIRE(slot(1, 2, 3) == 123);
|
||||
REQUIRE(slot(1, 2, 3) == 123);
|
||||
REQUIRE(lookups == 1);
|
||||
REQUIRE(slot(4, 2, 3) == 423);
|
||||
REQUIRE(slot(4, 5, 3) == 453);
|
||||
REQUIRE(slot(4, 5, 6) == 456);
|
||||
REQUIRE(lookups == 4);
|
||||
}
|
||||
|
||||
// Verify that emit_machine_limits_to_gcode emits the correct max value across
|
||||
// used extruders (regression for commit b4ee665: "Emit max value of machine
|
||||
// limit among used extruders").
|
||||
@@ -875,3 +905,46 @@ TEST_CASE("Custom G-code motion limits are restored before generated moves", "[G
|
||||
REQUIRE(gcode.find("M204 S6000 ; adjust acceleration", custom_gcode_pos) != std::string::npos);
|
||||
REQUIRE(gcode.find("M205 X8 Y8 ; adjust jerk", custom_gcode_pos) != std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("Percent accelerations resolve against the option they are a percentage of", "[GCodeWriter]")
|
||||
{
|
||||
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||
config.set_deserialize_strict({
|
||||
{ "gcode_flavor", "marlin" },
|
||||
{ "machine_max_acceleration_extruding", "20000,20000" },
|
||||
{ "default_acceleration", "4000" },
|
||||
{ "initial_layer_acceleration", "0" },
|
||||
{ "outer_wall_acceleration", "3000" },
|
||||
{ "bridge_acceleration", "50%" },
|
||||
{ "sparse_infill_acceleration", "25%" },
|
||||
{ "internal_solid_infill_acceleration", "60%" },
|
||||
{ "sparse_infill_density", "20%" },
|
||||
});
|
||||
// get_abs_value_at() resolves each percentage through the ratio_over in the config definitions.
|
||||
const std::map<std::string, int> expected = {
|
||||
{ "Bridge", int(config.get_abs_value_at("bridge_acceleration", 0)) },
|
||||
{ "Sparse infill", int(config.get_abs_value_at("sparse_infill_acceleration", 0)) },
|
||||
{ "Internal solid infill", int(config.get_abs_value_at("internal_solid_infill_acceleration", 0)) },
|
||||
};
|
||||
REQUIRE(expected.at("Bridge") == 1500);
|
||||
REQUIRE(expected.at("Sparse infill") == 1000);
|
||||
REQUIRE(expected.at("Internal solid infill") == 2400);
|
||||
|
||||
std::map<std::string, std::set<int>> accelerations_by_role;
|
||||
std::string role;
|
||||
int acceleration = 0;
|
||||
GCodeReader reader;
|
||||
reader.parse_buffer(Slic3r::Test::slice({ TestMesh::bridge }, config), [&](GCodeReader &self, const GCodeReader::GCodeLine &line) {
|
||||
float value;
|
||||
if (boost::starts_with(line.raw(), ";TYPE:"))
|
||||
role = line.raw().substr(6);
|
||||
else if (line.cmd_is("M204") && line.has_value('S', value))
|
||||
acceleration = int(value);
|
||||
else if (line.extruding(self) && line.dist_XY(self) > 0)
|
||||
accelerations_by_role[role].insert(acceleration);
|
||||
});
|
||||
for (const auto &[role_name, value] : expected) {
|
||||
INFO(role_name);
|
||||
REQUIRE(accelerations_by_role[role_name] == std::set<int>{ value });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "test_helpers.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/GCodeReader.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
@@ -7,11 +8,23 @@
|
||||
#include "libslic3r/Format/OBJ.hpp"
|
||||
#include "libslic3r/Format/STL.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Exception.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include <initializer_list>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <libslic3r/ModelArrange.hpp>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
@@ -225,7 +238,7 @@ DynamicPrintConfig multifilament_config(unsigned int filaments, std::initializer
|
||||
}
|
||||
|
||||
void init_print(std::vector<TriangleMesh> &&meshes, Slic3r::Print &print, Slic3r::Model &model, const DynamicPrintConfig &config_in,
|
||||
const std::vector<std::vector<ConfigBase::SetDeserializeItem>> *per_object_overrides, bool arrange)
|
||||
const std::vector<std::vector<ConfigBase::SetDeserializeItem>> *per_object_overrides, bool arrange, size_t instances)
|
||||
{
|
||||
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||
config.apply(config_in);
|
||||
@@ -236,7 +249,8 @@ void init_print(std::vector<TriangleMesh> &&meshes, Slic3r::Print &print, Slic3r
|
||||
ModelObject *object = model.add_object();
|
||||
object->name += "object.stl";
|
||||
object->add_volume(std::move(t));
|
||||
object->add_instance();
|
||||
for (size_t i = 0; i < instances; ++i)
|
||||
object->add_instance();
|
||||
|
||||
if (per_object_overrides && object_idx < per_object_overrides->size() && !(*per_object_overrides)[object_idx].empty()) {
|
||||
DynamicPrintConfig oc;
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <cstddef>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include <initializer_list>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
@@ -72,9 +76,11 @@ Slic3r::Model model(const std::string& model_name, TriangleMesh&& _mesh);
|
||||
DynamicPrintConfig multifilament_config(unsigned int filaments,
|
||||
std::initializer_list<Slic3r::ConfigBase::SetDeserializeItem> extra = {});
|
||||
|
||||
// Apply `meshes` and config to `print`/`model`; optional per-object overrides, auto-arranged unless `arrange` is false.
|
||||
// Apply `meshes` and config to `print`/`model`, each object with `instances` copies; optional per-object overrides,
|
||||
// auto-arranged unless `arrange` is false.
|
||||
void init_print(std::vector<TriangleMesh> &&meshes, Slic3r::Print &print, Slic3r::Model &model, const DynamicPrintConfig &config_in,
|
||||
const std::vector<std::vector<Slic3r::ConfigBase::SetDeserializeItem>> *per_object_overrides = nullptr, bool arrange = true);
|
||||
const std::vector<std::vector<Slic3r::ConfigBase::SetDeserializeItem>> *per_object_overrides = nullptr, bool arrange = true,
|
||||
size_t instances = 1);
|
||||
void init_print(std::initializer_list<TestMesh> meshes, Slic3r::Print &print, Slic3r::Model &model, const Slic3r::DynamicPrintConfig &config_in = Slic3r::DynamicPrintConfig::full_print_config());
|
||||
void init_print(std::initializer_list<TriangleMesh> meshes, Slic3r::Print &print, Slic3r::Model &model, const Slic3r::DynamicPrintConfig &config_in = Slic3r::DynamicPrintConfig::full_print_config());
|
||||
void init_print(std::initializer_list<TestMesh> meshes, Slic3r::Print &print, Slic3r::Model &model, std::initializer_list<Slic3r::ConfigBase::SetDeserializeItem> config_items);
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include <vector>
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/PrintBase.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/GCode/ToolOrdering.hpp"
|
||||
#include "libslic3r/MultiNozzleUtils.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/ModelArrange.hpp"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include <vector>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <cstddef>
|
||||
|
||||
#include "test_helpers.hpp"
|
||||
#include "test_utils.hpp"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
||||
#include "libslic3r/GCodeReader.hpp"
|
||||
|
||||
@@ -12,6 +15,11 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#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/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
||||
#include "libslic3r/Layer.hpp"
|
||||
@@ -10,8 +15,15 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include <cstddef>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/ExPolygon.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "test_helpers.hpp"
|
||||
|
||||
@@ -1,9 +1,24 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "test_helpers.hpp"
|
||||
#include "libslic3r/GCode/PreciseSeam.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/Layer.hpp"
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/GCode/SeamPlacer.hpp"
|
||||
#include <cstddef>
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
|
||||
@@ -8,6 +8,20 @@
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <string>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include <cstddef>
|
||||
#include "libslic3r/Surface.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/PrintBase.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
@@ -561,6 +575,40 @@ TEST_CASE("export_gcode writes G-code without a result pointer", "[Print][export
|
||||
REQUIRE_FALSE(gcode.empty());
|
||||
}
|
||||
|
||||
TEST_CASE("Exporting a sliced print again gives the same G-code", "[Print][export_gcode][Regression]")
|
||||
{
|
||||
const int instances = GENERATE(1, 3);
|
||||
CAPTURE(instances);
|
||||
DynamicPrintConfig config = DynamicPrintConfig::full_print_config();
|
||||
TestMesh mesh = TestMesh::ipadstand;
|
||||
SECTION("infill reversed by chaining") { config.set_deserialize_strict({{"sparse_infill_pattern", "gyroid"}}); }
|
||||
SECTION("support reversed by chaining") {
|
||||
mesh = TestMesh::overhang;
|
||||
config.set_deserialize_strict({{"enable_support", true}, {"support_interface_pattern", "concentric"}});
|
||||
}
|
||||
Print print;
|
||||
Model model;
|
||||
Slic3r::Test::init_print({Slic3r::Test::mesh(mesh)}, print, model, config, nullptr, true, instances);
|
||||
|
||||
const auto export_without_timestamp = [&print]() {
|
||||
std::string gcode = Slic3r::Test::gcode(print);
|
||||
const size_t line = gcode.find("; generated by ");
|
||||
REQUIRE(line != std::string::npos);
|
||||
gcode.erase(line, gcode.find('\n', line) - line);
|
||||
return gcode;
|
||||
};
|
||||
const std::string first = export_without_timestamp();
|
||||
const std::string second = export_without_timestamp();
|
||||
|
||||
// Shows the first differing line on failure.
|
||||
const size_t diff = std::mismatch(first.begin(), first.end(), second.begin(), second.end()).first - first.begin();
|
||||
const size_t line_start = diff == 0 ? 0 : first.rfind('\n', diff - 1) + 1;
|
||||
INFO("first export: " << first.substr(line_start, first.find('\n', diff) - line_start));
|
||||
INFO("second export: " << second.substr(line_start, second.find('\n', diff) - line_start));
|
||||
CHECK(diff == first.size());
|
||||
CHECK(first.size() == second.size());
|
||||
}
|
||||
|
||||
TEST_CASE("Sequential printing follows model order", "[Print]")
|
||||
{
|
||||
// Two objects of different heights, taller one added first. Orca prints
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/Layer.hpp"
|
||||
@@ -10,7 +16,20 @@
|
||||
#include "test_helpers.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#include "libslic3r/Surface.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Polyline.hpp"
|
||||
#include "libslic3r/Line.hpp"
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#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 "test_helpers.hpp"
|
||||
#include "libslic3r/GCode/SeamPlacer.hpp"
|
||||
#include "libslic3r/Layer.hpp"
|
||||
@@ -7,6 +12,16 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <vector>
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/Polyline.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#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/GCodeReader.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
@@ -9,6 +15,16 @@
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Polyline.hpp"
|
||||
#include <string>
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include <vector>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <string_view>
|
||||
|
||||
#include "test_helpers.hpp" // get access to init_print, etc
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include "libslic3r/Surface.hpp"
|
||||
#include <utility>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "test_helpers.hpp"
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "libslic3r/GCodeReader.hpp"
|
||||
#include "libslic3r/Layer.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/PrintBase.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include <map>
|
||||
#include <math.h>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "test_helpers.hpp" // get access to init_print, etc
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <iterator>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/PNGReadWrite.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <initializer_list>
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <cstddef>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/Layer.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/TriangleMeshSlicer.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
@@ -8,8 +9,14 @@
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <cmath>
|
||||
#include <future>
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include <math.h>
|
||||
#include "libslic3r/ExPolygon.hpp"
|
||||
|
||||
//#include "test_options.hpp"
|
||||
#include "test_helpers.hpp"
|
||||
|
||||
@@ -2,11 +2,27 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <cstddef>
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/calib.hpp"
|
||||
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#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/GCode/GCodeProcessor.hpp"
|
||||
#include "libslic3r/GCodeReader.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include <cstddef>
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
||||
|
||||
@@ -2,13 +2,18 @@
|
||||
#define FG_TEST_EVALUATOR_HPP
|
||||
|
||||
#include "fg_test_serialization.hpp"
|
||||
#include <cstddef>
|
||||
#include <libslic3r/FilamentGroup.hpp>
|
||||
#include <libslic3r/GCode/ToolOrderUtils.hpp>
|
||||
#include <libslic3r/MultiNozzleUtils.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <ratio>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace FGTest {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef FG_TEST_SERIALIZATION_HPP
|
||||
#define FG_TEST_SERIALIZATION_HPP
|
||||
|
||||
#include <cstdio>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <libslic3r/FilamentGroup.hpp>
|
||||
#include <libslic3r/FilamentGroupUtils.hpp>
|
||||
@@ -10,6 +11,7 @@
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
@@ -2,9 +2,16 @@
|
||||
#define FG_TEST_UTILS_HPP
|
||||
|
||||
#include "fg_test_serialization.hpp"
|
||||
#include "libslic3r/FilamentGroupUtils.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/FilamentGroup.hpp"
|
||||
#include <iterator>
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace FGTest {
|
||||
|
||||
@@ -11,13 +11,19 @@
|
||||
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/generators/catch_generators_range.hpp>
|
||||
#include "fg_test_serialization.hpp"
|
||||
#include "fg_test_evaluator.hpp"
|
||||
#include "fg_test_utils.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "libslic3r/FilamentGroup.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
// it here and include this header from every libnest2d test file.
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
#include "libnest2d/common.hpp"
|
||||
#include "libnest2d/geometry_traits_nfp.hpp"
|
||||
#include <libnest2d/libnest2d.hpp>
|
||||
#include <libnest2d/utils/rotcalipers.hpp>
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include "libnest2d/libnest2d.hpp"
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include "libnest2d/nester.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libnest2d_test_utils.hpp"
|
||||
|
||||
using namespace libnest2d;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef PRINTER_PARTS_H
|
||||
#define PRINTER_PARTS_H
|
||||
|
||||
#include "libnest2d/backends/libslic3r/geometries.hpp"
|
||||
#include <vector>
|
||||
#include <libnest2d/libnest2d.hpp>
|
||||
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
#include <algorithm>
|
||||
#include <boost/rational.hpp>
|
||||
#include <boost/multiprecision/fwd.hpp>
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <vector>
|
||||
#include "libnest2d/libnest2d.hpp"
|
||||
#include "libnest2d/geometry_traits.hpp"
|
||||
#include "libnest2d/backends/libslic3r/geometries.hpp"
|
||||
#include "libnest2d/common.hpp"
|
||||
#include <type_traits>
|
||||
#include <cstdlib>
|
||||
#include "libnest2d/placers/nfpplacer.hpp"
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <iterator>
|
||||
#include "libnest2d/utils/rotcalipers.hpp"
|
||||
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libnest2d_test_utils.hpp"
|
||||
#include "printer_parts.hpp"
|
||||
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include "libnest2d/libnest2d.hpp"
|
||||
#include <vector>
|
||||
#include "libnest2d/geometry_traits.hpp"
|
||||
#include "libnest2d/backends/libslic3r/geometries.hpp"
|
||||
#include "libnest2d/geometry_traits_nfp.hpp"
|
||||
#include "libnest2d/utils/boost_alg.hpp"
|
||||
#include "libnest2d/placers/nfpplacer.hpp"
|
||||
#include <iterator>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include "libnest2d_test_utils.hpp"
|
||||
|
||||
using namespace libnest2d;
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include "libnest2d/libnest2d.hpp"
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include "libnest2d/geometry_traits.hpp"
|
||||
#include "libnest2d/common.hpp"
|
||||
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "libnest2d_test_utils.hpp"
|
||||
|
||||
using namespace libnest2d;
|
||||
|
||||
@@ -42,6 +42,7 @@ add_executable(${_TEST_NAME}_tests
|
||||
test_stl.cpp
|
||||
test_triangle_selector.cpp
|
||||
test_meshboolean.cpp
|
||||
test_trianglemesh_slicer.cpp
|
||||
test_marchingsquares.cpp
|
||||
test_lay_on_face.cpp
|
||||
test_model.cpp
|
||||
@@ -57,6 +58,7 @@ add_executable(${_TEST_NAME}_tests
|
||||
# test_png_io.cpp
|
||||
test_indexed_triangle_set.cpp
|
||||
test_texture_displacement.cpp
|
||||
test_instance_lock.cpp
|
||||
../libnest2d/printer_parts.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <vector>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#define NANOSVG_IMPLEMENTATION
|
||||
#include "nanosvg/nanosvg.h"
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
|
||||
#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/Model.hpp"
|
||||
#include "libslic3r/Format/3mf.hpp"
|
||||
#include "libslic3r/Format/bbs_3mf.hpp"
|
||||
@@ -14,6 +19,15 @@
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#include <cstddef>
|
||||
#include <miniz.h>
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/TriangleSelector.hpp"
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <ios>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
@@ -25,8 +39,12 @@
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <type_traits> // for std::enable_if_t
|
||||
#include <typeinfo> // for typeid
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
namespace Catch {
|
||||
template <typename T>
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include "test_utils.hpp"
|
||||
|
||||
#include <igl/Hit.h>
|
||||
#include <cstddef>
|
||||
#include <libslic3r/TriangleMesh.hpp>
|
||||
#include <libslic3r/AABBTreeIndirect.hpp>
|
||||
#include <vector>
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/Arachne/WallToolPaths.hpp"
|
||||
#include "libslic3r/Arachne/SkeletalTrapezoidation.hpp"
|
||||
#include "libslic3r/Arachne/utils/ExtrusionLine.hpp"
|
||||
@@ -31,6 +34,14 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <math.h>
|
||||
#include "libslic3r/Arachne/utils/ExtrusionJunction.hpp"
|
||||
#include "libslic3r/PerimeterGenerator.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::Arachne;
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <string>
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <cstddef>
|
||||
#include <cmath>
|
||||
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "libslic3r/Arrange.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "slic3r/Utils/bambu_networking.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <vector>
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include "libslic3r/BuildVolume.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <Standard_TypeDef.hxx>
|
||||
#include <algorithm>
|
||||
#include <TopAbs_ShapeEnum.hxx>
|
||||
#include <GeomAbs_CurveType.hxx>
|
||||
#include <catch2/catch_all.hpp> // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp)
|
||||
#include <vector>
|
||||
#include <math.h>
|
||||
#include <utility>
|
||||
#include <sstream>
|
||||
#include <cstdint>
|
||||
#include <ios>
|
||||
#include <iterator>
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
// Substring assertions, spelled so this file compiles UNCHANGED on both forks.
|
||||
// Catch2 v2 (Snapmaker) spells it Matchers::Contains; v3 (orca_cad / mainline) spells it
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include "libslic3r/CustomGCode.hpp"
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include "libslic3r/calib.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <vector>
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include <math.h>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/ExPolygon.hpp"
|
||||
#include "libslic3r/SVG.hpp"
|
||||
@@ -22,7 +29,7 @@ SCENARIO("Constant offset", "[ClipperUtils]") {
|
||||
WHEN("Slic3r::offset()") {
|
||||
for (double miter : { 2.0, 1.5, 1.2 }) {
|
||||
DYNAMIC_SECTION("plus 1mm, miter " << miter << "x") {
|
||||
output = Slic3r::offset(box20mm, 1. * s, ClipperLib::jtMiter, miter);
|
||||
output = Slic3r::offset(box20mm, 1. * s, jtMiter, miter);
|
||||
#ifdef TESTS_EXPORT_SVGS
|
||||
{
|
||||
SVG svg(debug_out_path("constant_offset_box20mm_plus1mm_miter%lf.svg", miter).c_str(), get_extents(output));
|
||||
@@ -36,7 +43,7 @@ SCENARIO("Constant offset", "[ClipperUtils]") {
|
||||
}
|
||||
}
|
||||
DYNAMIC_SECTION("minus 1mm, miter " << miter << "x") {
|
||||
output = Slic3r::offset(box20mm, - 1. * s, ClipperLib::jtMiter, miter);
|
||||
output = Slic3r::offset(box20mm, - 1. * s, jtMiter, miter);
|
||||
#ifdef TESTS_EXPORT_SVGS
|
||||
{
|
||||
SVG svg(debug_out_path("constant_offset_box20mm_minus1mm_miter%lf.svg", miter).c_str(), get_extents(output));
|
||||
@@ -96,7 +103,7 @@ SCENARIO("Constant offset", "[ClipperUtils]") {
|
||||
for (double miter : { 2.0, 1.5, 1.2 }) {
|
||||
DYNAMIC_SECTION("miter " << miter << "x") {
|
||||
WHEN("plus 1mm") {
|
||||
output = Slic3r::offset_ex(box20mm, 1. * s, ClipperLib::jtMiter, miter);
|
||||
output = Slic3r::offset_ex(box20mm, 1. * s, jtMiter, miter);
|
||||
#ifdef TESTS_EXPORT_SVGS
|
||||
{
|
||||
SVG svg(debug_out_path("constant_offset_box20mm_10mm_hole_plus1mm_miter%lf.svg", miter).c_str(), get_extents(output));
|
||||
@@ -110,7 +117,7 @@ SCENARIO("Constant offset", "[ClipperUtils]") {
|
||||
}
|
||||
}
|
||||
WHEN("minus 1mm") {
|
||||
output = Slic3r::offset_ex(box20mm, - 1. * s, ClipperLib::jtMiter, miter);
|
||||
output = Slic3r::offset_ex(box20mm, - 1. * s, jtMiter, miter);
|
||||
#ifdef TESTS_EXPORT_SVGS
|
||||
{
|
||||
SVG svg(debug_out_path("constant_offset_box20mm_10mm_hole_minus1mm_miter%lf.svg", miter).c_str(), get_extents(output));
|
||||
@@ -176,7 +183,7 @@ SCENARIO("Constant offset", "[ClipperUtils]") {
|
||||
SECTION("Slic3r::offset()") {
|
||||
for (double miter : { 2.0, 1.5, 1.2 }) {
|
||||
DYNAMIC_SECTION("Outer offset 1mm, miter " << miter << "x") {
|
||||
output = Slic3r::offset(triangle20mm, offset * s, ClipperLib::jtMiter, 2.0);
|
||||
output = Slic3r::offset(triangle20mm, offset * s, jtMiter, 2.0);
|
||||
#ifdef TESTS_EXPORT_SVGS
|
||||
{
|
||||
SVG svg(debug_out_path("constant_offset_triangle20mm_plus1mm_miter%lf.svg", miter).c_str(), get_extents(output));
|
||||
|
||||
@@ -1,15 +1,44 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/Polyline.hpp"
|
||||
#include <cstddef>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <numeric>
|
||||
#include <iostream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <vector>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/ExPolygon.hpp"
|
||||
#include "libslic3r/SVG.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
// Clipper may start an output polygon at any of its vertices.
|
||||
static Polygon start_at_min(Polygon polygon)
|
||||
{
|
||||
std::rotate(polygon.points.begin(), std::min_element(polygon.points.begin(), polygon.points.end()), polygon.points.end());
|
||||
return polygon;
|
||||
}
|
||||
static Polygons start_at_min(Polygons polygons)
|
||||
{
|
||||
for (Polygon &polygon : polygons)
|
||||
polygon = start_at_min(std::move(polygon));
|
||||
return polygons;
|
||||
}
|
||||
static ExPolygons start_at_min(ExPolygons expolygons)
|
||||
{
|
||||
for (ExPolygon &expolygon : expolygons) {
|
||||
expolygon.contour = start_at_min(std::move(expolygon.contour));
|
||||
expolygon.holes = start_at_min(std::move(expolygon.holes));
|
||||
}
|
||||
return expolygons;
|
||||
}
|
||||
|
||||
SCENARIO("Various Clipper operations - xs/t/11_clipper.t", "[ClipperUtils]") {
|
||||
// CCW oriented contour
|
||||
Slic3r::Polygon square{ { 200, 100 }, {200, 200}, {100, 200}, {100, 100} };
|
||||
@@ -20,25 +49,25 @@ SCENARIO("Various Clipper operations - xs/t/11_clipper.t", "[ClipperUtils]") {
|
||||
WHEN("offset") {
|
||||
Polygons result = Slic3r::offset(square_with_hole, 5.f);
|
||||
THEN("offset matches") {
|
||||
REQUIRE(result == Polygons {
|
||||
REQUIRE(start_at_min(result) == start_at_min(Polygons {
|
||||
{ { 205, 205 }, { 95, 205 }, { 95, 95 }, { 205, 95 }, },
|
||||
{ { 155, 145 }, { 145, 145 }, { 145, 155 }, { 155, 155 } } });
|
||||
{ { 155, 145 }, { 145, 145 }, { 145, 155 }, { 155, 155 } } }));
|
||||
}
|
||||
}
|
||||
WHEN("offset_ex") {
|
||||
ExPolygons result = Slic3r::offset_ex(square_with_hole, 5.f);
|
||||
THEN("offset matches") {
|
||||
REQUIRE(result == ExPolygons { {
|
||||
REQUIRE(start_at_min(result) == start_at_min(ExPolygons { {
|
||||
{ { 205, 205 }, { 95, 205 }, { 95, 95 }, { 205, 95 }, },
|
||||
{ { 145, 145 }, { 145, 155 }, { 155, 155 }, { 155, 145 } } } } );
|
||||
{ { 145, 145 }, { 145, 155 }, { 155, 155 }, { 155, 145 } } } }));
|
||||
}
|
||||
}
|
||||
WHEN("offset2_ex") {
|
||||
ExPolygons result = Slic3r::offset2_ex({ square_with_hole }, 5.f, -2.f);
|
||||
THEN("offset matches") {
|
||||
REQUIRE(result == ExPolygons { {
|
||||
REQUIRE(start_at_min(result) == start_at_min(ExPolygons { {
|
||||
{ { 203, 203 }, { 97, 203 }, { 97, 97 }, { 203, 97 } },
|
||||
{ { 143, 143 }, { 143, 157 }, { 157, 157 }, { 157, 143 } } } } );
|
||||
{ { 143, 143 }, { 143, 157 }, { 157, 157 }, { 157, 143 } } } }));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -225,24 +254,7 @@ SCENARIO("Various Clipper operations - t/clipper.t", "[ClipperUtils]") {
|
||||
}
|
||||
}
|
||||
|
||||
template<e_ordering o = e_ordering::OFF, class P, class Tree, class Alloc>
|
||||
double polytree_area(const Tree &tree, std::vector<P, Alloc> *out)
|
||||
{
|
||||
traverse_pt<o>(tree, out);
|
||||
|
||||
return std::accumulate(out->begin(), out->end(), 0.0,
|
||||
[](double a, const P &p) { return a + p.area(); });
|
||||
}
|
||||
|
||||
size_t count_polys(const ExPolygons& expolys)
|
||||
{
|
||||
size_t c = 0;
|
||||
for (auto &ep : expolys) c += ep.holes.size() + 1;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
TEST_CASE("Traversing Clipper PolyTree", "[ClipperUtils]") {
|
||||
TEST_CASE("Top level expolygons of an even-odd union", "[ClipperUtils]") {
|
||||
// Create a polygon representing unit box
|
||||
Polygon unitbox;
|
||||
const auto UNIT = coord_t(1. / SCALING_FACTOR);
|
||||
@@ -266,36 +278,24 @@ TEST_CASE("Traversing Clipper PolyTree", "[ClipperUtils]") {
|
||||
Polygon inner_right = inner_left;
|
||||
inner_right.translate(UNIT * 10, 0);
|
||||
|
||||
Polygons reference = union_({box_frame, hole_left, hole_right, inner_left, inner_right});
|
||||
ExPolygons reference;
|
||||
for (const Polygon &polygon : union_({box_frame, hole_left, hole_right, inner_left, inner_right}))
|
||||
reference.emplace_back(polygon);
|
||||
|
||||
ClipperLib::PolyTree tree = union_pt(reference);
|
||||
double area_sum = box_frame.area() + hole_left.area() +
|
||||
hole_right.area() + inner_left.area() +
|
||||
inner_right.area();
|
||||
|
||||
REQUIRE(area_sum > 0);
|
||||
|
||||
SECTION("Traverse into Polygons WITHOUT spatial ordering") {
|
||||
Polygons output;
|
||||
REQUIRE(area_sum == Catch::Approx(polytree_area(tree.GetFirst(), &output)));
|
||||
REQUIRE(output.size() == reference.size());
|
||||
}
|
||||
|
||||
SECTION("Traverse into ExPolygons WITHOUT spatial ordering") {
|
||||
ExPolygons output;
|
||||
REQUIRE(area_sum == Catch::Approx(polytree_area(tree.GetFirst(), &output)));
|
||||
REQUIRE(count_polys(output) == reference.size());
|
||||
}
|
||||
|
||||
SECTION("Traverse into Polygons WITH spatial ordering") {
|
||||
Polygons output;
|
||||
REQUIRE(area_sum == Catch::Approx(polytree_area<e_ordering::ON>(tree.GetFirst(), &output)));
|
||||
REQUIRE(output.size() == reference.size());
|
||||
}
|
||||
|
||||
SECTION("Traverse into ExPolygons WITH spatial ordering") {
|
||||
ExPolygons output;
|
||||
REQUIRE(area_sum == Catch::Approx(polytree_area<e_ordering::ON>(tree.GetFirst(), &output)));
|
||||
REQUIRE(count_polys(output) == reference.size());
|
||||
}
|
||||
ExPolygons nested;
|
||||
ExPolygons top_level = top_level_expolygons(reference, &nested);
|
||||
auto area = [](const ExPolygons &expolys) {
|
||||
return std::accumulate(expolys.begin(), expolys.end(), 0.0, [](double a, const ExPolygon &e) { return a + e.area(); });
|
||||
};
|
||||
REQUIRE(top_level.size() == 1);
|
||||
REQUIRE(top_level.front().holes.size() == 2);
|
||||
REQUIRE(nested.size() == 2);
|
||||
REQUIRE(area_sum == Catch::Approx(area(top_level) + area(nested)));
|
||||
REQUIRE(top_level_expolygons(reference).size() == 1);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/PrintConfigConstants.hpp"
|
||||
#include "libslic3r/LocalesUtils.hpp"
|
||||
@@ -13,9 +18,16 @@
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <iterator>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -421,6 +433,109 @@ SCENARIO("update_diff_values_to_child_config tolerates legacy machine-limit vect
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("A variant index comes from the same variant and id, else the id's first variant", "[Config][Variant]") {
|
||||
const std::vector<std::string> variant_list{"Direct Drive Standard", "Direct Drive High Flow", "Direct Drive Standard"};
|
||||
const std::vector<int> variant_ids{1, 1, 2};
|
||||
|
||||
SECTION("same variant and id") {
|
||||
CHECK(Slic3r::find_variant_index("Direct Drive High Flow", 1, variant_list, variant_ids) == 1);
|
||||
CHECK(Slic3r::find_variant_index("Direct Drive Standard", 2, variant_list, variant_ids) == 2);
|
||||
}
|
||||
SECTION("a variant the id lacks falls back to the id's first variant") {
|
||||
CHECK(Slic3r::find_variant_index("Bowden Standard", 1, variant_list, variant_ids) == 0);
|
||||
CHECK(Slic3r::find_variant_index("Direct Drive High Flow", 2, variant_list, variant_ids) == 2);
|
||||
}
|
||||
SECTION("an id with no variants matches none") {
|
||||
CHECK(Slic3r::find_variant_index("Direct Drive Standard", 3, variant_list, variant_ids) == -1);
|
||||
}
|
||||
SECTION("a negative id or a list without ids matches any id") {
|
||||
CHECK(Slic3r::find_variant_index("Direct Drive High Flow", -1, variant_list, variant_ids) == 1);
|
||||
CHECK(Slic3r::find_variant_index("Direct Drive High Flow", 2, variant_list, {}) == 1);
|
||||
}
|
||||
SECTION("a variant past a shorter id list gets no variant index") {
|
||||
CHECK(Slic3r::map_variant_indices(variant_list, {1}, variant_list, variant_ids) == std::vector<int>{0, -1, -1});
|
||||
}
|
||||
SECTION("a list without variant strings has one variant per id, and an empty one a single variant") {
|
||||
CHECK(Slic3r::map_variant_indices(variant_list, variant_ids, {}, {1, 2}) == std::vector<int>{0, 0, 1});
|
||||
CHECK(Slic3r::map_variant_indices(variant_list, variant_ids, {}, {}) == std::vector<int>{0, 0, 0});
|
||||
}
|
||||
}
|
||||
|
||||
SCENARIO("update_diff_values_to_child_config keeps a child's 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 parent with three variants") {
|
||||
Slic3r::DynamicPrintConfig parent;
|
||||
parent.set_key_value("filament_extruder_variant",
|
||||
variants({"Direct Drive Standard", "Bowden Standard", "Direct Drive High Flow"}));
|
||||
parent.set_deserialize_strict("nozzle_temperature", "220,220,220");
|
||||
|
||||
WHEN("the child was saved when the parent had only its first variant") {
|
||||
Slic3r::DynamicPrintConfig child;
|
||||
child.set_key_value("filament_extruder_variant", variants({"Direct Drive Standard"}));
|
||||
child.set_deserialize_strict("nozzle_temperature", "199");
|
||||
parent.update_diff_values_to_child_config(child, "", "filament_extruder_variant",
|
||||
Slic3r::filament_options_with_variant, no_keys);
|
||||
THEN("the child's value applies to every variant") {
|
||||
REQUIRE(parent.opt_serialize("nozzle_temperature") == "199,199,199");
|
||||
}
|
||||
}
|
||||
WHEN("the child lists every variant, in another order") {
|
||||
Slic3r::DynamicPrintConfig child;
|
||||
child.set_key_value("filament_extruder_variant",
|
||||
variants({"Bowden Standard", "Direct Drive High Flow", "Direct Drive Standard"}));
|
||||
child.set_deserialize_strict("nozzle_temperature", "190,205,199");
|
||||
parent.update_diff_values_to_child_config(child, "", "filament_extruder_variant",
|
||||
Slic3r::filament_options_with_variant, no_keys);
|
||||
THEN("each variant keeps its own value") {
|
||||
REQUIRE(parent.opt_serialize("nozzle_temperature") == "199,190,205");
|
||||
}
|
||||
}
|
||||
WHEN("the child lists no variants") {
|
||||
Slic3r::DynamicPrintConfig child;
|
||||
child.set_deserialize_strict("nozzle_temperature", "199");
|
||||
parent.update_diff_values_to_child_config(child, "", "filament_extruder_variant",
|
||||
Slic3r::filament_options_with_variant, no_keys);
|
||||
THEN("the child's value applies to every variant") {
|
||||
REQUIRE(parent.opt_serialize("nozzle_temperature") == "199,199,199");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A two-extruder printer parent with two variants per extruder") {
|
||||
Slic3r::DynamicPrintConfig parent;
|
||||
parent.set_key_value("printer_extruder_variant",
|
||||
variants({"Direct Drive Standard", "Direct Drive High Flow", "Direct Drive Standard", "Direct Drive High Flow"}));
|
||||
parent.set_key_value("printer_extruder_id", new Slic3r::ConfigOptionInts({1, 1, 2, 2}));
|
||||
parent.set_deserialize_strict("retraction_length", "0.8,0.8,0.8,0.8");
|
||||
|
||||
WHEN("the child lists only the Standard variant of each extruder") {
|
||||
Slic3r::DynamicPrintConfig child;
|
||||
child.set_key_value("printer_extruder_variant", variants({"Direct Drive Standard", "Direct Drive Standard"}));
|
||||
child.set_key_value("printer_extruder_id", new Slic3r::ConfigOptionInts({1, 2}));
|
||||
child.set_deserialize_strict("retraction_length", "1.1,2.2");
|
||||
parent.update_diff_values_to_child_config(child, "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(parent.opt_serialize("retraction_length") == "1.1,1.1,2.2,2.2");
|
||||
}
|
||||
}
|
||||
WHEN("the child lists no variants") {
|
||||
Slic3r::DynamicPrintConfig child;
|
||||
child.set_deserialize_strict("retraction_length", "1.1");
|
||||
parent.update_diff_values_to_child_config(child, "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 child's value") {
|
||||
REQUIRE(parent.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();
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <cmath>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_vector.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/Preset.hpp"
|
||||
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/Format/DRC.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
|
||||
#include <draco/attributes/geometry_attribute.h>
|
||||
#include <cstdint>
|
||||
#include <draco/attributes/geometry_indices.h>
|
||||
#include <draco/compression/config/compression_shared.h>
|
||||
#include <draco/compression/encode.h>
|
||||
#include <draco/core/draco_types.h>
|
||||
#include <draco/core/encoder_buffer.h>
|
||||
#include <draco/mesh/mesh.h>
|
||||
#include <string>
|
||||
#include <ios>
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <vector>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/ElephantFootCompensation.hpp"
|
||||
#include "libslic3r/ExPolygon.hpp"
|
||||
@@ -14,7 +18,7 @@ using namespace Slic3r;
|
||||
// #define TESTS_EXPORT_SVGS
|
||||
|
||||
namespace Slic3r {
|
||||
ClipperLib::Path mittered_offset_path_scaled(const Points& contour, const std::vector<float>& deltas, double miter_limit);
|
||||
Points mittered_offset_path_scaled(const Points& contour, const std::vector<float>& deltas, double miter_limit);
|
||||
}
|
||||
|
||||
static ExPolygon spirograph_gear_1mm()
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include "libslic3r/FilamentMixer.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <cstddef>
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include <limits>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/Fill/FillCornerSmoothing.hpp"
|
||||
#include "libslic3r/Polyline.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
@@ -2,9 +2,18 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Fill/FillBase.hpp"
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include "libslic3r/Fill/FillPlanePath.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
@@ -17,7 +20,14 @@
|
||||
|
||||
#include "../libnest2d/printer_parts.hpp"
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <math.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/SLA/Hollowing.hpp"
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <limits>
|
||||
#include <random>
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/InstanceLock.hpp"
|
||||
#include "test_utils.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <boost/interprocess/sync/file_lock.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
using namespace Slic3r;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
// Sets a process-wide knob for one test and restores it however the test ends.
|
||||
template<typename T> struct ScopedStaticValue
|
||||
{
|
||||
T &ref;
|
||||
T saved;
|
||||
ScopedStaticValue(T &ref, T value) : ref(ref), saved(ref) { ref = value; }
|
||||
~ScopedStaticValue() { ref = saved; }
|
||||
};
|
||||
|
||||
TEST_CASE("InstanceLock creates its lock file and holds it for the guard's scope", "[InstanceLock]")
|
||||
{
|
||||
ScopedTemporaryFile lock_file(".lock");
|
||||
const std::string path = lock_file.string();
|
||||
|
||||
{
|
||||
InstanceLock lock(path);
|
||||
REQUIRE(lock.locked());
|
||||
REQUIRE(boost::filesystem::exists(path));
|
||||
}
|
||||
// Released: a fresh guard gets the lock at once instead of waiting out a timeout.
|
||||
const auto started = std::chrono::steady_clock::now();
|
||||
InstanceLock again(path, 5000ms);
|
||||
REQUIRE(again.locked());
|
||||
// Well inside the timeout it would otherwise have waited out; loose enough for a loaded runner.
|
||||
REQUIRE(std::chrono::steady_clock::now() - started < 4000ms);
|
||||
}
|
||||
|
||||
TEST_CASE("InstanceLock nests within one thread", "[InstanceLock]")
|
||||
{
|
||||
ScopedTemporaryFile lock_file(".lock");
|
||||
const std::string path = lock_file.string();
|
||||
|
||||
InstanceLock outer(path);
|
||||
{
|
||||
InstanceLock inner(path, 100ms);
|
||||
REQUIRE(inner.locked());
|
||||
}
|
||||
// The inner guard leaving does not release the outer one.
|
||||
REQUIRE(outer.locked());
|
||||
}
|
||||
|
||||
TEST_CASE("InstanceLock is a no-op for an empty path and survives an unwritable one", "[InstanceLock]")
|
||||
{
|
||||
ScopedTemporaryDir dir;
|
||||
|
||||
InstanceLock none("");
|
||||
REQUIRE_FALSE(none.locked());
|
||||
|
||||
// The directory does not exist, so the lock file cannot be created; the
|
||||
// guard still constructs and the write it guards can go ahead.
|
||||
InstanceLock unwritable((dir.path() / "missing" / "shared.lock").string(), 100ms);
|
||||
REQUIRE_FALSE(unwritable.locked());
|
||||
}
|
||||
|
||||
TEST_CASE("InstanceLock retries a lock file it could not open once the cool-down passes", "[InstanceLock]")
|
||||
{
|
||||
ScopedTemporaryDir dir;
|
||||
const std::string path = (dir.path() / "later" / "shared.lock").string();
|
||||
ScopedStaticValue cooldown(InstanceLock::cooldown, 300ms);
|
||||
|
||||
bool before_dir, during_cooldown, after_cooldown;
|
||||
const auto started = std::chrono::steady_clock::now();
|
||||
{
|
||||
InstanceLock lock(path, 100ms);
|
||||
before_dir = lock.locked();
|
||||
}
|
||||
boost::filesystem::create_directories(dir.path() / "later");
|
||||
{
|
||||
InstanceLock lock(path, 100ms);
|
||||
during_cooldown = lock.locked();
|
||||
}
|
||||
const bool second_guard_inside_cooldown = std::chrono::steady_clock::now() - started < InstanceLock::cooldown;
|
||||
std::this_thread::sleep_for(400ms);
|
||||
{
|
||||
InstanceLock lock(path, 100ms);
|
||||
after_cooldown = lock.locked();
|
||||
}
|
||||
|
||||
REQUIRE_FALSE(before_dir);
|
||||
// A loaded runner may take longer than the cool-down to get here; then the
|
||||
// second guard legitimately retried, so only assert when the timing held.
|
||||
if (second_guard_inside_cooldown)
|
||||
REQUIRE_FALSE(during_cooldown);
|
||||
REQUIRE(after_cooldown);
|
||||
}
|
||||
|
||||
TEST_CASE("InstanceLock reopens a lock file that was replaced on disk", "[InstanceLock]")
|
||||
{
|
||||
ScopedTemporaryFile lock_file(".lock");
|
||||
const std::string path = lock_file.string();
|
||||
{
|
||||
InstanceLock lock(path);
|
||||
REQUIRE(lock.locked());
|
||||
}
|
||||
|
||||
boost::filesystem::remove(path);
|
||||
InstanceLock lock(path);
|
||||
REQUIRE(lock.locked());
|
||||
// Each outermost guard opens the file afresh, so the deleted path is back.
|
||||
REQUIRE(boost::filesystem::exists(path));
|
||||
}
|
||||
|
||||
TEST_CASE("InstanceLock serialises the threads of one process", "[InstanceLock]")
|
||||
{
|
||||
ScopedTemporaryFile lock_file(".lock");
|
||||
const std::string path = lock_file.string();
|
||||
|
||||
std::atomic<bool> holder_ready{false};
|
||||
std::atomic<bool> holder_released{false};
|
||||
std::thread holder([&] {
|
||||
InstanceLock lock(path);
|
||||
holder_ready = true;
|
||||
std::this_thread::sleep_for(150ms);
|
||||
holder_released = true;
|
||||
});
|
||||
while (! holder_ready)
|
||||
std::this_thread::yield();
|
||||
|
||||
bool released_before_acquire = false;
|
||||
{
|
||||
InstanceLock lock(path);
|
||||
released_before_acquire = holder_released;
|
||||
}
|
||||
holder.join();
|
||||
REQUIRE(released_before_acquire);
|
||||
}
|
||||
|
||||
// Holds the OS lock on a file through a handle of its own, as another instance would. The lock
|
||||
// belongs to the handle on Windows and to the open file description elsewhere, so the guard's
|
||||
// handle is refused while this one holds it.
|
||||
class OtherHolder
|
||||
{
|
||||
public:
|
||||
explicit OtherHolder(const std::string &path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
boost::nowide::ofstream(path, std::ios::app).close();
|
||||
m_lock = boost::interprocess::file_lock(boost::nowide::widen(path).c_str());
|
||||
m_held = m_lock.try_lock();
|
||||
#else
|
||||
m_fd = ::open(path.c_str(), O_RDWR | O_CREAT, 0644);
|
||||
m_held = m_fd >= 0 && ::flock(m_fd, LOCK_EX | LOCK_NB) == 0;
|
||||
#endif
|
||||
}
|
||||
~OtherHolder() { release(); }
|
||||
OtherHolder(const OtherHolder &) = delete;
|
||||
OtherHolder &operator=(const OtherHolder &) = delete;
|
||||
|
||||
bool held() const { return m_held; }
|
||||
void release()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (m_held)
|
||||
m_lock.unlock();
|
||||
m_lock = boost::interprocess::file_lock();
|
||||
#else
|
||||
if (m_fd >= 0)
|
||||
::close(m_fd);
|
||||
m_fd = -1;
|
||||
#endif
|
||||
m_held = false;
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
boost::interprocess::file_lock m_lock;
|
||||
#else
|
||||
int m_fd{-1};
|
||||
#endif
|
||||
bool m_held{false};
|
||||
};
|
||||
|
||||
TEST_CASE("InstanceLock yields to a lock held through another handle and reports it", "[InstanceLock]")
|
||||
{
|
||||
ScopedTemporaryFile lock_file(".lock");
|
||||
const std::string path = lock_file.string();
|
||||
ScopedStaticValue cooldown(InstanceLock::cooldown, 300ms);
|
||||
|
||||
OtherHolder other(path);
|
||||
REQUIRE(other.held());
|
||||
|
||||
bool locked_while_other_holds;
|
||||
{
|
||||
InstanceLock lock(path, 100ms);
|
||||
locked_while_other_holds = lock.locked();
|
||||
}
|
||||
// The timed-out wait starts a cool-down: the next guard does not touch the file.
|
||||
const auto started = std::chrono::steady_clock::now();
|
||||
bool locked_during_cooldown;
|
||||
{
|
||||
InstanceLock lock(path, 5000ms);
|
||||
locked_during_cooldown = lock.locked();
|
||||
}
|
||||
const auto cooldown_wait = std::chrono::steady_clock::now() - started;
|
||||
other.release();
|
||||
|
||||
REQUIRE_FALSE(locked_while_other_holds);
|
||||
REQUIRE_FALSE(locked_during_cooldown);
|
||||
REQUIRE(cooldown_wait < 4000ms);
|
||||
// Once the cool-down passes, the lock the other holder released is taken again.
|
||||
std::this_thread::sleep_for(400ms);
|
||||
InstanceLock lock(path);
|
||||
REQUIRE(lock.locked());
|
||||
}
|
||||
@@ -1,5 +1,15 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <cstddef>
|
||||
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "libslic3r/LayOnFace.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <clocale>
|
||||
#include <locale.h>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/LocalesUtils.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -2,6 +2,28 @@
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <cstddef>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <utility>
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include "libslic3r/SLA/RasterBase.hpp"
|
||||
#include <agg/agg_gamma_functions.h>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include "libslic3r/ExPolygon.hpp"
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include <cstdlib>
|
||||
#include <catch2/benchmark/catch_benchmark.hpp>
|
||||
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include "test_utils.hpp"
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include "test_utils.hpp"
|
||||
|
||||
#include <libslic3r/TriangleMesh.hpp>
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/MinimumSpanningTree.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/directory.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/file_status.hpp>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/miniz_extension.hpp"
|
||||
|
||||
#include "test_utils.hpp"
|
||||
@@ -7,8 +14,11 @@
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <iterator>
|
||||
#include <miniz.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
// MultiMaterialSegmentation.hpp declares boost::polygon traits for ColoredLine, so its
|
||||
// geometry/boost dependencies must be included first.
|
||||
#include <boost/polygon/polygon.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include "libslic3r/Line.hpp"
|
||||
#include "libslic3r/Flow.hpp"
|
||||
#include "libslic3r/MultiMaterialSegmentation.hpp"
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <cstddef>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/MutablePolygon.hpp"
|
||||
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <queue>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <functional>
|
||||
#include <cstdlib>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/MutablePriorityQueue.hpp"
|
||||
|
||||
// based on https://raw.githubusercontent.com/rollbear/prio_queue/master/self_test.cpp
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <set>
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include <vector>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
#include <array>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/Format/OBJ.hpp"
|
||||
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <string>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <cstddef>
|
||||
|
||||
#include "test_utils.hpp"
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "test_utils.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <libslic3r/Optimize/BruteforceOptimizer.hpp>
|
||||
|
||||
#include <libslic3r/Optimize/NLoptOptimizer.hpp>
|
||||
#include "libslic3r/Optimize/Optimizer.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
void check_opt_result(double score, double ref, double abs_err, double rel_err)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <math.h>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#define SLIC3R_TEST_HARNESS
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
@@ -9,6 +10,7 @@
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/task_group.h>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/ParallelResolve.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "libslic3r/Config.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include "libslic3r/PlaceholderParser.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <cstddef>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "test_utils.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
@@ -12,7 +17,13 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include <cstddef>
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#include <miniz.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/directory.hpp>
|
||||
#include <boost/filesystem/file_status.hpp>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/ParallelResolve.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
@@ -16,6 +27,23 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include <utility>
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include <map>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/PublishSettings.hpp"
|
||||
#include <set>
|
||||
#include "libslic3r/TriangleSelector.hpp"
|
||||
#include <iterator>
|
||||
#include <miniz.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h> // geteuid
|
||||
#endif
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -5956,3 +5984,214 @@ TEST_CASE("A filament's variant index follows the extruder type and nozzle volum
|
||||
// the filament defines no Bowden High Flow variant
|
||||
CHECK(PresetBundle::get_filament_variant_index(filament, printer, 1, nvtHighFlow) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("A user preset saved over by another instance while its directory loads is read again under the lock", "[Preset][Bundle][InstanceLock]")
|
||||
{
|
||||
ScopedTemporaryDir temp_dir;
|
||||
ScopedDataDir data_dir_scope(temp_dir.path());
|
||||
RenameTestCollection coll;
|
||||
|
||||
Preset &parent = add_inmemory_preset(coll, "Parent Process");
|
||||
parent.config.option<ConfigOptionFloat>("layer_height", true)->value = 0.24;
|
||||
parent.is_system = true;
|
||||
|
||||
// Fewer than one batch, so every file is read before the first one is committed.
|
||||
constexpr int children = 8;
|
||||
static_assert(children <= int(resolve_batch_size));
|
||||
const fs::path dir = temp_dir.path() / PRESET_PRINT_NAME;
|
||||
for (int i = 0; i < children; ++ i)
|
||||
write_minimal_child(dir / ("Child " + std::to_string(i) + ".json"), "Child " + std::to_string(i), "Parent Process");
|
||||
|
||||
// The first commit stands in for another instance saving every other preset after
|
||||
// they were read and before they are committed.
|
||||
std::string first;
|
||||
auto save_the_others = [&](Preset &preset) {
|
||||
if (! first.empty())
|
||||
return;
|
||||
first = preset.name;
|
||||
for (int i = 0; i < children; ++ i) {
|
||||
const std::string name = "Child " + std::to_string(i);
|
||||
if (name != first)
|
||||
std::ofstream((dir / (name + ".json")).string())
|
||||
<< R"({"type":"process","name":")" << name
|
||||
<< R"(","from":"User","version":"1.0.0","inherits":"Parent Process","layer_height":"0.3"})";
|
||||
}
|
||||
};
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
coll.load_presets(temp_dir.path().string(), PRESET_PRINT_NAME, substitutions,
|
||||
ForwardCompatibilitySubstitutionRule::Disable, save_the_others);
|
||||
|
||||
REQUIRE_FALSE(first.empty());
|
||||
CHECK(coll.error_count() == 0);
|
||||
for (int i = 0; i < children; ++ i) {
|
||||
const std::string name = "Child " + std::to_string(i);
|
||||
const Preset *child = coll.find_preset(name);
|
||||
REQUIRE(child != nullptr);
|
||||
CHECK_THAT(child->config.opt_float("layer_height"), Catch::Matchers::WithinAbs(name == first ? 0.24 : 0.3, 1e-9));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("A user preset removed by another instance while its directory loads is not installed", "[Preset][Bundle][InstanceLock]")
|
||||
{
|
||||
ScopedTemporaryDir temp_dir;
|
||||
ScopedDataDir data_dir_scope(temp_dir.path());
|
||||
RenameTestCollection coll;
|
||||
|
||||
Preset &parent = add_inmemory_preset(coll, "Parent Process");
|
||||
parent.is_system = true;
|
||||
|
||||
// Fewer than one batch, so every file is read before the first one is committed.
|
||||
constexpr int children = 8;
|
||||
static_assert(children <= int(resolve_batch_size));
|
||||
const fs::path dir = temp_dir.path() / PRESET_PRINT_NAME;
|
||||
for (int i = 0; i < children; ++ i)
|
||||
write_minimal_child(dir / ("Child " + std::to_string(i) + ".json"), "Child " + std::to_string(i), "Parent Process");
|
||||
|
||||
std::string first;
|
||||
auto remove_the_others = [&](Preset &preset) {
|
||||
if (! first.empty())
|
||||
return;
|
||||
first = preset.name;
|
||||
for (int i = 0; i < children; ++ i)
|
||||
if (const std::string name = "Child " + std::to_string(i); name != first)
|
||||
fs::remove(dir / (name + ".json"));
|
||||
};
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
coll.load_presets(temp_dir.path().string(), PRESET_PRINT_NAME, substitutions,
|
||||
ForwardCompatibilitySubstitutionRule::Disable, remove_the_others);
|
||||
|
||||
REQUIRE_FALSE(first.empty());
|
||||
CHECK(coll.error_count() == 0);
|
||||
CHECK(coll.size() == 3); // the default preset, the parent and the first child
|
||||
CHECK(coll.find_preset(first) != nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE("Without the instance lock a user preset loads but its file is not written back", "[Preset][Bundle][InstanceLock]")
|
||||
{
|
||||
ScopedTemporaryDir temp_dir;
|
||||
ScopedDataDir data_dir_scope(temp_dir.path());
|
||||
// A directory where the lock file belongs, so the lock cannot be taken.
|
||||
fs::create_directories(fs::path(user_presets_lock_path()));
|
||||
PresetBundle bundle;
|
||||
const fs::path file = temp_dir.path() / PRESET_FILAMENT_NAME / "My PLA @Test Printer.json";
|
||||
write_preset_with_inherits(bundle.filaments.default_preset().config, file, "My PLA @Test Printer", std::string());
|
||||
const std::string before = read_file(file);
|
||||
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
bundle.filaments.load_presets(temp_dir.path().string(), PRESET_FILAMENT_NAME, substitutions,
|
||||
ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||
|
||||
const Preset *preset = bundle.filaments.find_preset("My PLA @Test Printer");
|
||||
REQUIRE(preset != nullptr);
|
||||
CHECK(preset->config.option<ConfigOptionStrings>("compatible_printers")->values == std::vector<std::string>{ "Test Printer" });
|
||||
CHECK(read_file(file) == before);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
// File permissions stop reading only on POSIX.
|
||||
TEST_CASE("A user preset that cannot be read under the instance lock is counted and removed", "[Preset][Bundle][InstanceLock]")
|
||||
{
|
||||
if (::geteuid() == 0)
|
||||
SKIP("file permissions do not stop root");
|
||||
ScopedTemporaryDir temp_dir;
|
||||
ScopedDataDir data_dir_scope(temp_dir.path());
|
||||
RenameTestCollection coll;
|
||||
|
||||
Preset &parent = add_inmemory_preset(coll, "Parent Process");
|
||||
parent.is_system = true;
|
||||
const fs::path file = temp_dir.path() / PRESET_PRINT_NAME / "Unreadable.json";
|
||||
write_minimal_child(file, "Unreadable", "Parent Process");
|
||||
fs::permissions(file, fs::no_perms);
|
||||
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
coll.load_presets(temp_dir.path().string(), PRESET_PRINT_NAME, substitutions,
|
||||
ForwardCompatibilitySubstitutionRule::Disable);
|
||||
|
||||
CHECK(coll.error_count() == 1);
|
||||
CHECK(coll.find_preset("Unreadable") == nullptr);
|
||||
CHECK_FALSE(fs::exists(file));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
// Creating a symlink needs no privilege only on POSIX.
|
||||
TEST_CASE("A user preset that is a symlink to itself is counted and removed while the rest still load", "[Preset][Bundle][InstanceLock]")
|
||||
{
|
||||
ScopedTemporaryDir temp_dir;
|
||||
ScopedDataDir data_dir_scope(temp_dir.path());
|
||||
RenameTestCollection coll;
|
||||
|
||||
Preset &parent = add_inmemory_preset(coll, "Parent Process");
|
||||
parent.is_system = true;
|
||||
const fs::path dir = temp_dir.path() / PRESET_PRINT_NAME;
|
||||
write_minimal_child(dir / "Good A.json", "Good A", "Parent Process");
|
||||
write_minimal_child(dir / "Good B.json", "Good B", "Parent Process");
|
||||
const fs::path loop = dir / "Loop.json";
|
||||
fs::create_symlink(loop.filename(), loop);
|
||||
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
REQUIRE_NOTHROW(coll.load_presets(temp_dir.path().string(), PRESET_PRINT_NAME, substitutions,
|
||||
ForwardCompatibilitySubstitutionRule::Disable));
|
||||
|
||||
CHECK(coll.error_count() == 1);
|
||||
CHECK(coll.find_preset("Good A") != nullptr);
|
||||
CHECK(coll.find_preset("Good B") != nullptr);
|
||||
CHECK(coll.find_preset("Loop") == nullptr);
|
||||
boost::system::error_code ec;
|
||||
CHECK(fs::symlink_status(loop, ec).type() == fs::file_not_found);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
// Creating a symlink needs no privilege only on POSIX.
|
||||
TEST_CASE("A user preset symlinked to a missing target is counted but the link is kept", "[Preset][Bundle][InstanceLock]")
|
||||
{
|
||||
ScopedTemporaryDir temp_dir;
|
||||
ScopedDataDir data_dir_scope(temp_dir.path());
|
||||
RenameTestCollection coll;
|
||||
|
||||
const fs::path dir = temp_dir.path() / PRESET_PRINT_NAME;
|
||||
const fs::path link = dir / "Linked.json";
|
||||
fs::create_directories(dir);
|
||||
fs::create_symlink(temp_dir.path() / "unmounted" / "Linked.json", link);
|
||||
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
coll.load_presets(temp_dir.path().string(), PRESET_PRINT_NAME, substitutions,
|
||||
ForwardCompatibilitySubstitutionRule::Disable);
|
||||
|
||||
CHECK(coll.error_count() == 1);
|
||||
CHECK(coll.find_preset("Linked") == nullptr);
|
||||
boost::system::error_code ec;
|
||||
CHECK(fs::symlink_status(link, ec).type() == fs::symlink_file);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
// The read-only bit on a directory stops file creation only on POSIX.
|
||||
TEST_CASE("A user filament whose derived compatible printer cannot be written back still loads with the failure counted", "[Preset][Bundle]")
|
||||
{
|
||||
if (::geteuid() == 0)
|
||||
SKIP("a read-only directory does not stop root");
|
||||
ScopedTemporaryDir temp_dir;
|
||||
PresetBundle bundle;
|
||||
const fs::path dir = temp_dir.path() / PRESET_FILAMENT_NAME;
|
||||
const fs::path file = dir / "My PLA @Test Printer.json";
|
||||
write_preset_with_inherits(bundle.filaments.default_preset().config, file, "My PLA @Test Printer", std::string());
|
||||
const std::string before = read_file(file);
|
||||
|
||||
fs::permissions(file, fs::owner_read);
|
||||
fs::permissions(dir, fs::owner_read | fs::owner_exe);
|
||||
PresetsConfigSubstitutions substitutions;
|
||||
bundle.filaments.load_presets(temp_dir.path().string(), PRESET_FILAMENT_NAME, substitutions,
|
||||
ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||
// Restored before any assertion, so a failure never leaves an unremovable directory behind.
|
||||
fs::permissions(dir, fs::owner_all);
|
||||
fs::permissions(file, fs::owner_read | fs::owner_write);
|
||||
|
||||
const Preset *preset = bundle.filaments.find_preset("My PLA @Test Printer");
|
||||
REQUIRE(preset != nullptr);
|
||||
CHECK(preset->config.option<ConfigOptionStrings>("compatible_printers")->values == std::vector<std::string>{ "Test Printer" });
|
||||
CHECK(bundle.filaments.error_count() == 1);
|
||||
CHECK(read_file(file) == before);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
|
||||
@@ -16,10 +16,14 @@
|
||||
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/Preset.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <string>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/Preset.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
#include <catch2/catch_all.hpp> // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp)
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <cstdlib>
|
||||
#include <math.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "libslic3r/CAD/SketchConstraints.hpp"
|
||||
#include "libslic3r/CAD/SketchEngine.hpp"
|
||||
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
#include <TopAbs_ShapeEnum.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <catch2/catch_all.hpp> // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp)
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include "libslic3r/CAD/SketchEngine.hpp"
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopAbs.hxx>
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp> // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp)
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include "libslic3r/CAD/SketchImport.hpp"
|
||||
#include "libslic3r/Utils.hpp" // resources_dir
|
||||
#include "test_utils.hpp" // ScopedTemporaryFile
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <string>
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_all.hpp> // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp)
|
||||
#include "libslic3r/CAD/SketchEngine.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <vector>
|
||||
using Catch::Approx; // v3 scopes Approx into the Catch namespace; v2 had it at global scope
|
||||
|
||||
#include "libslic3r/CAD/SketchInference.hpp"
|
||||
|
||||
@@ -9,11 +9,19 @@
|
||||
// So these cases assert the loop, not the coordinates. That is the invariant every sketch
|
||||
// operation has to preserve and the only one that predicts whether the GUI can build a solid
|
||||
// out of the result.
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <catch2/catch_all.hpp> // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp)
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include "libslic3r/CAD/SketchEngine.hpp"
|
||||
#include <BRepGProp.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <cmath>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <vector>
|
||||
#include <math.h>
|
||||
#include <cstddef>
|
||||
|
||||
using namespace Slic3r;
|
||||
using Catch::Matchers::WithinAbs;
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_all.hpp> // mainline OrcaSlicer ships Catch2 v3 (v2 was catch2/catch.hpp)
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
using Catch::Approx; // v3 scopes Approx into the Catch namespace; v2 had it at global scope
|
||||
|
||||
#include "libslic3r/CAD/SketchSolver.hpp"
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <string>
|
||||
#include <ios>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Format/STEP.hpp"
|
||||
#include "test_utils.hpp"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <string>
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Format/STL.hpp"
|
||||
|
||||
|
||||
@@ -1,6 +1,29 @@
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <ios>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <map>
|
||||
#include <math.h>
|
||||
#include "libslic3r/TextureBake/TextureBakeDisplace.hpp"
|
||||
#include "libslic3r/TextureBake/TextureBakeIndex.hpp"
|
||||
#include <tuple>
|
||||
#include <Eigen/Geometry>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "libslic3r/Time.hpp"
|
||||
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <locale>
|
||||
#include <string>
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include "libslic3r/FilamentGroupUtils.hpp"
|
||||
#include "libslic3r/MultiNozzleUtils.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
@@ -11,7 +15,11 @@
|
||||
#include "test_utils.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/GCode/ToolOrderUtils.hpp"
|
||||
#include "libslic3r/PrintBase.hpp"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -510,6 +518,22 @@ TEST_CASE("Print config-index resolvers pick per-filament Hybrid slots", "[Print
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Regrouping or rewriting the filament maps changes the config-index generation", "[Print][H2C]")
|
||||
{
|
||||
Model model;
|
||||
model.add_object("cube", "", make_cube(20, 20, 20))->add_instance();
|
||||
Print print;
|
||||
print.apply(model, DynamicPrintConfig::full_print_config());
|
||||
|
||||
size_t generation = print.config_index_generation();
|
||||
print.set_nozzle_group_result(nullptr);
|
||||
REQUIRE(print.config_index_generation() != generation);
|
||||
|
||||
generation = print.config_index_generation();
|
||||
print.update_filament_maps_to_config({1}, {(int) nvtStandard}, {0});
|
||||
REQUIRE(print.config_index_generation() != generation);
|
||||
}
|
||||
|
||||
TEST_CASE("Re-applying an unchanged config after slicing keeps the result valid", "[Print][H2C]")
|
||||
{
|
||||
// apply() rebuilds m_config.filament_map_2 to the real per-filament slot map, while the
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "libslic3r/TriangleSelector.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <tbb/global_control.h>
|
||||
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/TriangleMeshSlicer.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
// The slab slicer collects each slab's intersection lines from a parallel loop over the facets.
|
||||
// Its loops, and therefore the projected polygons, are derived from the order of those lines, so
|
||||
// the order has to be canonical or the same mesh projects to different polygons run to run.
|
||||
// The single-threaded projection is the reference; every multi-threaded run must reproduce it
|
||||
// exactly, vertex order included.
|
||||
TEST_CASE("Slab slicing projects the same polygons whatever the thread schedule", "[TriangleMeshSlicer]")
|
||||
{
|
||||
// A dense sphere, tilted so no facet is axis aligned: thousands of upward and downward
|
||||
// facing facets spread over every slab.
|
||||
indexed_triangle_set mesh = its_make_sphere(10., 0.05);
|
||||
Transform3d trafo = Transform3d::Identity();
|
||||
trafo.rotate(Eigen::AngleAxisd(0.37, Vec3d(0.3, 0.5, 1.).normalized()));
|
||||
trafo.translate(Vec3d(1., 2., 0.));
|
||||
std::vector<float> zs;
|
||||
for (float z = -9.7f; z < 9.7f; z += 0.2f)
|
||||
zs.emplace_back(z);
|
||||
|
||||
auto project = [&mesh, &trafo, &zs]() {
|
||||
std::vector<Polygons> top, bottom;
|
||||
slice_mesh_slabs(mesh, zs, trafo, &top, &bottom, nullptr, []{});
|
||||
return std::make_pair(std::move(top), std::move(bottom));
|
||||
};
|
||||
|
||||
std::pair<std::vector<Polygons>, std::vector<Polygons>> reference;
|
||||
{
|
||||
tbb::global_control single_thread(tbb::global_control::max_allowed_parallelism, 1);
|
||||
reference = project();
|
||||
}
|
||||
REQUIRE(reference.first.size() == zs.size());
|
||||
REQUIRE(std::any_of(reference.first.begin(), reference.first.end(), [](const Polygons &p) { return !p.empty(); }));
|
||||
REQUIRE(std::any_of(reference.second.begin(), reference.second.end(), [](const Polygons &p) { return !p.empty(); }));
|
||||
|
||||
for (int run = 0; run < 3; ++run) {
|
||||
DYNAMIC_SECTION("multi-threaded run " << run)
|
||||
{
|
||||
auto parallel = project();
|
||||
CHECK(parallel.first == reference.first);
|
||||
CHECK(parallel.second == reference.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,14 @@
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/directory.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/file_status.hpp>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/Utils.hpp"
|
||||
|
||||
#include "test_utils.hpp"
|
||||
@@ -8,8 +17,14 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h> // getuid
|
||||
@@ -62,6 +77,113 @@ TEST_CASE("per-user temp root is unchanged on Windows, isolated elsewhere", "[ut
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("write_file_atomically replaces the target and leaves no temporary file", "[utils]") {
|
||||
ScopedTemporaryDir dir;
|
||||
const boost::filesystem::path target = dir.path() / "preset.json";
|
||||
|
||||
REQUIRE_FALSE(write_file_atomically(target.string(), "first"));
|
||||
REQUIRE_FALSE(write_file_atomically(target.string(), "second"));
|
||||
|
||||
std::string content;
|
||||
load_string_file(target, content);
|
||||
REQUIRE(content == "second");
|
||||
size_t entries = 0;
|
||||
for (auto &entry : boost::filesystem::directory_iterator(dir.path())) {
|
||||
(void) entry;
|
||||
++entries;
|
||||
}
|
||||
REQUIRE(entries == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("write_file_atomically reports a missing directory and writes nothing", "[utils]") {
|
||||
ScopedTemporaryDir dir;
|
||||
const boost::filesystem::path target = dir.path() / "missing" / "preset.json";
|
||||
|
||||
const std::error_code ec = write_file_atomically(target.string(), "x");
|
||||
REQUIRE(ec == std::errc::no_such_file_or_directory);
|
||||
REQUIRE_FALSE(boost::filesystem::exists(target));
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
// The read-only bit on a directory stops file creation only on POSIX.
|
||||
TEST_CASE("write_file_atomically writes in place when no temporary can be created beside an existing target", "[utils]") {
|
||||
if (::geteuid() == 0)
|
||||
SKIP("a read-only directory does not stop root");
|
||||
ScopedTemporaryDir dir;
|
||||
const boost::filesystem::path target = dir.path() / "preset.json";
|
||||
REQUIRE_FALSE(write_file_atomically(target.string(), "first"));
|
||||
boost::filesystem::permissions(dir.path(), boost::filesystem::owner_read | boost::filesystem::owner_exe);
|
||||
|
||||
const std::error_code replaced = write_file_atomically(target.string(), "second");
|
||||
const std::error_code created = write_file_atomically((dir.path() / "new.json").string(), "x");
|
||||
// Restored before any assertion, so a failure never leaves an unremovable directory behind.
|
||||
boost::filesystem::permissions(dir.path(), boost::filesystem::owner_all);
|
||||
|
||||
REQUIRE_FALSE(replaced);
|
||||
REQUIRE(created == std::errc::permission_denied);
|
||||
std::string content;
|
||||
load_string_file(target, content);
|
||||
REQUIRE(content == "second");
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("write_file_atomically keeps bytes intact in binary mode", "[utils]") {
|
||||
ScopedTemporaryDir dir;
|
||||
const boost::filesystem::path target = dir.path() / "blob.bin";
|
||||
const std::string bytes("a\r\nb\0c", 6);
|
||||
|
||||
REQUIRE_FALSE(write_file_atomically(target.string(), bytes, /*binary=*/true));
|
||||
REQUIRE(boost::filesystem::file_size(target) == bytes.size());
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
TEST_CASE("write_file_atomically writes through a symlink and keeps the target's permissions", "[utils]") {
|
||||
ScopedTemporaryDir dir;
|
||||
const boost::filesystem::path real = dir.path() / "real.json";
|
||||
const boost::filesystem::path link = dir.path() / "link.json";
|
||||
REQUIRE_FALSE(write_file_atomically(real.string(), "first"));
|
||||
boost::filesystem::permissions(real, boost::filesystem::owner_read | boost::filesystem::owner_write);
|
||||
boost::filesystem::create_symlink(real, link);
|
||||
|
||||
REQUIRE_FALSE(write_file_atomically(link.string(), "second"));
|
||||
|
||||
REQUIRE(boost::filesystem::is_symlink(boost::filesystem::symlink_status(link)));
|
||||
std::string content;
|
||||
load_string_file(real, content);
|
||||
REQUIRE(content == "second");
|
||||
|
||||
REQUIRE_FALSE(write_file_atomically(real.string(), "third"));
|
||||
const auto perms = boost::filesystem::status(real).permissions() & boost::filesystem::all_all;
|
||||
REQUIRE(perms == (boost::filesystem::owner_read | boost::filesystem::owner_write));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("write_file_atomically survives two threads writing one target", "[utils]") {
|
||||
ScopedTemporaryDir dir;
|
||||
const boost::filesystem::path target = dir.path() / "shared.json";
|
||||
const std::string a(20000, 'a'), b(20000, 'b');
|
||||
|
||||
std::thread other([&] {
|
||||
for (int i = 0; i < 50; ++i)
|
||||
write_file_atomically(target.string(), a);
|
||||
});
|
||||
for (int i = 0; i < 50; ++i)
|
||||
write_file_atomically(target.string(), b);
|
||||
other.join();
|
||||
|
||||
std::string content;
|
||||
load_string_file(target, content);
|
||||
const bool whole = content == a || content == b;
|
||||
REQUIRE(whole);
|
||||
// No temporary may be left; a scanner on Windows may briefly hold the old
|
||||
// file under another name, so only the temporaries are counted.
|
||||
size_t temporaries = 0;
|
||||
for (auto &entry : boost::filesystem::directory_iterator(dir.path()))
|
||||
if (entry.path().extension() == ".tmp")
|
||||
++temporaries;
|
||||
REQUIRE(temporaries == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("copy_file reports the OS error when the destination cannot be written", "[utils]") {
|
||||
ScopedTemporaryFile source(".txt");
|
||||
{
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -5,19 +7,32 @@
|
||||
#include <cereal/archives/binary.hpp>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <ios>
|
||||
#include <iterator>
|
||||
#include "libslic3r/Semver.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <tbb/blocked_range.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/task_group.h>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/PresetCacheFormat.hpp"
|
||||
#include "libslic3r/Preset.hpp"
|
||||
@@ -1804,24 +1819,6 @@ TEST_CASE("a header claiming more body than the file holds is rejected", "[Vendo
|
||||
REQUIRE_FALSE(bundle.load_vendor_cache(cache, "Bounded", Semver(1, 0, 0)));
|
||||
}
|
||||
|
||||
TEST_CASE("a failed write leaves the previous cache in place", "[VendorCache]")
|
||||
{
|
||||
TempDir tmp;
|
||||
const std::string cache = (tmp.path / "Durable.opc").string();
|
||||
REQUIRE(save_one_vendor(cache, one_vendor("Durable"), "Durable", "1.0.0"));
|
||||
const std::string before = slurp(cache);
|
||||
|
||||
// A directory where the temp file wants to go: the write cannot complete,
|
||||
// and must not have destroyed what was already there to find that out.
|
||||
const fs::path blocker = fs::path(cache + "." + std::to_string(get_current_pid()) + ".tmp");
|
||||
fs::create_directories(blocker);
|
||||
|
||||
REQUIRE_FALSE(save_one_vendor(cache, one_vendor("Durable"), "Durable", "2.0.0"));
|
||||
CHECK(slurp(cache) == before);
|
||||
|
||||
fs::remove_all(blocker);
|
||||
}
|
||||
|
||||
TEST_CASE("a cache written by another build's option ordering still loads", "[VendorCache]")
|
||||
{
|
||||
// The regression the fingerprint used to prevent by refusing the file
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
#include <algorithm>
|
||||
#include <catch2/catch_all.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "test_utils.hpp"
|
||||
|
||||
#include "libslic3r/Geometry/Voronoi.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Line.hpp"
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include <libslic3r/Polygon.hpp>
|
||||
#include <libslic3r/Polyline.hpp>
|
||||
#include <libslic3r/EdgeGrid.hpp>
|
||||
@@ -9,8 +17,11 @@
|
||||
#include <libslic3r/Geometry/VoronoiOffset.hpp>
|
||||
#include <libslic3r/Geometry/VoronoiVisualUtils.hpp>
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <math.h>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
// #define VORONOI_DEBUG_OUT
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/catch_message.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/generators/catch_generators.hpp>
|
||||
#include "libslic3r/GCode/WipePathHelpers.hpp"
|
||||
#include "libslic3r/AABBTreeLines.hpp"
|
||||
#include "libslic3r/Polyline.hpp"
|
||||
@@ -9,7 +14,12 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <optional>
|
||||
|
||||
using namespace Slic3r;
|
||||
using Slic3r::AABBTreeLines::LinesDistancer;
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include <math.h>
|
||||
#include <utility>
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <cstddef>
|
||||
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers.hpp>
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/GCode/WipeTower.hpp"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user