PrusaSlicer-NonPlainar/tests/sla_print/sla_print_tests.cpp
tamasmeszaros 927b81ea97 Working small-to-normal support merging
Fixed fatal bug with anchors for mini supports

Make the optimization cleaner in support generatior

Much better widening behaviour

Add an optimizer interface and the NLopt implementation into libslic3r

New optimizer based only on nlopt C interfase
Fix build and tests
2020-08-03 19:05:30 +02:00

242 lines
7.4 KiB
C++

#include <unordered_set>
#include <unordered_map>
#include <random>
#include "sla_test_utils.hpp"
#include <libslic3r/SLA/SupportTreeMesher.hpp>
namespace {
const char *const BELOW_PAD_TEST_OBJECTS[] = {
"20mm_cube.obj",
"V.obj",
};
const char *const AROUND_PAD_TEST_OBJECTS[] = {
"20mm_cube.obj",
"V.obj",
"frog_legs.obj",
"cube_with_concave_hole_enlarged.obj",
};
const char *const SUPPORT_TEST_MODELS[] = {
"cube_with_concave_hole_enlarged_standing.obj",
"A_upsidedown.obj",
"extruder_idler.obj"
};
} // namespace
TEST_CASE("Pillar pairhash should be unique", "[SLASupportGeneration]") {
test_pairhash<int, int>();
test_pairhash<int, long>();
test_pairhash<unsigned, unsigned>();
test_pairhash<unsigned, unsigned long>();
}
TEST_CASE("Support point generator should be deterministic if seeded",
"[SLASupportGeneration], [SLAPointGen]") {
TriangleMesh mesh = load_model("A_upsidedown.obj");
sla::IndexedMesh emesh{mesh};
sla::SupportTreeConfig supportcfg;
sla::SupportPointGenerator::Config autogencfg;
autogencfg.head_diameter = float(2 * supportcfg.head_front_radius_mm);
sla::SupportPointGenerator point_gen{emesh, autogencfg, [] {}, [](int) {}};
TriangleMeshSlicer slicer{&mesh};
auto bb = mesh.bounding_box();
double zmin = bb.min.z();
double zmax = bb.max.z();
double gnd = zmin - supportcfg.object_elevation_mm;
auto layer_h = 0.05f;
auto slicegrid = grid(float(gnd), float(zmax), layer_h);
std::vector<ExPolygons> slices;
slicer.slice(slicegrid, SlicingMode::Regular, CLOSING_RADIUS, &slices, []{});
point_gen.seed(0);
point_gen.execute(slices, slicegrid);
auto get_chksum = [](const std::vector<sla::SupportPoint> &pts){
long long chksum = 0;
for (auto &pt : pts) {
auto p = scaled(pt.pos);
chksum += p.x() + p.y() + p.z();
}
return chksum;
};
long long checksum = get_chksum(point_gen.output());
size_t ptnum = point_gen.output().size();
REQUIRE(point_gen.output().size() > 0);
for (int i = 0; i < 20; ++i) {
point_gen.output().clear();
point_gen.seed(0);
point_gen.execute(slices, slicegrid);
REQUIRE(point_gen.output().size() == ptnum);
REQUIRE(checksum == get_chksum(point_gen.output()));
}
}
TEST_CASE("Flat pad geometry is valid", "[SLASupportGeneration]") {
sla::PadConfig padcfg;
// Disable wings
padcfg.wall_height_mm = .0;
for (auto &fname : BELOW_PAD_TEST_OBJECTS) test_pad(fname, padcfg);
}
TEST_CASE("WingedPadGeometryIsValid", "[SLASupportGeneration]") {
sla::PadConfig padcfg;
// Add some wings to the pad to test the cavity
padcfg.wall_height_mm = 1.;
for (auto &fname : BELOW_PAD_TEST_OBJECTS) test_pad(fname, padcfg);
}
TEST_CASE("FlatPadAroundObjectIsValid", "[SLASupportGeneration]") {
sla::PadConfig padcfg;
// Add some wings to the pad to test the cavity
padcfg.wall_height_mm = 0.;
// padcfg.embed_object.stick_stride_mm = 0.;
padcfg.embed_object.enabled = true;
padcfg.embed_object.everywhere = true;
for (auto &fname : AROUND_PAD_TEST_OBJECTS) test_pad(fname, padcfg);
}
TEST_CASE("WingedPadAroundObjectIsValid", "[SLASupportGeneration]") {
sla::PadConfig padcfg;
// Add some wings to the pad to test the cavity
padcfg.wall_height_mm = 1.;
padcfg.embed_object.enabled = true;
padcfg.embed_object.everywhere = true;
for (auto &fname : AROUND_PAD_TEST_OBJECTS) test_pad(fname, padcfg);
}
TEST_CASE("ElevatedSupportGeometryIsValid", "[SLASupportGeneration]") {
sla::SupportTreeConfig supportcfg;
supportcfg.object_elevation_mm = 5.;
for (auto fname : SUPPORT_TEST_MODELS) test_supports(fname);
}
TEST_CASE("FloorSupportGeometryIsValid", "[SLASupportGeneration]") {
sla::SupportTreeConfig supportcfg;
supportcfg.object_elevation_mm = 0;
for (auto &fname: SUPPORT_TEST_MODELS) test_supports(fname, supportcfg);
}
TEST_CASE("ElevatedSupportsDoNotPierceModel", "[SLASupportGeneration]") {
sla::SupportTreeConfig supportcfg;
for (auto fname : SUPPORT_TEST_MODELS)
test_support_model_collision(fname, supportcfg);
}
TEST_CASE("FloorSupportsDoNotPierceModel", "[SLASupportGeneration]") {
sla::SupportTreeConfig supportcfg;
supportcfg.object_elevation_mm = 0;
for (auto fname : SUPPORT_TEST_MODELS)
test_support_model_collision(fname, supportcfg);
}
TEST_CASE("InitializedRasterShouldBeNONEmpty", "[SLARasterOutput]") {
// Default Prusa SL1 display parameters
sla::RasterBase::Resolution res{2560, 1440};
sla::RasterBase::PixelDim pixdim{120. / res.width_px, 68. / res.height_px};
sla::RasterGrayscaleAAGammaPower raster(res, pixdim, {}, 1.);
REQUIRE(raster.resolution().width_px == res.width_px);
REQUIRE(raster.resolution().height_px == res.height_px);
REQUIRE(raster.pixel_dimensions().w_mm == Approx(pixdim.w_mm));
REQUIRE(raster.pixel_dimensions().h_mm == Approx(pixdim.h_mm));
}
TEST_CASE("MirroringShouldBeCorrect", "[SLARasterOutput]") {
sla::RasterBase::TMirroring mirrorings[] = {sla::RasterBase::NoMirror,
sla::RasterBase::MirrorX,
sla::RasterBase::MirrorY,
sla::RasterBase::MirrorXY};
sla::RasterBase::Orientation orientations[] =
{sla::RasterBase::roLandscape, sla::RasterBase::roPortrait};
for (auto orientation : orientations)
for (auto &mirror : mirrorings)
check_raster_transformations(orientation, mirror);
}
TEST_CASE("RasterizedPolygonAreaShouldMatch", "[SLARasterOutput]") {
double disp_w = 120., disp_h = 68.;
sla::RasterBase::Resolution res{2560, 1440};
sla::RasterBase::PixelDim pixdim{disp_w / res.width_px, disp_h / res.height_px};
double gamma = 1.;
sla::RasterGrayscaleAAGammaPower raster(res, pixdim, {}, gamma);
auto bb = BoundingBox({0, 0}, {scaled(disp_w), scaled(disp_h)});
ExPolygon poly = square_with_hole(10.);
poly.translate(bb.center().x(), bb.center().y());
raster.draw(poly);
double a = poly.area() / (scaled<double>(1.) * scaled(1.));
double ra = raster_white_area(raster);
double diff = std::abs(a - ra);
REQUIRE(diff <= predict_error(poly, pixdim));
raster.clear();
poly = square_with_hole(60.);
poly.translate(bb.center().x(), bb.center().y());
raster.draw(poly);
a = poly.area() / (scaled<double>(1.) * scaled(1.));
ra = raster_white_area(raster);
diff = std::abs(a - ra);
REQUIRE(diff <= predict_error(poly, pixdim));
sla::RasterGrayscaleAA raster0(res, pixdim, {}, [](double) { return 0.; });
REQUIRE(raster_pxsum(raster0) == 0);
raster0.draw(poly);
ra = raster_white_area(raster);
REQUIRE(raster_pxsum(raster0) == 0);
}
TEST_CASE("Triangle mesh conversions should be correct", "[SLAConversions]")
{
sla::Contour3D cntr;
{
std::fstream infile{"extruder_idler_quads.obj", std::ios::in};
cntr.from_obj(infile);
}
}
TEST_CASE("halfcone test", "[halfcone]") {
sla::DiffBridge br{Vec3d{1., 1., 1.}, Vec3d{10., 10., 10.}, 0.25, 0.5};
TriangleMesh m = sla::to_triangle_mesh(sla::get_mesh(br, 45));
m.require_shared_vertices();
m.WriteOBJFile("Halfcone.obj");
}