WIP on removing unused parts of pad

This commit is contained in:
tamasmeszaros 2019-06-17 18:06:52 +02:00
parent 90a854f704
commit 778b2cf293
5 changed files with 254 additions and 92 deletions

View File

@ -666,24 +666,19 @@ Polygons concave_hull(const Polygons& polys, double max_dist_mm = 50,
return punion;
}
void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
float layerh, ThrowOnCancel thrfn)
void base_plate(const TriangleMesh & mesh,
ExPolygons & output,
const std::vector<float> &heights,
ThrowOnCancel thrfn)
{
TriangleMesh m = mesh;
m.require_shared_vertices(); // TriangleMeshSlicer needs this
TriangleMeshSlicer slicer(&m);
auto bb = mesh.bounding_box();
float gnd = float(bb.min(Z));
std::vector<float> heights = {float(bb.min(Z))};
for(float hi = gnd + layerh; hi <= gnd + h; hi += layerh)
heights.emplace_back(hi);
std::vector<ExPolygons> out; out.reserve(size_t(std::ceil(h/layerh)));
// m.require_shared_vertices(); // TriangleMeshSlicer needs this
TriangleMeshSlicer slicer(&mesh);
std::vector<ExPolygons> out; out.reserve(heights.size());
slicer.slice(heights, 0.f, &out, thrfn);
size_t count = 0; for(auto& o : out) count += o.size();
// Now we have to unify all slice layers which can be an expensive operation
// so we will try to simplify the polygons
ExPolygons tmp; tmp.reserve(count);
@ -692,15 +687,31 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
auto&& exss = e.simplify(scaled(0.1));
for(ExPolygon& ep : exss) tmp.emplace_back(std::move(ep));
}
ExPolygons utmp = unify(tmp);
for(auto& o : utmp) {
auto&& smp = o.simplify(scaled(0.1));
output.insert(output.end(), smp.begin(), smp.end());
}
}
void base_plate(const TriangleMesh &mesh,
ExPolygons & output,
float h,
float layerh,
ThrowOnCancel thrfn)
{
auto bb = mesh.bounding_box();
float gnd = float(bb.min(Z));
std::vector<float> heights = {float(bb.min(Z))};
for(float hi = gnd + layerh; hi <= gnd + h; hi += layerh)
heights.emplace_back(hi);
base_plate(mesh, output, heights, thrfn);
}
Contour3D create_base_pool(const Polygons &ground_layer,
const ExPolygons &obj_self_pad = {},
const PoolConfig& cfg = PoolConfig())

View File

@ -21,10 +21,15 @@ using ThrowOnCancel = std::function<void(void)>;
/// Calculate the polygon representing the silhouette from the specified height
void base_plate(const TriangleMesh& mesh, // input mesh
ExPolygons& output, // Output will be merged with
float zlevel = 0.1f, // Plate creation level
float samplingheight = 0.1f, // The height range to sample
float layerheight = 0.05f, // The sampling height
ThrowOnCancel thrfn = [](){}); // Will be called frequently
void base_plate(const TriangleMesh& mesh, // input mesh
ExPolygons& output, // Output will be merged with
const std::vector<float>&, // Exact Z levels to sample
ThrowOnCancel thrfn = [](){}); // Will be called frequently
// Function to cut tiny connector cavities for a given polygon. The input poly
// will be offsetted by "padding" and small rectangle shaped cavities will be
// inserted along the perimeter in every "stride" distance. The stick rectangles

View File

