WIP on removing unused parts of pad
This commit is contained in:
parent
90a854f704
commit
778b2cf293
5 changed files with 254 additions and 92 deletions
|
@ -666,20 +666,15 @@ Polygons concave_hull(const Polygons& polys, double max_dist_mm = 50,
|
||||||
return punion;
|
return punion;
|
||||||
}
|
}
|
||||||
|
|
||||||
void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
|
void base_plate(const TriangleMesh & mesh,
|
||||||
float layerh, ThrowOnCancel thrfn)
|
ExPolygons & output,
|
||||||
|
const std::vector<float> &heights,
|
||||||
|
ThrowOnCancel thrfn)
|
||||||
{
|
{
|
||||||
TriangleMesh m = mesh;
|
// m.require_shared_vertices(); // TriangleMeshSlicer needs this
|
||||||
m.require_shared_vertices(); // TriangleMeshSlicer needs this
|
TriangleMeshSlicer slicer(&mesh);
|
||||||
TriangleMeshSlicer slicer(&m);
|
|
||||||
|
|
||||||
auto bb = mesh.bounding_box();
|
std::vector<ExPolygons> out; out.reserve(heights.size());
|
||||||
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)));
|
|
||||||
slicer.slice(heights, 0.f, &out, thrfn);
|
slicer.slice(heights, 0.f, &out, thrfn);
|
||||||
|
|
||||||
size_t count = 0; for(auto& o : out) count += o.size();
|
size_t count = 0; for(auto& o : out) count += o.size();
|
||||||
|
@ -701,6 +696,22 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
Contour3D create_base_pool(const Polygons &ground_layer,
|
||||||
const ExPolygons &obj_self_pad = {},
|
const ExPolygons &obj_self_pad = {},
|
||||||
const PoolConfig& cfg = PoolConfig())
|
const PoolConfig& cfg = PoolConfig())
|
||||||
|
|
|
@ -21,10 +21,15 @@ using ThrowOnCancel = std::function<void(void)>;
|
||||||
/// Calculate the polygon representing the silhouette from the specified height
|
/// Calculate the polygon representing the silhouette from the specified height
|
||||||
void base_plate(const TriangleMesh& mesh, // input mesh
|
void base_plate(const TriangleMesh& mesh, // input mesh
|
||||||
ExPolygons& output, // Output will be merged with
|
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
|
float layerheight = 0.05f, // The sampling height
|
||||||
ThrowOnCancel thrfn = [](){}); // Will be called frequently
|
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
|
// 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
|
// will be offsetted by "padding" and small rectangle shaped cavities will be
|
||||||
// inserted along the perimeter in every "stride" distance. The stick rectangles
|
// inserted along the perimeter in every "stride" distance. The stick rectangles
|
||||||
|
|
|
@ -7,13 +7,15 @@
|
||||||
|
|
||||||
#include <Eigen/Geometry>
|
#include <Eigen/Geometry>
|
||||||
|
|
||||||
|
#include <libslic3r/BoundingBox.hpp>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace sla {
|
namespace sla {
|
||||||
|
|
||||||
typedef Eigen::Matrix<double, 3, 1, Eigen::DontAlign> Vec3d;
|
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;
|
class Impl;
|
||||||
|
|
||||||
// We use Pimpl because it takes a long time to compile boost headers which
|
// 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;
|
std::unique_ptr<Impl> m_impl;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SpatIndex();
|
PointIndex();
|
||||||
~SpatIndex();
|
~PointIndex();
|
||||||
|
|
||||||
SpatIndex(const SpatIndex&);
|
PointIndex(const PointIndex&);
|
||||||
SpatIndex(SpatIndex&&);
|
PointIndex(PointIndex&&);
|
||||||
SpatIndex& operator=(const SpatIndex&);
|
PointIndex& operator=(const PointIndex&);
|
||||||
SpatIndex& operator=(SpatIndex&&);
|
PointIndex& operator=(PointIndex&&);
|
||||||
|
|
||||||
void insert(const SpatElement&);
|
void insert(const PointIndexEl&);
|
||||||
bool remove(const SpatElement&);
|
bool remove(const PointIndexEl&);
|
||||||
|
|
||||||
inline void insert(const Vec3d& v, unsigned idx)
|
inline void insert(const Vec3d& v, unsigned idx)
|
||||||
{
|
{
|
||||||
insert(std::make_pair(v, unsigned(idx)));
|
insert(std::make_pair(v, unsigned(idx)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SpatElement> query(std::function<bool(const SpatElement&)>);
|
std::vector<PointIndexEl> query(std::function<bool(const PointIndexEl&)>);
|
||||||
std::vector<SpatElement> nearest(const Vec3d&, unsigned k);
|
std::vector<PointIndexEl> nearest(const Vec3d&, unsigned k);
|
||||||
|
|
||||||
// For testing
|
// For testing
|
||||||
size_t size() const;
|
size_t size() const;
|
||||||
bool empty() const { return size() == 0; }
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -569,37 +569,74 @@ struct Pad {
|
||||||
sla::get_pad_elevation(pcfg))
|
sla::get_pad_elevation(pcfg))
|
||||||
{
|
{
|
||||||
Polygons basep;
|
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
|
thr();
|
||||||
// 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);
|
|
||||||
|
|
||||||
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) {
|
if(pcfg.embed_object) {
|
||||||
|
|
||||||
|
// 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;
|
ExPolygons modelbase_sticks = modelbase;
|
||||||
|
|
||||||
if (pcfg.embed_object.object_gap_mm > 0.0)
|
if (pcfg.embed_object.object_gap_mm > 0.0)
|
||||||
modelbase_sticks
|
modelbase_sticks
|
||||||
= offset_ex(modelbase_sticks,
|
= offset_ex(modelbase_sticks,
|
||||||
coord_t(pcfg.embed_object.object_gap_mm
|
float(scaled(pcfg.embed_object.object_gap_mm)));
|
||||||
/ SCALING_FACTOR));
|
|
||||||
|
|
||||||
for(auto& poly : modelbase_sticks) {
|
BoxIndex bindex;
|
||||||
basep.emplace_back(poly.contour);
|
{
|
||||||
sla::breakstick_holes(
|
unsigned idx = 0;
|
||||||
poly,
|
for(auto &bp : basep) {
|
||||||
pcfg.embed_object.object_gap_mm, // padding
|
auto bb = bp.bounding_box();
|
||||||
pcfg.embed_object.stick_stride_mm,
|
bb.offset(float(scaled(pcfg.min_wall_thickness_mm)));
|
||||||
pcfg.embed_object.stick_width_mm,
|
bindex.insert(bb, idx++);
|
||||||
pcfg.embed_object.stick_penetration_mm);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
create_base_pool(basep, tmesh, modelbase_sticks, cfg);
|
ExPolygons pad_stickholes; pad_stickholes.reserve(modelbase.size());
|
||||||
|
for(auto& poly : modelbase_sticks) {
|
||||||
|
|
||||||
|
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, pad_stickholes, cfg);
|
||||||
} else {
|
} else {
|
||||||
for (const ExPolygon &bp : modelbase) basep.emplace_back(bp.contour);
|
for (const ExPolygon &bp : modelbase) basep.emplace_back(bp.contour);
|
||||||
create_base_pool(basep, tmesh, {}, cfg);
|
create_base_pool(basep, tmesh, {}, cfg);
|
||||||
|
@ -630,7 +667,7 @@ inline Vec2d to_vec2(const Vec3d& v3) {
|
||||||
return {v3(X), v3(Y)};
|
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;
|
return e1.second == e2.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,7 +684,7 @@ ClusteredPoints cluster(const PointSet& points,
|
||||||
ClusteredPoints cluster(
|
ClusteredPoints cluster(
|
||||||
const std::vector<unsigned>& indices,
|
const std::vector<unsigned>& indices,
|
||||||
std::function<Vec3d(unsigned)> pointfn,
|
std::function<Vec3d(unsigned)> pointfn,
|
||||||
std::function<bool(const SpatElement&, const SpatElement&)> predicate,
|
std::function<bool(const PointIndexEl&, const PointIndexEl&)> predicate,
|
||||||
unsigned max_points);
|
unsigned max_points);
|
||||||
|
|
||||||
// This class will hold the support tree meshes with some additional bookkeeping
|
// This class will hold the support tree meshes with some additional bookkeeping
|
||||||
|
@ -974,7 +1011,7 @@ class SLASupportTree::Algorithm {
|
||||||
ThrowOnCancel m_thr;
|
ThrowOnCancel m_thr;
|
||||||
|
|
||||||
// A spatial index to easily find strong pillars to connect to.
|
// 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,
|
inline double ray_mesh_intersect(const Vec3d& s,
|
||||||
const Vec3d& dir)
|
const Vec3d& dir)
|
||||||
|
@ -1367,7 +1404,7 @@ class SLASupportTree::Algorithm {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool search_pillar_and_connect(const Head& head) {
|
bool search_pillar_and_connect(const Head& head) {
|
||||||
SpatIndex spindex = m_pillar_index;
|
PointIndex spindex = m_pillar_index;
|
||||||
|
|
||||||
long nearest_id = -1;
|
long nearest_id = -1;
|
||||||
|
|
||||||
|
@ -1747,8 +1784,8 @@ public:
|
||||||
return m_result.head(i).junction_point();
|
return m_result.head(i).junction_point();
|
||||||
};
|
};
|
||||||
|
|
||||||
auto predicate = [this](const SpatElement &e1,
|
auto predicate = [this](const PointIndexEl &e1,
|
||||||
const SpatElement &e2) {
|
const PointIndexEl &e2) {
|
||||||
double d2d = distance(to_2d(e1.first), to_2d(e2.first));
|
double d2d = distance(to_2d(e1.first), to_2d(e2.first));
|
||||||
double d3d = distance(e1.first, e2.first);
|
double d3d = distance(e1.first, e2.first);
|
||||||
return d2d < 2 * m_cfg.base_radius_mm
|
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
|
// be connected multiple times this is ensured by the 'pairs' set which
|
||||||
// remembers the processed pillar pairs
|
// remembers the processed pillar pairs
|
||||||
auto cascadefn =
|
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
|
Vec3d qp = el.first; // endpoint of the pillar
|
||||||
|
|
||||||
|
@ -2083,13 +2120,13 @@ public:
|
||||||
if(pillar.links >= neighbors) return;
|
if(pillar.links >= neighbors) return;
|
||||||
|
|
||||||
// Query all remaining points within reach
|
// 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;
|
return distance(e.first, qp) < d;
|
||||||
});
|
});
|
||||||
|
|
||||||
// sort the result by distance (have to check if this is needed)
|
// sort the result by distance (have to check if this is needed)
|
||||||
std::sort(qres.begin(), qres.end(),
|
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);
|
return distance(e1.first, qp) < distance(e2.first, qp);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -29,69 +29,137 @@ namespace sla {
|
||||||
using igl::PI;
|
using igl::PI;
|
||||||
|
|
||||||
/* **************************************************************************
|
/* **************************************************************************
|
||||||
* SpatIndex implementation
|
* PointIndex implementation
|
||||||
* ************************************************************************** */
|
* ************************************************************************** */
|
||||||
|
|
||||||
class SpatIndex::Impl {
|
class PointIndex::Impl {
|
||||||
public:
|
public:
|
||||||
using BoostIndex = boost::geometry::index::rtree< SpatElement,
|
using BoostIndex = boost::geometry::index::rtree< PointIndexEl,
|
||||||
boost::geometry::index::rstar<16, 4> /* ? */ >;
|
boost::geometry::index::rstar<16, 4> /* ? */ >;
|
||||||
|
|
||||||
BoostIndex m_store;
|
BoostIndex m_store;
|
||||||
};
|
};
|
||||||
|
|
||||||
SpatIndex::SpatIndex(): m_impl(new Impl()) {}
|
PointIndex::PointIndex(): m_impl(new Impl()) {}
|
||||||
SpatIndex::~SpatIndex() {}
|
PointIndex::~PointIndex() {}
|
||||||
|
|
||||||
SpatIndex::SpatIndex(const SpatIndex &cpy): m_impl(new Impl(*cpy.m_impl)) {}
|
PointIndex::PointIndex(const PointIndex &cpy): m_impl(new Impl(*cpy.m_impl)) {}
|
||||||
SpatIndex::SpatIndex(SpatIndex&& cpy): m_impl(std::move(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));
|
m_impl.reset(new Impl(*cpy.m_impl));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpatIndex& SpatIndex::operator=(SpatIndex &&cpy)
|
PointIndex& PointIndex::operator=(PointIndex &&cpy)
|
||||||
{
|
{
|
||||||
m_impl.swap(cpy.m_impl);
|
m_impl.swap(cpy.m_impl);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpatIndex::insert(const SpatElement &el)
|
void PointIndex::insert(const PointIndexEl &el)
|
||||||
{
|
{
|
||||||
m_impl->m_store.insert(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;
|
return m_impl->m_store.remove(el) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SpatElement>
|
std::vector<PointIndexEl>
|
||||||
SpatIndex::query(std::function<bool(const SpatElement &)> fn)
|
PointIndex::query(std::function<bool(const PointIndexEl &)> fn)
|
||||||
{
|
{
|
||||||
namespace bgi = boost::geometry::index;
|
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));
|
m_impl->m_store.query(bgi::satisfies(fn), std::back_inserter(ret));
|
||||||
return 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;
|
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));
|
m_impl->m_store.query(bgi::nearest(el, k), std::back_inserter(ret));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SpatIndex::size() const
|
size_t PointIndex::size() const
|
||||||
{
|
{
|
||||||
return m_impl->m_store.size();
|
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);
|
for(auto& el : m_impl->m_store) fn(el);
|
||||||
}
|
}
|
||||||
|
@ -352,12 +420,14 @@ PointSet normals(const PointSet& points,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
namespace bgi = boost::geometry::index;
|
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,
|
ClusteredPoints cluster(Index3D &sindex,
|
||||||
std::function<std::vector<SpatElement>(const Index3D&, const SpatElement&)> qfn)
|
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
|
// Recursive function for visiting all the points in a given distance to
|
||||||
// each other
|
// each other
|
||||||
|
@ -365,8 +435,8 @@ ClusteredPoints cluster(Index3D& sindex, unsigned max_points,
|
||||||
[&sindex, &group, max_points, qfn](Elems& pts, Elems& cluster)
|
[&sindex, &group, max_points, qfn](Elems& pts, Elems& cluster)
|
||||||
{
|
{
|
||||||
for(auto& p : pts) {
|
for(auto& p : pts) {
|
||||||
std::vector<SpatElement> tmp = qfn(sindex, p);
|
std::vector<PointIndexEl> tmp = qfn(sindex, p);
|
||||||
auto cmp = [](const SpatElement& e1, const SpatElement& e2){
|
auto cmp = [](const PointIndexEl& e1, const PointIndexEl& e2){
|
||||||
return e1.second < e2.second;
|
return e1.second < e2.second;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -410,12 +480,12 @@ ClusteredPoints cluster(Index3D& sindex, unsigned max_points,
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::vector<SpatElement> distance_queryfn(const Index3D& sindex,
|
std::vector<PointIndexEl> distance_queryfn(const Index3D& sindex,
|
||||||
const SpatElement& p,
|
const PointIndexEl& p,
|
||||||
double dist,
|
double dist,
|
||||||
unsigned max_points)
|
unsigned max_points)
|
||||||
{
|
{
|
||||||
std::vector<SpatElement> tmp; tmp.reserve(max_points);
|
std::vector<PointIndexEl> tmp; tmp.reserve(max_points);
|
||||||
sindex.query(
|
sindex.query(
|
||||||
bgi::nearest(p.first, max_points),
|
bgi::nearest(p.first, max_points),
|
||||||
std::back_inserter(tmp)
|
std::back_inserter(tmp)
|
||||||
|
@ -442,7 +512,7 @@ ClusteredPoints cluster(
|
||||||
for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx));
|
for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx));
|
||||||
|
|
||||||
return cluster(sindex, max_points,
|
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);
|
return distance_queryfn(sidx, p, dist, max_points);
|
||||||
});
|
});
|
||||||
|
@ -452,7 +522,7 @@ ClusteredPoints cluster(
|
||||||
ClusteredPoints cluster(
|
ClusteredPoints cluster(
|
||||||
const std::vector<unsigned>& indices,
|
const std::vector<unsigned>& indices,
|
||||||
std::function<Vec3d(unsigned)> pointfn,
|
std::function<Vec3d(unsigned)> pointfn,
|
||||||
std::function<bool(const SpatElement&, const SpatElement&)> predicate,
|
std::function<bool(const PointIndexEl&, const PointIndexEl&)> predicate,
|
||||||
unsigned max_points)
|
unsigned max_points)
|
||||||
{
|
{
|
||||||
// A spatial index for querying the nearest 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));
|
for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx));
|
||||||
|
|
||||||
return cluster(sindex, max_points,
|
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);
|
std::vector<PointIndexEl> tmp; tmp.reserve(max_points);
|
||||||
sidx.query(bgi::satisfies([p, predicate](const SpatElement& e){
|
sidx.query(bgi::satisfies([p, predicate](const PointIndexEl& e){
|
||||||
return predicate(p, e);
|
return predicate(p, e);
|
||||||
}), std::back_inserter(tmp));
|
}), std::back_inserter(tmp));
|
||||||
return 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)));
|
sindex.insert(std::make_pair(Vec3d(pts.row(i)), unsigned(i)));
|
||||||
|
|
||||||
return cluster(sindex, max_points,
|
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);
|
return distance_queryfn(sidx, p, dist, max_points);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue