FInish csg operation stacking in cgal side
Broken slicing
This commit is contained in:
parent
25ca46e3eb
commit
d75b951c39
@ -1,8 +1,12 @@
|
||||
#ifndef PERFORMCSGMESHBOOLEANS_HPP
|
||||
#define PERFORMCSGMESHBOOLEANS_HPP
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
#include "CSGMesh.hpp"
|
||||
|
||||
#include "libslic3r/Execution/ExecutionTBB.hpp"
|
||||
#include "libslic3r/MeshBoolean.hpp"
|
||||
|
||||
namespace Slic3r { namespace csg {
|
||||
@ -24,26 +28,134 @@ MeshBoolean::cgal::CGALMeshPtr get_cgalmesh(const CSGPartT &csgpart)
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<class It>
|
||||
void perform_csgmesh_booleans(MeshBoolean::cgal::CGALMesh &cgalm,
|
||||
const Range<It> &csgparts)
|
||||
namespace detail_cgal {
|
||||
|
||||
using MeshBoolean::cgal::CGALMeshPtr;
|
||||
|
||||
inline void perform_csg(CSGType op, CGALMeshPtr &dst, CGALMeshPtr &src)
|
||||
{
|
||||
for (auto &csgpart : csgparts) {
|
||||
auto m = get_cgalmesh(csgpart);
|
||||
if (m) {
|
||||
switch (get_operation(csgpart)) {
|
||||
case CSGType::Union:
|
||||
MeshBoolean::cgal::plus(cgalm, *m);
|
||||
break;
|
||||
case CSGType::Difference:
|
||||
MeshBoolean::cgal::minus(cgalm, *m);
|
||||
break;
|
||||
case CSGType::Intersection:
|
||||
MeshBoolean::cgal::intersect(cgalm, *m);
|
||||
break;
|
||||
}
|
||||
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
|
||||
|
||||
template<class It>
|
||||
void perform_csgmesh_booleans(MeshBoolean::cgal::CGALMeshPtr &cgalm,
|
||||
const Range<It> &csgrange)
|
||||
{
|
||||
using MeshBoolean::cgal::CGALMesh;
|
||||
using MeshBoolean::cgal::CGALMeshPtr;
|
||||
using namespace detail_cgal;
|
||||
|
||||
struct Frame { CSGType op = CSGType::Union; CGALMeshPtr cgalptr; };
|
||||
|
||||
std::stack opstack{std::vector<Frame>{}};
|
||||
|
||||
if (!csgrange.empty() &&
|
||||
csg::get_stack_operation(*csgrange.begin()) != CSGStackOp::Push)
|
||||
opstack.push({});
|
||||
|
||||
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({op, nullptr});
|
||||
op = CSGType::Union;
|
||||
}
|
||||
|
||||
Frame *top = &opstack.top();
|
||||
|
||||
if (!top->cgalptr && op == CSGType::Union) {
|
||||
top->cgalptr = std::move(cgalptr);
|
||||
} else if (top->cgalptr && cgalptr) {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!m || MeshBoolean::cgal::empty(*m))
|
||||
return;
|
||||
|
||||
if (!MeshBoolean::cgal::does_bound_a_volume(*m) ||
|
||||
MeshBoolean::cgal::does_self_intersect(*m))
|
||||
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 (it == csgrange.end())
|
||||
ret = it;
|
||||
}
|
||||
}
|
||||
|
||||
return csgrange.end();
|
||||
}
|
||||
|
||||
template<class It>
|
||||
It check_csgmesh_booleans(const Range<It> &csgrange)
|
||||
{
|
||||
return check_csgmesh_booleans(csgrange, [](auto &) {});
|
||||
}
|
||||
|
||||
template<class It>
|
||||
@ -51,7 +163,7 @@ MeshBoolean::cgal::CGALMeshPtr perform_csgmesh_booleans(const Range<It> &csgpart
|
||||
{
|
||||
auto ret = MeshBoolean::cgal::triangle_mesh_to_cgal(indexed_triangle_set{});
|
||||
if (ret)
|
||||
perform_csgmesh_booleans(*ret, csgparts);
|
||||
perform_csgmesh_booleans(ret, csgparts);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -11,6 +11,40 @@
|
||||
|
||||
namespace Slic3r { namespace csg {
|
||||
|
||||
namespace detail {
|
||||
|
||||
void merge_slices(csg::CSGType op, size_t i,
|
||||
std::vector<ExPolygons> &target,
|
||||
std::vector<ExPolygons> &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;
|
||||
}
|
||||
}
|
||||
|
||||
void collect_nonempty_indices(csg::CSGType op,
|
||||
const std::vector<float> &slicegrid,
|
||||
const std::vector<ExPolygons> &slices,
|
||||
std::vector<size_t> 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<class ItCSG>
|
||||
std::vector<ExPolygons> slice_csgmesh_ex(
|
||||
const Range<ItCSG> &csgrange,
|
||||
@ -18,6 +52,8 @@ std::vector<ExPolygons> slice_csgmesh_ex(
|
||||
const MeshSlicingParamsEx ¶ms,
|
||||
const std::function<void()> &throw_on_cancel = [] {})
|
||||
{
|
||||
using namespace detail;
|
||||
|
||||
struct Frame { CSGType op; std::vector<ExPolygons> slices; };
|
||||
|
||||
std::stack opstack{std::vector<Frame>{}};
|
||||
@ -49,32 +85,13 @@ std::vector<ExPolygons> slice_csgmesh_ex(
|
||||
|
||||
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);
|
||||
}
|
||||
collect_nonempty_indices(op, slicegrid, slices, nonempty_indices);
|
||||
|
||||
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));
|
||||
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) {
|
||||
@ -83,37 +100,19 @@ std::vector<ExPolygons> slice_csgmesh_ex(
|
||||
opstack.pop();
|
||||
std::vector<ExPolygons> &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);
|
||||
}
|
||||
collect_nonempty_indices(popop, slicegrid, popslices, nonempty_indices);
|
||||
|
||||
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));
|
||||
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<ExPolygons> 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);
|
||||
|
@ -28,10 +28,31 @@ VoxelGridPtr get_voxelgrid(const CSGPartT &csgpart, VoxelizeParams params)
|
||||
return ret;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline void perform_csg(CSGType op, VoxelGridPtr &dst, VoxelGridPtr &src)
|
||||
{
|
||||
switch (op) {
|
||||
case CSGType::Union:
|
||||
grid_union(*dst, *src);
|
||||
break;
|
||||
case CSGType::Difference:
|
||||
grid_difference(*dst, *src);
|
||||
break;
|
||||
case CSGType::Intersection:
|
||||
grid_intersection(*dst, *src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class It>
|
||||
VoxelGridPtr voxelize_csgmesh(const Range<It> &csgrange,
|
||||
const VoxelizeParams ¶ms = {})
|
||||
{
|
||||
using namespace detail;
|
||||
|
||||
VoxelGridPtr ret;
|
||||
|
||||
std::vector<VoxelGridPtr> grids (csgrange.size());
|
||||
@ -50,7 +71,8 @@ VoxelGridPtr voxelize_csgmesh(const Range<It> &csgrange,
|
||||
struct Frame { CSGType op = CSGType::Union; VoxelGridPtr grid; };
|
||||
std::stack opstack{std::vector<Frame>{}};
|
||||
|
||||
if (!csgrange.empty() && csg::get_stack_operation(*csgrange.begin()) != CSGStackOp::Push)
|
||||
if (!csgrange.empty() &&
|
||||
csg::get_stack_operation(*csgrange.begin()) != CSGStackOp::Push)
|
||||
opstack.push({});
|
||||
|
||||
for (auto &csgpart : csgrange) {
|
||||
@ -71,17 +93,7 @@ VoxelGridPtr voxelize_csgmesh(const Range<It> &csgrange,
|
||||
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(*(top->grid), *partgrid);
|
||||
break;
|
||||
case CSGType::Difference:
|
||||
grid_difference(*(top->grid), *partgrid);
|
||||
break;
|
||||
case CSGType::Intersection:
|
||||
grid_intersection(*(top->grid), *partgrid);
|
||||
break;
|
||||
}
|
||||
perform_csg(get_operation(csgpart), top->grid, partgrid);
|
||||
}
|
||||
|
||||
if (get_stack_operation(csgpart) == CSGStackOp::Pop) {
|
||||
@ -89,18 +101,7 @@ VoxelGridPtr voxelize_csgmesh(const Range<It> &csgrange,
|
||||
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;
|
||||
}
|
||||
perform_csg(popop, grid, popgrid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,7 +206,15 @@ indexed_triangle_set SLAPrint::Steps::generate_preview_vdb(
|
||||
|
||||
void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep step)
|
||||
{
|
||||
po.m_preview_meshes[step] = TriangleMesh{generate_preview_vdb(po, step)};
|
||||
auto r = range(po.m_mesh_to_slice);
|
||||
if (csg::check_csgmesh_booleans(r) == r.end()) {
|
||||
auto cgalmesh = csg::perform_csgmesh_booleans(r);
|
||||
po.m_preview_meshes[step] = MeshBoolean::cgal::cgal_to_triangle_mesh(*cgalmesh);
|
||||
} else {
|
||||
po.active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL,
|
||||
L("Can't do proper mesh booleans!"));
|
||||
po.m_preview_meshes[step] = TriangleMesh{generate_preview_vdb(po, step)};
|
||||
}
|
||||
|
||||
for (size_t i = size_t(step) + 1; i < slaposCount; ++i)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user