mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-23 06:33:57 -06:00
Merge some BS1.7 changes:
internal_solid_infill_pattern
This commit is contained in:
parent
7ece35931e
commit
bcbbbf35db
95 changed files with 44122 additions and 693 deletions
375
src/libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp
Normal file
375
src/libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp
Normal file
|
@ -0,0 +1,375 @@
|
|||
#ifndef PERFORMCSGMESHBOOLEANS_HPP
|
||||
#define PERFORMCSGMESHBOOLEANS_HPP
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
#include "CSGMesh.hpp"
|
||||
|
||||
#include "libslic3r/Execution/ExecutionTBB.hpp"
|
||||
//#include "libslic3r/Execution/ExecutionSeq.hpp"
|
||||
#include "libslic3r/MeshBoolean.hpp"
|
||||
|
||||
namespace Slic3r { namespace csg {
|
||||
|
||||
// This method can be overriden when a specific CSGPart type supports caching
|
||||
// of the voxel grid
|
||||
template<class CSGPartT>
|
||||
MeshBoolean::cgal::CGALMeshPtr get_cgalmesh(const CSGPartT &csgpart)
|
||||
{
|
||||
const indexed_triangle_set *its = csg::get_mesh(csgpart);
|
||||
indexed_triangle_set dummy;
|
||||
|
||||
if (!its)
|
||||
its = &dummy;
|
||||
|
||||
MeshBoolean::cgal::CGALMeshPtr ret;
|
||||
|
||||
indexed_triangle_set m = *its;
|
||||
its_transform(m, get_transform(csgpart), true);
|
||||
|
||||
try {
|
||||
ret = MeshBoolean::cgal::triangle_mesh_to_cgal(m);
|
||||
} catch (...) {
|
||||
// errors are ignored, simply return null
|
||||
ret = nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This method can be overriden when a specific CSGPart type supports caching
|
||||
// of the voxel grid
|
||||
template<class CSGPartT>
|
||||
MeshBoolean::mcut::McutMeshPtr get_mcutmesh(const CSGPartT& csgpart)
|
||||
{
|
||||
const indexed_triangle_set* its = csg::get_mesh(csgpart);
|
||||
indexed_triangle_set dummy;
|
||||
|
||||
if (!its)
|
||||
its = &dummy;
|
||||
|
||||
MeshBoolean::mcut::McutMeshPtr ret;
|
||||
|
||||
indexed_triangle_set m = *its;
|
||||
its_transform(m, get_transform(csgpart), true);
|
||||
|
||||
try {
|
||||
ret = MeshBoolean::mcut::triangle_mesh_to_mcut(m);
|
||||
}
|
||||
catch (...) {
|
||||
// errors are ignored, simply return null
|
||||
ret = nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
namespace detail_cgal {
|
||||
|
||||
using MeshBoolean::cgal::CGALMeshPtr;
|
||||
|
||||
inline void perform_csg(CSGType op, CGALMeshPtr &dst, CGALMeshPtr &src)
|
||||
{
|
||||
if (!dst && op == CSGType::Union && src) {
|
||||
dst = std::move(src);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dst || !src)
|
||||
return;
|
||||
|
||||
switch (op) {
|
||||
case CSGType::Union:
|
||||
MeshBoolean::cgal::plus(*dst, *src);
|
||||
break;
|
||||
case CSGType::Difference:
|
||||
MeshBoolean::cgal::minus(*dst, *src);
|
||||
break;
|
||||
case CSGType::Intersection:
|
||||
MeshBoolean::cgal::intersect(*dst, *src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<class Ex, class It>
|
||||
std::vector<CGALMeshPtr> get_cgalptrs(Ex policy, const Range<It> &csgrange)
|
||||
{
|
||||
std::vector<CGALMeshPtr> ret(csgrange.size());
|
||||
execution::for_each(policy, size_t(0), csgrange.size(),
|
||||
[&csgrange, &ret](size_t i) {
|
||||
auto it = csgrange.begin();
|
||||
std::advance(it, i);
|
||||
auto &csgpart = *it;
|
||||
ret[i] = get_cgalmesh(csgpart);
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace detail_mcut {
|
||||
|
||||
using MeshBoolean::mcut::McutMeshPtr;
|
||||
|
||||
inline void perform_csg(CSGType op, McutMeshPtr& dst, McutMeshPtr& src)
|
||||
{
|
||||
if (!dst && op == CSGType::Union && src) {
|
||||
dst = std::move(src);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dst || !src)
|
||||
return;
|
||||
|
||||
switch (op) {
|
||||
case CSGType::Union:
|
||||
MeshBoolean::mcut::do_boolean(*dst, *src,"UNION");
|
||||
break;
|
||||
case CSGType::Difference:
|
||||
MeshBoolean::mcut::do_boolean(*dst, *src,"A_NOT_B");
|
||||
break;
|
||||
case CSGType::Intersection:
|
||||
MeshBoolean::mcut::do_boolean(*dst, *src,"INTERSECTION");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<class Ex, class It>
|
||||
std::vector<McutMeshPtr> get_mcutptrs(Ex policy, const Range<It>& csgrange)
|
||||
{
|
||||
std::vector<McutMeshPtr> ret(csgrange.size());
|
||||
execution::for_each(policy, size_t(0), csgrange.size(),
|
||||
[&csgrange, &ret](size_t i) {
|
||||
auto it = csgrange.begin();
|
||||
std::advance(it, i);
|
||||
auto& csgpart = *it;
|
||||
ret[i] = get_mcutmesh(csgpart);
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace mcut_detail
|
||||
|
||||
// Process the sequence of CSG parts with CGAL.
|
||||
template<class It>
|
||||
void perform_csgmesh_booleans_cgal(MeshBoolean::cgal::CGALMeshPtr &cgalm,
|
||||
const Range<It> &csgrange)
|
||||
{
|
||||
using MeshBoolean::cgal::CGALMesh;
|
||||
using MeshBoolean::cgal::CGALMeshPtr;
|
||||
using namespace detail_cgal;
|
||||
|
||||
struct Frame {
|
||||
CSGType op; CGALMeshPtr cgalptr;
|
||||
explicit Frame(CSGType csgop = CSGType::Union)
|
||||
: op{ csgop }
|
||||
, cgalptr{ MeshBoolean::cgal::triangle_mesh_to_cgal(indexed_triangle_set{}) }
|
||||
{}
|
||||
};
|
||||
|
||||
std::stack opstack{ std::vector<Frame>{} };
|
||||
|
||||
opstack.push(Frame{});
|
||||
|
||||
std::vector<CGALMeshPtr> cgalmeshes = get_cgalptrs(ex_tbb, csgrange);
|
||||
|
||||
size_t csgidx = 0;
|
||||
for (auto& csgpart : csgrange) {
|
||||
|
||||
auto op = get_operation(csgpart);
|
||||
CGALMeshPtr& cgalptr = cgalmeshes[csgidx++];
|
||||
|
||||
if (get_stack_operation(csgpart) == CSGStackOp::Push) {
|
||||
opstack.push(Frame{ op });
|
||||
op = CSGType::Union;
|
||||
}
|
||||
|
||||
Frame* top = &opstack.top();
|
||||
|
||||
perform_csg(get_operation(csgpart), top->cgalptr, cgalptr);
|
||||
|
||||
if (get_stack_operation(csgpart) == CSGStackOp::Pop) {
|
||||
CGALMeshPtr src = std::move(top->cgalptr);
|
||||
auto popop = opstack.top().op;
|
||||
opstack.pop();
|
||||
CGALMeshPtr& dst = opstack.top().cgalptr;
|
||||
perform_csg(popop, dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
cgalm = std::move(opstack.top().cgalptr);
|
||||
}
|
||||
|
||||
// Process the sequence of CSG parts with mcut.
|
||||
template<class It>
|
||||
void perform_csgmesh_booleans_mcut(MeshBoolean::mcut::McutMeshPtr& mcutm,
|
||||
const Range<It>& csgrange)
|
||||
{
|
||||
using MeshBoolean::mcut::McutMesh;
|
||||
using MeshBoolean::mcut::McutMeshPtr;
|
||||
using namespace detail_mcut;
|
||||
|
||||
struct Frame {
|
||||
CSGType op; McutMeshPtr mcutptr;
|
||||
explicit Frame(CSGType csgop = CSGType::Union)
|
||||
: op{ csgop }
|
||||
, mcutptr{ MeshBoolean::mcut::triangle_mesh_to_mcut(indexed_triangle_set{}) }
|
||||
{}
|
||||
};
|
||||
|
||||
std::stack opstack{ std::vector<Frame>{} };
|
||||
|
||||
opstack.push(Frame{});
|
||||
|
||||
std::vector<McutMeshPtr> McutMeshes = get_mcutptrs(ex_tbb, csgrange);
|
||||
|
||||
size_t csgidx = 0;
|
||||
for (auto& csgpart : csgrange) {
|
||||
|
||||
auto op = get_operation(csgpart);
|
||||
McutMeshPtr& mcutptr = McutMeshes[csgidx++];
|
||||
|
||||
if (get_stack_operation(csgpart) == CSGStackOp::Push) {
|
||||
opstack.push(Frame{ op });
|
||||
op = CSGType::Union;
|
||||
}
|
||||
|
||||
Frame* top = &opstack.top();
|
||||
|
||||
perform_csg(get_operation(csgpart), top->mcutptr, mcutptr);
|
||||
|
||||
if (get_stack_operation(csgpart) == CSGStackOp::Pop) {
|
||||
McutMeshPtr src = std::move(top->mcutptr);
|
||||
auto popop = opstack.top().op;
|
||||
opstack.pop();
|
||||
McutMeshPtr& dst = opstack.top().mcutptr;
|
||||
perform_csg(popop, dst, src);
|
||||
}
|
||||
}
|
||||
|
||||
mcutm = std::move(opstack.top().mcutptr);
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<class It, class Visitor>
|
||||
It check_csgmesh_booleans(const Range<It> &csgrange, Visitor &&vfn)
|
||||
{
|
||||
using namespace detail_cgal;
|
||||
|
||||
std::vector<CGALMeshPtr> cgalmeshes(csgrange.size());
|
||||
auto check_part = [&csgrange, &cgalmeshes](size_t i)
|
||||
{
|
||||
auto it = csgrange.begin();
|
||||
std::advance(it, i);
|
||||
auto &csgpart = *it;
|
||||
auto m = get_cgalmesh(csgpart);
|
||||
|
||||
// mesh can be nullptr if this is a stack push or pull
|
||||
if (!get_mesh(csgpart) && get_stack_operation(csgpart) != CSGStackOp::Continue) {
|
||||
cgalmeshes[i] = MeshBoolean::cgal::triangle_mesh_to_cgal(indexed_triangle_set{});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!m || MeshBoolean::cgal::empty(*m))
|
||||
return;
|
||||
|
||||
if (!MeshBoolean::cgal::does_bound_a_volume(*m))
|
||||
return;
|
||||
|
||||
if (MeshBoolean::cgal::does_self_intersect(*m))
|
||||
return;
|
||||
}
|
||||
catch (...) { return; }
|
||||
|
||||
cgalmeshes[i] = std::move(m);
|
||||
};
|
||||
execution::for_each(ex_tbb, size_t(0), csgrange.size(), check_part);
|
||||
|
||||
It ret = csgrange.end();
|
||||
for (size_t i = 0; i < csgrange.size(); ++i) {
|
||||
if (!cgalmeshes[i]) {
|
||||
auto it = csgrange.begin();
|
||||
std::advance(it, i);
|
||||
vfn(it);
|
||||
|
||||
if (ret == csgrange.end())
|
||||
ret = it;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<class It>
|
||||
It check_csgmesh_booleans(const Range<It> &csgrange, bool use_mcut=false)
|
||||
{
|
||||
if(!use_mcut)
|
||||
return check_csgmesh_booleans(csgrange, [](auto &) {});
|
||||
else {
|
||||
using namespace detail_mcut;
|
||||
|
||||
std::vector<McutMeshPtr> McutMeshes(csgrange.size());
|
||||
auto check_part = [&csgrange, &McutMeshes](size_t i) {
|
||||
auto it = csgrange.begin();
|
||||
std::advance(it, i);
|
||||
auto& csgpart = *it;
|
||||
auto m = get_mcutmesh(csgpart);
|
||||
|
||||
// mesh can be nullptr if this is a stack push or pull
|
||||
if (!get_mesh(csgpart) && get_stack_operation(csgpart) != CSGStackOp::Continue) {
|
||||
McutMeshes[i] = MeshBoolean::mcut::triangle_mesh_to_mcut(indexed_triangle_set{});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!m || MeshBoolean::mcut::empty(*m))
|
||||
return;
|
||||
}
|
||||
catch (...) { return; }
|
||||
|
||||
McutMeshes[i] = std::move(m);
|
||||
};
|
||||
execution::for_each(ex_tbb, size_t(0), csgrange.size(), check_part);
|
||||
|
||||
It ret = csgrange.end();
|
||||
for (size_t i = 0; i < csgrange.size(); ++i) {
|
||||
if (!McutMeshes[i]) {
|
||||
auto it = csgrange.begin();
|
||||
std::advance(it, i);
|
||||
|
||||
if (ret == csgrange.end())
|
||||
ret = it;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
template<class It>
|
||||
MeshBoolean::cgal::CGALMeshPtr perform_csgmesh_booleans(const Range<It> &csgparts)
|
||||
{
|
||||
auto ret = MeshBoolean::cgal::triangle_mesh_to_cgal(indexed_triangle_set{});
|
||||
if (ret)
|
||||
perform_csgmesh_booleans_cgal(ret, csgparts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<class It>
|
||||
MeshBoolean::mcut::McutMeshPtr perform_csgmesh_booleans_mcut(const Range<It>& csgparts)
|
||||
{
|
||||
auto ret = MeshBoolean::mcut::triangle_mesh_to_mcut(indexed_triangle_set{});
|
||||
if (ret)
|
||||
perform_csgmesh_booleans_mcut(ret, csgparts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace csg
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // PERFORMCSGMESHBOOLEANS_HPP
|
Loading…
Add table
Add a link
Reference in a new issue