diff --git a/src/libslic3r/CSGMesh/CSGMesh.hpp b/src/libslic3r/CSGMesh/CSGMesh.hpp index 4655f684a..f30905066 100644 --- a/src/libslic3r/CSGMesh/CSGMesh.hpp +++ b/src/libslic3r/CSGMesh/CSGMesh.hpp @@ -18,6 +18,7 @@ namespace Slic3r { namespace csg { // Supported CSG operation types enum class CSGType { Union, Difference, Intersection }; +enum class CSGStackOp { Push, Continue, Pop }; // Get the CSG operation of the part. Can be overriden for any type template CSGType get_operation(const CSGPartT &part) @@ -25,6 +26,11 @@ template CSGType get_operation(const CSGPartT &part) return part.operation; } +template CSGStackOp get_stack_operation(const CSGPartT &part) +{ + return part.stack_operation; +} + // Get the mesh for the part. Can be overriden for any type template const indexed_triangle_set *get_mesh(const CSGPartT &part) @@ -48,6 +54,11 @@ inline CSGType get_operation(const indexed_triangle_set &part) return CSGType::Union; } +inline CSGStackOp get_stack_operation(const indexed_triangle_set &part) +{ + return CSGStackOp::Continue; +} + inline const indexed_triangle_set * get_mesh(const indexed_triangle_set &part) { return ∂ @@ -63,6 +74,7 @@ struct CSGPart { AnyPtr its_ptr; Transform3f trafo; CSGType operation; + CSGStackOp stack_operation; CSGPart(AnyPtr ptr = {}, CSGType op = CSGType::Union, diff --git a/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp b/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp index f7247ea70..3d1941294 100644 --- a/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp +++ b/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp @@ -5,13 +5,15 @@ #include "libslic3r/Model.hpp" #include "libslic3r/SLA/Hollowing.hpp" +#include "libslic3r/MeshSplitImpl.hpp" namespace Slic3r { namespace csg { enum ModelParts { mpartsPositive = 1, mpartsNegative = 2, - mpartsDrillHoles = 4 + mpartsDrillHoles = 4, + mpartsDoSplits = 8 }; template @@ -22,20 +24,43 @@ void model_to_csgmesh(const ModelObject &mo, int parts_to_include = mpartsPositive ) { - bool do_positives = parts_to_include & mpartsPositive; - bool do_negatives = parts_to_include & mpartsNegative; + bool do_positives = parts_to_include & mpartsPositive; + bool do_negatives = parts_to_include & mpartsNegative; bool do_drillholes = parts_to_include & mpartsDrillHoles; + bool do_splits = parts_to_include & mpartsDoSplits; for (const ModelVolume *vol : mo.volumes) { if (vol && vol->mesh_ptr() && ((do_positives && vol->is_model_part()) || (do_negatives && vol->is_negative_volume()))) { - CSGPart part{&(vol->mesh().its), - vol->is_model_part() ? CSGType::Union : CSGType::Difference, - (trafo * vol->get_matrix()).cast()}; - *out = std::move(part); - ++out; + if (do_splits && its_is_splittable(vol->mesh().its)) { + CSGPart part_begin{{}, vol->is_model_part() ? CSGType::Union : CSGType::Difference}; + part_begin.stack_operation = CSGStackOp::Push; + *out = std::move(part_begin); + ++out; + + its_split(vol->mesh().its, SplitOutputFn{[&out, &vol, &trafo](indexed_triangle_set &&its) { + CSGPart part{std::make_unique(std::move(its)), + CSGType::Union, + (trafo * vol->get_matrix()).cast()}; + + *out = std::move(part); + ++out; + }}); + + CSGPart part_end{{}}; + part_end.stack_operation = CSGStackOp::Pop; + *out = std::move(part_end); + ++out; + } else { + CSGPart part{&(vol->mesh().its), + vol->is_model_part() ? CSGType::Union : CSGType::Difference, + (trafo * vol->get_matrix()).cast()}; + + *out = std::move(part); + ++out; + } } } diff --git a/src/libslic3r/CSGMesh/SliceCSGMesh.hpp b/src/libslic3r/CSGMesh/SliceCSGMesh.hpp index 76ca22ec4..06302faa4 100644 --- a/src/libslic3r/CSGMesh/SliceCSGMesh.hpp +++ b/src/libslic3r/CSGMesh/SliceCSGMesh.hpp @@ -2,6 +2,9 @@ #define SLICECSGMESH_HPP #include "CSGMesh.hpp" + +#include + #include "libslic3r/TriangleMeshSlicer.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/Execution/ExecutionTBB.hpp" @@ -10,57 +13,107 @@ namespace Slic3r { namespace csg { template std::vector slice_csgmesh_ex( - const Range &csg, + const Range &csgrange, const std::vector &slicegrid, const MeshSlicingParamsEx ¶ms, const std::function &throw_on_cancel = [] {}) { - std::vector ret(slicegrid.size()); + struct Frame { CSGType op; std::vector slices; }; + + std::stack opstack{std::vector{}}; MeshSlicingParamsEx params_cpy = params; auto trafo = params.trafo; auto nonempty_indices = reserve_vector(slicegrid.size()); - for (const auto &m : csg) { - const indexed_triangle_set *its = csg::get_mesh(m); - if (!its) - continue; + if (!csgrange.empty() && csg::get_stack_operation(*csgrange.begin()) != CSGStackOp::Push) + opstack.push({CSGType::Union, std::vector(slicegrid.size())}); - params_cpy.trafo = trafo * csg::get_transform(m).template cast(); - std::vector slices = slice_mesh_ex(*its, - slicegrid, params_cpy, - throw_on_cancel); + for (const auto &csgpart : csgrange) { + const indexed_triangle_set *its = csg::get_mesh(csgpart); - assert(slices.size() == slicegrid.size()); + auto op = get_operation(csgpart); - nonempty_indices.clear(); - for (size_t i = 0; i < slicegrid.size(); ++i) { - if (get_operation(m) == CSGType::Intersection || !slices[i].empty()) - nonempty_indices.emplace_back(i); + if (get_stack_operation(csgpart) == CSGStackOp::Push) { + opstack.push({op, std::vector(slicegrid.size())}); + op = CSGType::Union; } - auto mergefn = [&m, &slices, &ret](size_t i){ - switch(get_operation(m)) { - case CSGType::Union: - for (ExPolygon &expoly : slices[i]) - ret[i].emplace_back(std::move(expoly)); + Frame *top = &opstack.top(); - break; - case CSGType::Difference: - ret[i] = diff_ex(ret[i], slices[i]); - break; - case CSGType::Intersection: - ret[i] = intersection_ex(ret[i], slices[i]); - break; + if (its) { + params_cpy.trafo = trafo * csg::get_transform(csgpart).template cast(); + std::vector slices = slice_mesh_ex(*its, + slicegrid, params_cpy, + throw_on_cancel); + + assert(slices.size() == slicegrid.size()); + + nonempty_indices.clear(); + for (size_t i = 0; i < slicegrid.size(); ++i) { + if (op == CSGType::Intersection || !slices[i].empty()) + nonempty_indices.emplace_back(i); } - }; - execution::for_each(ex_tbb, - nonempty_indices.begin(), nonempty_indices.end(), - mergefn, - execution::max_concurrency(ex_tbb)); + auto mergefn = [&csgpart, &slices, &top](size_t i){ + switch(get_operation(csgpart)) { + case CSGType::Union: + for (ExPolygon &expoly : slices[i]) + top->slices[i].emplace_back(std::move(expoly)); + + break; + case CSGType::Difference: + top->slices[i] = diff_ex(top->slices[i], slices[i]); + break; + case CSGType::Intersection: + top->slices[i] = intersection_ex(top->slices[i], slices[i]); + break; + } + }; + + execution::for_each(ex_tbb, + nonempty_indices.begin(), nonempty_indices.end(), + mergefn, + execution::max_concurrency(ex_tbb)); + } + + if (get_stack_operation(csgpart) == CSGStackOp::Pop) { + std::vector popslices = std::move(top->slices); + auto popop = opstack.top().op; + opstack.pop(); + std::vector &prev_slices = opstack.top().slices; + + nonempty_indices.clear(); + for (size_t i = 0; i < slicegrid.size(); ++i) { + if (popop == CSGType::Intersection || !popslices[i].empty()) + nonempty_indices.emplace_back(i); + } + + auto mergefn2 = [&popslices, &prev_slices, popop](size_t i){ + switch(popop) { + case CSGType::Union: + for (ExPolygon &expoly : popslices[i]) + prev_slices[i].emplace_back(std::move(expoly)); + + break; + case CSGType::Difference: + prev_slices[i] = diff_ex(prev_slices[i], popslices[i]); + break; + case CSGType::Intersection: + prev_slices[i] = intersection_ex(prev_slices[i], popslices[i]); + break; + } + }; + + execution::for_each(ex_tbb, + nonempty_indices.begin(), nonempty_indices.end(), + mergefn2, + execution::max_concurrency(ex_tbb)); + } } + std::vector ret = std::move(opstack.top().slices); + execution::for_each(ex_tbb, ret.begin(), ret.end(), [](ExPolygons &slice) { auto it = std::remove_if(slice.begin(), slice.end(), [](const ExPolygon &p){ return p.area() < double(SCALED_EPSILON) * double(SCALED_EPSILON); diff --git a/src/libslic3r/CSGMesh/VoxelizeCSGMesh.hpp b/src/libslic3r/CSGMesh/VoxelizeCSGMesh.hpp index 0f2e8c898..ac54cf922 100644 --- a/src/libslic3r/CSGMesh/VoxelizeCSGMesh.hpp +++ b/src/libslic3r/CSGMesh/VoxelizeCSGMesh.hpp @@ -2,6 +2,7 @@ #define VOXELIZECSGMESH_HPP #include +#include #include "CSGMesh.hpp" #include "libslic3r/OpenVDBUtils.hpp" @@ -46,29 +47,65 @@ VoxelGridPtr voxelize_csgmesh(const Range &csgrange, }, execution::max_concurrency(ex_tbb)); size_t csgidx = 0; + struct Frame { CSGType op = CSGType::Union; VoxelGridPtr grid; }; + std::stack opstack{std::vector{}}; + + if (!csgrange.empty() && csg::get_stack_operation(*csgrange.begin()) != CSGStackOp::Push) + opstack.push({}); + for (auto &csgpart : csgrange) { if (params.statusfn() && params.statusfn()(-1)) break; auto &partgrid = grids[csgidx++]; - if (!ret && get_operation(csgpart) == CSGType::Union) { - ret = std::move(partgrid); - } else if (ret) { + auto op = get_operation(csgpart); + + if (get_stack_operation(csgpart) == CSGStackOp::Push) { + opstack.push({op, nullptr}); + op = CSGType::Union; + } + + Frame *top = &opstack.top(); + + if (!top->grid && op == CSGType::Union) { + top->grid = std::move(partgrid); + } else if (top->grid && partgrid) { switch (get_operation(csgpart)) { case CSGType::Union: - grid_union(*ret, *partgrid); + grid_union(*(top->grid), *partgrid); break; case CSGType::Difference: - grid_difference(*ret, *partgrid); + grid_difference(*(top->grid), *partgrid); break; case CSGType::Intersection: - grid_intersection(*ret, *partgrid); + grid_intersection(*(top->grid), *partgrid); + break; + } + } + + if (get_stack_operation(csgpart) == CSGStackOp::Pop) { + VoxelGridPtr popgrid = std::move(top->grid); + auto popop = opstack.top().op; + opstack.pop(); + VoxelGridPtr &grid = opstack.top().grid; + + switch (popop) { + case CSGType::Union: + grid_union(*grid, *popgrid); + break; + case CSGType::Difference: + grid_difference(*grid, *popgrid); + break; + case CSGType::Intersection: + grid_intersection(*grid, *popgrid); break; } } } + ret = std::move(opstack.top().grid); + return ret; } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index dc05148fc..f37638fb4 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1114,7 +1114,7 @@ VoxelGridPtr get_voxelgrid(const CSGPartForStep &part, VoxelizeParams p) { VoxelGridPtr &ret = part.gridcache[p]; - if (!ret) { + if (!ret && csg::get_mesh(part)) { p.trafo(csg::get_transform(part)); ret = mesh_to_grid(*csg::get_mesh(part), p); } diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index 215a3bdce..623dee4e6 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -242,7 +242,7 @@ void SLAPrint::Steps::mesh_assembly(SLAPrintObject &po) csg::model_to_csgmesh(*po.model_object(), po.trafo(), csg_inserter{po.m_mesh_to_slice, slaposAssembly}, - csg::mpartsPositive | csg::mpartsNegative); + csg::mpartsPositive | csg::mpartsNegative | csg::mpartsDoSplits); generate_preview(po, slaposAssembly); } @@ -352,9 +352,18 @@ template BoundingBoxf3 csgmesh_positive_bb(const Cont &csg) bounding_box(*csg::get_mesh(*csg.begin()), csg::get_transform(*csg.begin())); + bool skip = false; for (const auto &m : csg) { - if (m.operation == csg::CSGType::Union) + auto op = csg::get_operation(m); + auto stackop = csg::get_stack_operation(m); + if (stackop == csg::CSGStackOp::Push && op != csg::CSGType::Union) + skip = true; + + if (!skip && csg::get_mesh(m) && op == csg::CSGType::Union) bb3d.merge(bounding_box(*csg::get_mesh(m), csg::get_transform(m))); + + if (stackop == csg::CSGStackOp::Pop) + skip = false; } return bb3d;