#ifndef SLICECSGMESH_HPP #define SLICECSGMESH_HPP #include "CSGMesh.hpp" #include #include "libslic3r/TriangleMeshSlicer.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/Execution/ExecutionTBB.hpp" namespace Slic3r { namespace csg { namespace detail { inline void merge_slices(csg::CSGType op, size_t i, std::vector &target, std::vector &source) { switch(op) { case CSGType::Union: for (ExPolygon &expoly : source[i]) target[i].emplace_back(std::move(expoly)); break; case CSGType::Difference: target[i] = diff_ex(target[i], source[i]); break; case CSGType::Intersection: target[i] = intersection_ex(target[i], source[i]); break; } } inline void collect_nonempty_indices(csg::CSGType op, const std::vector &slicegrid, const std::vector &slices, std::vector &indices) { indices.clear(); for (size_t i = 0; i < slicegrid.size(); ++i) { if (op == CSGType::Intersection || !slices[i].empty()) indices.emplace_back(i); } } } // namespace detail template std::vector slice_csgmesh_ex( const Range &csgrange, const std::vector &slicegrid, const MeshSlicingParamsEx ¶ms, const std::function &throw_on_cancel = [] {}) { using namespace detail; 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()); opstack.push({CSGType::Union, std::vector(slicegrid.size())}); for (const auto &csgpart : csgrange) { const indexed_triangle_set *its = csg::get_mesh(csgpart); auto op = get_operation(csgpart); if (get_stack_operation(csgpart) == CSGStackOp::Push) { opstack.push({op, std::vector(slicegrid.size())}); op = CSGType::Union; } Frame *top = &opstack.top(); 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()); collect_nonempty_indices(op, slicegrid, slices, nonempty_indices); execution::for_each( ex_tbb, nonempty_indices.begin(), nonempty_indices.end(), [op, &slices, &top](size_t i) { merge_slices(op, i, top->slices, slices); }, 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; collect_nonempty_indices(popop, slicegrid, popslices, nonempty_indices); execution::for_each( ex_tbb, nonempty_indices.begin(), nonempty_indices.end(), [&popslices, &prev_slices, popop](size_t i) { merge_slices(popop, i, prev_slices, popslices); }, execution::max_concurrency(ex_tbb)); } } std::vector ret = std::move(opstack.top().slices); // TODO: verify if this part can be omitted or not. 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); }); // Hopefully, ExPolygons are moved, not copied to new positions // and that is cheap for expolygons slice.erase(it, slice.end()); slice = union_ex(slice); }, execution::max_concurrency(ex_tbb)); return ret; } }} // namespace Slic3r::csg #endif // SLICECSGMESH_HPP