@ -7,13 +7,15 @@
#include <Eigen/Geometry>
#include <libslic3r/BoundingBox.hpp>
namespace Slic3r {
namespace sla {
typedef Eigen::Matrix<double, 3, 1, Eigen::DontAlign> Vec3d;
using SpatElement = std::pair<Vec3d, unsigned>;
using PointIndexEl = std::pair<Vec3d, unsigned>;
class SpatIndex {
class PointIndex {
class Impl;
// We use Pimpl because it takes a long time to compile boost headers which
@ -21,30 +23,67 @@ class SpatIndex {
std::unique_ptr<Impl> m_impl;
public:
SpatIndex();
~SpatIndex();
PointIndex();
~PointIndex();
SpatIndex(const SpatIndex&);
SpatIndex(SpatIndex&&);
SpatIndex& operator=(const SpatIndex&);
SpatIndex& operator=(SpatIndex&&);
PointIndex(const PointIndex&);
PointIndex(PointIndex&&);
PointIndex& operator=(const PointIndex&);
PointIndex& operator=(PointIndex&&);
void insert(const SpatElement&);
bool remove(const SpatElement&);
void insert(const PointIndexEl&);
bool remove(const PointIndexEl&);
inline void insert(const Vec3d& v, unsigned idx)
{
insert(std::make_pair(v, unsigned(idx)));
}
std::vector<SpatElement> query(std::function<bool(const SpatElement&)>);
std::vector<SpatElement> nearest(const Vec3d&, unsigned k);
std::vector<PointIndexEl> query(std::function<bool(const PointIndexEl&)>);
std::vector<PointIndexEl> nearest(const Vec3d&, unsigned k);
// For testing
size_t size() const;
bool empty() const { return size() == 0; }
void foreach(std::function<void(const SpatElement& el)> fn);
void foreach(std::function<void(const PointIndexEl& el)> fn);
};
using BoxIndexEl = std::pair<Slic3r::BoundingBox, unsigned>;
class BoxIndex {
class Impl;
// We use Pimpl because it takes a long time to compile boost headers which
// is the engine of this class. We include it only in the cpp file.
std::unique_ptr<Impl> m_impl;
public:
BoxIndex();
~BoxIndex();
BoxIndex(const BoxIndex&);
BoxIndex(BoxIndex&&);
BoxIndex& operator=(const BoxIndex&);
BoxIndex& operator=(BoxIndex&&);
void insert(const BoxIndexEl&);
inline void insert(const BoundingBox& bb, unsigned idx)
{
insert(std::make_pair(bb, unsigned(idx)));
}
bool remove(const BoxIndexEl&);
enum QueryType { qtIntersects, qtWithin };
std::vector<BoxIndexEl> query(const BoundingBox&, QueryType qt);
// For testing
size_t size() const;
bool empty() const { return size() == 0; }
void foreach(std::function<void(const BoxIndexEl& el)> fn);
};
}

View File

@ -569,37 +569,74 @@ struct Pad {
sla::get_pad_elevation(pcfg))
{
Polygons basep;
cfg.throw_on_cancel();
auto &thr = cfg.throw_on_cancel;
// The 0.1f is the layer height with which the mesh is sampled and then
// the layers are unified into one vector of polygons.
ExPolygons platetmp;
base_plate(object_support_mesh, platetmp,
float(cfg.min_wall_height_mm + cfg.min_wall_thickness_mm),
0.1f, pcfg.throw_on_cancel);
thr();
for (const ExPolygon &bp : platetmp) basep.emplace_back(bp.contour);
// Get a sample for the pad from the support mesh
{
ExPolygons platetmp;
float plateZ = float(get_pad_fullheight(pcfg) + EPSILON);
base_plate(object_support_mesh, platetmp, plateZ, 0.1f, thr);
// We don't need no... holes control...
for (const ExPolygon &bp : platetmp)
basep.emplace_back(std::move(bp.contour));
}
if(pcfg.embed_object) {
ExPolygons modelbase_sticks = modelbase;
// If the zero elevation mode is ON, we need to process the model
// base silhouette. Create the offsetted version and punch the
// breaksticks across its perimeter.
ExPolygons modelbase_sticks = modelbase;
if (pcfg.embed_object.object_gap_mm > 0.0)
modelbase_sticks
= offset_ex(modelbase_sticks,
coord_t(pcfg.embed_object.object_gap_mm
/ SCALING_FACTOR));
float(scaled(pcfg.embed_object.object_gap_mm)));
BoxIndex bindex;
{
unsigned idx = 0;
for(auto &bp : basep) {
auto bb = bp.bounding_box();
bb.offset(float(scaled(pcfg.min_wall_thickness_mm)));
bindex.insert(bb, idx++);
}
}
ExPolygons pad_stickholes; pad_stickholes.reserve(modelbase.size());
for(auto& poly : modelbase_sticks) {
basep.emplace_back(poly.contour);
sla::breakstick_holes(
poly,
pcfg.embed_object.object_gap_mm, // padding
pcfg.embed_object.stick_stride_mm,
pcfg.embed_object.stick_width_mm,
pcfg.embed_object.stick_penetration_mm);
if (!bindex.query(poly.contour.bounding_box(),
BoxIndex::qtIntersects).empty()) {
basep.emplace_back(poly.contour);
auto it = poly.holes.begin();
while(it != poly.holes.end()) {
if (bindex.query(it->bounding_box(),
BoxIndex::qtIntersects).empty())
it = poly.holes.erase(it);
else
++it;
}
sla::breakstick_holes(
poly,
pcfg.embed_object.object_gap_mm, // padding
pcfg.embed_object.stick_stride_mm,
pcfg.embed_object.stick_width_mm,
pcfg.embed_object.stick_penetration_mm);
pad_stickholes.emplace_back(poly);
}
}
create_base_pool(basep, tmesh, modelbase_sticks, cfg);
create_base_pool(basep, tmesh, pad_stickholes, cfg);
} else {
for (const ExPolygon &bp : modelbase) basep.emplace_back(bp.contour);
create_base_pool(basep, tmesh, {}, cfg);
@ -630,7 +667,7 @@ inline Vec2d to_vec2(const Vec3d& v3) {
return {v3(X), v3(Y)};
}
bool operator==(const SpatElement& e1, const SpatElement& e2) {
bool operator==(const PointIndexEl& e1, const PointIndexEl& e2) {
return e1.second == e2.second;
}
@ -647,7 +684,7 @@ ClusteredPoints cluster(const PointSet& points,
ClusteredPoints cluster(
const std::vector<unsigned>& indices,
std::function<Vec3d(unsigned)> pointfn,
std::function<bool(const SpatElement&, const SpatElement&)> predicate,
std::function<bool(const PointIndexEl&, const PointIndexEl&)> predicate,
unsigned max_points);
// This class will hold the support tree meshes with some additional bookkeeping
@ -974,7 +1011,7 @@ class SLASupportTree::Algorithm {
ThrowOnCancel m_thr;
// A spatial index to easily find strong pillars to connect to.
SpatIndex m_pillar_index;
PointIndex m_pillar_index;
inline double ray_mesh_intersect(const Vec3d& s,
const Vec3d& dir)
@ -1367,7 +1404,7 @@ class SLASupportTree::Algorithm {
}
bool search_pillar_and_connect(const Head& head) {
SpatIndex spindex = m_pillar_index;
PointIndex spindex = m_pillar_index;
long nearest_id = -1;
@ -1747,8 +1784,8 @@ public:
return m_result.head(i).junction_point();
};
auto predicate = [this](const SpatElement &e1,
const SpatElement &e2) {
auto predicate = [this](const PointIndexEl &e1,
const PointIndexEl &e2) {
double d2d = distance(to_2d(e1.first), to_2d(e2.first));
double d3d = distance(e1.first, e2.first);
return d2d < 2 * m_cfg.base_radius_mm
@ -2070,7 +2107,7 @@ public:
// be connected multiple times this is ensured by the 'pairs' set which
// remembers the processed pillar pairs
auto cascadefn =
[this, d, &pairs, min_height_ratio, H1] (const SpatElement& el)
[this, d, &pairs, min_height_ratio, H1] (const PointIndexEl& el)
{
Vec3d qp = el.first; // endpoint of the pillar
@ -2083,13 +2120,13 @@ public:
if(pillar.links >= neighbors) return;
// Query all remaining points within reach
auto qres = m_pillar_index.query([qp, d](const SpatElement& e){
auto qres = m_pillar_index.query([qp, d](const PointIndexEl& e){
return distance(e.first, qp) < d;
});
// sort the result by distance (have to check if this is needed)
std::sort(qres.begin(), qres.end(),
[qp](const SpatElement& e1, const SpatElement& e2){
[qp](const PointIndexEl& e1, const PointIndexEl& e2){
return distance(e1.first, qp) < distance(e2.first, qp);
});

View File

@ -29,69 +29,137 @@ namespace sla {
using igl::PI;
/* **************************************************************************
* SpatIndex implementation
* PointIndex implementation
* ************************************************************************** */
class SpatIndex::Impl {
class PointIndex::Impl {
public:
using BoostIndex = boost::geometry::index::rtree< SpatElement,
using BoostIndex = boost::geometry::index::rtree< PointIndexEl,
boost::geometry::index::rstar<16, 4> /* ? */ >;
BoostIndex m_store;
};
SpatIndex::SpatIndex(): m_impl(new Impl()) {}
SpatIndex::~SpatIndex() {}
PointIndex::PointIndex(): m_impl(new Impl()) {}
PointIndex::~PointIndex() {}
SpatIndex::SpatIndex(const SpatIndex &cpy): m_impl(new Impl(*cpy.m_impl)) {}
SpatIndex::SpatIndex(SpatIndex&& cpy): m_impl(std::move(cpy.m_impl)) {}
PointIndex::PointIndex(const PointIndex &cpy): m_impl(new Impl(*cpy.m_impl)) {}
PointIndex::PointIndex(PointIndex&& cpy): m_impl(std::move(cpy.m_impl)) {}
SpatIndex& SpatIndex::operator=(const SpatIndex &cpy)
PointIndex& PointIndex::operator=(const PointIndex &cpy)
{
m_impl.reset(new Impl(*cpy.m_impl));
return *this;
}
SpatIndex& SpatIndex::operator=(SpatIndex &&cpy)
PointIndex& PointIndex::operator=(PointIndex &&cpy)
{
m_impl.swap(cpy.m_impl);
return *this;
}
void SpatIndex::insert(const SpatElement &el)
void PointIndex::insert(const PointIndexEl &el)
{
m_impl->m_store.insert(el);
}
bool SpatIndex::remove(const SpatElement& el)
bool PointIndex::remove(const PointIndexEl& el)
{
return m_impl->m_store.remove(el) == 1;
}
std::vector<SpatElement>
SpatIndex::query(std::function<bool(const SpatElement &)> fn)
std::vector<PointIndexEl>
PointIndex::query(std::function<bool(const PointIndexEl &)> fn)
{
namespace bgi = boost::geometry::index;
std::vector<SpatElement> ret;
std::vector<PointIndexEl> ret;
m_impl->m_store.query(bgi::satisfies(fn), std::back_inserter(ret));
return ret;
}
std::vector<SpatElement> SpatIndex::nearest(const Vec3d &el, unsigned k = 1)
std::vector<PointIndexEl> PointIndex::nearest(const Vec3d &el, unsigned k = 1)
{
namespace bgi = boost::geometry::index;
std::vector<SpatElement> ret; ret.reserve(k);
std::vector<PointIndexEl> ret; ret.reserve(k);
m_impl->m_store.query(bgi::nearest(el, k), std::back_inserter(ret));
return ret;
}
size_t SpatIndex::size() const
size_t PointIndex::size() const
{
return m_impl->m_store.size();
}
void SpatIndex::foreach(std::function<void (const SpatElement &)> fn)
void PointIndex::foreach(std::function<void (const PointIndexEl &)> fn)
{
for(auto& el : m_impl->m_store) fn(el);
}
/* **************************************************************************
* BoxIndex implementation
* ************************************************************************** */
class BoxIndex::Impl {
public:
using BoostIndex = boost::geometry::index::
rtree<BoxIndexEl, boost::geometry::index::rstar<16, 4> /* ? */>;
BoostIndex m_store;
};
BoxIndex::BoxIndex(): m_impl(new Impl()) {}
BoxIndex::~BoxIndex() {}
BoxIndex::BoxIndex(const BoxIndex &cpy): m_impl(new Impl(*cpy.m_impl)) {}
BoxIndex::BoxIndex(BoxIndex&& cpy): m_impl(std::move(cpy.m_impl)) {}
BoxIndex& BoxIndex::operator=(const BoxIndex &cpy)
{
m_impl.reset(new Impl(*cpy.m_impl));
return *this;
}
BoxIndex& BoxIndex::operator=(BoxIndex &&cpy)
{
m_impl.swap(cpy.m_impl);
return *this;
}
void BoxIndex::insert(const BoxIndexEl &el)
{
m_impl->m_store.insert(el);
}
bool BoxIndex::remove(const BoxIndexEl& el)
{
return m_impl->m_store.remove(el) == 1;
}
std::vector<BoxIndexEl> BoxIndex::query(const BoundingBox &qrbb,
BoxIndex::QueryType qt)
{
namespace bgi = boost::geometry::index;
std::vector<BoxIndexEl> ret; ret.reserve(m_impl->m_store.size());
switch (qt) {
case qtIntersects:
m_impl->m_store.query(bgi::intersects(qrbb), std::back_inserter(ret));
break;
case qtWithin:
m_impl->m_store.query(bgi::within(qrbb), std::back_inserter(ret));
}
return ret;
}
size_t BoxIndex::size() const
{
return m_impl->m_store.size();
}
void BoxIndex::foreach(std::function<void (const BoxIndexEl &)> fn)
{
for(auto& el : m_impl->m_store) fn(el);
}
@ -352,12 +420,14 @@ PointSet normals(const PointSet& points,
return ret;
}
namespace bgi = boost::geometry::index;
using Index3D = bgi::rtree< SpatElement, bgi::rstar<16, 4> /* ? */ >;
using Index3D = bgi::rtree< PointIndexEl, bgi::rstar<16, 4> /* ? */ >;
ClusteredPoints cluster(Index3D& sindex, unsigned max_points,
std::function<std::vector<SpatElement>(const Index3D&, const SpatElement&)> qfn)
ClusteredPoints cluster(Index3D &sindex,
unsigned max_points,
std::function<std::vector<PointIndexEl>(
const Index3D &, const PointIndexEl &)> qfn)
{
using Elems = std::vector<SpatElement>;
using Elems = std::vector<PointIndexEl>;
// Recursive function for visiting all the points in a given distance to
// each other
@ -365,8 +435,8 @@ ClusteredPoints cluster(Index3D& sindex, unsigned max_points,
[&sindex, &group, max_points, qfn](Elems& pts, Elems& cluster)
{
for(auto& p : pts) {
std::vector<SpatElement> tmp = qfn(sindex, p);
auto cmp = [](const SpatElement& e1, const SpatElement& e2){
std::vector<PointIndexEl> tmp = qfn(sindex, p);
auto cmp = [](const PointIndexEl& e1, const PointIndexEl& e2){
return e1.second < e2.second;
};
@ -410,12 +480,12 @@ ClusteredPoints cluster(Index3D& sindex, unsigned max_points,
}
namespace {
std::vector<SpatElement> distance_queryfn(const Index3D& sindex,
const SpatElement& p,
std::vector<PointIndexEl> distance_queryfn(const Index3D& sindex,
const PointIndexEl& p,
double dist,
unsigned max_points)
{
std::vector<SpatElement> tmp; tmp.reserve(max_points);
std::vector<PointIndexEl> tmp; tmp.reserve(max_points);
sindex.query(
bgi::nearest(p.first, max_points),
std::back_inserter(tmp)
@ -442,7 +512,7 @@ ClusteredPoints cluster(
for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx));
return cluster(sindex, max_points,
[dist, max_points](const Index3D& sidx, const SpatElement& p)
[dist, max_points](const Index3D& sidx, const PointIndexEl& p)
{
return distance_queryfn(sidx, p, dist, max_points);
});
@ -452,7 +522,7 @@ ClusteredPoints cluster(
ClusteredPoints cluster(
const std::vector<unsigned>& indices,
std::function<Vec3d(unsigned)> pointfn,
std::function<bool(const SpatElement&, const SpatElement&)> predicate,
std::function<bool(const PointIndexEl&, const PointIndexEl&)> predicate,
unsigned max_points)
{
// A spatial index for querying the nearest points
@ -462,10 +532,10 @@ ClusteredPoints cluster(
for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx));
return cluster(sindex, max_points,
[max_points, predicate](const Index3D& sidx, const SpatElement& p)
[max_points, predicate](const Index3D& sidx, const PointIndexEl& p)
{
std::vector<SpatElement> tmp; tmp.reserve(max_points);
sidx.query(bgi::satisfies([p, predicate](const SpatElement& e){
std::vector<PointIndexEl> tmp; tmp.reserve(max_points);
sidx.query(bgi::satisfies([p, predicate](const PointIndexEl& e){
return predicate(p, e);
}), std::back_inserter(tmp));
return tmp;
@ -482,7 +552,7 @@ ClusteredPoints cluster(const PointSet& pts, double dist, unsigned max_points)
sindex.insert(std::make_pair(Vec3d(pts.row(i)), unsigned(i)));
return cluster(sindex, max_points,
[dist, max_points](const Index3D& sidx, const SpatElement& p)
[dist, max_points](const Index3D& sidx, const PointIndexEl& p)
{
return distance_queryfn(sidx, p, dist, max_points);
});