From 82954ba7152dc05f76445614e17ed97edbe0091e Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 17 Dec 2020 16:38:04 +0100 Subject: [PATCH] Group hollowing result (including grid) into one struct --- src/libslic3r/SLA/Hollowing.cpp | 104 +++++++++++++++++++++-------- src/libslic3r/SLA/Hollowing.hpp | 23 +++++-- src/libslic3r/SLAPrint.cpp | 5 +- src/libslic3r/SLAPrint.hpp | 4 +- src/libslic3r/SLAPrintSteps.cpp | 28 +++++--- tests/libslic3r/test_hollowing.cpp | 30 ++++----- tests/sla_print/sla_test_utils.cpp | 6 +- 7 files changed, 133 insertions(+), 67 deletions(-) diff --git a/src/libslic3r/SLA/Hollowing.cpp b/src/libslic3r/SLA/Hollowing.cpp index 61e1e122b..44358cebe 100644 --- a/src/libslic3r/SLA/Hollowing.cpp +++ b/src/libslic3r/SLA/Hollowing.cpp @@ -26,11 +26,36 @@ inline void _scale(S s, TriangleMesh &m) { m.scale(float(s)); } template> inline void _scale(S s, Contour3D &m) { for (auto &p : m.points) p *= s; } -static TriangleMesh _generate_interior(const TriangleMesh &mesh, - const JobController &ctl, - double min_thickness, - double voxel_scale, - double closing_dist) +struct Interior { + TriangleMesh mesh; + openvdb::FloatGrid::Ptr gridptr; + double closing_distance = 0.; + double thickness = 0.; + double voxel_scale = 1.; + double nb_in = 3.; + double nb_out = 3.; +}; + +void InteriorDeleter::operator()(Interior *p) +{ + delete p; +} + +TriangleMesh &get_mesh(Interior &interior) +{ + return interior.mesh; +} + +const TriangleMesh &get_mesh(const Interior &interior) +{ + return interior.mesh; +} + +static InteriorPtr generate_interior_verbose(const TriangleMesh & mesh, + const JobController &ctl, + double min_thickness, + double voxel_scale, + double closing_dist) { double offset = voxel_scale * min_thickness; double D = voxel_scale * closing_dist; @@ -64,22 +89,30 @@ static TriangleMesh _generate_interior(const TriangleMesh &mesh, else ctl.statuscb(70, L("Hollowing")); double adaptivity = 0.; + InteriorPtr interior = InteriorPtr{new Interior{}}; - auto omesh = grid_to_mesh(*gridptr, iso_surface, adaptivity); + interior->mesh = grid_to_mesh(*gridptr, iso_surface, adaptivity); + interior->gridptr = gridptr; if (ctl.stopcondition()) return {}; else ctl.statuscb(100, L("Hollowing")); - return omesh; + interior->closing_distance = D; + interior->thickness = offset; + interior->voxel_scale = voxel_scale; + interior->nb_in = narrowb; + interior->nb_out = narrowb; + + return interior; } -std::unique_ptr generate_interior(const TriangleMesh & mesh, - const HollowingConfig &hc, - const JobController & ctl) +InteriorPtr generate_interior(const TriangleMesh & mesh, + const HollowingConfig &hc, + const JobController & ctl) { static const double MIN_OVERSAMPL = 3.; static const double MAX_OVERSAMPL = 8.; - + // I can't figure out how to increase the grid resolution through openvdb // API so the model will be scaled up before conversion and the result // scaled down. Voxels have a unit size. If I set voxelSize smaller, it @@ -88,26 +121,29 @@ std::unique_ptr generate_interior(const TriangleMesh & mesh, // // max 8x upscale, min is native voxel size auto voxel_scale = MIN_OVERSAMPL + (MAX_OVERSAMPL - MIN_OVERSAMPL) * hc.quality; - auto meshptr = std::make_unique( - _generate_interior(mesh, ctl, hc.min_thickness, voxel_scale, - hc.closing_distance)); - - if (meshptr && !meshptr->empty()) { - + + InteriorPtr interior = + generate_interior_verbose(mesh, ctl, hc.min_thickness, voxel_scale, + hc.closing_distance); + + if (interior && !interior->mesh.empty()) { + // This flips the normals to be outward facing... - meshptr->require_shared_vertices(); - indexed_triangle_set its = std::move(meshptr->its); - + interior->mesh.require_shared_vertices(); + indexed_triangle_set its = std::move(interior->mesh.its); + Slic3r::simplify_mesh(its); - + // flip normals back... for (stl_triangle_vertex_indices &ind : its.indices) std::swap(ind(0), ind(2)); - - *meshptr = Slic3r::TriangleMesh{its}; + + interior->mesh = Slic3r::TriangleMesh{its}; + interior->mesh.repaired = true; + interior->mesh.require_shared_vertices(); } - - return meshptr; + + return interior; } Contour3D DrainHole::to_mesh() const @@ -269,12 +305,22 @@ void cut_drainholes(std::vector & obj_slices, obj_slices[i] = diff_ex(obj_slices[i], hole_slices[i]); } -void hollow_mesh(TriangleMesh &mesh, const HollowingConfig &cfg) +void hollow_mesh(TriangleMesh &mesh, const HollowingConfig &cfg, int flags) { - std::unique_ptr inter_ptr = - Slic3r::sla::generate_interior(mesh); + InteriorPtr interior = generate_interior(mesh, cfg, JobController{}); + if (!interior) return; - if (inter_ptr) mesh.merge(*inter_ptr); + hollow_mesh(mesh, *interior, flags); +} + +void hollow_mesh(TriangleMesh &mesh, const Interior &interior, int flags) +{ + if (mesh.empty() || interior.mesh.empty()) return; + +// if (flags & hfRemoveInsideTriangles && interior.gridptr) +// erase_inside_triangles_2(mesh, interior); + + mesh.merge(interior.mesh); mesh.require_shared_vertices(); } diff --git a/src/libslic3r/SLA/Hollowing.hpp b/src/libslic3r/SLA/Hollowing.hpp index 949cc2393..356907846 100644 --- a/src/libslic3r/SLA/Hollowing.hpp +++ b/src/libslic3r/SLA/Hollowing.hpp @@ -19,6 +19,17 @@ struct HollowingConfig bool enabled = true; }; +enum HollowingFlags { hfRemoveInsideTriangles = 0x1 }; + +// All data related to a generated mesh interior. Includes the 3D grid and mesh +// and various metadata. No need to manipulate from outside. +struct Interior; +struct InteriorDeleter { void operator()(Interior *p); }; +using InteriorPtr = std::unique_ptr; + +TriangleMesh & get_mesh(Interior &interior); +const TriangleMesh &get_mesh(const Interior &interior); + struct DrainHole { Vec3f pos; @@ -60,11 +71,15 @@ using DrainHoles = std::vector; constexpr float HoleStickOutLength = 1.f; -std::unique_ptr generate_interior(const TriangleMesh &mesh, - const HollowingConfig & = {}, - const JobController &ctl = {}); +InteriorPtr generate_interior(const TriangleMesh &mesh, + const HollowingConfig & = {}, + const JobController &ctl = {}); -void hollow_mesh(TriangleMesh &mesh, const HollowingConfig &cfg); +// Will do the hollowing +void hollow_mesh(TriangleMesh &mesh, const HollowingConfig &cfg, int flags = 0); + +// Hollowing prepared in "interior", merge with original mesh +void hollow_mesh(TriangleMesh &mesh, const Interior &interior, int flags = 0); void cut_drainholes(std::vector & obj_slices, const std::vector &slicegrid, diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 16b068cb9..07042692a 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1149,8 +1149,9 @@ const TriangleMesh& SLAPrintObject::pad_mesh() const const TriangleMesh &SLAPrintObject::hollowed_interior_mesh() const { - if (m_hollowing_data && m_config.hollowing_enable.getBool()) - return m_hollowing_data->interior; + if (m_hollowing_data && m_hollowing_data->interior && + m_config.hollowing_enable.getBool()) + return sla::get_mesh(*m_hollowing_data->interior); return EMPTY_MESH; } diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index bed66ab4f..87ab3db8a 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -327,8 +327,8 @@ private: class HollowingData { public: - - TriangleMesh interior; + + sla::InteriorPtr interior; mutable TriangleMesh hollow_mesh_with_holes; // caching the complete hollowed mesh }; diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index d8bea62ae..976e6d3d1 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -131,13 +131,14 @@ void SLAPrint::Steps::hollow_model(SLAPrintObject &po) double quality = po.m_config.hollowing_quality.getFloat(); double closing_d = po.m_config.hollowing_closing_distance.getFloat(); sla::HollowingConfig hlwcfg{thickness, quality, closing_d}; - auto meshptr = generate_interior(po.transformed_mesh(), hlwcfg); - if (meshptr->empty()) + sla::InteriorPtr interior = generate_interior(po.transformed_mesh(), hlwcfg); + + if (!interior || sla::get_mesh(*interior).empty()) BOOST_LOG_TRIVIAL(warning) << "Hollowed interior is empty!"; else { po.m_hollowing_data.reset(new SLAPrintObject::HollowingData()); - po.m_hollowing_data->interior = *meshptr; + po.m_hollowing_data->interior = std::move(interior); } } @@ -145,7 +146,9 @@ void SLAPrint::Steps::hollow_model(SLAPrintObject &po) void SLAPrint::Steps::drill_holes(SLAPrintObject &po) { bool needs_drilling = ! po.m_model_object->sla_drain_holes.empty(); - bool is_hollowed = (po.m_hollowing_data && ! po.m_hollowing_data->interior.empty()); + bool is_hollowed = + (po.m_hollowing_data && po.m_hollowing_data->interior && + !sla::get_mesh(*po.m_hollowing_data->interior).empty()); if (! is_hollowed && ! needs_drilling) { // In this case we can dump any data that might have been @@ -163,10 +166,7 @@ void SLAPrint::Steps::drill_holes(SLAPrintObject &po) // holes that are no longer on the frontend. TriangleMesh &hollowed_mesh = po.m_hollowing_data->hollow_mesh_with_holes; hollowed_mesh = po.transformed_mesh(); - if (! po.m_hollowing_data->interior.empty()) { - hollowed_mesh.merge(po.m_hollowing_data->interior); - hollowed_mesh.require_shared_vertices(); - } + sla::hollow_mesh(hollowed_mesh, *po.m_hollowing_data->interior/*, sla::hfRemoveInsideTriangles*/); if (! needs_drilling) { BOOST_LOG_TRIVIAL(info) << "Drilling skipped (no holes)."; @@ -260,9 +260,15 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po) auto &slice_grid = po.m_model_height_levels; slicer.slice(slice_grid, SlicingMode::Regular, closing_r, &po.m_model_slices, thr); - if (po.m_hollowing_data && ! po.m_hollowing_data->interior.empty()) { - po.m_hollowing_data->interior.repair(true); - TriangleMeshSlicer interior_slicer(&po.m_hollowing_data->interior); + sla::Interior *interior = po.m_hollowing_data ? + po.m_hollowing_data->interior.get() : + nullptr; + + if (interior && ! sla::get_mesh(*interior).empty()) { + TriangleMesh interiormesh = sla::get_mesh(*interior); + interiormesh.repaired = false; + interiormesh.repair(true); + TriangleMeshSlicer interior_slicer(&interiormesh); std::vector interior_slices; interior_slicer.slice(slice_grid, SlicingMode::Regular, closing_r, &interior_slices, thr); diff --git a/tests/libslic3r/test_hollowing.cpp b/tests/libslic3r/test_hollowing.cpp index 65b87c2a2..2218a27b7 100644 --- a/tests/libslic3r/test_hollowing.cpp +++ b/tests/libslic3r/test_hollowing.cpp @@ -26,21 +26,19 @@ static Slic3r::TriangleMesh load_model(const std::string &obj_filename) } -TEST_CASE("Negative 3D offset should produce smaller object.", "[Hollowing]") -{ - Slic3r::TriangleMesh in_mesh = load_model("20mm_cube.obj"); - Benchmark bench; - bench.start(); - - std::unique_ptr out_mesh_ptr = - Slic3r::sla::generate_interior(in_mesh); - - bench.stop(); - - std::cout << "Elapsed processing time: " << bench.getElapsedSec() << std::endl; - - if (out_mesh_ptr) in_mesh.merge(*out_mesh_ptr); - in_mesh.require_shared_vertices(); - in_mesh.WriteOBJFile("merged_out.obj"); +TEST_CASE("Hollow two overlapping spheres") { + using namespace Slic3r; + + TriangleMesh sphere1 = make_sphere(10., 2 * PI / 20.), sphere2 = sphere1; + + sphere1.translate(-5.f, 0.f, 0.f); + sphere2.translate( 5.f, 0.f, 0.f); + + sphere1.merge(sphere2); + sphere1.require_shared_vertices(); + + sla::hollow_mesh(sphere1, sla::HollowingConfig{}, sla::HollowingFlags::hfRemoveInsideTriangles); + + sphere1.WriteOBJFile("twospheres.obj"); } diff --git a/tests/sla_print/sla_test_utils.cpp b/tests/sla_print/sla_test_utils.cpp index 653221cd3..1ec890beb 100644 --- a/tests/sla_print/sla_test_utils.cpp +++ b/tests/sla_print/sla_test_utils.cpp @@ -88,9 +88,9 @@ void test_supports(const std::string &obj_filename, REQUIRE_FALSE(mesh.empty()); if (hollowingcfg.enabled) { - auto inside = sla::generate_interior(mesh, hollowingcfg); - REQUIRE(inside); - mesh.merge(*inside); + sla::InteriorPtr interior = sla::generate_interior(mesh, hollowingcfg); + REQUIRE(interior); + mesh.merge(sla::get_mesh(*interior)); mesh.require_shared_vertices(); }