Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorenricoturri1966 <enricoturri@seznam.cz>2020-04-24 11:59:03 +0300
committerenricoturri1966 <enricoturri@seznam.cz>2020-04-24 11:59:03 +0300
commite5c45405d4b7ce60b061f79bd213c05c8f253039 (patch)
tree483d0a17ba95b7259f9dc355d1aa8c3e95d3965f /tests
parent81a29169aee1e9af381c360a8005897189b06b6e (diff)
parent4f622e4541d3e3da0be0203776c5b7c03aef7eaf (diff)
Fixed conflicts after merge with master
Diffstat (limited to 'tests')
-rw-r--r--tests/fff_print/test_data.cpp4
-rw-r--r--tests/fff_print/test_model.cpp4
-rw-r--r--tests/libnest2d/libnest2d_tests_main.cpp136
-rw-r--r--tests/libslic3r/CMakeLists.txt1
-rw-r--r--tests/libslic3r/test_marchingsquares.cpp371
-rw-r--r--tests/sla_print/sla_print_tests.cpp40
-rw-r--r--tests/sla_print/sla_test_utils.cpp39
-rw-r--r--tests/sla_print/sla_test_utils.hpp13
8 files changed, 544 insertions, 64 deletions
diff --git a/tests/fff_print/test_data.cpp b/tests/fff_print/test_data.cpp
index 4ee43e2b1..09ca730ec 100644
--- a/tests/fff_print/test_data.cpp
+++ b/tests/fff_print/test_data.cpp
@@ -12,6 +12,7 @@
#include <boost/nowide/cstdio.hpp>
#include <boost/filesystem.hpp>
+#include <libslic3r/ModelArrange.hpp>
using namespace std;
@@ -167,8 +168,7 @@ void init_print(std::vector<TriangleMesh> &&meshes, Slic3r::Print &print, Slic3r
object->add_volume(std::move(t));
object->add_instance();
}
- model.arrange_objects(PrintConfig::min_object_distance(&config));
- model.center_instances_around_point(Slic3r::Vec2d(100, 100));
+ arrange_objects(model, InfiniteBed{}, ArrangeParams{ scaled(min_object_distance(config))});
for (ModelObject *mo : model.objects) {
mo->ensure_on_bed();
print.auto_assign_extruders(mo);
diff --git a/tests/fff_print/test_model.cpp b/tests/fff_print/test_model.cpp
index 3d3b54ef0..45a080f31 100644
--- a/tests/fff_print/test_model.cpp
+++ b/tests/fff_print/test_model.cpp
@@ -2,6 +2,7 @@
#include "libslic3r/libslic3r.h"
#include "libslic3r/Model.hpp"
+#include "libslic3r/ModelArrange.hpp"
#include <boost/nowide/cstdio.hpp>
#include <boost/filesystem.hpp>
@@ -41,8 +42,7 @@ SCENARIO("Model construction", "[Model]") {
}
}
model_object->add_instance();
- model.arrange_objects(PrintConfig::min_object_distance(&config));
- model.center_instances_around_point(Slic3r::Vec2d(100, 100));
+ arrange_objects(model, InfiniteBed{scaled(Vec2d(100, 100))}, ArrangeParams{scaled(min_object_distance(config))});
model_object->ensure_on_bed();
print.auto_assign_extruders(model_object);
THEN("Print works?") {
diff --git a/tests/libnest2d/libnest2d_tests_main.cpp b/tests/libnest2d/libnest2d_tests_main.cpp
index c7259ae53..e0692f4e7 100644
--- a/tests/libnest2d/libnest2d_tests_main.cpp
+++ b/tests/libnest2d/libnest2d_tests_main.cpp
@@ -472,32 +472,30 @@ TEST_CASE("ArrangeRectanglesLoose", "[Nesting]")
namespace {
using namespace libnest2d;
-template<long long SCALE = 1, class Bin>
-void exportSVG(std::vector<std::reference_wrapper<Item>>& result, const Bin& bin, int idx = 0) {
- std::string loc = "out";
+template<long long SCALE = 1, class It>
+void exportSVG(const char *loc, It from, It to) {
- static std::string svg_header =
- R"raw(<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+ static const char* svg_header =
+R"raw(<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg height="500" width="500" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
)raw";
- int i = idx;
- auto r = result;
// for(auto r : result) {
- std::fstream out(loc + std::to_string(i) + ".svg", std::fstream::out);
+ std::fstream out(loc, std::fstream::out);
if(out.is_open()) {
out << svg_header;
- Item rbin( RectangleItem(bin.width(), bin.height()) );
- for(unsigned j = 0; j < rbin.vertexCount(); j++) {
- auto v = rbin.vertex(j);
- setY(v, -getY(v)/SCALE + 500 );
- setX(v, getX(v)/SCALE);
- rbin.setVertex(j, v);
- }
- out << shapelike::serialize<Formats::SVG>(rbin.rawShape()) << std::endl;
- for(Item& sh : r) {
- Item tsh(sh.transformedShape());
+// Item rbin( RectangleItem(bin.width(), bin.height()) );
+// for(unsigned j = 0; j < rbin.vertexCount(); j++) {
+// auto v = rbin.vertex(j);
+// setY(v, -getY(v)/SCALE + 500 );
+// setX(v, getX(v)/SCALE);
+// rbin.setVertex(j, v);
+// }
+// out << shapelike::serialize<Formats::SVG>(rbin.rawShape()) << std::endl;
+ for(auto it = from; it != to; ++it) {
+ const Item &itm = *it;
+ Item tsh(itm.transformedShape());
for(unsigned j = 0; j < tsh.vertexCount(); j++) {
auto v = tsh.vertex(j);
setY(v, -getY(v)/SCALE + 500);
@@ -509,10 +507,16 @@ void exportSVG(std::vector<std::reference_wrapper<Item>>& result, const Bin& bin
out << "\n</svg>" << std::endl;
}
out.close();
-
+
// i++;
// }
}
+
+template<long long SCALE = 1>
+void exportSVG(std::vector<std::reference_wrapper<Item>>& result, int idx = 0) {
+ exportSVG((std::string("out") + std::to_string(idx) + ".svg").c_str(),
+ result.begin(), result.end());
+}
}
TEST_CASE("BottomLeftStressTest", "[Geometry]") {
@@ -541,7 +545,7 @@ TEST_CASE("BottomLeftStressTest", "[Geometry]") {
valid = (valid && !r1.isInside(r2) && !r2.isInside(r1));
if(!valid) {
std::cout << "error index: " << i << std::endl;
- exportSVG(result, bin, i);
+ exportSVG<SCALE>(result, i);
}
REQUIRE(valid);
} else {
@@ -894,7 +898,7 @@ void testNfp(const std::vector<ItemPair>& testdata) {
int TEST_CASEcase = 0;
- auto& exportfun = exportSVG<SCALE, Box>;
+ auto& exportfun = exportSVG<SCALE>;
auto onetest = [&](Item& orbiter, Item& stationary, unsigned /*testidx*/){
TEST_CASEcase++;
@@ -941,7 +945,7 @@ void testNfp(const std::vector<ItemPair>& testdata) {
std::ref(stationary), std::ref(tmp), std::ref(infp)
};
- exportfun(inp, bin, TEST_CASEcase*i++);
+ exportfun(inp, TEST_CASEcase*i++);
}
REQUIRE(touching);
@@ -1096,3 +1100,91 @@ TEST_CASE("MinAreaBBWithRotatingCalipers", "[Geometry]") {
REQUIRE(succ);
}
}
+
+template<class It> MultiPolygon merged_pile(It from, It to, int bin_id)
+{
+ MultiPolygon pile;
+ pile.reserve(size_t(to - from));
+
+ for (auto it = from; it != to; ++it) {
+ if (it->binId() == bin_id) pile.emplace_back(it->transformedShape());
+ }
+
+ return nfp::merge(pile);
+}
+
+TEST_CASE("Test for bed center distance optimization", "[Nesting], [NestKernels]")
+{
+ static const constexpr ClipperLib::cInt W = 10000000;
+
+ // Get the input items and define the bin.
+ std::vector<RectangleItem> input(9, {W, W});
+
+ auto bin = Box::infinite();
+
+ NfpPlacer::Config pconfig;
+
+ pconfig.object_function = [](const Item &item) -> double {
+ return pl::magnsq<PointImpl, double>(item.boundingBox().center());
+ };
+
+ size_t bins = nest(input, bin, 0, NestConfig{pconfig});
+
+ REQUIRE(bins == 1);
+
+ // Gather the items into piles of arranged polygons...
+ MultiPolygon pile;
+ pile.reserve(input.size());
+
+ for (auto &itm : input) {
+ REQUIRE(itm.binId() == 0);
+ pile.emplace_back(itm.transformedShape());
+ }
+
+ MultiPolygon m = merged_pile(input.begin(), input.end(), 0);
+
+ REQUIRE(m.size() == 1);
+
+ REQUIRE(sl::area(m) == Approx(9. * W * W));
+}
+
+TEST_CASE("Test for biggest bounding box area", "[Nesting], [NestKernels]")
+{
+ static const constexpr ClipperLib::cInt W = 10000000;
+ static const constexpr size_t N = 100;
+
+ // Get the input items and define the bin.
+ std::vector<RectangleItem> input(N, {W, W});
+
+ auto bin = Box::infinite();
+
+ NfpPlacer::Config pconfig;
+ pconfig.rotations = {0.};
+ Box pile_box;
+ pconfig.before_packing =
+ [&pile_box](const MultiPolygon &pile,
+ const _ItemGroup<PolygonImpl> &/*packed_items*/,
+ const _ItemGroup<PolygonImpl> &/*remaining_items*/) {
+ pile_box = sl::boundingBox(pile);
+ };
+
+ pconfig.object_function = [&pile_box](const Item &item) -> double {
+ Box b = sl::boundingBox(item.boundingBox(), pile_box);
+ double area = b.area<double>() / (W * W);
+ return -area;
+ };
+
+ size_t bins = nest(input, bin, 0, NestConfig{pconfig});
+
+ // To debug:
+ exportSVG<1000000>("out", input.begin(), input.end());
+
+ REQUIRE(bins == 1);
+
+ MultiPolygon pile = merged_pile(input.begin(), input.end(), 0);
+ Box bb = sl::boundingBox(pile);
+
+ // Here the result shall be a stairway of boxes
+ REQUIRE(pile.size() == N);
+ REQUIRE(bb.area() == N * N * W * W);
+}
diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt
index 2353414f9..b41dbf8ba 100644
--- a/tests/libslic3r/CMakeLists.txt
+++ b/tests/libslic3r/CMakeLists.txt
@@ -13,6 +13,7 @@ add_executable(${_TEST_NAME}_tests
test_stl.cpp
test_meshsimplify.cpp
test_meshboolean.cpp
+ test_marchingsquares.cpp
test_timeutils.cpp
)
diff --git a/tests/libslic3r/test_marchingsquares.cpp b/tests/libslic3r/test_marchingsquares.cpp
new file mode 100644
index 000000000..9912ff2ca
--- /dev/null
+++ b/tests/libslic3r/test_marchingsquares.cpp
@@ -0,0 +1,371 @@
+#define NOMINMAX
+
+#include <catch2/catch.hpp>
+#include <test_utils.hpp>
+
+#include <fstream>
+
+#include <libslic3r/MarchingSquares.hpp>
+#include <libslic3r/SLA/RasterToPolygons.hpp>
+
+#include <libslic3r/SLA/AGGRaster.hpp>
+#include <libslic3r/MTUtils.hpp>
+#include <libslic3r/SVG.hpp>
+#include <libslic3r/ClipperUtils.hpp>
+
+#include <libslic3r/TriangulateWall.hpp>
+#include <libslic3r/Tesselate.hpp>
+#include <libslic3r/SlicesToTriangleMesh.hpp>
+#include <libslic3r/SLA/Contour3D.hpp>
+
+using namespace Slic3r;
+
+static double area(const sla::RasterBase::PixelDim &pxd)
+{
+ return pxd.w_mm * pxd.h_mm;
+}
+
+static Slic3r::sla::RasterGrayscaleAA create_raster(
+ const sla::RasterBase::Resolution &res,
+ double disp_w = 100.,
+ double disp_h = 100.)
+{
+ sla::RasterBase::PixelDim pixdim{disp_w / res.width_px, disp_h / res.height_px};
+
+ auto bb = BoundingBox({0, 0}, {scaled(disp_w), scaled(disp_h)});
+ sla::RasterBase::Trafo trafo;
+ trafo.center_x = bb.center().x();
+ trafo.center_y = bb.center().y();
+
+ return sla::RasterGrayscaleAA{res, pixdim, trafo, agg::gamma_threshold(.5)};
+}
+
+static ExPolygon square(double a, Point center = {0, 0})
+{
+ ExPolygon poly;
+ coord_t V = scaled(a / 2.);
+
+ poly.contour.points = {{-V, -V}, {V, -V}, {V, V}, {-V, V}};
+ poly.translate(center.x(), center.y());
+
+ return poly;
+}
+
+static ExPolygon square_with_hole(double a, Point center = {0, 0})
+{
+ ExPolygon poly = square(a);
+
+ poly.holes.emplace_back();
+ coord_t V = scaled(a / 4.);
+ poly.holes.front().points = {{-V, V}, {V, V}, {V, -V}, {-V, -V}};
+
+ poly.translate(center.x(), center.y());
+
+ return poly;
+}
+
+static ExPolygons circle_with_hole(double r, Point center = {0, 0}) {
+
+ ExPolygon poly;
+
+ std::vector<double> pis = linspace_vector(0., 2 * PI, 100);
+
+ coord_t rs = scaled(r);
+ for (double phi : pis) {
+ poly.contour.points.emplace_back(rs * std::cos(phi), rs * std::sin(phi));
+ }
+
+ poly.holes.emplace_back(poly.contour);
+ poly.holes.front().reverse();
+ for (auto &p : poly.holes.front().points) p /= 2;
+
+ poly.translate(center.x(), center.y());
+
+ return {poly};
+}
+
+static const Vec2i W4x4 = {4, 4};
+static const Vec2i W2x2 = {2, 2};
+
+template<class Rst>
+static void test_expolys(Rst && rst,
+ const ExPolygons & ref,
+ Vec2i window,
+ const std::string &name = "test")
+{
+ for (const ExPolygon &expoly : ref) rst.draw(expoly);
+
+ std::fstream out(name + ".png", std::ios::out);
+ out << rst.encode(sla::PNGRasterEncoder{});
+ out.close();
+
+ ExPolygons extracted = sla::raster_to_polygons(rst, window);
+
+ SVG svg(name + ".svg");
+ svg.draw(extracted);
+ svg.draw(ref, "green");
+ svg.Close();
+
+ double max_rel_err = 0.1;
+ sla::RasterBase::PixelDim pxd = rst.pixel_dimensions();
+ double max_abs_err = area(pxd) * scaled(1.) * scaled(1.);
+
+ BoundingBox ref_bb;
+ for (auto &expoly : ref) ref_bb.merge(expoly.contour.bounding_box());
+
+ double max_displacement = 4. * (std::pow(pxd.h_mm, 2) + std::pow(pxd.w_mm, 2));
+ max_displacement *= scaled<double>(1.) * scaled(1.);
+
+ REQUIRE(extracted.size() == ref.size());
+ for (size_t i = 0; i < ref.size(); ++i) {
+ REQUIRE(extracted[i].contour.is_counter_clockwise());
+ REQUIRE(extracted[i].holes.size() == ref[i].holes.size());
+
+ for (auto &h : extracted[i].holes) REQUIRE(h.is_clockwise());
+
+ double refa = ref[i].area();
+ double abs_err = std::abs(extracted[i].area() - refa);
+ double rel_err = abs_err / refa;
+
+ REQUIRE((rel_err <= max_rel_err || abs_err <= max_abs_err));
+
+ BoundingBox bb;
+ for (auto &expoly : extracted) bb.merge(expoly.contour.bounding_box());
+
+ Point d = bb.center() - ref_bb.center();
+ REQUIRE(double(d.transpose() * d) <= max_displacement);
+ }
+}
+
+TEST_CASE("Empty raster should result in empty polygons", "[MarchingSquares]") {
+ sla::RasterGrayscaleAAGammaPower rst{{}, {}, {}};
+ ExPolygons extracted = sla::raster_to_polygons(rst);
+ REQUIRE(extracted.size() == 0);
+}
+
+TEST_CASE("Marching squares directions", "[MarchingSquares]") {
+ marchsq::Coord crd{1, 1};
+
+ REQUIRE(step(crd, marchsq::__impl::Dir::left).r == 1);
+ REQUIRE(step(crd, marchsq::__impl::Dir::left).c == 0);
+
+ REQUIRE(step(crd, marchsq::__impl::Dir::down).r == 2);
+ REQUIRE(step(crd, marchsq::__impl::Dir::down).c == 1);
+
+ REQUIRE(step(crd, marchsq::__impl::Dir::right).r == 1);
+ REQUIRE(step(crd, marchsq::__impl::Dir::right).c == 2);
+
+ REQUIRE(step(crd, marchsq::__impl::Dir::up).r == 0);
+ REQUIRE(step(crd, marchsq::__impl::Dir::up).c == 1);
+}
+
+TEST_CASE("Fully covered raster should result in a rectangle", "[MarchingSquares]") {
+ auto rst = create_raster({4, 4}, 4., 4.);
+
+ ExPolygon rect = square(4);
+
+ SECTION("Full accuracy") {
+ test_expolys(rst, {rect}, W2x2, "fully_covered_full_acc");
+ }
+
+ SECTION("Half accuracy") {
+ test_expolys(rst, {rect}, W4x4, "fully_covered_half_acc");
+ }
+}
+
+TEST_CASE("4x4 raster with one ring", "[MarchingSquares]") {
+
+ sla::RasterBase::PixelDim pixdim{1, 1};
+
+ // We need one additional row and column to detect edges
+ sla::RasterGrayscaleAA rst{{4, 4}, pixdim, {}, agg::gamma_threshold(.5)};
+
+ // Draw a triangle from individual pixels
+ rst.draw(square(1., {0500000, 0500000}));
+ rst.draw(square(1., {1500000, 0500000}));
+ rst.draw(square(1., {2500000, 0500000}));
+
+ rst.draw(square(1., {1500000, 1500000}));
+ rst.draw(square(1., {2500000, 1500000}));
+
+ rst.draw(square(1., {2500000, 2500000}));
+
+ std::fstream out("4x4.png", std::ios::out);
+ out << rst.encode(sla::PNGRasterEncoder{});
+ out.close();
+
+ ExPolygons extracted = sla::raster_to_polygons(rst);
+
+ SVG svg("4x4.svg");
+ svg.draw(extracted);
+ svg.Close();
+
+ REQUIRE(extracted.size() == 1);
+}
+
+TEST_CASE("4x4 raster with two rings", "[MarchingSquares]") {
+
+ sla::RasterBase::PixelDim pixdim{1, 1};
+
+ // We need one additional row and column to detect edges
+ sla::RasterGrayscaleAA rst{{5, 5}, pixdim, {}, agg::gamma_threshold(.5)};
+
+ SECTION("Ambiguous case with 'ac' square") {
+
+ // Draw a triangle from individual pixels
+ rst.draw(square(1., {3500000, 2500000}));
+ rst.draw(square(1., {3500000, 3500000}));
+ rst.draw(square(1., {2500000, 3500000}));
+
+ rst.draw(square(1., {2500000, 1500000}));
+ rst.draw(square(1., {1500000, 1500000}));
+ rst.draw(square(1., {1500000, 2500000}));
+
+ std::fstream out("4x4_ac.png", std::ios::out);
+ out << rst.encode(sla::PNGRasterEncoder{});
+ out.close();
+
+ ExPolygons extracted = sla::raster_to_polygons(rst);
+
+ SVG svg("4x4_ac.svg");
+ svg.draw(extracted);
+ svg.Close();
+
+ REQUIRE(extracted.size() == 2);
+ }
+
+ SECTION("Ambiguous case with 'bd' square") {
+
+ // Draw a triangle from individual pixels
+ rst.draw(square(1., {3500000, 1500000}));
+ rst.draw(square(1., {3500000, 2500000}));
+ rst.draw(square(1., {2500000, 1500000}));
+
+ rst.draw(square(1., {1500000, 2500000}));
+ rst.draw(square(1., {1500000, 3500000}));
+ rst.draw(square(1., {2500000, 3500000}));
+
+ std::fstream out("4x4_bd.png", std::ios::out);
+ out << rst.encode(sla::PNGRasterEncoder{});
+ out.close();
+
+ ExPolygons extracted = sla::raster_to_polygons(rst);
+
+ SVG svg("4x4_bd.svg");
+ svg.draw(extracted);
+ svg.Close();
+
+ REQUIRE(extracted.size() == 2);
+ }
+}
+
+TEST_CASE("Square with hole in the middle", "[MarchingSquares]") {
+ using namespace Slic3r;
+
+ ExPolygons inp = {square_with_hole(50.)};
+
+ SECTION("Proportional raster, 1x1 mm pixel size, full accuracy") {
+ test_expolys(create_raster({100, 100}, 100., 100.), inp, W2x2, "square_with_hole_proportional_1x1_mm_px_full");
+ }
+
+ SECTION("Proportional raster, 1x1 mm pixel size, half accuracy") {
+ test_expolys(create_raster({100, 100}, 100., 100.), inp, W4x4, "square_with_hole_proportional_1x1_mm_px_half");
+ }
+
+ SECTION("Landscape raster, 1x1 mm pixel size, full accuracy") {
+ test_expolys(create_raster({150, 100}, 150., 100.), inp, W2x2, "square_with_hole_landsc_1x1_mm_px_full");
+ }
+
+ SECTION("Landscape raster, 1x1 mm pixel size, half accuracy") {
+ test_expolys(create_raster({150, 100}, 150., 100.), inp, W4x4, "square_with_hole_landsc_1x1_mm_px_half");
+ }
+
+ SECTION("Portrait raster, 1x1 mm pixel size, full accuracy") {
+ test_expolys(create_raster({100, 150}, 100., 150.), inp, W2x2, "square_with_hole_portrait_1x1_mm_px_full");
+ }
+
+ SECTION("Portrait raster, 1x1 mm pixel size, half accuracy") {
+ test_expolys(create_raster({100, 150}, 100., 150.), inp, W4x4, "square_with_hole_portrait_1x1_mm_px_half");
+ }
+
+ SECTION("Proportional raster, 2x2 mm pixel size, full accuracy") {
+ test_expolys(create_raster({200, 200}, 100., 100.), inp, W2x2, "square_with_hole_proportional_2x2_mm_px_full");
+ }
+
+ SECTION("Proportional raster, 2x2 mm pixel size, half accuracy") {
+ test_expolys(create_raster({200, 200}, 100., 100.), inp, W4x4, "square_with_hole_proportional_2x2_mm_px_half");
+ }
+
+ SECTION("Proportional raster, 0.5x0.5 mm pixel size, full accuracy") {
+ test_expolys(create_raster({50, 50}, 100., 100.), inp, W2x2, "square_with_hole_proportional_0.5x0.5_mm_px_full");
+ }
+
+ SECTION("Proportional raster, 0.5x0.5 mm pixel size, half accuracy") {
+ test_expolys(create_raster({50, 50}, 100., 100.), inp, W4x4, "square_with_hole_proportional_0.5x0.5_mm_px_half");
+ }
+}
+
+TEST_CASE("Circle with hole in the middle", "[MarchingSquares]") {
+ using namespace Slic3r;
+
+ test_expolys(create_raster({1000, 1000}), circle_with_hole(25.), W2x2, "circle_with_hole");
+}
+
+static void recreate_object_from_rasters(const std::string &objname, float lh) {
+ TriangleMesh mesh = load_model(objname);
+
+ auto bb = mesh.bounding_box();
+ Vec3f tr = -bb.center().cast<float>();
+ mesh.translate(tr.x(), tr.y(), tr.z());
+ bb = mesh.bounding_box();
+
+ std::vector<ExPolygons> layers;
+ slice_mesh(mesh, grid(float(bb.min.z()) + lh, float(bb.max.z()), lh), layers, 0.f, []{});
+
+ sla::RasterBase::Resolution res{2560, 1440};
+ double disp_w = 120.96;
+ double disp_h = 68.04;
+
+ size_t cntr = 0;
+ for (ExPolygons &layer : layers) {
+ auto rst = create_raster(res, disp_w, disp_h);
+
+ for (ExPolygon &island : layer) {
+ rst.draw(island);
+ }
+
+ std::fstream out(objname + std::to_string(cntr) + ".png", std::ios::out);
+ out << rst.encode(sla::PNGRasterEncoder{});
+ out.close();
+
+ ExPolygons layer_ = sla::raster_to_polygons(rst);
+// float delta = scaled(std::min(rst.pixel_dimensions().h_mm,
+// rst.pixel_dimensions().w_mm)) / 2;
+
+// layer_ = expolygons_simplify(layer_, delta);
+
+ SVG svg(objname + std::to_string(cntr) + ".svg", BoundingBox(Point{0, 0}, Point{scaled(disp_w), scaled(disp_h)}));
+ svg.draw(layer_);
+ svg.draw(layer, "green");
+ svg.Close();
+
+ double layera = 0., layera_ = 0.;
+ for (auto &p : layer) layera += p.area();
+ for (auto &p : layer_) layera_ += p.area();
+
+ std::cout << cntr++ << std::endl;
+ double diff = std::abs(layera_ - layera);
+ REQUIRE((diff <= 0.1 * layera || diff < scaled<double>(1.) * scaled<double>(1.)));
+
+ layer = std::move(layer_);
+ }
+
+ TriangleMesh out = slices_to_triangle_mesh(layers, bb.min.z(), double(lh), double(lh));
+
+ out.require_shared_vertices();
+ out.WriteOBJFile("out_from_rasters.obj");
+}
+
+TEST_CASE("Recreate object from rasters", "[SL1Import]") {
+ recreate_object_from_rasters("frog_legs.obj", 0.05f);
+}
diff --git a/tests/sla_print/sla_print_tests.cpp b/tests/sla_print/sla_print_tests.cpp
index 10f5742d3..82df2c1a6 100644
--- a/tests/sla_print/sla_print_tests.cpp
+++ b/tests/sla_print/sla_print_tests.cpp
@@ -154,19 +154,12 @@ TEST_CASE("FloorSupportsDoNotPierceModel", "[SLASupportGeneration]") {
test_support_model_collision(fname, supportcfg);
}
-TEST_CASE("DefaultRasterShouldBeEmpty", "[SLARasterOutput]") {
- sla::Raster raster;
- REQUIRE(raster.empty());
-}
-
TEST_CASE("InitializedRasterShouldBeNONEmpty", "[SLARasterOutput]") {
// Default Prusa SL1 display parameters
- sla::Raster::Resolution res{2560, 1440};
- sla::Raster::PixelDim pixdim{120. / res.width_px, 68. / res.height_px};
+ sla::RasterBase::Resolution res{2560, 1440};
+ sla::RasterBase::PixelDim pixdim{120. / res.width_px, 68. / res.height_px};
- sla::Raster raster;
- raster.reset(res, pixdim);
- REQUIRE_FALSE(raster.empty());
+ 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));
@@ -174,13 +167,14 @@ TEST_CASE("InitializedRasterShouldBeNONEmpty", "[SLARasterOutput]") {
}
TEST_CASE("MirroringShouldBeCorrect", "[SLARasterOutput]") {
- sla::Raster::TMirroring mirrorings[] = {sla::Raster::NoMirror,
- sla::Raster::MirrorX,
- sla::Raster::MirrorY,
- sla::Raster::MirrorXY};
+ 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};
- sla::Raster::Orientation orientations[] = {sla::Raster::roLandscape,
- sla::Raster::roPortrait};
for (auto orientation : orientations)
for (auto &mirror : mirrorings)
check_raster_transformations(orientation, mirror);
@@ -189,10 +183,11 @@ TEST_CASE("MirroringShouldBeCorrect", "[SLARasterOutput]") {
TEST_CASE("RasterizedPolygonAreaShouldMatch", "[SLARasterOutput]") {
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};
+ sla::RasterBase::Resolution res{2560, 1440};
+ sla::RasterBase::PixelDim pixdim{disp_w / res.width_px, disp_h / res.height_px};
- sla::Raster raster{res, pixdim};
+ 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.);
@@ -215,6 +210,13 @@ TEST_CASE("RasterizedPolygonAreaShouldMatch", "[SLARasterOutput]") {
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]")
diff --git a/tests/sla_print/sla_test_utils.cpp b/tests/sla_print/sla_test_utils.cpp
index a844b2eae..883e4268a 100644
--- a/tests/sla_print/sla_test_utils.cpp
+++ b/tests/sla_print/sla_test_utils.cpp
@@ -1,4 +1,5 @@
#include "sla_test_utils.hpp"
+#include "libslic3r/SLA/AGGRaster.hpp"
void test_support_model_collision(const std::string &obj_filename,
const sla::SupportConfig &input_supportcfg,
@@ -293,18 +294,19 @@ void check_validity(const TriangleMesh &input_mesh, int flags)
}
}
-void check_raster_transformations(sla::Raster::Orientation o, sla::Raster::TMirroring mirroring)
+void check_raster_transformations(sla::RasterBase::Orientation o, sla::RasterBase::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};
+ sla::RasterBase::Resolution res{2560, 1440};
+ sla::RasterBase::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::RasterBase::Trafo trafo{o, mirroring};
+ trafo.center_x = bb.center().x();
+ trafo.center_y = bb.center().y();
+ double gamma = 1.;
- sla::Raster raster{res, pixdim, trafo};
+ sla::RasterGrayscaleAAGammaPower raster{res, pixdim, trafo, gamma};
// create box of size 32x32 pixels (not 1x1 to avoid antialiasing errors)
coord_t pw = 32 * coord_t(std::ceil(scaled<double>(pixdim.w_mm)));
@@ -319,7 +321,7 @@ void check_raster_transformations(sla::Raster::Orientation o, sla::Raster::TMirr
// Now calculate the position of the translated box according to output
// trafo.
- if (o == sla::Raster::Orientation::roPortrait) expected_box.rotate(PI / 2.);
+ if (o == sla::RasterBase::Orientation::roPortrait) expected_box.rotate(PI / 2.);
if (mirroring[X])
for (auto &p : expected_box.contour.points) p.x() = -p.x();
@@ -340,10 +342,9 @@ void check_raster_transformations(sla::Raster::Orientation o, sla::Raster::TMirr
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);
+ outf << raster.encode(sla::PNGRasterEncoder());
}
REQUIRE(px == FullWhite);
@@ -361,9 +362,21 @@ ExPolygon square_with_hole(double v)
return poly;
}
-double raster_white_area(const sla::Raster &raster)
+long raster_pxsum(const sla::RasterGrayscaleAA &raster)
{
- if (raster.empty()) return std::nan("");
+ auto res = raster.resolution();
+ long a = 0;
+
+ for (size_t x = 0; x < res.width_px; ++x)
+ for (size_t y = 0; y < res.height_px; ++y)
+ a += raster.read_pixel(x, y);
+
+ return a;
+}
+
+double raster_white_area(const sla::RasterGrayscaleAA &raster)
+{
+ if (raster.resolution().pixels() == 0) return std::nan("");
auto res = raster.resolution();
double a = 0;
@@ -377,7 +390,7 @@ double raster_white_area(const sla::Raster &raster)
return a;
}
-double predict_error(const ExPolygon &p, const sla::Raster::PixelDim &pd)
+double predict_error(const ExPolygon &p, const sla::RasterBase::PixelDim &pd)
{
auto lines = p.lines();
double pix_err = pixel_area(FullWhite, pd) / 2.;
diff --git a/tests/sla_print/sla_test_utils.hpp b/tests/sla_print/sla_test_utils.hpp
index f3727bd39..3652b1f81 100644
--- a/tests/sla_print/sla_test_utils.hpp
+++ b/tests/sla_print/sla_test_utils.hpp
@@ -16,7 +16,7 @@
#include "libslic3r/SLA/SupportTreeBuilder.hpp"
#include "libslic3r/SLA/SupportTreeBuildsteps.hpp"
#include "libslic3r/SLA/SupportPointGenerator.hpp"
-#include "libslic3r/SLA/Raster.hpp"
+#include "libslic3r/SLA/AGGRaster.hpp"
#include "libslic3r/SLA/ConcaveHull.hpp"
#include "libslic3r/MTUtils.hpp"
@@ -170,18 +170,19 @@ static constexpr const TPixel FullBlack = 0;
template <class A, int N> constexpr int arraysize(const A (&)[N]) { return N; }
-void check_raster_transformations(sla::Raster::Orientation o,
- sla::Raster::TMirroring mirroring);
+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::Raster::PixelDim &pxdim)
+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::Raster &raster);
+double raster_white_area(const sla::RasterGrayscaleAA &raster);
+long raster_pxsum(const sla::RasterGrayscaleAA &raster);
-double predict_error(const ExPolygon &p, const sla::Raster::PixelDim &pd);
+double predict_error(const ExPolygon &p, const sla::RasterBase::PixelDim &pd);
#endif // SLA_TEST_UTILS_HPP