PrusaSlicer/tests/sla_print/sla_supptgen_tests.cpp
Filip Sykala - NTB T15p c41d4997e5 SPE-2714 fixed
bad merging of island parts(UniformSupportIsland.cpp:1853-56) + multi insertation of same change for part(UniformSupportIsland.cpp:2167-191)
+ add test case
+ add gui to set current head diameter and density to configurable GUI
+ add visualization of Parts
+ add check for uniqness of change in part
2025-03-20 15:21:00 +01:00

659 lines
25 KiB
C++

#include <catch2/catch_test_macros.hpp>
#include <test_utils.hpp>
#include <libslic3r/ExPolygon.hpp>
#include <libslic3r/BoundingBox.hpp>
#include <libslic3r/SLA/SpatIndex.hpp>
#include <libslic3r/ClipperUtils.hpp>
#include <libslic3r/TriangleMeshSlicer.hpp>
#include <libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp>
#include <libslic3r/SLA/SupportIslands/SampleConfig.hpp>
#include <libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp>
#include <libslic3r/SLA/SupportIslands/UniformSupportIsland.hpp>
#include <libslic3r/SLA/SupportIslands/PolygonUtils.hpp>
#include "nanosvg/nanosvg.h" // load SVG file
#include "sla_test_utils.hpp"
using namespace Slic3r;
using namespace Slic3r::sla;
//#define STORE_SAMPLE_INTO_SVG_FILES "C:/data/temp/test_islands/sample_"
//#define STORE_ISLAND_ISSUES "C:/data/temp/issues/"
TEST_CASE("Overhanging point should be supported", "[SupGen]") {
// Pyramid with 45 deg slope
TriangleMesh mesh = make_pyramid(10.f, 10.f);
mesh.rotate_y(float(PI));
//mesh.WriteOBJFile("Pyramid.obj");
sla::SupportPoints pts = calc_support_pts(mesh);
// The overhang, which is the upside-down pyramid's edge
Vec3f overh{0., 0., -10.};
REQUIRE(!pts.empty());
float dist = (overh - pts.front().pos).norm();
for (const auto &pt : pts)
dist = std::min(dist, (overh - pt.pos).norm());
// Should require exactly one support point at the overhang
REQUIRE(pts.size() > 0);
REQUIRE(dist < 1.f);
}
double min_point_distance(const sla::SupportPoints &pts)
{
sla::PointIndex index;
for (size_t i = 0; i < pts.size(); ++i)
index.insert(pts[i].pos.cast<double>(), i);
auto d = std::numeric_limits<double>::max();
index.foreach([&d, &index](const sla::PointIndexEl &el) {
auto res = index.nearest(el.first, 2);
for (const sla::PointIndexEl &r : res)
if (r.second != el.second)
d = std::min(d, (el.first - r.first).norm());
});
return d;
}
TEST_CASE("Overhanging horizontal surface should be supported", "[SupGen]") {
double width = 10., depth = 10., height = 1.;
TriangleMesh mesh = make_cube(width, depth, height);
mesh.translate(0., 0., 5.); // lift up
// mesh.WriteOBJFile("Cuboid.obj");
sla::SupportPoints pts = calc_support_pts(mesh);
REQUIRE(!pts.empty());
}
template<class M> auto&& center_around_bb(M &&mesh)
{
auto bb = mesh.bounding_box();
mesh.translate(-bb.center().template cast<float>());
return std::forward<M>(mesh);
}
TEST_CASE("Overhanging edge should be supported", "[SupGen]") {
float width = 10.f, depth = 10.f, height = 5.f;
TriangleMesh mesh = make_prism(width, depth, height);
mesh.rotate_y(float(PI)); // rotate on its back
mesh.translate(0., 0., height);
mesh.WriteOBJFile("Prism.obj");
sla::SupportPoints pts = calc_support_pts(mesh);
Linef3 overh{ {0.f, -depth / 2.f, 0.f}, {0.f, depth / 2.f, 0.f}};
// Get all the points closer that 1 mm to the overhanging edge:
sla::SupportPoints overh_pts; overh_pts.reserve(pts.size());
std::copy_if(pts.begin(), pts.end(), std::back_inserter(overh_pts),
[&overh](const sla::SupportPoint &pt){
return line_alg::distance_to(overh, Vec3d{pt.pos.cast<double>()}) < 1.;
});
//double ddiff = min_point_distance(pts) - cfg.minimal_distance;
//REQUIRE(ddiff > - 0.1 * cfg.minimal_distance);
}
TEST_CASE("Hollowed cube should be supported from the inside", "[SupGen][Hollowed]") {
TriangleMesh mesh = make_cube(20., 20., 20.);
hollow_mesh(mesh, HollowingConfig{});
mesh.WriteOBJFile("cube_hollowed.obj");
auto bb = mesh.bounding_box();
auto h = float(bb.max.z() - bb.min.z());
Vec3f mv = bb.center().cast<float>() - Vec3f{0.f, 0.f, 0.5f * h};
mesh.translate(-mv);
sla::SupportPoints pts = calc_support_pts(mesh);
//sla::remove_bottom_points(pts, mesh.bounding_box().min.z() + EPSILON);
REQUIRE(!pts.empty());
}
TEST_CASE("Two parallel plates should be supported", "[SupGen][Hollowed]")
{
double width = 20., depth = 20., height = 1.;
TriangleMesh mesh = center_around_bb(make_cube(width + 5., depth + 5., height));
TriangleMesh mesh_high = center_around_bb(make_cube(width, depth, height));
mesh_high.translate(0., 0., 10.); // lift up
mesh.merge(mesh_high);
mesh.WriteOBJFile("parallel_plates.obj");
sla::SupportPoints pts = calc_support_pts(mesh);
//sla::remove_bottom_points(pts, mesh.bounding_box().min.z() + EPSILON);
REQUIRE(!pts.empty());
}
Slic3r::Polygon create_cross_roads(double size, double width)
{
auto r1 = PolygonUtils::create_rect(5.3 * size, width);
r1.rotate(3.14/4);
r1.translate(2 * size, width / 2);
auto r2 = PolygonUtils::create_rect(6.1 * size, 3 / 4. * width);
r2.rotate(-3.14 / 5);
r2.translate(3 * size, width / 2);
auto r3 = PolygonUtils::create_rect(7.9 * size, 4 / 5. * width);
r3.translate(2*size, width/2);
auto r4 = PolygonUtils::create_rect(5 / 6. * width, 5.7 * size);
r4.translate(-size,3*size);
Polygons rr = union_(Polygons({r1, r2, r3, r4}));
return rr.front();
}
ExPolygon create_trinagle_with_hole(double size)
{
auto hole = PolygonUtils::create_equilateral_triangle(size / 3);
hole.reverse();
hole.rotate(3.14 / 4);
return ExPolygon(PolygonUtils::create_equilateral_triangle(size), hole);
}
ExPolygon create_square_with_hole(double size, double hole_size)
{
assert(sqrt(hole_size *hole_size / 2) < size);
auto hole = PolygonUtils::create_square(hole_size);
hole.rotate(M_PI / 4.); // 45
hole.reverse();
return ExPolygon(PolygonUtils::create_square(size), hole);
}
ExPolygon create_square_with_4holes(double size, double hole_size) {
auto hole = PolygonUtils::create_square(hole_size);
hole.reverse();
double size_4 = size / 4;
auto h1 = hole;
h1.translate(size_4, size_4);
auto h2 = hole;
h2.translate(-size_4, size_4);
auto h3 = hole;
h3.translate(size_4, -size_4);
auto h4 = hole;
h4.translate(-size_4, -size_4);
ExPolygon result(PolygonUtils::create_square(size));
result.holes = Polygons({h1, h2, h3, h4});
return result;
}
// boudary of circle
ExPolygon create_disc(double radius, double width, size_t count_line_segments)
{
double width_2 = width / 2;
auto hole = PolygonUtils::create_circle(radius - width_2,
count_line_segments);
hole.reverse();
return ExPolygon(PolygonUtils::create_circle(radius + width_2,
count_line_segments),
hole);
}
Slic3r::Polygon create_V_shape(double height, double line_width, double angle = M_PI/4) {
double angle_2 = angle / 2;
auto left_side = PolygonUtils::create_rect(line_width, height);
auto right_side = left_side;
right_side.rotate(-angle_2);
double small_move = cos(angle_2) * line_width / 2;
double side_move = sin(angle_2) * height / 2 + small_move;
right_side.translate(side_move,0);
left_side.rotate(angle_2);
left_side.translate(-side_move, 0);
auto bottom = PolygonUtils::create_rect(4 * small_move, line_width);
bottom.translate(0., -cos(angle_2) * height / 2 + line_width/2);
Polygons polygons = union_(Polygons({left_side, right_side, bottom}));
return polygons.front();
}
ExPolygon create_tiny_wide_test_1(double wide, double tiny)
{
double hole_size = wide;
double width = 2 * wide + hole_size;
double height = wide + hole_size + tiny;
auto outline = PolygonUtils::create_rect(width, height);
auto hole = PolygonUtils::create_rect(hole_size, hole_size);
hole.reverse();
int hole_move_y = height/2 - (hole_size/2 + tiny);
hole.translate(0, hole_move_y);
ExPolygon result(outline);
result.holes = {hole};
return result;
}
ExPolygon create_tiny_wide_test_2(double wide, double tiny)
{
double hole_size = wide;
double width = (3 + 1) * wide + 3 * hole_size;
double height = 2*wide + 2*tiny + 3*hole_size;
auto outline = PolygonUtils::create_rect( width, height);
auto hole = PolygonUtils::create_rect(hole_size, hole_size);
hole.reverse();
auto hole2 = hole;// copy
auto hole3 = hole; // copy
auto hole4 = hole; // copy
int hole_move_x = wide + hole_size;
int hole_move_y = wide + hole_size;
hole.translate(hole_move_x, hole_move_y);
hole2.translate(-hole_move_x, hole_move_y);
hole3.translate(hole_move_x, -hole_move_y);
hole4.translate(-hole_move_x, -hole_move_y);
auto hole5 = PolygonUtils::create_circle(hole_size / 2, 16);
hole5.reverse();
auto hole6 = hole5; // copy
hole5.translate(0, hole_move_y);
hole6.translate(0, -hole_move_y);
auto hole7 = PolygonUtils::create_equilateral_triangle(hole_size);
hole7.reverse();
auto hole8 = PolygonUtils::create_circle(hole_size/2, 7, Point(hole_move_x,0));
hole8.reverse();
auto hole9 = PolygonUtils::create_circle(hole_size/2, 5, Point(-hole_move_x,0));
hole9.reverse();
ExPolygon result(outline);
result.holes = {hole, hole2, hole3, hole4, hole5, hole6, hole7, hole8, hole9};
return result;
}
ExPolygon create_tiny_between_holes(double wide, double tiny)
{
double hole_size = wide;
double width = 2 * wide + 2*hole_size + tiny;
double height = 2 * wide + hole_size;
auto outline = PolygonUtils::create_rect(width, height);
auto holeL = PolygonUtils::create_rect(hole_size, hole_size);
holeL.reverse();
auto holeR = holeL;
int hole_move_x = (hole_size + tiny)/2;
holeL.translate(-hole_move_x, 0);
holeR.translate(hole_move_x, 0);
ExPolygon result(outline);
result.holes = {holeL, holeR};
return result;
}
// stress test for longest path
// needs reshape
ExPolygon create_mountains(double size) {
return ExPolygon({{0., 0.},
{size, 0.},
{5 * size / 6, size},
{4 * size / 6, size / 6},
{3 * size / 7, 2 * size},
{2 * size / 7, size / 6},
{size / 7, size}});
}
/// Neighbor points create trouble for voronoi - test of neccessary offseting(closing) of contour
ExPolygon create_cylinder_bottom_slice() {
indexed_triangle_set its_cylinder = its_make_cylinder(6.6551999999999998, 11.800000000000001);
MeshSlicingParams param;
Polygons polygons = slice_mesh(its_cylinder, 0.0125000002, param);
return ExPolygon{polygons.front()};
}
ExPolygon load_frog(){
TriangleMesh mesh = load_model("frog_legs.obj");
std::vector<ExPolygons> slices = slice_mesh_ex(mesh.its, {0.1f});
return slices.front()[1];
}
ExPolygon load_svg(const std::string& svg_filepath) {
struct NSVGimage *image = nsvgParseFromFile(svg_filepath.c_str(), "px", 96);
ScopeGuard sg_image([&image] { nsvgDelete(image); });
auto to_polygon = [](NSVGpath *path) {
Polygon r;
r.points.reserve(path->npts);
for (int i = 0; i < path->npts; i++)
r.points.push_back(Point(path->pts[2 * i], path->pts[2 * i + 1]));
return r;
};
for (NSVGshape *shape_ptr = image->shapes; shape_ptr != NULL; shape_ptr = shape_ptr->next) {
const NSVGshape &shape = *shape_ptr;
if (!(shape.flags & NSVG_FLAGS_VISIBLE)) continue; // is visible
if (shape.fill.type != NSVG_PAINT_NONE) continue; // is not used fill
if (shape.stroke.type == NSVG_PAINT_NONE) continue; // exist stroke
//if (shape.strokeWidth < 1e-5f) continue; // is visible stroke width
//if (shape.stroke.color != 4278190261) continue; // is red
ExPolygon result;
for (NSVGpath *path = shape.paths; path != NULL; path = path->next) {
// Path order is reverse to path in file
if (path->next == NULL) // last path is contour
result.contour = to_polygon(path);
else
result.holes.push_back(to_polygon(path));
}
return result;
}
REQUIRE(false);
return {};
}
ExPolygons createTestIslands(double size)
{
std::string dir = std::string(TEST_DATA_DIR PATH_SEPARATOR) + "sla_islands/";
bool useFrogLeg = false;
// need post reorganization of longest path
ExPolygons result = {
// one support point
ExPolygon(PolygonUtils::create_equilateral_triangle(size)),
ExPolygon(PolygonUtils::create_square(size)),
ExPolygon(PolygonUtils::create_rect(size / 2, size)),
ExPolygon(PolygonUtils::create_isosceles_triangle(size / 2, 3 * size / 2)), // small sharp triangle
ExPolygon(PolygonUtils::create_circle(size / 2, 10)),
create_square_with_4holes(size, size / 4),
create_disc(size/4, size / 4, 10),
ExPolygon(create_V_shape(2*size/3, size / 4)),
// two support points
ExPolygon(PolygonUtils::create_isosceles_triangle(size / 2, 3 * size)), // small sharp triangle
ExPolygon(PolygonUtils::create_rect(size / 2, 3 * size)),
ExPolygon(create_V_shape(1.5*size, size/3)),
// tiny line support points
ExPolygon(PolygonUtils::create_rect(size / 2, 10 * size)), // long line
ExPolygon(create_V_shape(size*4, size / 3)),
ExPolygon(create_cross_roads(size, size / 3)),
create_disc(3*size, size / 4, 30),
create_disc(2*size, size, 12), // 3 points
create_square_with_4holes(5 * size, 5 * size / 2 - size / 3),
// Tiny and wide part together with holes
ExPolygon(PolygonUtils::create_isosceles_triangle(5. * size, 40. * size)),
create_tiny_wide_test_1(3 * size, 2 / 3. * size),
create_tiny_wide_test_2(3 * size, 2 / 3. * size),
create_tiny_between_holes(3 * size, 2 / 3. * size),
ExPolygon(PolygonUtils::create_equilateral_triangle(scale_(18.6))),
create_cylinder_bottom_slice(),
load_svg(dir + "lm_issue.svg"), // change from thick to thin and vice versa on circle
load_svg(dir + "SPE-2674.svg"), // center of longest path lay inside of the VD node
load_svg(dir + "SPE-2674_2.svg"), // missing Voronoi vertex even after the rotation of input.
// still problem
// three support points
ExPolygon(PolygonUtils::create_equilateral_triangle(3 * size)),
ExPolygon(PolygonUtils::create_circle(size, 20)),
create_mountains(size),
create_trinagle_with_hole(size),
create_square_with_hole(size, size / 2),
create_square_with_hole(size, size / 3)
};
if (useFrogLeg)
result.push_back(load_frog());
return result;
}
Points createNet(const BoundingBox& bounding_box, double distance)
{
Point size = bounding_box.size();
double distance_2 = distance / 2;
int cols1 = static_cast<int>(floor(size.x() / distance))+1;
int cols2 = static_cast<int>(floor((size.x() - distance_2) / distance))+1;
// equilateral triangle height with side distance
double h = sqrt(distance * distance - distance_2 * distance_2);
int rows = static_cast<int>(floor(size.y() / h)) +1;
int rows_2 = rows / 2;
size_t count_points = rows_2 * (cols1 + static_cast<size_t>(cols2));
if (rows % 2 == 1) count_points += cols2;
Points result;
result.reserve(count_points);
bool isOdd = true;
Point offset = bounding_box.min;
double x_max = offset.x() + static_cast<double>(size.x());
double y_max = offset.y() + static_cast<double>(size.y());
for (double y = offset.y(); y <= y_max; y += h) {
double x_offset = offset.x();
if (isOdd) x_offset += distance_2;
isOdd = !isOdd;
for (double x = x_offset; x <= x_max; x += distance) {
result.emplace_back(x, y);
}
}
assert(result.size() == count_points);
return result;
}
// create uniform triangle net and return points laying inside island
Points rasterize(const ExPolygon &island, double distance) {
BoundingBox bb;
for (const Point &pt : island.contour.points) bb.merge(pt);
Points fullNet = createNet(bb, distance);
Points result;
result.reserve(fullNet.size());
std::copy_if(fullNet.begin(), fullNet.end(), std::back_inserter(result),
[&island](const Point &p) { return island.contains(p); });
return result;
}
SupportIslandPoints test_island_sampling(const ExPolygon & island,
const SampleConfig &config)
{
auto points = uniform_support_island(island, {}, config);
Points chck_points = rasterize(island, config.head_radius); // TODO: Use resolution of printer
bool is_island_supported = true; // Check rasterized island points that exist support point in max_distance
double max_distance = config.thick_inner_max_distance;
std::vector<double> point_distances(chck_points.size(), {max_distance + 1});
for (size_t index = 0; index < chck_points.size(); ++index) {
const Point &chck_point = chck_points[index];
double &min_distance = point_distances[index];
bool exist_close_support_point = false;
for (const auto &island_point : points) {
const Point& p = island_point->point;
Point abs_diff(fabs(p.x() - chck_point.x()),
fabs(p.y() - chck_point.y()));
if (abs_diff.x() < min_distance && abs_diff.y() < min_distance) {
double distance = sqrt((double) abs_diff.x() * abs_diff.x() +
(double) abs_diff.y() * abs_diff.y());
if (min_distance > distance) {
min_distance = distance;
exist_close_support_point = true;
}
}
}
if (!exist_close_support_point) is_island_supported = false;
}
bool is_all_points_inside_island = true;
for (const auto &point : points)
if (!island.contains(point->point))
is_all_points_inside_island = false;
#ifdef STORE_ISLAND_ISSUES
if (!is_island_supported || !is_all_points_inside_island) { // visualize
static int counter = 0;
BoundingBox bb;
for (const Point &pt : island.contour.points) bb.merge(pt);
SVG svg(STORE_ISLAND_ISSUES + std::string("Error") + std::to_string(++counter) + ".svg", bb);
svg.draw(island, "blue", 0.5f);
for (auto& p : points)
svg.draw(p->point, island.contains(p->point) ? "lightgreen" : "red", config.head_radius);
for (size_t index = 0; index < chck_points.size(); ++index) {
const Point &chck_point = chck_points[index];
double distance = point_distances[index];
bool isOk = distance < max_distance;
std::string color = (isOk) ? "gray" : "red";
svg.draw(chck_point, color, config.head_radius / 4);
}
}
#endif // STORE_ISLAND_ISSUES
CHECK(!points.empty());
CHECK(is_all_points_inside_island);
// CHECK(is_island_supported); // TODO: skip special cases with one point and 2 points
return points;
}
SampleConfig create_sample_config(double size) {
float head_diameter = .4f;
return SampleConfigFactory::create(head_diameter);
//coord_t max_distance = 3 * size + 0.1;
//SampleConfig cfg;
//cfg.head_radius = size / 4;
//cfg.minimal_distance_from_outline = cfg.head_radius;
//cfg.maximal_distance_from_outline = max_distance/4;
//cfg.max_length_for_one_support_point = 2*size;
//cfg.max_length_for_two_support_points = 4*size;
//cfg.thin_max_width = size;
//cfg.thick_min_width = cfg.thin_max_width;
//cfg.thick_outline_max_distance = max_distance;
//cfg.minimal_move = static_cast<coord_t>(size/30);
//cfg.count_iteration = 100;
//cfg.max_align_distance = 0;
//return cfg;
}
#ifdef STORE_SAMPLE_INTO_SVG_FILES
namespace {
void store_sample(const SupportIslandPoints &samples, const ExPolygon &island) {
static int counter = 0;
BoundingBox bb(island.contour.points);
SVG svg((STORE_SAMPLE_INTO_SVG_FILES + std::to_string(counter++) + ".svg").c_str(), bb);
double mm = scale_(1);
svg.draw(island, "lightgray");
for (const auto &s : samples)
svg.draw(s->point, "blue", 0.2*mm);
// draw resolution
Point p(bb.min.x() + 1e6, bb.max.y() - 2e6);
svg.draw_text(p, (std::to_string(samples.size()) + " samples").c_str(), "black");
svg.draw_text(p - Point(0., 1.8e6), "Scale 1 cm ", "black");
Point start = p - Point(0., 2.3e6);
svg.draw(Line(start + Point(0., 5e5), start + Point(10*mm, 5e5)), "black", 2e5);
svg.draw(Line(start + Point(0., -5e5), start + Point(10*mm, -5e5)), "black", 2e5);
svg.draw(Line(start + Point(10*mm, 5e5), start + Point(10*mm, -5e5)), "black", 2e5);
for (int i=0; i<10;i+=2)
svg.draw(Line(start + Point(i*mm, 0.), start + Point((i+1)*mm, 0.)), "black", 1e6);
}
} // namespace
#endif // STORE_SAMPLE_INTO_SVG_FILES
/// <summary>
/// Check for correct sampling of island
/// </summary>
TEST_CASE("Uniform sample test islands", "[SupGen], [VoronoiSkeleton]")
{
//set_logging_level(5);
float head_diameter = .4f;
SampleConfig cfg = SampleConfigFactory::create(head_diameter);
//cfg.path = "C:/data/temp/islands/<<order>>.svg";
ExPolygons islands = createTestIslands(7 * scale_(head_diameter));
for (ExPolygon &island : islands) {
// information for debug which island cause problem
[[maybe_unused]] size_t debug_index = &island - &islands.front();
SupportIslandPoints points = test_island_sampling(island, cfg);
#ifdef STORE_SAMPLE_INTO_SVG_FILES
store_sample(points, island);
#endif // STORE_SAMPLE_INTO_SVG_FILES
double angle = 3.14 / 3; // cca 60 degree
island.rotate(angle);
SupportIslandPoints pointsR = test_island_sampling(island, cfg);
#ifdef STORE_SAMPLE_INTO_SVG_FILES
store_sample(pointsR, island);
#endif // STORE_SAMPLE_INTO_SVG_FILES
// points count should be the same
//CHECK(points.size() == pointsR.size())
}
}
TEST_CASE("Sample island with config", "[SupportIsland]") {
// set_logging_level(5);
SampleConfig cfg{
/*thin_max_distance*/ 5832568,
/*thick_inner_max_distance*/ 7290710,
/*thick_outline_max_distance*/ 5468032,
/*head_radius*/ 250000,
/*minimal_distance_from_outline*/ 250000,
/*maximal_distance_from_outline*/ 1944189,
/*max_length_for_one_support_point*/ 1869413,
/*max_length_for_two_support_points*/ 7290710,
/*max_length_ratio_for_two_support_points*/ 0.250000000f,
/*thin_max_width*/ 4673532,
/*thick_min_width*/ 4019237,
/*min_part_length*/ 5832568,
/*minimal_move*/ 100000,
/*count_iteration*/ 30,
/*max_align_distance*/ 3645355,
/*simplification_tolerance*/ 50000.000000000007
//*path*/, "C:/data/temp/islands/<<order>>.svg" // need define OPTION_TO_STORE_ISLAND in SampleConfig.hpp
};
std::string dir = std::string(TEST_DATA_DIR PATH_SEPARATOR) + "sla_islands/";
ExPolygon island = load_svg(dir + "SPE-2709.svg"); // Bad field creation
SupportIslandPoints points = test_island_sampling(island, cfg);
// in time of write poins.size() == 39
CHECK(points.size() > 22); // not only thin parts
}
TEST_CASE("Disable visualization", "[hide]")
{
CHECK(true);
#ifdef STORE_SAMPLE_INTO_SVG_FILES
CHECK(false);
#endif // STORE_SAMPLE_INTO_SVG_FILES
#ifdef STORE_ISLAND_ISSUES
CHECK(false);
#endif // STORE_ISLAND_ISSUES
#ifdef USE_ISLAND_GUI_FOR_SETTINGS
CHECK(false);
#endif // USE_ISLAND_GUI_FOR_SETTINGS
CHECK(is_uniform_support_island_visualization_disabled());
}
TEST_CASE("SPE-2714 3DBenchy - Sample island with config", "[SupportIsland]") {
// set_logging_level(5);
SampleConfig cfg{
/*thin_max_distance*/ 5832568,
/*thick_inner_max_distance*/ 7290710,
/*thick_outline_max_distance*/ 5468032,
/*head_radius*/ 250000,
/*minimal_distance_from_outline*/ 250000,
/*maximal_distance_from_outline*/ 1944189,
/*max_length_for_one_support_point*/ 1869413,
/*max_length_for_two_support_points*/ 7290710,
/*max_length_ratio_for_two_support_points*/ 0.250000000f,
/*thin_max_width*/ 4673532,
/*thick_min_width*/ 4019237,
/*min_part_length*/ 5832568,
/*minimal_move*/ 100000,
/*count_iteration*/ 30,
/*max_align_distance*/ 3645355,
/*simplification_tolerance*/ 50000.000000000007
//*path*/, "C:/data/temp/islands/spe_2714_<<order>>.svg" // define OPTION_TO_STORE_ISLAND in SampleConfig.hpp
};
std::string dir = std::string(TEST_DATA_DIR PATH_SEPARATOR) + "sla_islands/";
ExPolygon island = load_svg(dir + "SPE-2714.svg"); // Bad field creation
SupportIslandPoints points = test_island_sampling(island, cfg);
CHECK(points.size() > 22); // Before fix it not finished
}