FInish csg operation stacking in cgal side

Broken slicing
This commit is contained in:
tamasmeszaros 2022-12-21 13:53:33 +01:00
parent 25ca46e3eb
commit d75b951c39
4 changed files with 213 additions and 93 deletions

View File

@ -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;
}

View File

@ -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 &params,
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);

View File

@ -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 &params = {})
{
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);
}
}

View File

@ -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)
{