From 0a3b17f940db3a7cfea7e58b6e2d166e0f833b3e Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 17 May 2022 10:52:52 +0200 Subject: [PATCH] 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 --- src/libslic3r/SLA/BranchingTreeSLA.cpp | 11 +-- src/libslic3r/SLAPrint.cpp | 6 +- tests/sla_print/sla_test_utils.cpp | 92 ++++++++++++++------------ tests/sla_print/sla_test_utils.hpp | 2 +- 4 files changed, 61 insertions(+), 50 deletions(-) diff --git a/src/libslic3r/SLA/BranchingTreeSLA.cpp b/src/libslic3r/SLA/BranchingTreeSLA.cpp index 9ec6f987f6..5f85df1402 100644 --- a/src/libslic3r/SLA/BranchingTreeSLA.cpp +++ b/src/libslic3r/SLA/BranchingTreeSLA.cpp @@ -120,7 +120,7 @@ bool BranchingTreeBuilder::add_bridge(const branchingtree::Node &from, double fromR = get_radius(from), toR = get_radius(to); Beam beam{Ball{fromd, fromR}, Ball{tod, toR}}; 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(); @@ -140,7 +140,8 @@ bool BranchingTreeBuilder::add_merger(const branchingtree::Node &node, double closestR = get_radius(closest); Beam beam1{Ball{from1d, nodeR}, 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 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, - const branchingtree::Node &to) + const branchingtree::Node &to) { sla::Junction fromj = {from.pos.cast(), 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, 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); } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index d9b8e33df0..4f58c3aa13 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -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_pillar_link_distance_mm = c.support_max_pillar_link_distance.getFloat(); 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.base_radius_mm = 0.5*c.support_base_diameter.getFloat(); scfg.base_height_mm = c.support_base_height.getFloat(); diff --git a/tests/sla_print/sla_test_utils.cpp b/tests/sla_print/sla_test_utils.cpp index a33a23c882..b9ad696ed4 100644 --- a/tests/sla_print/sla_test_utils.cpp +++ b/tests/sla_print/sla_test_utils.cpp @@ -6,54 +6,58 @@ #include -void test_support_model_collision(const std::string &obj_filename, - const sla::SupportTreeConfig &input_supportcfg, - const sla::HollowingConfig &hollowingcfg, - const sla::DrainHoles &drainholes) +void test_support_model_collision( + const std::string &obj_filename, + const sla::SupportTreeConfig &input_supportcfg, + const sla::HollowingConfig &hollowingcfg, + const sla::DrainHoles &drainholes) { SupportByproducts byproducts; - + 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 // the supports will not touch the model body. supportcfg.head_penetration_mm = -0.2; - + test_supports(obj_filename, supportcfg, hollowingcfg, drainholes, byproducts); - + // Slice the support mesh given the slice grid of the model. std::vector support_slices = - sla::slice(byproducts.supporttree.retrieve_mesh(sla::MeshType::Support), - byproducts.supporttree.retrieve_mesh(sla::MeshType::Pad), + sla::slice(byproducts.suptree_builder.retrieve_mesh(sla::MeshType::Support), + byproducts.suptree_builder.retrieve_mesh(sla::MeshType::Pad), byproducts.slicegrid, CLOSING_RADIUS, {}); // The slices originate from the same slice grid so the numbers must match - + bool support_mesh_is_empty = - byproducts.supporttree.retrieve_mesh(sla::MeshType::Pad).empty() && - byproducts.supporttree.retrieve_mesh(sla::MeshType::Support).empty(); - + byproducts.suptree_builder.retrieve_mesh(sla::MeshType::Pad).empty() && + byproducts.suptree_builder.retrieve_mesh(sla::MeshType::Support).empty(); + if (support_mesh_is_empty) REQUIRE(support_slices.empty()); else REQUIRE(support_slices.size() == byproducts.model_slices.size()); - + bool notouch = true; for (size_t n = 0; notouch && n < support_slices.size(); ++n) { const ExPolygons &sup_slice = support_slices[n]; const ExPolygons &mod_slice = byproducts.model_slices[n]; - + Polygons intersections = intersection(sup_slice, mod_slice); - + double pinhead_r = scaled(input_supportcfg.head_front_radius_mm); // TODO:: make it strict without a threshold of PI * pihead_radius ^ 2 notouch = notouch && area(intersections) < PI * pinhead_r * pinhead_r; } - + if (!notouch) export_failed_case(support_slices, byproducts); - + REQUIRE(notouch); } @@ -80,7 +84,7 @@ void export_failed_case(const std::vector &support_slices, const Sup if (do_export_stl) { indexed_triangle_set its; - byproducts.supporttree.retrieve_full_mesh(its); + byproducts.suptree_builder.retrieve_full_mesh(its); TriangleMesh m{its}; m.merge(byproducts.input_mesh); m.WriteOBJFile((Catch::getResultCapture().getCurrentTestName() + "_" + @@ -96,49 +100,49 @@ void test_supports(const std::string &obj_filename, { using namespace Slic3r; TriangleMesh mesh = load_model(obj_filename); - + REQUIRE_FALSE(mesh.empty()); - + if (hollowingcfg.enabled) { sla::InteriorPtr interior = sla::generate_interior(mesh, hollowingcfg); REQUIRE(interior); mesh.merge(TriangleMesh{sla::get_mesh(*interior)}); } - + auto bb = mesh.bounding_box(); double zmin = bb.min.z(); double zmax = bb.max.z(); double gnd = zmin - supportcfg.object_elevation_mm; auto layer_h = 0.05f; - + out.slicegrid = grid(float(gnd), float(zmax), layer_h); out.model_slices = slice_mesh_ex(mesh.its, out.slicegrid, CLOSING_RADIUS); sla::cut_drainholes(out.model_slices, out.slicegrid, CLOSING_RADIUS, drainholes, []{}); - + // Create the special index-triangle mesh with spatial indexing which // is the input of the support point and support mesh generators AABBMesh emesh{mesh}; -#ifdef SLIC3R_HOLE_RAYCASTER - if (hollowingcfg.enabled) + #ifdef SLIC3R_HOLE_RAYCASTER + if (hollowingcfg.enabled) emesh.load_holes(drainholes); -#endif + #endif // TODO: do the cgal hole cutting... - + // Create the support point generator sla::SupportPointGenerator::Config autogencfg; autogencfg.head_diameter = float(2 * supportcfg.head_front_radius_mm); sla::SupportPointGenerator point_gen{emesh, autogencfg, [] {}, [](int) {}}; - + point_gen.seed(0); // Make the test repeatable point_gen.execute(out.model_slices, out.slicegrid); - + // Get the calculated support points. std::vector support_points = point_gen.output(); - + int validityflags = ASSUME_NO_REPAIR; - + // If there is no elevation, support points shall be removed from the // bottom of the object. if (std::abs(supportcfg.object_elevation_mm) < EPSILON) { @@ -146,11 +150,11 @@ void test_supports(const std::string &obj_filename, } else { // Should be support points at least on the bottom of the model REQUIRE_FALSE(support_points.empty()); - + // Also the support mesh should not be empty. validityflags |= ASSUME_NO_EMPTY; } - + // Generate the actual support tree sla::SupportTreeBuilder treebuilder; 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)}; - + check_validity(output_mesh, validityflags); - + // Quick check if the dimensions and placement of supports are correct auto obb = output_mesh.bounding_box(); - + double allowed_zmin = zmin - supportcfg.object_elevation_mm; - + if (std::abs(supportcfg.object_elevation_mm) < EPSILON) allowed_zmin = zmin - 2 * supportcfg.head_back_radius_mm; - + REQUIRE(obb.min.z() >= Approx(allowed_zmin)); REQUIRE(obb.max.z() <= Approx(zmax)); - + // Move out the support tree into the byproducts, we can examine it further // in various tests. - out.obj_fname = std::move(obj_filename); - out.supporttree = std::move(treebuilder); - out.input_mesh = std::move(mesh); + out.obj_fname = std::move(obj_filename); + out.suptree_builder = std::move(treebuilder); + out.input_mesh = std::move(mesh); } void check_support_tree_integrity(const sla::SupportTreeBuilder &stree, diff --git a/tests/sla_print/sla_test_utils.hpp b/tests/sla_print/sla_test_utils.hpp index c5943bd5c3..187a72d545 100644 --- a/tests/sla_print/sla_test_utils.hpp +++ b/tests/sla_print/sla_test_utils.hpp @@ -60,7 +60,7 @@ struct SupportByproducts std::string obj_fname; std::vector slicegrid; std::vector model_slices; - sla::SupportTreeBuilder supporttree; + sla::SupportTreeBuilder suptree_builder; TriangleMesh input_mesh; };