mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 03:15:51 +08:00
Add support permanent points for island and peninsulas
This commit is contained in:
parent
c66df2ce99
commit
33f878e5bd
@ -25,6 +25,8 @@ public:
|
||||
thin_part_loop, // on the last edge -> loop into itself part of island
|
||||
thick_part_outline, // keep position align with island outline
|
||||
thick_part_inner, // point inside wide part, without restriction on move
|
||||
|
||||
permanent, // permanent support point with static position
|
||||
undefined
|
||||
};
|
||||
|
||||
|
@ -3,11 +3,11 @@
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#include <libslic3r/ClipperUtils.hpp> // allign
|
||||
#include <libslic3r/KDTreeIndirect.hpp> // closest point
|
||||
#include <libslic3r/Geometry.hpp>
|
||||
#include "libslic3r/Geometry/Voronoi.hpp"
|
||||
#include <libslic3r/Geometry/VoronoiOffset.hpp>
|
||||
@ -514,6 +514,65 @@ void align_samples(SupportIslandPoints &samples, const ExPolygon &island, const
|
||||
|
||||
}
|
||||
|
||||
void align_samples_with_permanent(
|
||||
SupportIslandPoints &samples, const ExPolygon &island, const Points& permanent, const SampleConfig &config)
|
||||
{
|
||||
assert(!permanent.empty());
|
||||
if (permanent.empty())
|
||||
return align_samples(samples, island, config);
|
||||
|
||||
// detect whether add adding support points
|
||||
size_t tolerance = 1 + size_t(permanent.size() * 0.1); // 1 + 10% of permanent points
|
||||
bool extend_permanent = samples.size() > (permanent.size() + tolerance);
|
||||
if (!extend_permanent) // use only permanent support points
|
||||
return samples.clear();
|
||||
|
||||
// find closest samples to permanent support points
|
||||
Points points;
|
||||
points.reserve(samples.size());
|
||||
for (const SupportIslandPointPtr &p : samples)
|
||||
points.push_back(p->point);
|
||||
auto point_accessor = [&points](size_t idx, size_t dim) -> coord_t & {
|
||||
return points[idx][dim]; };
|
||||
KDTreeIndirect<2, coord_t, decltype(point_accessor)> tree(point_accessor, samples.size());
|
||||
for (size_t i = 0; i < permanent.size(); ++i) {
|
||||
std::array<size_t, 5> closests = find_closest_points<5>(tree, permanent[i]);
|
||||
bool found_closest = false;
|
||||
for (size_t idx : closests) {
|
||||
if (idx >= samples.size())
|
||||
continue; // closest function return also size_t::max()
|
||||
SupportIslandPointPtr &sample = samples[idx];
|
||||
if (sample->type == SupportIslandPoint::Type::permanent)
|
||||
continue; // already used
|
||||
sample->type = SupportIslandPoint::Type::permanent;
|
||||
found_closest = true;
|
||||
break;
|
||||
}
|
||||
if (!found_closest) { // backup solution when closest 5 fails, took first non permanent
|
||||
for (const auto &sample : samples)
|
||||
if (sample->type != SupportIslandPoint::Type::permanent) {
|
||||
sample->type = SupportIslandPoint::Type::permanent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove samples marked as permanent
|
||||
samples.erase(std::remove_if(samples.begin(), samples.end(), [](const SupportIslandPointPtr &sample) {
|
||||
return sample->type == SupportIslandPoint::Type::permanent; }), samples.end());
|
||||
|
||||
// add permanent into samples
|
||||
for (const Point&p: permanent)
|
||||
samples.push_back(
|
||||
std::make_unique<SupportIslandNoMovePoint>(p, SupportIslandPoint::Type::permanent));
|
||||
|
||||
align_samples(samples, island, config);
|
||||
|
||||
// remove permanent samples inserted for aligning
|
||||
samples.erase(std::remove_if(samples.begin(), samples.end(), [](const SupportIslandPointPtr &sample) {
|
||||
return sample->type == SupportIslandPoint::Type::permanent; }), samples.end());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Separation of thin and thick part of island
|
||||
/// </summary>
|
||||
@ -2231,7 +2290,8 @@ void draw(SVG &svg, const SupportIslandPoints &supportIslandPoints, coord_t radi
|
||||
/// uniform support island ///
|
||||
//////////////////////////////
|
||||
namespace Slic3r::sla {
|
||||
SupportIslandPoints uniform_support_island(const ExPolygon &island, const SampleConfig &config){
|
||||
SupportIslandPoints uniform_support_island(
|
||||
const ExPolygon &island, const Points& permanent, const SampleConfig &config){
|
||||
ExPolygon simplified_island = get_simplified(island, config);
|
||||
#ifdef OPTION_TO_STORE_ISLAND
|
||||
std::string path;
|
||||
@ -2334,7 +2394,11 @@ SupportIslandPoints uniform_support_island(const ExPolygon &island, const Sample
|
||||
#endif // OPTION_TO_STORE_ISLAND
|
||||
|
||||
// allign samples
|
||||
align_samples(supports, island, config);
|
||||
if (permanent.empty())
|
||||
align_samples(supports, island, config);
|
||||
else
|
||||
align_samples_with_permanent(supports, island, permanent, config);
|
||||
|
||||
#ifdef OPTION_TO_STORE_ISLAND
|
||||
if (!path.empty()) {
|
||||
SVG svg = draw_island(path, island, simplified_island);
|
||||
@ -2354,7 +2418,8 @@ SupportIslandPoints uniform_support_island(const ExPolygon &island, const Sample
|
||||
}
|
||||
|
||||
// Follow implementation "create_supports_for_thick_part("
|
||||
SupportIslandPoints uniform_support_peninsula(const Peninsula &peninsula, const SampleConfig &config){
|
||||
SupportIslandPoints uniform_support_peninsula(
|
||||
const Peninsula &peninsula, const Points& permanent, const SampleConfig &config){
|
||||
// create_peninsula_field
|
||||
Field field;
|
||||
field.border = peninsula.unsuported_area;
|
||||
@ -2372,7 +2437,12 @@ SupportIslandPoints uniform_support_peninsula(const Peninsula &peninsula, const
|
||||
std::transform(inner_points.begin(), inner_points.end(), std::back_inserter(results),
|
||||
[&inner](const Point &point) { return std::make_unique<SupportIslandInnerPoint>(
|
||||
point, inner, SupportIslandPoint::Type::thick_part_inner);});
|
||||
align_samples(results, peninsula.unsuported_area, config);
|
||||
|
||||
// allign samples
|
||||
if (permanent.empty())
|
||||
align_samples(results, peninsula.unsuported_area, config);
|
||||
else
|
||||
align_samples_with_permanent(results, peninsula.unsuported_area, permanent, config);
|
||||
return results;
|
||||
}
|
||||
|
||||
|
@ -12,17 +12,21 @@ namespace Slic3r::sla {
|
||||
/// Distribute support points across island area defined by ExPolygon.
|
||||
/// </summary>
|
||||
/// <param name="island">Shape of island</param>
|
||||
/// <param name="permanent">Place supported by already existing supports</param>
|
||||
/// <param name="config">Configuration of support density</param>
|
||||
/// <returns>Support points laying inside of island</returns>
|
||||
SupportIslandPoints uniform_support_island(const ExPolygon &island, const SampleConfig &config);
|
||||
/// <returns>Support points laying inside of the island</returns>
|
||||
SupportIslandPoints uniform_support_island(
|
||||
const ExPolygon &island, const Points &permanent, const SampleConfig &config);
|
||||
|
||||
/// <summary>
|
||||
/// Distribute support points across peninsula
|
||||
/// </summary>
|
||||
/// <param name="peninsula">half island with anotation of the coast and land outline</param>
|
||||
/// <param name="permanent">Place supported by already existing supports</param>
|
||||
/// <param name="config">Density distribution parameters</param>
|
||||
/// <returns></returns>
|
||||
SupportIslandPoints uniform_support_peninsula(const Peninsula &peninsula, const SampleConfig &config);
|
||||
/// <returns>Support points laying inside of the peninsula</returns>
|
||||
SupportIslandPoints uniform_support_peninsula(
|
||||
const Peninsula &peninsula, const Points& permanent, const SampleConfig &config);
|
||||
|
||||
/// <summary>
|
||||
/// Check for tests that developer do not forget disable visualization after debuging.
|
||||
|
@ -16,8 +16,6 @@
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::sla;
|
||||
|
||||
//#define PERMANENT_SUPPORTS
|
||||
|
||||
namespace {
|
||||
/// <summary>
|
||||
/// Struct to store support points in KD tree to fast search for nearest ones.
|
||||
@ -274,10 +272,11 @@ void support_part_overhangs(
|
||||
/// <param name="part">Island to support</param>
|
||||
/// <param name="near_points">OUT place to store new supports</param>
|
||||
/// <param name="part_z">z coordinate of part</param>
|
||||
/// <param name="permanent">z coordinate of part</param>
|
||||
/// <param name="cfg"></param>
|
||||
void support_island(const LayerPart &part, NearPoints& near_points, float part_z,
|
||||
const SupportPointGeneratorConfig &cfg) {
|
||||
SupportIslandPoints samples = uniform_support_island(*part.shape, cfg.island_configuration);
|
||||
const Points &permanent, const SupportPointGeneratorConfig &cfg) {
|
||||
SupportIslandPoints samples = uniform_support_island(*part.shape, permanent, cfg.island_configuration);
|
||||
for (const SupportIslandPointPtr &sample : samples)
|
||||
near_points.add(LayerSupportPoint{
|
||||
SupportPoint{
|
||||
@ -296,10 +295,10 @@ void support_island(const LayerPart &part, NearPoints& near_points, float part_z
|
||||
}
|
||||
|
||||
void support_peninsulas(const Peninsulas& peninsulas, NearPoints& near_points, float part_z,
|
||||
const SupportPointGeneratorConfig &cfg) {
|
||||
const Points &permanent, const SupportPointGeneratorConfig &cfg) {
|
||||
for (const Peninsula& peninsula: peninsulas) {
|
||||
SupportIslandPoints peninsula_supports =
|
||||
uniform_support_peninsula(peninsula, cfg.island_configuration);
|
||||
uniform_support_peninsula(peninsula, permanent, cfg.island_configuration);
|
||||
for (const SupportIslandPointPtr &support : peninsula_supports)
|
||||
near_points.add(LayerSupportPoint{
|
||||
SupportPoint{
|
||||
@ -814,11 +813,9 @@ std::vector<Vec2f> load_curve_from_file() {
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifdef PERMANENT_SUPPORTS
|
||||
// Processing permanent support points
|
||||
// Permanent are manualy edited points by user
|
||||
namespace {
|
||||
|
||||
size_t get_index_of_closest_part(const Point &coor, const LayerParts &parts, double max_allowed_distance_sq) {
|
||||
size_t count_lines = 0;
|
||||
std::vector<size_t> part_lines_ends;
|
||||
@ -1041,6 +1038,9 @@ PermanentSupports prepare_permanent_supports(
|
||||
// How to propagate permanent support position into previous layers? and how deep? requirements
|
||||
// are chained. IMHO it should start togetjer from islands and permanent than propagate over surface
|
||||
|
||||
if (permanent_supports.empty())
|
||||
return {};
|
||||
|
||||
// permanent supports MUST be sorted by z
|
||||
assert(std::is_sorted(permanent_supports.begin(), permanent_supports.end(),
|
||||
[](const SupportPoint &a, const SupportPoint &b) { return a.pos.z() < b.pos.z(); }));
|
||||
@ -1102,10 +1102,12 @@ bool exist_permanent_support(const PermanentSupports& supports, size_t current_s
|
||||
|
||||
/// <summary>
|
||||
/// copy permanent supports into near points
|
||||
/// which has influence into current layer part
|
||||
/// </summary>
|
||||
/// <param name="near_points">OUTPUT for all permanent supports for this layer and part</param>
|
||||
/// <param name="supports">Copied from</param>
|
||||
/// <param name="supports">source for Copy</param>
|
||||
/// <param name="support_index">current index into supports</param>
|
||||
/// <param name="print_z">current layer index</param>
|
||||
/// <param name="layer_index">current layer index</param>
|
||||
/// <param name="part_index">current part index</param>
|
||||
void copy_permanent_supports(NearPoints& near_points, const PermanentSupports& supports, size_t& support_index,
|
||||
@ -1118,12 +1120,23 @@ void copy_permanent_supports(NearPoints& near_points, const PermanentSupports& s
|
||||
/* radius_curve_index */ 0, // before support point - earlier influence on point distribution
|
||||
/* current_radius */ calc_influence_radius(fabs(support.point_it->pos.z() - print_z), config)
|
||||
});
|
||||
|
||||
// NOTE: increment index globaly
|
||||
++support_index;
|
||||
}
|
||||
}
|
||||
|
||||
Points get_permanents(const PermanentSupports &supports, size_t support_index,
|
||||
size_t layer_index, size_t part_index) {
|
||||
Points result;
|
||||
while (exist_permanent_support(supports, support_index, layer_index, part_index)) {
|
||||
result.push_back(supports[support_index].layer_position); // copy
|
||||
++support_index; // only local(temporary) increment
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif // PERMANENT_SUPPORTS
|
||||
|
||||
LayerSupportPoints Slic3r::sla::generate_support_points(
|
||||
const SupportPointGeneratorData &data,
|
||||
@ -1148,12 +1161,10 @@ LayerSupportPoints Slic3r::sla::generate_support_points(
|
||||
// Storage for support points used by grid
|
||||
LayerSupportPoints result;
|
||||
|
||||
#ifdef PERMANENT_SUPPORTS
|
||||
// Index into data.permanent_supports
|
||||
size_t permanent_index = 0;
|
||||
PermanentSupports permanent_supports =
|
||||
prepare_permanent_supports(data.permanent_supports, layers, config);
|
||||
#endif // PERMANENT_SUPPORTS
|
||||
|
||||
// grid index == part in layer index
|
||||
std::vector<NearPoints> prev_grids; // same count as previous layer item size
|
||||
@ -1166,11 +1177,12 @@ LayerSupportPoints Slic3r::sla::generate_support_points(
|
||||
grids.reserve(layer.parts.size());
|
||||
|
||||
for (const LayerPart &part : layer.parts) {
|
||||
if (part.prev_parts.empty()) { // Island ?
|
||||
// only island add new grid
|
||||
grids.emplace_back(&result);
|
||||
// new island - needs support no doubt
|
||||
support_island(part, grids.back(), layer.print_z, config);
|
||||
size_t part_id = &part - &layer.parts.front();
|
||||
if (part.prev_parts.empty()) { // Island ?
|
||||
grids.emplace_back(&result); // only island add new grid
|
||||
Points permanent = get_permanents(permanent_supports, permanent_index, layer_id, part_id);
|
||||
support_island(part, grids.back(), layer.print_z, permanent, config);
|
||||
copy_permanent_supports(grids.back(), permanent_supports, permanent_index, layer.print_z, layer_id, part_id, config);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1179,12 +1191,11 @@ LayerSupportPoints Slic3r::sla::generate_support_points(
|
||||
const LayerParts &prev_layer_parts = layers[layer_id - 1].parts;
|
||||
NearPoints near_points = create_near_points(prev_layer_parts, part, prev_grids);
|
||||
remove_supports_out_of_part(near_points, part, config);
|
||||
#ifdef PERMANENT_SUPPORTS
|
||||
size_t part_id = &part - &layer.parts.front();
|
||||
if (!part.peninsulas.empty()) {
|
||||
Points permanent = get_permanents(permanent_supports, permanent_index, layer_id, part_id);
|
||||
support_peninsulas(part.peninsulas, near_points, layer.print_z, permanent, config);
|
||||
}
|
||||
copy_permanent_supports(near_points, permanent_supports, permanent_index, layer.print_z, layer_id, part_id, config);
|
||||
#endif // PERMANENT_SUPPORTS
|
||||
if (!part.peninsulas.empty())
|
||||
support_peninsulas(part.peninsulas, near_points, layer.print_z, config);
|
||||
support_part_overhangs(part, config, near_points, layer.print_z, maximal_radius);
|
||||
grids.push_back(std::move(near_points));
|
||||
}
|
||||
|
@ -450,7 +450,7 @@ Points rasterize(const ExPolygon &island, double distance) {
|
||||
SupportIslandPoints test_island_sampling(const ExPolygon & island,
|
||||
const SampleConfig &config)
|
||||
{
|
||||
auto points = uniform_support_island(island, config);
|
||||
auto points = uniform_support_island(island, {}, config);
|
||||
|
||||
Points chck_points = rasterize(island, config.head_radius); // TODO: Use resolution of printer
|
||||
bool is_ok = true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user