mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-15 01:15:55 +08:00
Supported point are created by distance(xy + z) to previous one
This commit is contained in:
parent
f1f0fbc9ad
commit
63f6b293bf
File diff suppressed because it is too large
Load Diff
@ -2,42 +2,23 @@
|
|||||||
///|/
|
///|/
|
||||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||||
///|/
|
///|/
|
||||||
#ifndef SLA_SUPPORTPOINTGENERATOR_HPP
|
#ifndef SLA_SUPPORTPOINTGENERATOR_NEW_HPP
|
||||||
#define SLA_SUPPORTPOINTGENERATOR_HPP
|
#define SLA_SUPPORTPOINTGENERATOR_NEW_HPP
|
||||||
|
|
||||||
#include <libslic3r/AABBMesh.hpp>
|
|
||||||
#include <libslic3r/SLA/SupportPoint.hpp>
|
|
||||||
#include <libslic3r/BoundingBox.hpp>
|
|
||||||
#include <libslic3r/ClipperUtils.hpp>
|
|
||||||
#include <libslic3r/Point.hpp>
|
|
||||||
#include <boost/container/small_vector.hpp>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <random>
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <functional>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cinttypes>
|
#include <functional>
|
||||||
|
|
||||||
|
#include <boost/container/small_vector.hpp>
|
||||||
|
|
||||||
|
#include "libslic3r/Point.hpp"
|
||||||
#include "libslic3r/ExPolygon.hpp"
|
#include "libslic3r/ExPolygon.hpp"
|
||||||
#include "libslic3r/Polygon.hpp"
|
|
||||||
#include "libslic3r/libslic3r.h"
|
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r::sla {
|
||||||
class AABBMesh;
|
|
||||||
} // namespace Slic3r
|
|
||||||
|
|
||||||
// #define SLA_SUPPORTPOINTGEN_DEBUG
|
|
||||||
|
|
||||||
namespace Slic3r { namespace sla {
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configuration for automatic support placement
|
/// Configuration for automatic support placement
|
||||||
/// </summary>
|
/// </summary>
|
||||||
struct SupportPointGeneratorConfig{
|
struct SupportPointGeneratorConfig{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 0 mean only one support point for each island
|
/// 0 mean only one support point for each island
|
||||||
/// lower than one mean less amount of support points
|
/// lower than one mean less amount of support points
|
||||||
@ -47,235 +28,163 @@ struct SupportPointGeneratorConfig{
|
|||||||
float density_relative{1.f};
|
float density_relative{1.f};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Minimal distance between support points
|
/// Size range for support point interface (head)
|
||||||
/// Should correspond with density relative
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
float minimal_distance{1.f};
|
MinMax<float> head_diameter = {0.2f, 0.6f}; // [in mm]
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// size of supported point - range in future
|
|
||||||
/// </summary>
|
|
||||||
float head_diameter{0.4f};
|
|
||||||
|
|
||||||
// FIXME: calculate actual pixel area from printer config:
|
// FIXME: calculate actual pixel area from printer config:
|
||||||
// const float pixel_area =
|
// const float pixel_area =
|
||||||
// pow(wxGetApp().preset_bundle->project_config.option<ConfigOptionFloat>("display_width") /
|
// pow(wxGetApp().preset_bundle->project_config.option<ConfigOptionFloat>("display_width") /
|
||||||
// wxGetApp().preset_bundle->project_config.option<ConfigOptionInt>("display_pixels_x"), 2.f); //
|
// wxGetApp().preset_bundle->project_config.option<ConfigOptionInt>("display_pixels_x"), 2.f); //
|
||||||
// Minimal island Area to print - TODO: Should be modifiable from UI
|
// Minimal island Area to print - TODO: Should be modifiable from UI
|
||||||
|
// !! Filter should be out of sampling algorithm !!
|
||||||
float minimal_island_area = pow(0.047f, 2.f); // [in mm^2] pixel_area
|
float minimal_island_area = pow(0.047f, 2.f); // [in mm^2] pixel_area
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LayerPart; // forward decl.
|
||||||
|
using LayerParts = std::vector<LayerPart>;
|
||||||
|
|
||||||
class SupportPointGenerator {
|
struct PartLink
|
||||||
public:
|
{
|
||||||
|
LayerParts::const_iterator part_it;
|
||||||
|
// float overlap_area; // sum of overlap areas
|
||||||
SupportPointGenerator(const AABBMesh& emesh, const std::vector<ExPolygons>& slices, const std::vector<float>& heights,
|
// ExPolygons overlap; // clipper intersection_ex
|
||||||
std::function<void(void)> throw_on_cancel, std::function<void(int)> statusfn);
|
// ExPolygons overhang; // clipper diff_ex
|
||||||
|
};
|
||||||
const std::vector<SupportPoint>& output() const { return m_output; }
|
|
||||||
std::vector<SupportPoint>& output() { return m_output; }
|
|
||||||
|
|
||||||
struct MyLayer;
|
|
||||||
|
|
||||||
// Keep data for one area(ExPlygon) on the layer(on slice Expolygons)
|
|
||||||
struct Structure {
|
|
||||||
Structure(MyLayer &layer, const ExPolygon& poly, const BoundingBox &bbox, float area) :
|
|
||||||
layer(&layer), polygon(&poly), bbox(bbox), area(area)
|
|
||||||
#ifdef SLA_SUPPORTPOINTGEN_DEBUG
|
|
||||||
, unique_id(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()))
|
|
||||||
#endif /* SLA_SUPPORTPOINTGEN_DEBUG */
|
|
||||||
{}
|
|
||||||
// Parent layer - with all ExPolygons in layer + layer_height
|
|
||||||
MyLayer *layer;
|
|
||||||
// Source ExPolygon
|
|
||||||
const ExPolygon* polygon = nullptr;
|
|
||||||
// Cache bounding box of polygon
|
|
||||||
const BoundingBox bbox;
|
|
||||||
// area of polygon [in mm^2] without holes
|
|
||||||
const float area = 0.f;
|
|
||||||
|
|
||||||
// How well is this ExPolygon held to the print base?
|
|
||||||
// Positive number, the higher the better.
|
|
||||||
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; }
|
|
||||||
#ifdef SLA_SUPPORTPOINTGEN_DEBUG
|
|
||||||
std::chrono::milliseconds unique_id;
|
|
||||||
#endif /* SLA_SUPPORTPOINTGEN_DEBUG */
|
|
||||||
|
|
||||||
struct Link {
|
|
||||||
Link(Structure *island, float overlap_area) : island(island), overlap_area(overlap_area) {}
|
|
||||||
Structure *island;
|
|
||||||
float overlap_area;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
// In release mode, use the optimized container.
|
// In release mode, use the optimized container.
|
||||||
boost::container::small_vector<Link, 4> islands_above;
|
using PartLinks = boost::container::small_vector<PartLink, 4>;
|
||||||
boost::container::small_vector<Link, 4> islands_below;
|
|
||||||
#else
|
#else
|
||||||
// In debug mode, use the standard vector, which is well handled by debugger visualizer.
|
// In debug mode, use the standard vector, which is well handled by debugger visualizer.
|
||||||
std::vector<Link> islands_above;
|
using PartLinks = std::vector<PartLink>;
|
||||||
std::vector<Link> islands_below;
|
|
||||||
#endif
|
#endif
|
||||||
// Overhangs, that are dangling considerably.
|
|
||||||
ExPolygons dangling_areas;
|
|
||||||
// Complete overhangs.
|
|
||||||
ExPolygons overhangs;
|
|
||||||
// Overhangs, where the surface must slope.
|
|
||||||
ExPolygons overhangs_slopes;
|
|
||||||
// Sum of all overhang areas from structure
|
|
||||||
float overhangs_area = 0.f; // [in mm^2]
|
|
||||||
|
|
||||||
bool overlaps(const Structure &rhs) const {
|
// Part on layer is defined by its shape
|
||||||
return this->bbox.overlap(rhs.bbox) && this->polygon->overlaps(*rhs.polygon);
|
struct LayerPart {
|
||||||
}
|
// Pointer to expolygon stored in input
|
||||||
float overlap_area(const Structure &rhs) const {
|
const ExPolygon *shape;
|
||||||
double out = 0.;
|
|
||||||
if (this->bbox.overlap(rhs.bbox)) {
|
|
||||||
Polygons polys = intersection(*this->polygon, *rhs.polygon);
|
|
||||||
for (const Polygon &poly : polys)
|
|
||||||
out += poly.area();
|
|
||||||
}
|
|
||||||
return float(out);
|
|
||||||
}
|
|
||||||
float area_below() const {
|
|
||||||
float area = 0.f;
|
|
||||||
for (const Link &below : this->islands_below)
|
|
||||||
area += below.island->area;
|
|
||||||
return area;
|
|
||||||
}
|
|
||||||
Polygons polygons_below() const {
|
|
||||||
size_t cnt = 0;
|
|
||||||
for (const Link &below : this->islands_below)
|
|
||||||
cnt += 1 + below.island->polygon->holes.size();
|
|
||||||
Polygons out;
|
|
||||||
out.reserve(cnt);
|
|
||||||
for (const Link &below : this->islands_below) {
|
|
||||||
out.emplace_back(below.island->polygon->contour);
|
|
||||||
append(out, below.island->polygon->holes);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
ExPolygons expolygons_below() const {
|
|
||||||
ExPolygons out;
|
|
||||||
out.reserve(this->islands_below.size());
|
|
||||||
for (const Link &below : this->islands_below)
|
|
||||||
out.emplace_back(*below.island->polygon);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
// 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(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MyLayer {
|
// rectangular bounding box of shape
|
||||||
MyLayer(const size_t layer_id, coordf_t print_z) : layer_id(layer_id), print_z(print_z) {}
|
BoundingBox shape_extent;
|
||||||
// index into heights + slices
|
|
||||||
size_t layer_id;
|
|
||||||
// Absolute distance from Zero - copy value from heights<float>
|
|
||||||
coordf_t print_z; // [in mm]
|
|
||||||
std::vector<Structure> islands;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RichSupportPoint {
|
// uniformly sampled shape contour
|
||||||
Vec3f position;
|
Slic3r::Points samples;
|
||||||
Structure *island;
|
// IMPROVE: sample only overhangs part of shape
|
||||||
};
|
|
||||||
|
|
||||||
struct PointGrid3D {
|
// Parts from previous printed layer, which is connected to current part
|
||||||
struct GridHash {
|
PartLinks prev_parts;
|
||||||
std::size_t operator()(const Vec3i &cell_id) const {
|
PartLinks next_parts;
|
||||||
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, float print_z, float radius) {
|
|
||||||
Vec3f pos3d(pos.x(), pos.y(), 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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void execute(const std::vector<ExPolygons> &slices,
|
|
||||||
const std::vector<float> & heights);
|
|
||||||
|
|
||||||
void seed(std::mt19937::result_type s) { m_rng.seed(s); }
|
|
||||||
private:
|
|
||||||
std::vector<SupportPoint> m_output;
|
|
||||||
|
|
||||||
// Configuration
|
|
||||||
SupportPointGenerator::Config m_config;
|
|
||||||
|
|
||||||
void process(const std::vector<ExPolygons>& slices, const std::vector<float>& heights);
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum IslandCoverageFlags : uint8_t { icfNone = 0x0, icfIsNew = 0x1, icfWithBoundary = 0x2 };
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void uniformly_cover(const ExPolygons& islands, Structure& structure, float deficit, PointGrid3D &grid3d, IslandCoverageFlags flags = icfNone);
|
|
||||||
|
|
||||||
void add_support_points(Structure& structure, PointGrid3D &grid3d);
|
|
||||||
|
|
||||||
void project_onto_mesh(std::vector<SupportPoint>& points) const;
|
|
||||||
|
|
||||||
#ifdef SLA_SUPPORTPOINTGEN_DEBUG
|
|
||||||
static void output_expolygons(const ExPolygons& expolys, const std::string &filename);
|
|
||||||
static void output_structures(const std::vector<Structure> &structures);
|
|
||||||
#endif // SLA_SUPPORTPOINTGEN_DEBUG
|
|
||||||
|
|
||||||
const AABBMesh& m_emesh;
|
|
||||||
std::function<void(void)> m_throw_on_cancel;
|
|
||||||
std::function<void(int)> m_statusfn;
|
|
||||||
|
|
||||||
std::mt19937 m_rng;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void remove_bottom_points(std::vector<SupportPoint> &pts, float lvl);
|
/// <summary>
|
||||||
|
/// One slice divided into
|
||||||
|
/// </summary>
|
||||||
|
struct Layer
|
||||||
|
{
|
||||||
|
// index into parent Layesr + heights + slices
|
||||||
|
// [[deprecated]] Use index to layers insted of adress from item
|
||||||
|
size_t layer_id;
|
||||||
|
|
||||||
std::vector<Vec2f> sample_expolygon(const ExPolygon &expoly, float samples_per_mm2, std::mt19937 &rng);
|
// Absolute distance from Zero - copy value from heights<float>
|
||||||
void sample_expolygon_boundary(const ExPolygon &expoly, float samples_per_mm, std::vector<Vec2f> &out, std::mt19937 &rng);
|
// [[deprecated]] Use index to layers insted of adress from item
|
||||||
|
double print_z; // [in mm]
|
||||||
|
|
||||||
}} // namespace Slic3r::sla
|
// data for one expolygon
|
||||||
|
LayerParts parts;
|
||||||
|
};
|
||||||
|
using Layers = std::vector<Layer>;
|
||||||
|
|
||||||
#endif // SUPPORTPOINTGENERATOR_HPP
|
/// <summary>
|
||||||
|
/// Keep state of Support Point generation
|
||||||
|
/// Used for resampling with different configuration
|
||||||
|
/// </summary>
|
||||||
|
struct SupportPointGeneratorData
|
||||||
|
{
|
||||||
|
// Input slices of mesh
|
||||||
|
std::vector<ExPolygons> slices;
|
||||||
|
// Same size as slices
|
||||||
|
std::vector<float> heights;
|
||||||
|
|
||||||
|
// link to slices
|
||||||
|
Layers layers;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reason of automatic support placement usage
|
||||||
|
enum class SupportPointType {
|
||||||
|
manual_add,
|
||||||
|
island, // no move
|
||||||
|
slope,
|
||||||
|
thin,
|
||||||
|
stability,
|
||||||
|
edge
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generated support point
|
||||||
|
/// </summary>
|
||||||
|
struct SupportPoint
|
||||||
|
{
|
||||||
|
// radius of the touching interface
|
||||||
|
// Also define force it must keep
|
||||||
|
float head_front_radius{1.f};
|
||||||
|
|
||||||
|
// type
|
||||||
|
SupportPointType type{SupportPointType::manual_add};
|
||||||
|
|
||||||
|
// Pointer on source ExPolygon otherwise nullptr
|
||||||
|
const LayerPart *part{nullptr};
|
||||||
|
|
||||||
|
// 2d coordinate on layer
|
||||||
|
// use only when part is not nullptr
|
||||||
|
Point position_on_layer; // [scaled_ unit]
|
||||||
|
|
||||||
|
// height of part
|
||||||
|
float z_height;
|
||||||
|
|
||||||
|
// 2d direction into expolygon mass
|
||||||
|
// used as ray to positioning point on mesh surface
|
||||||
|
Point direction_to_mass;
|
||||||
|
};
|
||||||
|
using SupportPoints = std::vector<SupportPoint>;
|
||||||
|
|
||||||
|
// call during generation of support points to check cancel event
|
||||||
|
using ThrowOnCancel = std::function<void(void)>;
|
||||||
|
// call to say progress of generation into gui in range from 0 to 100
|
||||||
|
using StatusFunction= std::function<void(int)>;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prepare data for generate support points
|
||||||
|
/// Used for interactive resampling to store permanent data between configuration changes.,
|
||||||
|
/// Everything which could be prepared are stored into result.
|
||||||
|
/// Need to regenerate on mesh change(Should be connected with ObjectId) OR change of slicing heights
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="slices">Countour cut from mesh</param>
|
||||||
|
/// <param name="heights">Heights of the slices - Same size as slices</param>
|
||||||
|
/// <param name="throw_on_cancel">Call in meanwhile to check cancel event</param>
|
||||||
|
/// <param name="statusfn">Say progress of generation into gui</param>
|
||||||
|
/// <returns>Data prepared for generate support points</returns>
|
||||||
|
SupportPointGeneratorData prepare_generator_data(
|
||||||
|
std::vector<ExPolygons> &&slices,
|
||||||
|
std::vector<float> &&heights,
|
||||||
|
ThrowOnCancel throw_on_cancel,
|
||||||
|
StatusFunction statusfn
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generate support points on islands by configuration parameters
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">Preprocessed data needed for sampling</param>
|
||||||
|
/// <param name="config">Define density of samples</param>
|
||||||
|
/// <param name="throw_on_cancel">Call in meanwhile to check cancel event</param>
|
||||||
|
/// <param name="statusfn">Progress of generation into gui</param>
|
||||||
|
/// <returns>Generated support points</returns>
|
||||||
|
SupportPoints generate_support_points(
|
||||||
|
const SupportPointGeneratorData &data,
|
||||||
|
const SupportPointGeneratorConfig &config,
|
||||||
|
ThrowOnCancel throw_on_cancel,
|
||||||
|
StatusFunction statusfn
|
||||||
|
);
|
||||||
|
|
||||||
|
} // namespace Slic3r::sla
|
||||||
|
|
||||||
|
#endif // SLA_SUPPORTPOINTGENERATOR_NEW_HPP
|
||||||
|
Loading…
x
Reference in New Issue
Block a user