From 7f476f38b930838d8742c2907e1fad759943416d Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 30 Jan 2020 15:53:32 +0100 Subject: [PATCH] [refactor] Move remaining utility functions into sla_test_utils --- tests/sla_print/sla_print_tests.cpp | 167 ---------------------------- tests/sla_print/sla_test_utils.cpp | 100 +++++++++++++++++ tests/sla_print/sla_test_utils.hpp | 75 +++++++++++++ 3 files changed, 175 insertions(+), 167 deletions(-) diff --git a/tests/sla_print/sla_print_tests.cpp b/tests/sla_print/sla_print_tests.cpp index f34fb9096..32bca4ec0 100644 --- a/tests/sla_print/sla_print_tests.cpp +++ b/tests/sla_print/sla_print_tests.cpp @@ -26,58 +26,6 @@ const char *const SUPPORT_TEST_MODELS[] = { } // namespace -// 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); - } -} - TEST_CASE("Pillar pairhash should be unique", "[SLASupportGeneration]") { test_pairhash(); test_pairhash(); @@ -225,69 +173,6 @@ TEST_CASE("InitializedRasterShouldBeNONEmpty", "[SLARasterOutput]") { REQUIRE(raster.pixel_dimensions().h_mm == Approx(pixdim.h_mm)); } -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; } - -static void check_raster_transformations(sla::Raster::Orientation o, - sla::Raster::TMirroring mirroring) -{ - double disp_w = 120., disp_h = 68.; - sla::Raster::Resolution res{2560, 1440}; - sla::Raster::PixelDim pixdim{disp_w / res.width_px, disp_h / res.height_px}; - - auto bb = BoundingBox({0, 0}, {scaled(disp_w), scaled(disp_h)}); - sla::Raster::Trafo trafo{o, mirroring}; - trafo.origin_x = bb.center().x(); - trafo.origin_y = bb.center().y(); - - sla::Raster raster{res, pixdim, trafo}; - - // create box of size 32x32 pixels (not 1x1 to avoid antialiasing errors) - coord_t pw = 32 * coord_t(std::ceil(scaled(pixdim.w_mm))); - coord_t ph = 32 * coord_t(std::ceil(scaled(pixdim.h_mm))); - ExPolygon box; - box.contour.points = {{-pw, -ph}, {pw, -ph}, {pw, ph}, {-pw, ph}}; - - double tr_x = scaled(20.), tr_y = tr_x; - - box.translate(tr_x, tr_y); - ExPolygon expected_box = box; - - // Now calculate the position of the translated box according to output - // trafo. - if (o == sla::Raster::Orientation::roPortrait) expected_box.rotate(PI / 2.); - - if (mirroring[X]) - for (auto &p : expected_box.contour.points) p.x() = -p.x(); - - if (mirroring[Y]) - for (auto &p : expected_box.contour.points) p.y() = -p.y(); - - raster.draw(box); - - Point expected_coords = expected_box.contour.bounding_box().center(); - double rx = unscaled(expected_coords.x() + bb.center().x()) / pixdim.w_mm; - double ry = unscaled(expected_coords.y() + bb.center().y()) / pixdim.h_mm; - auto w = size_t(std::floor(rx)); - auto h = res.height_px - size_t(std::floor(ry)); - - REQUIRE((w < res.width_px && h < res.height_px)); - - auto px = raster.read_pixel(w, h); - - if (px != FullWhite) { - sla::PNGImage img; - std::fstream outf("out.png", std::ios::out); - - outf << img.serialize(raster); - } - - REQUIRE(px == FullWhite); -} - TEST_CASE("MirroringShouldBeCorrect", "[SLARasterOutput]") { sla::Raster::TMirroring mirrorings[] = {sla::Raster::NoMirror, sla::Raster::MirrorX, @@ -301,54 +186,6 @@ TEST_CASE("MirroringShouldBeCorrect", "[SLARasterOutput]") { check_raster_transformations(orientation, mirror); } -static ExPolygon square_with_hole(double v) -{ - ExPolygon poly; - coord_t V = scaled(v / 2.); - - poly.contour.points = {{-V, -V}, {V, -V}, {V, V}, {-V, V}}; - poly.holes.emplace_back(); - V = V / 2; - poly.holes.front().points = {{-V, V}, {V, V}, {V, -V}, {-V, -V}}; - return poly; -} - -static double pixel_area(TPixel px, const sla::Raster::PixelDim &pxdim) -{ - return (pxdim.h_mm * pxdim.w_mm) * px * 1. / (FullWhite - FullBlack); -} - -static double raster_white_area(const sla::Raster &raster) -{ - if (raster.empty()) return std::nan(""); - - auto res = raster.resolution(); - double a = 0; - - for (size_t x = 0; x < res.width_px; ++x) - for (size_t y = 0; y < res.height_px; ++y) { - auto px = raster.read_pixel(x, y); - a += pixel_area(px, raster.pixel_dimensions()); - } - - return a; -} - -static double predict_error(const ExPolygon &p, const sla::Raster::PixelDim &pd) -{ - auto lines = p.lines(); - double pix_err = pixel_area(FullWhite, pd) / 2.; - - // Worst case is when a line is parallel to the shorter axis of one pixel, - // when the line will be composed of the max number of pixels - double pix_l = std::min(pd.h_mm, pd.w_mm); - - double error = 0.; - for (auto &l : lines) - error += (unscaled(l.length()) / pix_l) * pix_err; - - return error; -} TEST_CASE("RasterizedPolygonAreaShouldMatch", "[SLARasterOutput]") { double disp_w = 120., disp_h = 68.; @@ -388,8 +225,4 @@ TEST_CASE("Triangle mesh conversions should be correct", "[SLAConversions]") std::fstream infile{"extruder_idler_quads.obj", std::ios::in}; cntr.from_obj(infile); } - - - - } diff --git a/tests/sla_print/sla_test_utils.cpp b/tests/sla_print/sla_test_utils.cpp index 0804adb4f..44a15ff90 100644 --- a/tests/sla_print/sla_test_utils.cpp +++ b/tests/sla_print/sla_test_utils.cpp @@ -292,3 +292,103 @@ void check_validity(const TriangleMesh &input_mesh, int flags) REQUIRE(mesh.is_manifold()); } } + +void check_raster_transformations(sla::Raster::Orientation o, sla::Raster::TMirroring mirroring) +{ + double disp_w = 120., disp_h = 68.; + sla::Raster::Resolution res{2560, 1440}; + sla::Raster::PixelDim pixdim{disp_w / res.width_px, disp_h / res.height_px}; + + auto bb = BoundingBox({0, 0}, {scaled(disp_w), scaled(disp_h)}); + sla::Raster::Trafo trafo{o, mirroring}; + trafo.origin_x = bb.center().x(); + trafo.origin_y = bb.center().y(); + + sla::Raster raster{res, pixdim, trafo}; + + // create box of size 32x32 pixels (not 1x1 to avoid antialiasing errors) + coord_t pw = 32 * coord_t(std::ceil(scaled(pixdim.w_mm))); + coord_t ph = 32 * coord_t(std::ceil(scaled(pixdim.h_mm))); + ExPolygon box; + box.contour.points = {{-pw, -ph}, {pw, -ph}, {pw, ph}, {-pw, ph}}; + + double tr_x = scaled(20.), tr_y = tr_x; + + box.translate(tr_x, tr_y); + ExPolygon expected_box = box; + + // Now calculate the position of the translated box according to output + // trafo. + if (o == sla::Raster::Orientation::roPortrait) expected_box.rotate(PI / 2.); + + if (mirroring[X]) + for (auto &p : expected_box.contour.points) p.x() = -p.x(); + + if (mirroring[Y]) + for (auto &p : expected_box.contour.points) p.y() = -p.y(); + + raster.draw(box); + + Point expected_coords = expected_box.contour.bounding_box().center(); + double rx = unscaled(expected_coords.x() + bb.center().x()) / pixdim.w_mm; + double ry = unscaled(expected_coords.y() + bb.center().y()) / pixdim.h_mm; + auto w = size_t(std::floor(rx)); + auto h = res.height_px - size_t(std::floor(ry)); + + REQUIRE((w < res.width_px && h < res.height_px)); + + auto px = raster.read_pixel(w, h); + + if (px != FullWhite) { + sla::PNGImage img; + std::fstream outf("out.png", std::ios::out); + + outf << img.serialize(raster); + } + + REQUIRE(px == FullWhite); +} + +ExPolygon square_with_hole(double v) +{ + ExPolygon poly; + coord_t V = scaled(v / 2.); + + poly.contour.points = {{-V, -V}, {V, -V}, {V, V}, {-V, V}}; + poly.holes.emplace_back(); + V = V / 2; + poly.holes.front().points = {{-V, V}, {V, V}, {V, -V}, {-V, -V}}; + return poly; +} + +double raster_white_area(const sla::Raster &raster) +{ + if (raster.empty()) return std::nan(""); + + auto res = raster.resolution(); + double a = 0; + + for (size_t x = 0; x < res.width_px; ++x) + for (size_t y = 0; y < res.height_px; ++y) { + auto px = raster.read_pixel(x, y); + a += pixel_area(px, raster.pixel_dimensions()); + } + + return a; +} + +double predict_error(const ExPolygon &p, const sla::Raster::PixelDim &pd) +{ + auto lines = p.lines(); + double pix_err = pixel_area(FullWhite, pd) / 2.; + + // Worst case is when a line is parallel to the shorter axis of one pixel, + // when the line will be composed of the max number of pixels + double pix_l = std::min(pd.h_mm, pd.w_mm); + + double error = 0.; + for (auto &l : lines) + error += (unscaled(l.length()) / pix_l) * pix_err; + + return error; +} diff --git a/tests/sla_print/sla_test_utils.hpp b/tests/sla_print/sla_test_utils.hpp index dcb4934ef..f3727bd39 100644 --- a/tests/sla_print/sla_test_utils.hpp +++ b/tests/sla_print/sla_test_utils.hpp @@ -6,6 +6,7 @@ // Debug #include +#include #include "libslic3r/libslic3r.h" #include "libslic3r/Format/OBJ.hpp" @@ -109,4 +110,78 @@ inline void test_support_model_collision( 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::Raster::Orientation o, + sla::Raster::TMirroring mirroring); + +ExPolygon square_with_hole(double v); + +inline double pixel_area(TPixel px, const sla::Raster::PixelDim &pxdim) +{ + return (pxdim.h_mm * pxdim.w_mm) * px * 1. / (FullWhite - FullBlack); +} + +double raster_white_area(const sla::Raster &raster); + +double predict_error(const ExPolygon &p, const sla::Raster::PixelDim &pd); + #endif // SLA_TEST_UTILS_HPP