#ifndef SLA_TEST_UTILS_HPP #define SLA_TEST_UTILS_HPP #include #include // Debug #include #include #include "libslic3r/libslic3r.h" #include "libslic3r/Format/OBJ.hpp" #include "libslic3r/SLAPrint.hpp" #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/SLA/Pad.hpp" #include "libslic3r/SLA/SupportTreeBuilder.hpp" #include "libslic3r/SLA/SupportTreeBuildsteps.hpp" #include "libslic3r/SLA/SupportPointGenerator.hpp" #include "libslic3r/SLA/AGGRaster.hpp" #include "libslic3r/SLA/ConcaveHull.hpp" #include "libslic3r/MTUtils.hpp" #include "libslic3r/SVG.hpp" #include "libslic3r/Format/OBJ.hpp" using namespace Slic3r; enum e_validity { ASSUME_NO_EMPTY = 1, ASSUME_MANIFOLD = 2, ASSUME_NO_REPAIR = 4 }; void check_validity(const TriangleMesh &input_mesh, int flags = ASSUME_NO_EMPTY | ASSUME_MANIFOLD | ASSUME_NO_REPAIR); struct PadByproducts { ExPolygons model_contours; ExPolygons support_contours; TriangleMesh mesh; }; void test_concave_hull(const ExPolygons &polys); void test_pad(const std::string & obj_filename, const sla::PadConfig &padcfg, PadByproducts & out); inline void test_pad(const std::string & obj_filename, const sla::PadConfig &padcfg = {}) { PadByproducts byproducts; test_pad(obj_filename, padcfg, byproducts); } struct SupportByproducts { std::string obj_fname; std::vector slicegrid; std::vector model_slices; sla::SupportTreeBuilder supporttree; TriangleMesh input_mesh; }; const constexpr float CLOSING_RADIUS = 0.005f; void check_support_tree_integrity(const sla::SupportTreeBuilder &stree, const sla::SupportTreeConfig &cfg); void test_supports(const std::string &obj_filename, const sla::SupportTreeConfig &supportcfg, const sla::HollowingConfig &hollowingcfg, const sla::DrainHoles &drainholes, SupportByproducts &out); inline void test_supports(const std::string &obj_filename, const sla::SupportTreeConfig &supportcfg, SupportByproducts &out) { sla::HollowingConfig hcfg; hcfg.enabled = false; test_supports(obj_filename, supportcfg, hcfg, {}, out); } inline void test_supports(const std::string &obj_filename, const sla::SupportTreeConfig &supportcfg = {}) { SupportByproducts byproducts; test_supports(obj_filename, supportcfg, byproducts); } void export_failed_case(const std::vector &support_slices, const SupportByproducts &byproducts); void test_support_model_collision( const std::string &obj_filename, const sla::SupportTreeConfig &input_supportcfg, const sla::HollowingConfig &hollowingcfg, const sla::DrainHoles &drainholes); inline void test_support_model_collision( const std::string &obj_filename, const sla::SupportTreeConfig &input_supportcfg = {}) { sla::HollowingConfig hcfg; hcfg.enabled = false; test_support_model_collision(obj_filename, input_supportcfg, hcfg, {}); } // Test pair hash for 'nums' random number pairs. template void test_pairhash() { const constexpr size_t nums = 1000; I A[nums] = {0}, B[nums] = {0}; std::unordered_set CH; std::unordered_map> ints; std::random_device rd; std::mt19937 gen(rd()); const I Ibits = int(sizeof(I) * CHAR_BIT); const II IIbits = int(sizeof(II) * CHAR_BIT); int bits = IIbits / 2 < Ibits ? Ibits / 2 : Ibits; if (std::is_signed::value) bits -= 1; const I Imin = 0; const I Imax = I(std::pow(2., bits) - 1); std::uniform_int_distribution dis(Imin, Imax); for (size_t i = 0; i < nums;) { I a = dis(gen); if (CH.find(a) == CH.end()) { CH.insert(a); A[i] = a; ++i; } } for (size_t i = 0; i < nums;) { I b = dis(gen); if (CH.find(b) == CH.end()) { CH.insert(b); B[i] = b; ++i; } } for (size_t i = 0; i < nums; ++i) { I a = A[i], b = B[i]; REQUIRE(a != b); II hash_ab = sla::pairhash(a, b); II hash_ba = sla::pairhash(b, a); REQUIRE(hash_ab == hash_ba); auto it = ints.find(hash_ab); if (it != ints.end()) { REQUIRE(( (it->second.first == a && it->second.second == b) || (it->second.first == b && it->second.second == a) )); } else ints[hash_ab] = std::make_pair(a, b); } } // SLA Raster test utils: using TPixel = uint8_t; static constexpr const TPixel FullWhite = 255; static constexpr const TPixel FullBlack = 0; template constexpr int arraysize(const A (&)[N]) { return N; } void check_raster_transformations(sla::RasterBase::Orientation o, sla::RasterBase::TMirroring mirroring); ExPolygon square_with_hole(double v); inline double pixel_area(TPixel px, const sla::RasterBase::PixelDim &pxdim) { return (pxdim.h_mm * pxdim.w_mm) * px * 1. / (FullWhite - FullBlack); } double raster_white_area(const sla::RasterGrayscaleAA &raster); long raster_pxsum(const sla::RasterGrayscaleAA &raster); double predict_error(const ExPolygon &p, const sla::RasterBase::PixelDim &pd); sla::SupportPoints calc_support_pts( const TriangleMesh & mesh, const sla::SupportPointGenerator::Config &cfg = {}); #endif // SLA_TEST_UTILS_HPP