diff --git a/resources/icons/cancel.svg b/resources/icons/cancel.svg
new file mode 100644
index 000000000..da44606a0
--- /dev/null
+++ b/resources/icons/cancel.svg
@@ -0,0 +1,10 @@
+
+
+
diff --git a/resources/icons/cross_focus_large.svg b/resources/icons/cross_focus_large.svg
new file mode 100644
index 000000000..c246f2bd9
--- /dev/null
+++ b/resources/icons/cross_focus_large.svg
@@ -0,0 +1,81 @@
+
+
diff --git a/resources/icons/timer_dot.svg b/resources/icons/timer_dot.svg
new file mode 100644
index 000000000..3a77962b6
--- /dev/null
+++ b/resources/icons/timer_dot.svg
@@ -0,0 +1,72 @@
+
+
diff --git a/resources/icons/timer_dot_empty.svg b/resources/icons/timer_dot_empty.svg
new file mode 100644
index 000000000..a8e776b49
--- /dev/null
+++ b/resources/icons/timer_dot_empty.svg
@@ -0,0 +1,73 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h
index d32f64aa4..feda857ae 100644
--- a/src/imgui/imconfig.h
+++ b/src/imgui/imconfig.h
@@ -113,7 +113,12 @@ namespace ImGui
const char PrinterSlaIconMarker = 0x6;
const char FilamentIconMarker = 0x7;
const char MaterialIconMarker = 0x8;
-
+ const char CloseIconMarker = 0xB;
+ const char CloseIconHoverMarker = 0xC;
+ const char TimerDotMarker = 0xE;
+ const char TimerDotEmptyMarker = 0xF;
+ const char WarningMarker = 0x10;
+ const char ErrorMarker = 0x11;
// void MyFunction(const char* name, const MyMatrix44& v);
}
diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt
index 7ef7d7c32..ce62454c0 100644
--- a/src/libslic3r/CMakeLists.txt
+++ b/src/libslic3r/CMakeLists.txt
@@ -205,12 +205,13 @@ add_library(libslic3r STATIC
SimplifyMeshImpl.hpp
SimplifyMesh.cpp
MarchingSquares.hpp
+ Optimizer.hpp
${OpenVDBUtils_SOURCES}
- SLA/Common.hpp
- SLA/Common.cpp
SLA/Pad.hpp
SLA/Pad.cpp
SLA/SupportTreeBuilder.hpp
+ SLA/SupportTreeMesher.hpp
+ SLA/SupportTreeMesher.cpp
SLA/SupportTreeBuildsteps.hpp
SLA/SupportTreeBuildsteps.cpp
SLA/SupportTreeBuilder.cpp
@@ -222,6 +223,7 @@ add_library(libslic3r STATIC
SLA/Rotfinder.cpp
SLA/BoostAdapter.hpp
SLA/SpatIndex.hpp
+ SLA/SpatIndex.cpp
SLA/RasterBase.hpp
SLA/RasterBase.cpp
SLA/AGGRaster.hpp
@@ -237,8 +239,10 @@ add_library(libslic3r STATIC
SLA/SupportPointGenerator.cpp
SLA/Contour3D.hpp
SLA/Contour3D.cpp
- SLA/EigenMesh3D.hpp
+ SLA/IndexedMesh.hpp
+ SLA/IndexedMesh.cpp
SLA/Clustering.hpp
+ SLA/Clustering.cpp
SLA/ReprojectPointsOnMesh.hpp
)
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index 880572b2b..d7db315a7 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -691,6 +691,7 @@ std::vector>> GCode::collec
std::sort(ordering.begin(), ordering.end(), [](const OrderingItem& oi1, const OrderingItem& oi2) { return oi1.print_z < oi2.print_z; });
std::vector>> layers_to_print;
+
// Merge numerically very close Z values.
for (size_t i = 0; i < ordering.size();) {
// Find the last layer with roughly the same print_z.
diff --git a/src/libslic3r/OpenVDBUtils.hpp b/src/libslic3r/OpenVDBUtils.hpp
index c493845a1..e35231d35 100644
--- a/src/libslic3r/OpenVDBUtils.hpp
+++ b/src/libslic3r/OpenVDBUtils.hpp
@@ -2,7 +2,6 @@
#define OPENVDBUTILS_HPP
#include
-#include
#include
#include
diff --git a/src/libslic3r/Optimizer.hpp b/src/libslic3r/Optimizer.hpp
new file mode 100644
index 000000000..6495ae7ff
--- /dev/null
+++ b/src/libslic3r/Optimizer.hpp
@@ -0,0 +1,380 @@
+#ifndef NLOPTOPTIMIZER_HPP
+#define NLOPTOPTIMIZER_HPP
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4244)
+#pragma warning(disable: 4267)
+#endif
+#include
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Slic3r { namespace opt {
+
+// A type to hold the complete result of the optimization.
+template struct Result {
+ int resultcode;
+ std::array optimum;
+ double score;
+};
+
+// An interval of possible input values for optimization
+class Bound {
+ double m_min, m_max;
+
+public:
+ Bound(double min = std::numeric_limits::min(),
+ double max = std::numeric_limits::max())
+ : m_min(min), m_max(max)
+ {}
+
+ double min() const noexcept { return m_min; }
+ double max() const noexcept { return m_max; }
+};
+
+// Helper types for optimization function input and bounds
+template using Input = std::array;
+template using Bounds = std::array;
+
+// A type for specifying the stop criteria. Setter methods can be concatenated
+class StopCriteria {
+
+ // If the absolute value difference between two scores.
+ double m_abs_score_diff = std::nan("");
+
+ // If the relative value difference between two scores.
+ double m_rel_score_diff = std::nan("");
+
+ // Stop if this value or better is found.
+ double m_stop_score = std::nan("");
+
+ // A predicate that if evaluates to true, the optimization should terminate
+ // and the best result found prior to termination should be returned.
+ std::function m_stop_condition = [] { return false; };
+
+ // The max allowed number of iterations.
+ unsigned m_max_iterations = 0;
+
+public:
+
+ StopCriteria & abs_score_diff(double val)
+ {
+ m_abs_score_diff = val; return *this;
+ }
+
+ double abs_score_diff() const { return m_abs_score_diff; }
+
+ StopCriteria & rel_score_diff(double val)
+ {
+ m_rel_score_diff = val; return *this;
+ }
+
+ double rel_score_diff() const { return m_rel_score_diff; }
+
+ StopCriteria & stop_score(double val)
+ {
+ m_stop_score = val; return *this;
+ }
+
+ double stop_score() const { return m_stop_score; }
+
+ StopCriteria & max_iterations(double val)
+ {
+ m_max_iterations = val; return *this;
+ }
+
+ double max_iterations() const { return m_max_iterations; }
+
+ template StopCriteria & stop_condition(Fn &&cond)
+ {
+ m_stop_condition = cond; return *this;
+ }
+
+ bool stop_condition() { return m_stop_condition(); }
+};
+
+// Helper class to use optimization methods involving gradient.
+template struct ScoreGradient {
+ double score;
+ std::optional> gradient;
+
+ ScoreGradient(double s, const std::array &grad)
+ : score{s}, gradient{grad}
+ {}
+};
+
+// Helper to be used in static_assert.
+template struct always_false { enum { value = false }; };
+
+// Basic interface to optimizer object
+template class Optimizer {
+public:
+
+ Optimizer(const StopCriteria &)
+ {
+ static_assert (always_false::value,
+ "Optimizer unimplemented for given method!");
+ }
+
+ Optimizer &to_min() { return *this; }
+ Optimizer &to_max() { return *this; }
+ Optimizer &set_criteria(const StopCriteria &) { return *this; }
+ StopCriteria get_criteria() const { return {}; };
+
+ template
+ Result optimize(Func&& func,
+ const Input &initvals,
+ const Bounds& bounds) { return {}; }
+
+ // optional for randomized methods:
+ void seed(long /*s*/) {}
+};
+
+namespace detail {
+
+// Helper types for NLopt algorithm selection in template contexts
+template struct NLoptAlg {};
+
+// NLopt can combine multiple algorithms if one is global an other is a local
+// method. This is how template specializations can be informed about this fact.
+template
+struct NLoptAlgComb {};
+
+template struct IsNLoptAlg {
+ static const constexpr bool value = false;
+};
+
+template struct IsNLoptAlg> {
+ static const constexpr bool value = true;
+};
+
+template
+struct IsNLoptAlg> {
+ static const constexpr bool value = true;
+};
+
+template
+using NLoptOnly = std::enable_if_t::value, T>;
+
+// Helper to convert C style array to std::array. The copy should be optimized
+// away with modern compilers.
+template auto to_arr(const T *a)
+{
+ std::array r;
+ std::copy(a, a + N, std::begin(r));
+ return r;
+}
+
+template auto to_arr(const T (&a) [N])
+{
+ return to_arr(static_cast(a));
+}
+
+enum class OptDir { MIN, MAX }; // Where to optimize
+
+struct NLopt { // Helper RAII class for nlopt_opt
+ nlopt_opt ptr = nullptr;
+
+ template explicit NLopt(A&&...a)
+ {
+ ptr = nlopt_create(std::forward(a)...);
+ }
+
+ NLopt(const NLopt&) = delete;
+ NLopt(NLopt&&) = delete;
+ NLopt& operator=(const NLopt&) = delete;
+ NLopt& operator=(NLopt&&) = delete;
+
+ ~NLopt() { nlopt_destroy(ptr); }
+};
+
+template class NLoptOpt {};
+
+// Optimizers based on NLopt.
+template class NLoptOpt> {
+protected:
+ StopCriteria m_stopcr;
+ OptDir m_dir;
+
+ template using TOptData =
+ std::tuple*, NLoptOpt*, nlopt_opt>;
+
+ template
+ static double optfunc(unsigned n, const double *params,
+ double *gradient,
+ void *data)
+ {
+ assert(n >= N);
+
+ auto tdata = static_cast*>(data);
+
+ if (std::get<1>(*tdata)->m_stopcr.stop_condition())
+ nlopt_force_stop(std::get<2>(*tdata));
+
+ auto fnptr = std::get<0>(*tdata);
+ auto funval = to_arr(params);
+
+ double scoreval = 0.;
+ using RetT = decltype((*fnptr)(funval));
+ if constexpr (std::is_convertible_v>) {
+ ScoreGradient score = (*fnptr)(funval);
+ for (size_t i = 0; i < n; ++i) gradient[i] = (*score.gradient)[i];
+ scoreval = score.score;
+ } else {
+ scoreval = (*fnptr)(funval);
+ }
+
+ return scoreval;
+ }
+
+ template
+ void set_up(NLopt &nl, const Bounds& bounds)
+ {
+ std::array lb, ub;
+
+ for (size_t i = 0; i < N; ++i) {
+ lb[i] = bounds[i].min();
+ ub[i] = bounds[i].max();
+ }
+
+ nlopt_set_lower_bounds(nl.ptr, lb.data());
+ nlopt_set_upper_bounds(nl.ptr, ub.data());
+
+ double abs_diff = m_stopcr.abs_score_diff();
+ double rel_diff = m_stopcr.rel_score_diff();
+ double stopval = m_stopcr.stop_score();
+ if(!std::isnan(abs_diff)) nlopt_set_ftol_abs(nl.ptr, abs_diff);
+ if(!std::isnan(rel_diff)) nlopt_set_ftol_rel(nl.ptr, rel_diff);
+ if(!std::isnan(stopval)) nlopt_set_stopval(nl.ptr, stopval);
+
+ if(this->m_stopcr.max_iterations() > 0)
+ nlopt_set_maxeval(nl.ptr, this->m_stopcr.max_iterations());
+ }
+
+ template
+ Result optimize(NLopt &nl, Fn &&fn, const Input &initvals)
+ {
+ Result r;
+
+ TOptData data = std::make_tuple(&fn, this, nl.ptr);
+
+ switch(m_dir) {
+ case OptDir::MIN:
+ nlopt_set_min_objective(nl.ptr, optfunc, &data); break;
+ case OptDir::MAX:
+ nlopt_set_max_objective(nl.ptr, optfunc, &data); break;
+ }
+
+ r.optimum = initvals;
+ r.resultcode = nlopt_optimize(nl.ptr, r.optimum.data(), &r.score);
+
+ return r;
+ }
+
+public:
+
+ template
+ Result optimize(Func&& func,
+ const Input &initvals,
+ const Bounds& bounds)
+ {
+ NLopt nl{alg, N};
+ set_up(nl, bounds);
+
+ return optimize(nl, std::forward(func), initvals);
+ }
+
+ explicit NLoptOpt(StopCriteria stopcr = {}) : m_stopcr(stopcr) {}
+
+ void set_criteria(const StopCriteria &cr) { m_stopcr = cr; }
+ const StopCriteria &get_criteria() const noexcept { return m_stopcr; }
+ void set_dir(OptDir dir) noexcept { m_dir = dir; }
+
+ void seed(long s) { nlopt_srand(s); }
+};
+
+template
+class NLoptOpt>: public NLoptOpt>
+{
+ using Base = NLoptOpt>;
+public:
+
+ template
+ Result optimize(Fn&& f,
+ const Input &initvals,
+ const Bounds& bounds)
+ {
+ NLopt nl_glob{glob, N}, nl_loc{loc, N};
+
+ Base::set_up(nl_glob, bounds);
+ Base::set_up(nl_loc, bounds);
+ nlopt_set_local_optimizer(nl_glob.ptr, nl_loc.ptr);
+
+ return Base::optimize(nl_glob, std::forward(f), initvals);
+ }
+
+ explicit NLoptOpt(StopCriteria stopcr = {}) : Base{stopcr} {}
+};
+
+} // namespace detail;
+
+// Optimizers based on NLopt.
+template class Optimizer> {
+ detail::NLoptOpt m_opt;
+
+public:
+
+ Optimizer& to_max() { m_opt.set_dir(detail::OptDir::MAX); return *this; }
+ Optimizer& to_min() { m_opt.set_dir(detail::OptDir::MIN); return *this; }
+
+ template
+ Result optimize(Func&& func,
+ const Input &initvals,
+ const Bounds& bounds)
+ {
+ return m_opt.optimize(std::forward(func), initvals, bounds);
+ }
+
+ explicit Optimizer(StopCriteria stopcr = {}) : m_opt(stopcr) {}
+
+ Optimizer &set_criteria(const StopCriteria &cr)
+ {
+ m_opt.set_criteria(cr); return *this;
+ }
+
+ const StopCriteria &get_criteria() const { return m_opt.get_criteria(); }
+
+ void seed(long s) { m_opt.seed(s); }
+};
+
+template Bounds bounds(const Bound (&b) [N]) { return detail::to_arr(b); }
+template Input initvals(const double (&a) [N]) { return detail::to_arr(a); }
+template auto score_gradient(double s, const double (&grad)[N])
+{
+ return ScoreGradient(s, detail::to_arr(grad));
+}
+
+// Predefinded NLopt algorithms that are used in the codebase
+using AlgNLoptGenetic = detail::NLoptAlgComb;
+using AlgNLoptSubplex = detail::NLoptAlg;
+using AlgNLoptSimplex = detail::NLoptAlg;
+
+// TODO: define others if needed...
+
+// Helper defs for pre-crafted global and local optimizers that work well.
+using DefaultGlobalOptimizer = Optimizer;
+using DefaultLocalOptimizer = Optimizer;
+
+}} // namespace Slic3r::opt
+
+#endif // NLOPTOPTIMIZER_HPP
diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp
index b818cd8be..8c1c69fde 100644
--- a/src/libslic3r/Point.hpp
+++ b/src/libslic3r/Point.hpp
@@ -60,10 +60,13 @@ inline int64_t cross2(const Vec2i64 &v1, const Vec2i64 &v2) { return v1(0) * v2(
inline float cross2(const Vec2f &v1, const Vec2f &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
inline double cross2(const Vec2d &v1, const Vec2d &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
-inline Vec2i32 to_2d(const Vec2i32 &pt3) { return Vec2i32(pt3(0), pt3(1)); }
-inline Vec2i64 to_2d(const Vec3i64 &pt3) { return Vec2i64(pt3(0), pt3(1)); }
-inline Vec2f to_2d(const Vec3f &pt3) { return Vec2f (pt3(0), pt3(1)); }
-inline Vec2d to_2d(const Vec3d &pt3) { return Vec2d (pt3(0), pt3(1)); }
+template Eigen::Matrix
+to_2d(const Eigen::Matrix &ptN) { return {ptN(0), ptN(1)}; }
+
+//inline Vec2i32 to_2d(const Vec3i32 &pt3) { return Vec2i32(pt3(0), pt3(1)); }
+//inline Vec2i64 to_2d(const Vec3i64 &pt3) { return Vec2i64(pt3(0), pt3(1)); }
+//inline Vec2f to_2d(const Vec3f &pt3) { return Vec2f (pt3(0), pt3(1)); }
+//inline Vec2d to_2d(const Vec3d &pt3) { return Vec2d (pt3(0), pt3(1)); }
inline Vec3d to_3d(const Vec2d &v, double z) { return Vec3d(v(0), v(1), z); }
inline Vec3f to_3d(const Vec2f &v, float z) { return Vec3f(v(0), v(1), z); }
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index a25292298..5c1ce4b7f 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -2715,7 +2715,7 @@ void PrintConfigDef::init_sla_params()
def->set_default_value(new ConfigOptionBool(true));
def = this->add("support_head_front_diameter", coFloat);
- def->label = L("Support head front diameter");
+ def->label = L("Pinhead front diameter");
def->category = L("Supports");
def->tooltip = L("Diameter of the pointing side of the head");
def->sidetext = L("mm");
@@ -2724,7 +2724,7 @@ void PrintConfigDef::init_sla_params()
def->set_default_value(new ConfigOptionFloat(0.4));
def = this->add("support_head_penetration", coFloat);
- def->label = L("Support head penetration");
+ def->label = L("Head penetration");
def->category = L("Supports");
def->tooltip = L("How much the pinhead has to penetrate the model surface");
def->sidetext = L("mm");
@@ -2733,7 +2733,7 @@ void PrintConfigDef::init_sla_params()
def->set_default_value(new ConfigOptionFloat(0.2));
def = this->add("support_head_width", coFloat);
- def->label = L("Support head width");
+ def->label = L("Pinhead width");
def->category = L("Supports");
def->tooltip = L("Width from the back sphere center to the front sphere center");
def->sidetext = L("mm");
@@ -2743,7 +2743,7 @@ void PrintConfigDef::init_sla_params()
def->set_default_value(new ConfigOptionFloat(1.0));
def = this->add("support_pillar_diameter", coFloat);
- def->label = L("Support pillar diameter");
+ def->label = L("Pillar diameter");
def->category = L("Supports");
def->tooltip = L("Diameter in mm of the support pillars");
def->sidetext = L("mm");
@@ -2751,6 +2751,17 @@ void PrintConfigDef::init_sla_params()
def->max = 15;
def->mode = comSimple;
def->set_default_value(new ConfigOptionFloat(1.0));
+
+ def = this->add("support_small_pillar_diameter_percent", coPercent);
+ def->label = L("Small pillar diameter percent");
+ def->category = L("Supports");
+ def->tooltip = L("The percentage of smaller pillars compared to the normal pillar diameter "
+ "which are used in problematic areas where a normal pilla cannot fit.");
+ def->sidetext = L("%");
+ def->min = 1;
+ def->max = 100;
+ def->mode = comExpert;
+ def->set_default_value(new ConfigOptionPercent(50));
def = this->add("support_max_bridges_on_pillar", coInt);
def->label = L("Max bridges on a pillar");
@@ -2763,7 +2774,7 @@ void PrintConfigDef::init_sla_params()
def->set_default_value(new ConfigOptionInt(3));
def = this->add("support_pillar_connection_mode", coEnum);
- def->label = L("Support pillar connection mode");
+ def->label = L("Pillar connection mode");
def->tooltip = L("Controls the bridge type between two neighboring pillars."
" Can be zig-zag, cross (double zig-zag) or dynamic which"
" will automatically switch between the first two depending"
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index f28ef2a22..0213a6d6b 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -1018,6 +1018,10 @@ public:
// Radius in mm of the support pillars.
ConfigOptionFloat support_pillar_diameter /*= 0.8*/;
+
+ // The percentage of smaller pillars compared to the normal pillar diameter
+ // which are used in problematic areas where a normal pilla cannot fit.
+ ConfigOptionPercent support_small_pillar_diameter_percent;
// How much bridge (supporting another pinhead) can be placed on a pillar.
ConfigOptionInt support_max_bridges_on_pillar;
@@ -1142,6 +1146,7 @@ protected:
OPT_PTR(support_head_penetration);
OPT_PTR(support_head_width);
OPT_PTR(support_pillar_diameter);
+ OPT_PTR(support_small_pillar_diameter_percent);
OPT_PTR(support_max_bridges_on_pillar);
OPT_PTR(support_pillar_connection_mode);
OPT_PTR(support_buildplate_only);
diff --git a/src/libslic3r/SLA/BoostAdapter.hpp b/src/libslic3r/SLA/BoostAdapter.hpp
index b7b3c63a6..13e0465b1 100644
--- a/src/libslic3r/SLA/BoostAdapter.hpp
+++ b/src/libslic3r/SLA/BoostAdapter.hpp
@@ -1,7 +1,9 @@
#ifndef SLA_BOOSTADAPTER_HPP
#define SLA_BOOSTADAPTER_HPP
-#include
+#include
+#include
+
#include
namespace boost {
diff --git a/src/libslic3r/SLA/Clustering.cpp b/src/libslic3r/SLA/Clustering.cpp
new file mode 100644
index 000000000..41ff1d4f0
--- /dev/null
+++ b/src/libslic3r/SLA/Clustering.cpp
@@ -0,0 +1,152 @@
+#include "Clustering.hpp"
+#include "boost/geometry/index/rtree.hpp"
+
+#include
+#include
+
+namespace Slic3r { namespace sla {
+
+namespace bgi = boost::geometry::index;
+using Index3D = bgi::rtree< PointIndexEl, bgi::rstar<16, 4> /* ? */ >;
+
+namespace {
+
+bool cmp_ptidx_elements(const PointIndexEl& e1, const PointIndexEl& e2)
+{
+ return e1.second < e2.second;
+};
+
+ClusteredPoints cluster(Index3D &sindex,
+ unsigned max_points,
+ std::function(
+ const Index3D &, const PointIndexEl &)> qfn)
+{
+ using Elems = std::vector;
+
+ // Recursive function for visiting all the points in a given distance to
+ // each other
+ std::function group =
+ [&sindex, &group, max_points, qfn](Elems& pts, Elems& cluster)
+ {
+ for(auto& p : pts) {
+ std::vector tmp = qfn(sindex, p);
+
+ std::sort(tmp.begin(), tmp.end(), cmp_ptidx_elements);
+
+ Elems newpts;
+ std::set_difference(tmp.begin(), tmp.end(),
+ cluster.begin(), cluster.end(),
+ std::back_inserter(newpts), cmp_ptidx_elements);
+
+ int c = max_points && newpts.size() + cluster.size() > max_points?
+ int(max_points - cluster.size()) : int(newpts.size());
+
+ cluster.insert(cluster.end(), newpts.begin(), newpts.begin() + c);
+ std::sort(cluster.begin(), cluster.end(), cmp_ptidx_elements);
+
+ if(!newpts.empty() && (!max_points || cluster.size() < max_points))
+ group(newpts, cluster);
+ }
+ };
+
+ std::vector clusters;
+ for(auto it = sindex.begin(); it != sindex.end();) {
+ Elems cluster = {};
+ Elems pts = {*it};
+ group(pts, cluster);
+
+ for(auto& c : cluster) sindex.remove(c);
+ it = sindex.begin();
+
+ clusters.emplace_back(cluster);
+ }
+
+ ClusteredPoints result;
+ for(auto& cluster : clusters) {
+ result.emplace_back();
+ for(auto c : cluster) result.back().emplace_back(c.second);
+ }
+
+ return result;
+}
+
+std::vector distance_queryfn(const Index3D& sindex,
+ const PointIndexEl& p,
+ double dist,
+ unsigned max_points)
+{
+ std::vector tmp; tmp.reserve(max_points);
+ sindex.query(
+ bgi::nearest(p.first, max_points),
+ std::back_inserter(tmp)
+ );
+
+ for(auto it = tmp.begin(); it < tmp.end(); ++it)
+ if((p.first - it->first).norm() > dist) it = tmp.erase(it);
+
+ return tmp;
+}
+
+} // namespace
+
+// Clustering a set of points by the given criteria
+ClusteredPoints cluster(
+ const std::vector& indices,
+ std::function pointfn,
+ double dist,
+ unsigned max_points)
+{
+ // A spatial index for querying the nearest points
+ Index3D sindex;
+
+ // Build the index
+ for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx));
+
+ return cluster(sindex, max_points,
+ [dist, max_points](const Index3D& sidx, const PointIndexEl& p)
+ {
+ return distance_queryfn(sidx, p, dist, max_points);
+ });
+}
+
+// Clustering a set of points by the given criteria
+ClusteredPoints cluster(
+ const std::vector& indices,
+ std::function pointfn,
+ std::function predicate,
+ unsigned max_points)
+{
+ // A spatial index for querying the nearest points
+ Index3D sindex;
+
+ // Build the index
+ for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx));
+
+ return cluster(sindex, max_points,
+ [max_points, predicate](const Index3D& sidx, const PointIndexEl& p)
+ {
+ std::vector tmp; tmp.reserve(max_points);
+ sidx.query(bgi::satisfies([p, predicate](const PointIndexEl& e){
+ return predicate(p, e);
+ }), std::back_inserter(tmp));
+ return tmp;
+ });
+}
+
+ClusteredPoints cluster(const Eigen::MatrixXd& pts, double dist, unsigned max_points)
+{
+ // A spatial index for querying the nearest points
+ Index3D sindex;
+
+ // Build the index
+ for(Eigen::Index i = 0; i < pts.rows(); i++)
+ sindex.insert(std::make_pair(Vec3d(pts.row(i)), unsigned(i)));
+
+ return cluster(sindex, max_points,
+ [dist, max_points](const Index3D& sidx, const PointIndexEl& p)
+ {
+ return distance_queryfn(sidx, p, dist, max_points);
+ });
+}
+
+}} // namespace Slic3r::sla
diff --git a/src/libslic3r/SLA/Clustering.hpp b/src/libslic3r/SLA/Clustering.hpp
index 1b0d47d95..269ec2882 100644
--- a/src/libslic3r/SLA/Clustering.hpp
+++ b/src/libslic3r/SLA/Clustering.hpp
@@ -2,7 +2,8 @@
#define SLA_CLUSTERING_HPP
#include
-#include
+
+#include
#include
namespace Slic3r { namespace sla {
@@ -16,7 +17,7 @@ ClusteredPoints cluster(const std::vector& indices,
double dist,
unsigned max_points);
-ClusteredPoints cluster(const PointSet& points,
+ClusteredPoints cluster(const Eigen::MatrixXd& points,
double dist,
unsigned max_points);
@@ -26,5 +27,56 @@ ClusteredPoints cluster(
std::function predicate,
unsigned max_points);
-}}
+// This function returns the position of the centroid in the input 'clust'
+// vector of point indices.
+template
+long cluster_centroid(const ClusterEl &clust, PointFn pointfn, DistFn df)
+{
+ switch(clust.size()) {
+ case 0: /* empty cluster */ return -1;
+ case 1: /* only one element */ return 0;
+ case 2: /* if two elements, there is no center */ return 0;
+ default: ;
+ }
+
+ // The function works by calculating for each point the average distance
+ // from all the other points in the cluster. We create a selector bitmask of
+ // the same size as the cluster. The bitmask will have two true bits and
+ // false bits for the rest of items and we will loop through all the
+ // permutations of the bitmask (combinations of two points). Get the
+ // distance for the two points and add the distance to the averages.
+ // The point with the smallest average than wins.
+
+ // The complexity should be O(n^2) but we will mostly apply this function
+ // for small clusters only (cca 3 elements)
+
+ std::vector sel(clust.size(), false); // create full zero bitmask
+ std::fill(sel.end() - 2, sel.end(), true); // insert the two ones
+ std::vector avgs(clust.size(), 0.0); // store the average distances
+
+ do {
+ std::array idx;
+ for(size_t i = 0, j = 0; i < clust.size(); i++)
+ if(sel[i]) idx[j++] = i;
+
+ double d = df(pointfn(clust[idx[0]]),
+ pointfn(clust[idx[1]]));
+
+ // add the distance to the sums for both associated points
+ for(auto i : idx) avgs[i] += d;
+
+ // now continue with the next permutation of the bitmask with two 1s
+ } while(std::next_permutation(sel.begin(), sel.end()));
+
+ // Divide by point size in the cluster to get the average (may be redundant)
+ for(auto& a : avgs) a /= clust.size();
+
+ // get the lowest average distance and return the index
+ auto minit = std::min_element(avgs.begin(), avgs.end());
+ return long(minit - avgs.begin());
+}
+
+
+}} // namespace Slic3r::sla
+
#endif // CLUSTERING_HPP
diff --git a/src/libslic3r/SLA/Common.hpp b/src/libslic3r/SLA/Common.hpp
deleted file mode 100644
index ca616cabc..000000000
--- a/src/libslic3r/SLA/Common.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef SLA_COMMON_HPP
-#define SLA_COMMON_HPP
-
-#include
-#include
-#include
-#include
-#include
-
-
-namespace Slic3r {
-
-// Typedefs from Point.hpp
-typedef Eigen::Matrix Vec3f;
-typedef Eigen::Matrix Vec3d;
-typedef Eigen::Matrix Vec3i;
-typedef Eigen::Matrix Vec4i;
-
-namespace sla {
-
-using PointSet = Eigen::MatrixXd;
-
-} // namespace sla
-} // namespace Slic3r
-
-
-#endif // SLASUPPORTTREE_HPP
diff --git a/src/libslic3r/SLA/Contour3D.cpp b/src/libslic3r/SLA/Contour3D.cpp
index 408465d43..96d10af20 100644
--- a/src/libslic3r/SLA/Contour3D.cpp
+++ b/src/libslic3r/SLA/Contour3D.cpp
@@ -1,5 +1,5 @@
#include
-#include
+#include
#include
@@ -27,7 +27,7 @@ Contour3D::Contour3D(TriangleMesh &&trmesh)
faces3.swap(trmesh.its.indices);
}
-Contour3D::Contour3D(const EigenMesh3D &emesh) {
+Contour3D::Contour3D(const IndexedMesh &emesh) {
points.reserve(emesh.vertices().size());
faces3.reserve(emesh.indices().size());
diff --git a/src/libslic3r/SLA/Contour3D.hpp b/src/libslic3r/SLA/Contour3D.hpp
index 295612f19..3380cd6ab 100644
--- a/src/libslic3r/SLA/Contour3D.hpp
+++ b/src/libslic3r/SLA/Contour3D.hpp
@@ -1,13 +1,16 @@
#ifndef SLA_CONTOUR3D_HPP
#define SLA_CONTOUR3D_HPP
-#include
-
#include
-namespace Slic3r { namespace sla {
+namespace Slic3r {
-class EigenMesh3D;
+// Used for quads (TODO: remove this, and convert quads to triangles in OpenVDBUtils)
+using Vec4i = Eigen::Matrix;
+
+namespace sla {
+
+class IndexedMesh;
/// Dumb vertex mesh consisting of triangles (or) quads. Capable of merging with
/// other meshes of this type and converting to and from other mesh formats.
@@ -19,7 +22,7 @@ struct Contour3D {
Contour3D() = default;
Contour3D(const TriangleMesh &trmesh);
Contour3D(TriangleMesh &&trmesh);
- Contour3D(const EigenMesh3D &emesh);
+ Contour3D(const IndexedMesh &emesh);
Contour3D& merge(const Contour3D& ctr);
Contour3D& merge(const Pointf3s& triangles);
diff --git a/src/libslic3r/SLA/Hollowing.cpp b/src/libslic3r/SLA/Hollowing.cpp
index 0dd9436a1..5334054a0 100644
--- a/src/libslic3r/SLA/Hollowing.cpp
+++ b/src/libslic3r/SLA/Hollowing.cpp
@@ -3,11 +3,10 @@
#include
#include
#include
-#include
-#include
-#include
+#include
#include
#include
+#include
#include
@@ -160,7 +159,7 @@ bool DrainHole::get_intersections(const Vec3f& s, const Vec3f& dir,
const Eigen::ParametrizedLine ray(s, dir.normalized());
for (size_t i=0; i<2; ++i)
- out[i] = std::make_pair(sla::EigenMesh3D::hit_result::infty(), Vec3d::Zero());
+ out[i] = std::make_pair(sla::IndexedMesh::hit_result::infty(), Vec3d::Zero());
const float sqr_radius = pow(radius, 2.f);
diff --git a/src/libslic3r/SLA/Hollowing.hpp b/src/libslic3r/SLA/Hollowing.hpp
index cc7d310ea..1f65fa8b7 100644
--- a/src/libslic3r/SLA/Hollowing.hpp
+++ b/src/libslic3r/SLA/Hollowing.hpp
@@ -2,7 +2,6 @@
#define SLA_HOLLOWING_HPP
#include
-#include
#include
#include
diff --git a/src/libslic3r/SLA/Common.cpp b/src/libslic3r/SLA/IndexedMesh.cpp
similarity index 53%
rename from src/libslic3r/SLA/Common.cpp
rename to src/libslic3r/SLA/IndexedMesh.cpp
index a7420a7fb..573b62b6d 100644
--- a/src/libslic3r/SLA/Common.cpp
+++ b/src/libslic3r/SLA/IndexedMesh.cpp
@@ -1,187 +1,18 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+#include "IndexedMesh.hpp"
+#include "Concurrency.hpp"
+
#include
+#include
-// for concave hull merging decisions
-#include
-#include "boost/geometry/index/rtree.hpp"
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable: 4244)
-#pragma warning(disable: 4267)
-#endif
-
-
-#include
+#include
#ifdef SLIC3R_HOLE_RAYCASTER
- #include
+#include
#endif
+namespace Slic3r { namespace sla {
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-
-namespace Slic3r {
-namespace sla {
-
-
-/* **************************************************************************
- * PointIndex implementation
- * ************************************************************************** */
-
-class PointIndex::Impl {
-public:
- using BoostIndex = boost::geometry::index::rtree< PointIndexEl,
- boost::geometry::index::rstar<16, 4> /* ? */ >;
-
- BoostIndex m_store;
-};
-
-PointIndex::PointIndex(): m_impl(new Impl()) {}
-PointIndex::~PointIndex() {}
-
-PointIndex::PointIndex(const PointIndex &cpy): m_impl(new Impl(*cpy.m_impl)) {}
-PointIndex::PointIndex(PointIndex&& cpy): m_impl(std::move(cpy.m_impl)) {}
-
-PointIndex& PointIndex::operator=(const PointIndex &cpy)
-{
- m_impl.reset(new Impl(*cpy.m_impl));
- return *this;
-}
-
-PointIndex& PointIndex::operator=(PointIndex &&cpy)
-{
- m_impl.swap(cpy.m_impl);
- return *this;
-}
-
-void PointIndex::insert(const PointIndexEl &el)
-{
- m_impl->m_store.insert(el);
-}
-
-bool PointIndex::remove(const PointIndexEl& el)
-{
- return m_impl->m_store.remove(el) == 1;
-}
-
-std::vector
-PointIndex::query(std::function fn) const
-{
- namespace bgi = boost::geometry::index;
-
- std::vector ret;
- m_impl->m_store.query(bgi::satisfies(fn), std::back_inserter(ret));
- return ret;
-}
-
-std::vector PointIndex::nearest(const Vec3d &el, unsigned k = 1) const
-{
- namespace bgi = boost::geometry::index;
- std::vector ret; ret.reserve(k);
- m_impl->m_store.query(bgi::nearest(el, k), std::back_inserter(ret));
- return ret;
-}
-
-size_t PointIndex::size() const
-{
- return m_impl->m_store.size();
-}
-
-void PointIndex::foreach(std::function fn)
-{
- for(auto& el : m_impl->m_store) fn(el);
-}
-
-void PointIndex::foreach(std::function fn) const
-{
- for(const auto &el : m_impl->m_store) fn(el);
-}
-
-/* **************************************************************************
- * BoxIndex implementation
- * ************************************************************************** */
-
-class BoxIndex::Impl {
-public:
- using BoostIndex = boost::geometry::index::
- rtree /* ? */>;
-
- 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 BoxIndex::query(const BoundingBox &qrbb,
- BoxIndex::QueryType qt)
-{
- namespace bgi = boost::geometry::index;
-
- std::vector 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 fn)
-{
- for(auto& el : m_impl->m_store) fn(el);
-}
-
-
-/* ****************************************************************************
- * EigenMesh3D implementation
- * ****************************************************************************/
-
-
-class EigenMesh3D::AABBImpl {
+class IndexedMesh::AABBImpl {
private:
AABBTreeIndirect::Tree3f m_tree;
@@ -189,7 +20,7 @@ public:
void init(const TriangleMesh& tm)
{
m_tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(
- tm.its.vertices, tm.its.indices);
+ tm.its.vertices, tm.its.indices);
}
void intersect_ray(const TriangleMesh& tm,
@@ -215,9 +46,9 @@ public:
size_t idx_unsigned = 0;
Vec3d closest_vec3d(closest);
double dist = AABBTreeIndirect::squared_distance_to_indexed_triangle_set(
- tm.its.vertices,
- tm.its.indices,
- m_tree, point, idx_unsigned, closest_vec3d);
+ tm.its.vertices,
+ tm.its.indices,
+ m_tree, point, idx_unsigned, closest_vec3d);
i = int(idx_unsigned);
closest = closest_vec3d;
return dist;
@@ -226,72 +57,71 @@ public:
static const constexpr double MESH_EPS = 1e-6;
-EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh)
+IndexedMesh::IndexedMesh(const TriangleMesh& tmesh)
: m_aabb(new AABBImpl()), m_tm(&tmesh)
{
auto&& bb = tmesh.bounding_box();
m_ground_level += bb.min(Z);
-
+
// Build the AABB accelaration tree
m_aabb->init(tmesh);
}
-EigenMesh3D::~EigenMesh3D() {}
+IndexedMesh::~IndexedMesh() {}
-EigenMesh3D::EigenMesh3D(const EigenMesh3D &other):
+IndexedMesh::IndexedMesh(const IndexedMesh &other):
m_tm(other.m_tm), m_ground_level(other.m_ground_level),
m_aabb( new AABBImpl(*other.m_aabb) ) {}
-EigenMesh3D &EigenMesh3D::operator=(const EigenMesh3D &other)
+IndexedMesh &IndexedMesh::operator=(const IndexedMesh &other)
{
m_tm = other.m_tm;
m_ground_level = other.m_ground_level;
m_aabb.reset(new AABBImpl(*other.m_aabb)); return *this;
}
-EigenMesh3D &EigenMesh3D::operator=(EigenMesh3D &&other) = default;
+IndexedMesh &IndexedMesh::operator=(IndexedMesh &&other) = default;
-EigenMesh3D::EigenMesh3D(EigenMesh3D &&other) = default;
+IndexedMesh::IndexedMesh(IndexedMesh &&other) = default;
-const std::vector& EigenMesh3D::vertices() const
+const std::vector& IndexedMesh::vertices() const
{
return m_tm->its.vertices;
}
-const std::vector& EigenMesh3D::indices() const
+const std::vector& IndexedMesh::indices() const
{
return m_tm->its.indices;
}
-const Vec3f& EigenMesh3D::vertices(size_t idx) const
+const Vec3f& IndexedMesh::vertices(size_t idx) const
{
return m_tm->its.vertices[idx];
}
-const Vec3i& EigenMesh3D::indices(size_t idx) const
+const Vec3i& IndexedMesh::indices(size_t idx) const
{
return m_tm->its.indices[idx];
}
-Vec3d EigenMesh3D::normal_by_face_id(int face_id) const {
+Vec3d IndexedMesh::normal_by_face_id(int face_id) const {
return m_tm->stl.facet_start[face_id].normal.cast();
}
-
-EigenMesh3D::hit_result
-EigenMesh3D::query_ray_hit(const Vec3d &s, const Vec3d &dir) const
+IndexedMesh::hit_result
+IndexedMesh::query_ray_hit(const Vec3d &s, const Vec3d &dir) const
{
assert(is_approx(dir.norm(), 1.));
igl::Hit hit;
@@ -319,13 +149,13 @@ EigenMesh3D::query_ray_hit(const Vec3d &s, const Vec3d &dir) const
return ret;
}
-std::vector
-EigenMesh3D::query_ray_hits(const Vec3d &s, const Vec3d &dir) const
+std::vector
+IndexedMesh::query_ray_hits(const Vec3d &s, const Vec3d &dir) const
{
- std::vector outs;
+ std::vector outs;
std::vector hits;
m_aabb->intersect_ray(*m_tm, s, dir, hits);
-
+
// The sort is necessary, the hits are not always sorted.
std::sort(hits.begin(), hits.end(),
[](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; });
@@ -334,13 +164,13 @@ EigenMesh3D::query_ray_hits(const Vec3d &s, const Vec3d &dir) const
// along an axis of a cube due to floating-point approximations in igl (?)
hits.erase(std::unique(hits.begin(), hits.end(),
[](const igl::Hit& a, const igl::Hit& b)
- { return a.t == b.t; }),
+ { return a.t == b.t; }),
hits.end());
// Convert the igl::Hit into hit_result
outs.reserve(hits.size());
for (const igl::Hit& hit : hits) {
- outs.emplace_back(EigenMesh3D::hit_result(*this));
+ outs.emplace_back(IndexedMesh::hit_result(*this));
outs.back().m_t = double(hit.t);
outs.back().m_dir = dir;
outs.back().m_source = s;
@@ -355,8 +185,8 @@ EigenMesh3D::query_ray_hits(const Vec3d &s, const Vec3d &dir) const
#ifdef SLIC3R_HOLE_RAYCASTER
-EigenMesh3D::hit_result EigenMesh3D::filter_hits(
- const std::vector& object_hits) const
+IndexedMesh::hit_result IndexedMesh::filter_hits(
+ const std::vector& object_hits) const
{
assert(! m_holes.empty());
hit_result out(*this);
@@ -377,7 +207,7 @@ EigenMesh3D::hit_result EigenMesh3D::filter_hits(
};
std::vector hole_isects;
hole_isects.reserve(m_holes.size());
-
+
auto sf = s.cast();
auto dirf = dir.cast();
@@ -452,7 +282,7 @@ EigenMesh3D::hit_result EigenMesh3D::filter_hits(
#endif
-double EigenMesh3D::squared_distance(const Vec3d &p, int& i, Vec3d& c) const {
+double IndexedMesh::squared_distance(const Vec3d &p, int& i, Vec3d& c) const {
double sqdst = 0;
Eigen::Matrix pp = p;
Eigen::Matrix cc;
@@ -461,31 +291,19 @@ double EigenMesh3D::squared_distance(const Vec3d &p, int& i, Vec3d& c) const {
return sqdst;
}
-/* ****************************************************************************
- * Misc functions
- * ****************************************************************************/
-namespace {
-
-bool point_on_edge(const Vec3d& p, const Vec3d& e1, const Vec3d& e2,
- double eps = 0.05)
+static bool point_on_edge(const Vec3d& p, const Vec3d& e1, const Vec3d& e2,
+ double eps = 0.05)
{
using Line3D = Eigen::ParametrizedLine;
-
+
auto line = Line3D::Through(e1, e2);
double d = line.distance(p);
return std::abs(d) < eps;
}
-template double distance(const Vec& pp1, const Vec& pp2) {
- auto p = pp2 - pp1;
- return std::sqrt(p.transpose() * p);
-}
-
-}
-
PointSet normals(const PointSet& points,
- const EigenMesh3D& mesh,
+ const IndexedMesh& mesh,
double eps,
std::function thr, // throw on cancel
const std::vector& pt_indices)
@@ -531,11 +349,11 @@ PointSet normals(const PointSet& points,
// ic will mark a single vertex.
int ia = -1, ib = -1, ic = -1;
- if (std::abs(distance(p, p1)) < eps) {
+ if (std::abs((p - p1).norm()) < eps) {
ic = trindex(0);
- } else if (std::abs(distance(p, p2)) < eps) {
+ } else if (std::abs((p - p2).norm()) < eps) {
ic = trindex(1);
- } else if (std::abs(distance(p, p3)) < eps) {
+ } else if (std::abs((p - p3).norm()) < eps) {
ic = trindex(2);
} else if (point_on_edge(p, p1, p2, eps)) {
ia = trindex(0);
@@ -612,148 +430,4 @@ PointSet normals(const PointSet& points,
return ret;
}
-namespace bgi = boost::geometry::index;
-using Index3D = bgi::rtree< PointIndexEl, bgi::rstar<16, 4> /* ? */ >;
-
-namespace {
-
-bool cmp_ptidx_elements(const PointIndexEl& e1, const PointIndexEl& e2)
-{
- return e1.second < e2.second;
-};
-
-ClusteredPoints cluster(Index3D &sindex,
- unsigned max_points,
- std::function(
- const Index3D &, const PointIndexEl &)> qfn)
-{
- using Elems = std::vector;
-
- // Recursive function for visiting all the points in a given distance to
- // each other
- std::function group =
- [&sindex, &group, max_points, qfn](Elems& pts, Elems& cluster)
- {
- for(auto& p : pts) {
- std::vector tmp = qfn(sindex, p);
-
- std::sort(tmp.begin(), tmp.end(), cmp_ptidx_elements);
-
- Elems newpts;
- std::set_difference(tmp.begin(), tmp.end(),
- cluster.begin(), cluster.end(),
- std::back_inserter(newpts), cmp_ptidx_elements);
-
- int c = max_points && newpts.size() + cluster.size() > max_points?
- int(max_points - cluster.size()) : int(newpts.size());
-
- cluster.insert(cluster.end(), newpts.begin(), newpts.begin() + c);
- std::sort(cluster.begin(), cluster.end(), cmp_ptidx_elements);
-
- if(!newpts.empty() && (!max_points || cluster.size() < max_points))
- group(newpts, cluster);
- }
- };
-
- std::vector clusters;
- for(auto it = sindex.begin(); it != sindex.end();) {
- Elems cluster = {};
- Elems pts = {*it};
- group(pts, cluster);
-
- for(auto& c : cluster) sindex.remove(c);
- it = sindex.begin();
-
- clusters.emplace_back(cluster);
- }
-
- ClusteredPoints result;
- for(auto& cluster : clusters) {
- result.emplace_back();
- for(auto c : cluster) result.back().emplace_back(c.second);
- }
-
- return result;
-}
-
-std::vector distance_queryfn(const Index3D& sindex,
- const PointIndexEl& p,
- double dist,
- unsigned max_points)
-{
- std::vector tmp; tmp.reserve(max_points);
- sindex.query(
- bgi::nearest(p.first, max_points),
- std::back_inserter(tmp)
- );
-
- for(auto it = tmp.begin(); it < tmp.end(); ++it)
- if(distance(p.first, it->first) > dist) it = tmp.erase(it);
-
- return tmp;
-}
-
-} // namespace
-
-// Clustering a set of points by the given criteria
-ClusteredPoints cluster(
- const std::vector& indices,
- std::function pointfn,
- double dist,
- unsigned max_points)
-{
- // A spatial index for querying the nearest points
- Index3D sindex;
-
- // Build the index
- for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx));
-
- return cluster(sindex, max_points,
- [dist, max_points](const Index3D& sidx, const PointIndexEl& p)
- {
- return distance_queryfn(sidx, p, dist, max_points);
- });
-}
-
-// Clustering a set of points by the given criteria
-ClusteredPoints cluster(
- const std::vector& indices,
- std::function pointfn,
- std::function predicate,
- unsigned max_points)
-{
- // A spatial index for querying the nearest points
- Index3D sindex;
-
- // Build the index
- for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx));
-
- return cluster(sindex, max_points,
- [max_points, predicate](const Index3D& sidx, const PointIndexEl& p)
- {
- std::vector tmp; tmp.reserve(max_points);
- sidx.query(bgi::satisfies([p, predicate](const PointIndexEl& e){
- return predicate(p, e);
- }), std::back_inserter(tmp));
- return tmp;
- });
-}
-
-ClusteredPoints cluster(const PointSet& pts, double dist, unsigned max_points)
-{
- // A spatial index for querying the nearest points
- Index3D sindex;
-
- // Build the index
- for(Eigen::Index i = 0; i < pts.rows(); i++)
- sindex.insert(std::make_pair(Vec3d(pts.row(i)), unsigned(i)));
-
- return cluster(sindex, max_points,
- [dist, max_points](const Index3D& sidx, const PointIndexEl& p)
- {
- return distance_queryfn(sidx, p, dist, max_points);
- });
-}
-
-} // namespace sla
-} // namespace Slic3r
+}} // namespace Slic3r::sla
diff --git a/src/libslic3r/SLA/EigenMesh3D.hpp b/src/libslic3r/SLA/IndexedMesh.hpp
similarity index 81%
rename from src/libslic3r/SLA/EigenMesh3D.hpp
rename to src/libslic3r/SLA/IndexedMesh.hpp
index b932c0c18..a72492b34 100644
--- a/src/libslic3r/SLA/EigenMesh3D.hpp
+++ b/src/libslic3r/SLA/IndexedMesh.hpp
@@ -1,8 +1,10 @@
-#ifndef SLA_EIGENMESH3D_H
-#define SLA_EIGENMESH3D_H
+#ifndef SLA_INDEXEDMESH_H
+#define SLA_INDEXEDMESH_H
-#include
+#include
+#include
+#include
// There is an implementation of a hole-aware raycaster that was eventually
// not used in production version. It is now hidden under following define
@@ -19,10 +21,12 @@ class TriangleMesh;
namespace sla {
+using PointSet = Eigen::MatrixXd;
+
/// An index-triangle structure for libIGL functions. Also serves as an
/// alternative (raw) input format for the SLASupportTree.
// Implemented in libslic3r/SLA/Common.cpp
-class EigenMesh3D {
+class IndexedMesh {
class AABBImpl;
const TriangleMesh* m_tm;
@@ -38,15 +42,15 @@ class EigenMesh3D {
public:
- explicit EigenMesh3D(const TriangleMesh&);
+ explicit IndexedMesh(const TriangleMesh&);
- EigenMesh3D(const EigenMesh3D& other);
- EigenMesh3D& operator=(const EigenMesh3D&);
+ IndexedMesh(const IndexedMesh& other);
+ IndexedMesh& operator=(const IndexedMesh&);
- EigenMesh3D(EigenMesh3D &&other);
- EigenMesh3D& operator=(EigenMesh3D &&other);
+ IndexedMesh(IndexedMesh &&other);
+ IndexedMesh& operator=(IndexedMesh &&other);
- ~EigenMesh3D();
+ ~IndexedMesh();
inline double ground_level() const { return m_ground_level + m_gnd_offset; }
inline void ground_level_offset(double o) { m_gnd_offset = o; }
@@ -62,15 +66,15 @@ public:
// m_t holds a distance from m_source to the intersection.
double m_t = infty();
int m_face_id = -1;
- const EigenMesh3D *m_mesh = nullptr;
+ const IndexedMesh *m_mesh = nullptr;
Vec3d m_dir;
Vec3d m_source;
Vec3d m_normal;
- friend class EigenMesh3D;
+ friend class IndexedMesh;
// A valid object of this class can only be obtained from
- // EigenMesh3D::query_ray_hit method.
- explicit inline hit_result(const EigenMesh3D& em): m_mesh(&em) {}
+ // IndexedMesh::query_ray_hit method.
+ explicit inline hit_result(const IndexedMesh& em): m_mesh(&em) {}
public:
// This denotes no hit on the mesh.
static inline constexpr double infty() { return std::numeric_limits::infinity(); }
@@ -83,7 +87,7 @@ public:
inline Vec3d position() const { return m_source + m_dir * m_t; }
inline int face() const { return m_face_id; }
inline bool is_valid() const { return m_mesh != nullptr; }
- inline bool is_hit() const { return !std::isinf(m_t); }
+ inline bool is_hit() const { return m_face_id >= 0 && !std::isinf(m_t); }
inline const Vec3d& normal() const {
assert(is_valid());
@@ -107,7 +111,7 @@ public:
// This function is currently not used anywhere, it was written when the
// holes were subtracted on slices, that is, before we started using CGAL
// to actually cut the holes into the mesh.
- hit_result filter_hits(const std::vector& obj_hits) const;
+ hit_result filter_hits(const std::vector& obj_hits) const;
#endif
// Casting a ray on the mesh, returns the distance where the hit occures.
@@ -125,16 +129,18 @@ public:
}
Vec3d normal_by_face_id(int face_id) const;
+
+ const TriangleMesh * get_triangle_mesh() const { return m_tm; }
};
// Calculate the normals for the selected points (from 'points' set) on the
// mesh. This will call squared distance for each point.
PointSet normals(const PointSet& points,
- const EigenMesh3D& convert_mesh,
+ const IndexedMesh& convert_mesh,
double eps = 0.05, // min distance from edges
std::function throw_on_cancel = [](){},
const std::vector& selected_points = {});
}} // namespace Slic3r::sla
-#endif // EIGENMESH3D_H
+#endif // INDEXEDMESH_H
diff --git a/src/libslic3r/SLA/JobController.hpp b/src/libslic3r/SLA/JobController.hpp
index 3baa3d12d..b815e4d6f 100644
--- a/src/libslic3r/SLA/JobController.hpp
+++ b/src/libslic3r/SLA/JobController.hpp
@@ -2,6 +2,7 @@
#define SLA_JOBCONTROLLER_HPP
#include
+#include
namespace Slic3r { namespace sla {
diff --git a/src/libslic3r/SLA/Pad.cpp b/src/libslic3r/SLA/Pad.cpp
index d933ef5ed..f2b189cd1 100644
--- a/src/libslic3r/SLA/Pad.cpp
+++ b/src/libslic3r/SLA/Pad.cpp
@@ -1,5 +1,4 @@
#include
-#include
#include
#include
#include
diff --git a/src/libslic3r/SLA/ReprojectPointsOnMesh.hpp b/src/libslic3r/SLA/ReprojectPointsOnMesh.hpp
index 702d1bce1..4737a6c21 100644
--- a/src/libslic3r/SLA/ReprojectPointsOnMesh.hpp
+++ b/src/libslic3r/SLA/ReprojectPointsOnMesh.hpp
@@ -4,7 +4,7 @@
#include "libslic3r/Point.hpp"
#include "SupportPoint.hpp"
#include "Hollowing.hpp"
-#include "EigenMesh3D.hpp"
+#include "IndexedMesh.hpp"
#include "libslic3r/Model.hpp"
#include
@@ -15,7 +15,7 @@ template Vec3d pos(const Pt &p) { return p.pos.template cast()
template void pos(Pt &p, const Vec3d &pp) { p.pos = pp.cast(); }
template
-void reproject_support_points(const EigenMesh3D &mesh, std::vector &pts)
+void reproject_support_points(const IndexedMesh &mesh, std::vector &pts)
{
tbb::parallel_for(size_t(0), pts.size(), [&mesh, &pts](size_t idx) {
int junk;
@@ -40,7 +40,7 @@ inline void reproject_points_and_holes(ModelObject *object)
TriangleMesh rmsh = object->raw_mesh();
rmsh.require_shared_vertices();
- EigenMesh3D emesh{rmsh};
+ IndexedMesh emesh{rmsh};
if (has_sppoints)
reproject_support_points(emesh, object->sla_support_points);
diff --git a/src/libslic3r/SLA/Rotfinder.cpp b/src/libslic3r/SLA/Rotfinder.cpp
index fda8383b1..81ef00e6b 100644
--- a/src/libslic3r/SLA/Rotfinder.cpp
+++ b/src/libslic3r/SLA/Rotfinder.cpp
@@ -2,7 +2,6 @@
#include
#include