Fix failing sla tree tests

Try to increase number of rays in Beam to prevent colisions


Put back threshold for intersections with model in sla tree tests 


Increase safety distance for branching tree instead of increasing rays
This commit is contained in:
tamasmeszaros 2022-05-17 10:52:52 +02:00
parent fd8fd77077
commit 0a3b17f940
4 changed files with 61 additions and 50 deletions

View File

@ -120,7 +120,7 @@ bool BranchingTreeBuilder::add_bridge(const branchingtree::Node &from,
double fromR = get_radius(from), toR = get_radius(to); double fromR = get_radius(from), toR = get_radius(to);
Beam beam{Ball{fromd, fromR}, Ball{tod, toR}}; Beam beam{Ball{fromd, fromR}, Ball{tod, toR}};
auto hit = beam_mesh_hit(ex_tbb, m_sm.emesh, beam, auto hit = beam_mesh_hit(ex_tbb, m_sm.emesh, beam,
m_sm.cfg.safety_distance_mm); 2 * m_sm.cfg.safety_distance_mm);
bool ret = hit.distance() > (tod - fromd).norm(); bool ret = hit.distance() > (tod - fromd).norm();
@ -140,7 +140,8 @@ bool BranchingTreeBuilder::add_merger(const branchingtree::Node &node,
double closestR = get_radius(closest); double closestR = get_radius(closest);
Beam beam1{Ball{from1d, nodeR}, Ball{tod, mergeR}}; Beam beam1{Ball{from1d, nodeR}, Ball{tod, mergeR}};
Beam beam2{Ball{from2d, closestR}, Ball{tod, mergeR}}; Beam beam2{Ball{from2d, closestR}, Ball{tod, mergeR}};
auto sd = m_sm.cfg.safety_distance_mm;
auto sd = 2 * m_sm.cfg.safety_distance_mm;
auto hit1 = beam_mesh_hit(ex_tbb, m_sm.emesh, beam1, sd); auto hit1 = beam_mesh_hit(ex_tbb, m_sm.emesh, beam1, sd);
auto hit2 = beam_mesh_hit(ex_tbb, m_sm.emesh, beam2, sd); auto hit2 = beam_mesh_hit(ex_tbb, m_sm.emesh, beam2, sd);
@ -166,7 +167,7 @@ bool BranchingTreeBuilder::add_ground_bridge(const branchingtree::Node &from,
} }
bool BranchingTreeBuilder::add_mesh_bridge(const branchingtree::Node &from, bool BranchingTreeBuilder::add_mesh_bridge(const branchingtree::Node &from,
const branchingtree::Node &to) const branchingtree::Node &to)
{ {
sla::Junction fromj = {from.pos.cast<double>(), get_radius(from)}; sla::Junction fromj = {from.pos.cast<double>(), get_radius(from)};
@ -178,7 +179,9 @@ bool BranchingTreeBuilder::add_mesh_bridge(const branchingtree::Node &from,
m_builder.add_diffbridge(fromj.pos, anchor->junction_point(), fromj.r, m_builder.add_diffbridge(fromj.pos, anchor->junction_point(), fromj.r,
anchor->r_back_mm); anchor->r_back_mm);
m_builder.add_anchor(*anchor); if (!m_sm.cfg.ground_facing_only) { // Easter egg, to omit the anchors
m_builder.add_anchor(*anchor);
}
build_subtree(from.id); build_subtree(from.id);
} }

View File

@ -57,7 +57,11 @@ sla::SupportTreeConfig make_support_cfg(const SLAPrintObjectConfig& c)
scfg.max_bridge_length_mm = c.support_max_bridge_length.getFloat(); scfg.max_bridge_length_mm = c.support_max_bridge_length.getFloat();
scfg.max_pillar_link_distance_mm = c.support_max_pillar_link_distance.getFloat(); scfg.max_pillar_link_distance_mm = c.support_max_pillar_link_distance.getFloat();
scfg.pillar_connection_mode = c.support_pillar_connection_mode.value; scfg.pillar_connection_mode = c.support_pillar_connection_mode.value;
scfg.ground_facing_only = c.support_buildplate_only.getBool(); if (scfg.tree_type != sla::SupportTreeType::Branching) {
// Branching tree is all about routing to model body, it doesn't support
// this option.
scfg.ground_facing_only = c.support_buildplate_only.getBool();
}
scfg.pillar_widening_factor = c.support_pillar_widening_factor.getFloat(); scfg.pillar_widening_factor = c.support_pillar_widening_factor.getFloat();
scfg.base_radius_mm = 0.5*c.support_base_diameter.getFloat(); scfg.base_radius_mm = 0.5*c.support_base_diameter.getFloat();
scfg.base_height_mm = c.support_base_height.getFloat(); scfg.base_height_mm = c.support_base_height.getFloat();

View File

@ -6,54 +6,58 @@
#include <iomanip> #include <iomanip>
void test_support_model_collision(const std::string &obj_filename, void test_support_model_collision(
const sla::SupportTreeConfig &input_supportcfg, const std::string &obj_filename,
const sla::HollowingConfig &hollowingcfg, const sla::SupportTreeConfig &input_supportcfg,
const sla::DrainHoles &drainholes) const sla::HollowingConfig &hollowingcfg,
const sla::DrainHoles &drainholes)
{ {
SupportByproducts byproducts; SupportByproducts byproducts;
sla::SupportTreeConfig supportcfg = input_supportcfg; sla::SupportTreeConfig supportcfg = input_supportcfg;
// Ensure that there are no anchors which would pierce the model.
supportcfg.ground_facing_only = true;
// Set head penetration to a small negative value which should ensure that // Set head penetration to a small negative value which should ensure that
// the supports will not touch the model body. // the supports will not touch the model body.
supportcfg.head_penetration_mm = -0.2; supportcfg.head_penetration_mm = -0.2;
test_supports(obj_filename, supportcfg, hollowingcfg, drainholes, byproducts); test_supports(obj_filename, supportcfg, hollowingcfg, drainholes, byproducts);
// Slice the support mesh given the slice grid of the model. // Slice the support mesh given the slice grid of the model.
std::vector<ExPolygons> support_slices = std::vector<ExPolygons> support_slices =
sla::slice(byproducts.supporttree.retrieve_mesh(sla::MeshType::Support), sla::slice(byproducts.suptree_builder.retrieve_mesh(sla::MeshType::Support),
byproducts.supporttree.retrieve_mesh(sla::MeshType::Pad), byproducts.suptree_builder.retrieve_mesh(sla::MeshType::Pad),
byproducts.slicegrid, CLOSING_RADIUS, {}); byproducts.slicegrid, CLOSING_RADIUS, {});
// The slices originate from the same slice grid so the numbers must match // The slices originate from the same slice grid so the numbers must match
bool support_mesh_is_empty = bool support_mesh_is_empty =
byproducts.supporttree.retrieve_mesh(sla::MeshType::Pad).empty() && byproducts.suptree_builder.retrieve_mesh(sla::MeshType::Pad).empty() &&
byproducts.supporttree.retrieve_mesh(sla::MeshType::Support).empty(); byproducts.suptree_builder.retrieve_mesh(sla::MeshType::Support).empty();
if (support_mesh_is_empty) if (support_mesh_is_empty)
REQUIRE(support_slices.empty()); REQUIRE(support_slices.empty());
else else
REQUIRE(support_slices.size() == byproducts.model_slices.size()); REQUIRE(support_slices.size() == byproducts.model_slices.size());
bool notouch = true; bool notouch = true;
for (size_t n = 0; notouch && n < support_slices.size(); ++n) { for (size_t n = 0; notouch && n < support_slices.size(); ++n) {
const ExPolygons &sup_slice = support_slices[n]; const ExPolygons &sup_slice = support_slices[n];
const ExPolygons &mod_slice = byproducts.model_slices[n]; const ExPolygons &mod_slice = byproducts.model_slices[n];
Polygons intersections = intersection(sup_slice, mod_slice); Polygons intersections = intersection(sup_slice, mod_slice);
double pinhead_r = scaled(input_supportcfg.head_front_radius_mm); double pinhead_r = scaled(input_supportcfg.head_front_radius_mm);
// TODO:: make it strict without a threshold of PI * pihead_radius ^ 2 // TODO:: make it strict without a threshold of PI * pihead_radius ^ 2
notouch = notouch && area(intersections) < PI * pinhead_r * pinhead_r; notouch = notouch && area(intersections) < PI * pinhead_r * pinhead_r;
} }
if (!notouch) if (!notouch)
export_failed_case(support_slices, byproducts); export_failed_case(support_slices, byproducts);
REQUIRE(notouch); REQUIRE(notouch);
} }
@ -80,7 +84,7 @@ void export_failed_case(const std::vector<ExPolygons> &support_slices, const Sup
if (do_export_stl) { if (do_export_stl) {
indexed_triangle_set its; indexed_triangle_set its;
byproducts.supporttree.retrieve_full_mesh(its); byproducts.suptree_builder.retrieve_full_mesh(its);
TriangleMesh m{its}; TriangleMesh m{its};
m.merge(byproducts.input_mesh); m.merge(byproducts.input_mesh);
m.WriteOBJFile((Catch::getResultCapture().getCurrentTestName() + "_" + m.WriteOBJFile((Catch::getResultCapture().getCurrentTestName() + "_" +
@ -96,49 +100,49 @@ void test_supports(const std::string &obj_filename,
{ {
using namespace Slic3r; using namespace Slic3r;
TriangleMesh mesh = load_model(obj_filename); TriangleMesh mesh = load_model(obj_filename);
REQUIRE_FALSE(mesh.empty()); REQUIRE_FALSE(mesh.empty());
if (hollowingcfg.enabled) { if (hollowingcfg.enabled) {
sla::InteriorPtr interior = sla::generate_interior(mesh, hollowingcfg); sla::InteriorPtr interior = sla::generate_interior(mesh, hollowingcfg);
REQUIRE(interior); REQUIRE(interior);
mesh.merge(TriangleMesh{sla::get_mesh(*interior)}); mesh.merge(TriangleMesh{sla::get_mesh(*interior)});
} }
auto bb = mesh.bounding_box(); auto bb = mesh.bounding_box();
double zmin = bb.min.z(); double zmin = bb.min.z();
double zmax = bb.max.z(); double zmax = bb.max.z();
double gnd = zmin - supportcfg.object_elevation_mm; double gnd = zmin - supportcfg.object_elevation_mm;
auto layer_h = 0.05f; auto layer_h = 0.05f;
out.slicegrid = grid(float(gnd), float(zmax), layer_h); out.slicegrid = grid(float(gnd), float(zmax), layer_h);
out.model_slices = slice_mesh_ex(mesh.its, out.slicegrid, CLOSING_RADIUS); out.model_slices = slice_mesh_ex(mesh.its, out.slicegrid, CLOSING_RADIUS);
sla::cut_drainholes(out.model_slices, out.slicegrid, CLOSING_RADIUS, drainholes, []{}); sla::cut_drainholes(out.model_slices, out.slicegrid, CLOSING_RADIUS, drainholes, []{});
// Create the special index-triangle mesh with spatial indexing which // Create the special index-triangle mesh with spatial indexing which
// is the input of the support point and support mesh generators // is the input of the support point and support mesh generators
AABBMesh emesh{mesh}; AABBMesh emesh{mesh};
#ifdef SLIC3R_HOLE_RAYCASTER #ifdef SLIC3R_HOLE_RAYCASTER
if (hollowingcfg.enabled) if (hollowingcfg.enabled)
emesh.load_holes(drainholes); emesh.load_holes(drainholes);
#endif #endif
// TODO: do the cgal hole cutting... // TODO: do the cgal hole cutting...
// Create the support point generator // Create the support point generator
sla::SupportPointGenerator::Config autogencfg; sla::SupportPointGenerator::Config autogencfg;
autogencfg.head_diameter = float(2 * supportcfg.head_front_radius_mm); autogencfg.head_diameter = float(2 * supportcfg.head_front_radius_mm);
sla::SupportPointGenerator point_gen{emesh, autogencfg, [] {}, [](int) {}}; sla::SupportPointGenerator point_gen{emesh, autogencfg, [] {}, [](int) {}};
point_gen.seed(0); // Make the test repeatable point_gen.seed(0); // Make the test repeatable
point_gen.execute(out.model_slices, out.slicegrid); point_gen.execute(out.model_slices, out.slicegrid);
// Get the calculated support points. // Get the calculated support points.
std::vector<sla::SupportPoint> support_points = point_gen.output(); std::vector<sla::SupportPoint> support_points = point_gen.output();
int validityflags = ASSUME_NO_REPAIR; int validityflags = ASSUME_NO_REPAIR;
// If there is no elevation, support points shall be removed from the // If there is no elevation, support points shall be removed from the
// bottom of the object. // bottom of the object.
if (std::abs(supportcfg.object_elevation_mm) < EPSILON) { if (std::abs(supportcfg.object_elevation_mm) < EPSILON) {
@ -146,11 +150,11 @@ void test_supports(const std::string &obj_filename,
} else { } else {
// Should be support points at least on the bottom of the model // Should be support points at least on the bottom of the model
REQUIRE_FALSE(support_points.empty()); REQUIRE_FALSE(support_points.empty());
// Also the support mesh should not be empty. // Also the support mesh should not be empty.
validityflags |= ASSUME_NO_EMPTY; validityflags |= ASSUME_NO_EMPTY;
} }
// Generate the actual support tree // Generate the actual support tree
sla::SupportTreeBuilder treebuilder; sla::SupportTreeBuilder treebuilder;
sla::SupportableMesh sm{emesh, support_points, supportcfg}; sla::SupportableMesh sm{emesh, support_points, supportcfg};
@ -170,25 +174,25 @@ void test_supports(const std::string &obj_filename,
} }
TriangleMesh output_mesh{treebuilder.retrieve_mesh(sla::MeshType::Support)}; TriangleMesh output_mesh{treebuilder.retrieve_mesh(sla::MeshType::Support)};
check_validity(output_mesh, validityflags); check_validity(output_mesh, validityflags);
// Quick check if the dimensions and placement of supports are correct // Quick check if the dimensions and placement of supports are correct
auto obb = output_mesh.bounding_box(); auto obb = output_mesh.bounding_box();
double allowed_zmin = zmin - supportcfg.object_elevation_mm; double allowed_zmin = zmin - supportcfg.object_elevation_mm;
if (std::abs(supportcfg.object_elevation_mm) < EPSILON) if (std::abs(supportcfg.object_elevation_mm) < EPSILON)
allowed_zmin = zmin - 2 * supportcfg.head_back_radius_mm; allowed_zmin = zmin - 2 * supportcfg.head_back_radius_mm;
REQUIRE(obb.min.z() >= Approx(allowed_zmin)); REQUIRE(obb.min.z() >= Approx(allowed_zmin));
REQUIRE(obb.max.z() <= Approx(zmax)); REQUIRE(obb.max.z() <= Approx(zmax));
// Move out the support tree into the byproducts, we can examine it further // Move out the support tree into the byproducts, we can examine it further
// in various tests. // in various tests.
out.obj_fname = std::move(obj_filename); out.obj_fname = std::move(obj_filename);
out.supporttree = std::move(treebuilder); out.suptree_builder = std::move(treebuilder);
out.input_mesh = std::move(mesh); out.input_mesh = std::move(mesh);
} }
void check_support_tree_integrity(const sla::SupportTreeBuilder &stree, void check_support_tree_integrity(const sla::SupportTreeBuilder &stree,

View File

@ -60,7 +60,7 @@ struct SupportByproducts
std::string obj_fname; std::string obj_fname;
std::vector<float> slicegrid; std::vector<float> slicegrid;
std::vector<ExPolygons> model_slices; std::vector<ExPolygons> model_slices;
sla::SupportTreeBuilder supporttree; sla::SupportTreeBuilder suptree_builder;
TriangleMesh input_mesh; TriangleMesh input_mesh;
}; };