2018-12-07 13:10:16 +00:00
|
|
|
#ifndef SLAAUTOSUPPORTS_HPP_
|
|
|
|
#define SLAAUTOSUPPORTS_HPP_
|
|
|
|
|
|
|
|
#include <libslic3r/Point.hpp>
|
2018-12-07 14:24:50 +00:00
|
|
|
#include <libslic3r/TriangleMesh.hpp>
|
2019-02-01 15:12:00 +00:00
|
|
|
#include <libslic3r/SLA/SLACommon.hpp>
|
2018-12-07 13:10:16 +00:00
|
|
|
|
2019-02-18 10:46:06 +00:00
|
|
|
#include <boost/container/small_vector.hpp>
|
|
|
|
|
2018-12-22 09:55:15 +00:00
|
|
|
// #define SLA_AUTOSUPPORTS_DEBUG
|
2018-12-07 13:10:16 +00:00
|
|
|
|
|
|
|
namespace Slic3r {
|
|
|
|
|
|
|
|
class SLAAutoSupports {
|
|
|
|
public:
|
|
|
|
struct Config {
|
|
|
|
float density_at_horizontal;
|
|
|
|
float density_at_45;
|
|
|
|
float minimal_z;
|
2019-01-30 07:26:23 +00:00
|
|
|
///////////////
|
2019-02-19 09:09:41 +00:00
|
|
|
// float support_force = 30.f; // a force one point can support (arbitrary force unit)
|
|
|
|
float support_force = 10.f; // a force one point can support (arbitrary force unit)
|
|
|
|
float tear_pressure = 1.f; // pressure that the display exerts (the force unit per mm2)
|
2018-12-07 13:10:16 +00:00
|
|
|
};
|
|
|
|
|
2019-01-30 07:26:23 +00:00
|
|
|
SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector<ExPolygons>& slices,
|
|
|
|
const std::vector<float>& heights, const Config& config, std::function<void(void)> throw_on_cancel);
|
|
|
|
const std::vector<sla::SupportPoint>& output() { return m_output; }
|
2018-12-07 13:10:16 +00:00
|
|
|
|
2019-02-18 10:46:06 +00:00
|
|
|
struct MyLayer;
|
2019-01-30 07:26:23 +00:00
|
|
|
|
|
|
|
struct Structure {
|
2019-02-18 10:46:06 +00:00
|
|
|
Structure(MyLayer &layer, const ExPolygon& poly, const BoundingBox &bbox, const Vec2f ¢roid, float area, float h) :
|
|
|
|
layer(&layer), polygon(&poly), bbox(bbox), centroid(centroid), area(area), height(h)
|
2019-02-06 09:57:45 +00:00
|
|
|
#ifdef SLA_AUTOSUPPORTS_DEBUG
|
|
|
|
, unique_id(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
|
|
|
|
#endif /* SLA_AUTOSUPPORTS_DEBUG */
|
|
|
|
{}
|
2019-02-18 10:46:06 +00:00
|
|
|
MyLayer *layer;
|
2019-01-30 07:26:23 +00:00
|
|
|
const ExPolygon* polygon = nullptr;
|
2019-02-06 09:57:45 +00:00
|
|
|
const BoundingBox bbox;
|
2019-02-06 10:09:00 +00:00
|
|
|
const Vec2f centroid = Vec2f::Zero();
|
2019-02-06 09:57:45 +00:00
|
|
|
const float area = 0.f;
|
2019-01-30 07:26:23 +00:00
|
|
|
float height = 0;
|
2019-02-06 09:57:45 +00:00
|
|
|
// How well is this ExPolygon held to the print base?
|
|
|
|
// Positive number, the higher the better.
|
2019-02-19 09:09:41 +00:00
|
|
|
float supports_force_this_layer = 0.f;
|
|
|
|
float supports_force_inherited = 0.f;
|
|
|
|
float supports_force_total() const { return this->supports_force_this_layer + this->supports_force_inherited; }
|
2019-02-06 09:57:45 +00:00
|
|
|
#ifdef SLA_AUTOSUPPORTS_DEBUG
|
2019-01-30 07:26:23 +00:00
|
|
|
std::chrono::milliseconds unique_id;
|
2019-02-06 09:57:45 +00:00
|
|
|
#endif /* SLA_AUTOSUPPORTS_DEBUG */
|
|
|
|
|
2019-02-19 09:09:41 +00:00
|
|
|
#ifdef NDEBUG
|
|
|
|
// In release mode, use the optimized container.
|
2019-02-18 10:46:06 +00:00
|
|
|
boost::container::small_vector<Structure*, 4> islands_above;
|
|
|
|
boost::container::small_vector<Structure*, 4> islands_below;
|
2019-02-19 09:09:41 +00:00
|
|
|
#else
|
|
|
|
// In debug mode, use the standard vector, which is well handled by debugger visualizer.
|
|
|
|
std::vector<Structure*> islands_above;
|
|
|
|
std::vector<Structure*> islands_below;
|
|
|
|
#endif
|
2019-02-18 10:46:06 +00:00
|
|
|
ExPolygons dangling_areas;
|
|
|
|
ExPolygons overhangs;
|
|
|
|
float overhangs_area;
|
|
|
|
|
2019-02-06 09:57:45 +00:00
|
|
|
bool overlaps(const Structure &rhs) const { return this->bbox.overlap(rhs.bbox) && (this->polygon->overlaps(*rhs.polygon) || rhs.polygon->overlaps(*this->polygon)); }
|
|
|
|
float area_below() const {
|
|
|
|
float area = 0.f;
|
2019-02-18 10:46:06 +00:00
|
|
|
for (const Structure *below : this->islands_below)
|
2019-02-06 09:57:45 +00:00
|
|
|
area += below->area;
|
|
|
|
return area;
|
|
|
|
}
|
|
|
|
Polygons polygons_below() const {
|
|
|
|
size_t cnt = 0;
|
2019-02-18 10:46:06 +00:00
|
|
|
for (const Structure *below : this->islands_below)
|
2019-02-06 09:57:45 +00:00
|
|
|
cnt += 1 + below->polygon->holes.size();
|
|
|
|
Polygons out;
|
|
|
|
out.reserve(cnt);
|
2019-02-18 10:46:06 +00:00
|
|
|
for (const Structure *below : this->islands_below) {
|
2019-02-06 09:57:45 +00:00
|
|
|
out.emplace_back(below->polygon->contour);
|
|
|
|
append(out, below->polygon->holes);
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
ExPolygons expolygons_below() const {
|
|
|
|
ExPolygons out;
|
2019-02-18 10:46:06 +00:00
|
|
|
out.reserve(this->islands_below.size());
|
|
|
|
for (const Structure *below : this->islands_below)
|
2019-02-06 09:57:45 +00:00
|
|
|
out.emplace_back(*below->polygon);
|
|
|
|
return out;
|
|
|
|
}
|
2019-02-19 09:09:41 +00:00
|
|
|
// Positive deficit of the supports. If negative, this area is well supported. If positive, more supports need to be added.
|
|
|
|
float support_force_deficit(const float tear_pressure) const { return this->area * tear_pressure - this->supports_force_total(); }
|
2019-01-30 07:26:23 +00:00
|
|
|
};
|
2019-02-06 09:57:45 +00:00
|
|
|
|
2019-02-18 10:46:06 +00:00
|
|
|
struct MyLayer {
|
|
|
|
MyLayer(const size_t layer_id, coordf_t print_z) : layer_id(layer_id), print_z(print_z) {}
|
|
|
|
size_t layer_id;
|
|
|
|
coordf_t print_z;
|
|
|
|
std::vector<Structure> islands;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct RichSupportPoint {
|
|
|
|
Vec3f position;
|
|
|
|
Structure *island;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PointGrid3D {
|
|
|
|
struct GridHash {
|
2019-02-18 11:47:15 +00:00
|
|
|
std::size_t operator()(const Vec3i &cell_id) const {
|
2019-02-18 10:46:06 +00:00
|
|
|
return std::hash<int>()(cell_id.x()) ^ std::hash<int>()(cell_id.y() * 593) ^ std::hash<int>()(cell_id.z() * 7919);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
typedef std::unordered_multimap<Vec3i, RichSupportPoint, GridHash> Grid;
|
|
|
|
|
|
|
|
Vec3f cell_size;
|
|
|
|
Grid grid;
|
|
|
|
|
|
|
|
Vec3i cell_id(const Vec3f &pos) {
|
|
|
|
return Vec3i(int(floor(pos.x() / cell_size.x())),
|
|
|
|
int(floor(pos.y() / cell_size.y())),
|
|
|
|
int(floor(pos.z() / cell_size.z())));
|
|
|
|
}
|
|
|
|
|
|
|
|
void insert(const Vec2f &pos, Structure *island) {
|
|
|
|
RichSupportPoint pt;
|
|
|
|
pt.position = Vec3f(pos.x(), pos.y(), float(island->layer->print_z));
|
|
|
|
pt.island = island;
|
|
|
|
grid.emplace(cell_id(pt.position), pt);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool collides_with(const Vec2f &pos, Structure *island, float radius) {
|
|
|
|
Vec3f pos3d(pos.x(), pos.y(), float(island->layer->print_z));
|
|
|
|
Vec3i cell = cell_id(pos3d);
|
|
|
|
std::pair<Grid::const_iterator, Grid::const_iterator> it_pair = grid.equal_range(cell);
|
|
|
|
if (collides_with(pos3d, radius, it_pair.first, it_pair.second))
|
|
|
|
return true;
|
|
|
|
for (int i = -1; i < 2; ++ i)
|
|
|
|
for (int j = -1; j < 2; ++ j)
|
|
|
|
for (int k = -1; k < 1; ++ k) {
|
|
|
|
if (i == 0 && j == 0 && k == 0)
|
|
|
|
continue;
|
|
|
|
it_pair = grid.equal_range(cell + Vec3i(i, j, k));
|
|
|
|
if (collides_with(pos3d, radius, it_pair.first, it_pair.second))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool collides_with(const Vec3f &pos, float radius, Grid::const_iterator it_begin, Grid::const_iterator it_end) {
|
|
|
|
for (Grid::const_iterator it = it_begin; it != it_end; ++ it) {
|
|
|
|
float dist2 = (it->second.position - pos).squaredNorm();
|
|
|
|
if (dist2 < radius * radius)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::vector<sla::SupportPoint> m_output;
|
|
|
|
|
|
|
|
SLAAutoSupports::Config m_config;
|
|
|
|
|
2019-01-30 07:26:23 +00:00
|
|
|
float m_supports_force_total = 0.f;
|
|
|
|
|
|
|
|
void process(const std::vector<ExPolygons>& slices, const std::vector<float>& heights);
|
2019-02-19 09:09:41 +00:00
|
|
|
void uniformly_cover(const ExPolygons& islands, Structure& structure, PointGrid3D &grid3d, bool is_new_island = false, bool just_one = false);
|
2019-01-30 07:26:23 +00:00
|
|
|
void project_onto_mesh(std::vector<sla::SupportPoint>& points) const;
|
|
|
|
|
2019-02-06 09:57:45 +00:00
|
|
|
#ifdef SLA_AUTOSUPPORTS_DEBUG
|
|
|
|
static void output_expolygons(const ExPolygons& expolys, const std::string &filename);
|
|
|
|
static void output_structures(const std::vector<Structure> &structures);
|
|
|
|
#endif // SLA_AUTOSUPPORTS_DEBUG
|
2019-01-30 07:26:23 +00:00
|
|
|
|
2018-12-22 10:21:21 +00:00
|
|
|
std::function<void(void)> m_throw_on_cancel;
|
2019-02-04 08:50:25 +00:00
|
|
|
const sla::EigenMesh3D& m_emesh;
|
2018-12-07 13:10:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace Slic3r
|
|
|
|
|
|
|
|
|
|
|
|
#endif // SLAAUTOSUPPORTS_HPP_
|