mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 04:25:57 +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
|
thin_part_loop, // on the last edge -> loop into itself part of island
|
||||||
thick_part_outline, // keep position align with island outline
|
thick_part_outline, // keep position align with island outline
|
||||||
thick_part_inner, // point inside wide part, without restriction on move
|
thick_part_inner, // point inside wide part, without restriction on move
|
||||||
|
|
||||||
|
permanent, // permanent support point with static position
|
||||||
undefined
|
undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <optional>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <libslic3r/ClipperUtils.hpp> // allign
|
#include <libslic3r/ClipperUtils.hpp> // allign
|
||||||
|
#include <libslic3r/KDTreeIndirect.hpp> // closest point
|
||||||
#include <libslic3r/Geometry.hpp>
|
#include <libslic3r/Geometry.hpp>
|
||||||
#include "libslic3r/Geometry/Voronoi.hpp"
|
#include "libslic3r/Geometry/Voronoi.hpp"
|
||||||
#include <libslic3r/Geometry/VoronoiOffset.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>
|
/// <summary>
|
||||||
/// Separation of thin and thick part of island
|
/// Separation of thin and thick part of island
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -2231,7 +2290,8 @@ void draw(SVG &svg, const SupportIslandPoints &supportIslandPoints, coord_t radi
|
|||||||
/// uniform support island ///
|
/// uniform support island ///
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
namespace Slic3r::sla {
|
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);
|
ExPolygon simplified_island = get_simplified(island, config);
|
||||||
#ifdef OPTION_TO_STORE_ISLAND
|
#ifdef OPTION_TO_STORE_ISLAND
|
||||||
std::string path;
|
std::string path;
|
||||||
@ -2334,7 +2394,11 @@ SupportIslandPoints uniform_support_island(const ExPolygon &island, const Sample
|
|||||||
#endif // OPTION_TO_STORE_ISLAND
|
#endif // OPTION_TO_STORE_ISLAND
|
||||||
|
|
||||||
// allign samples
|
// 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
|
#ifdef OPTION_TO_STORE_ISLAND
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
SVG svg = draw_island(path, island, simplified_island);
|
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("
|
// 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
|
// create_peninsula_field
|
||||||
Field field;
|
Field field;
|
||||||
field.border = peninsula.unsuported_area;
|
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),
|
std::transform(inner_points.begin(), inner_points.end(), std::back_inserter(results),
|
||||||
[&inner](const Point &point) { return std::make_unique<SupportIslandInnerPoint>(
|
[&inner](const Point &point) { return std::make_unique<SupportIslandInnerPoint>(
|
||||||
point, inner, SupportIslandPoint::Type::thick_part_inner);});
|
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;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,17 +12,21 @@ namespace Slic3r::sla {
|
|||||||
/// Distribute support points across island area defined by ExPolygon.
|
/// Distribute support points across island area defined by ExPolygon.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="island">Shape of island</param>
|
/// <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>
|
/// <param name="config">Configuration of support density</param>
|
||||||
/// <returns>Support points laying inside of island</returns>
|
/// <returns>Support points laying inside of the island</returns>
|
||||||
SupportIslandPoints uniform_support_island(const ExPolygon &island, const SampleConfig &config);
|
SupportIslandPoints uniform_support_island(
|
||||||
|
const ExPolygon &island, const Points &permanent, const SampleConfig &config);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Distribute support points across peninsula
|
/// Distribute support points across peninsula
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="peninsula">half island with anotation of the coast and land outline</param>
|
/// <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>
|
/// <param name="config">Density distribution parameters</param>
|
||||||
/// <returns></returns>
|
/// <returns>Support points laying inside of the peninsula</returns>
|
||||||
SupportIslandPoints uniform_support_peninsula(const Peninsula &peninsula, const SampleConfig &config);
|
SupportIslandPoints uniform_support_peninsula(
|
||||||
|
const Peninsula &peninsula, const Points& permanent, const SampleConfig &config);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check for tests that developer do not forget disable visualization after debuging.
|
/// Check for tests that developer do not forget disable visualization after debuging.
|
||||||
|
@ -16,8 +16,6 @@
|
|||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
using namespace Slic3r::sla;
|
using namespace Slic3r::sla;
|
||||||
|
|
||||||
//#define PERMANENT_SUPPORTS
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Struct to store support points in KD tree to fast search for nearest ones.
|
/// 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="part">Island to support</param>
|
||||||
/// <param name="near_points">OUT place to store new supports</param>
|
/// <param name="near_points">OUT place to store new supports</param>
|
||||||
/// <param name="part_z">z coordinate of part</param>
|
/// <param name="part_z">z coordinate of part</param>
|
||||||
|
/// <param name="permanent">z coordinate of part</param>
|
||||||
/// <param name="cfg"></param>
|
/// <param name="cfg"></param>
|
||||||
void support_island(const LayerPart &part, NearPoints& near_points, float part_z,
|
void support_island(const LayerPart &part, NearPoints& near_points, float part_z,
|
||||||
const SupportPointGeneratorConfig &cfg) {
|
const Points &permanent, const SupportPointGeneratorConfig &cfg) {
|
||||||
SupportIslandPoints samples = uniform_support_island(*part.shape, cfg.island_configuration);
|
SupportIslandPoints samples = uniform_support_island(*part.shape, permanent, cfg.island_configuration);
|
||||||
for (const SupportIslandPointPtr &sample : samples)
|
for (const SupportIslandPointPtr &sample : samples)
|
||||||
near_points.add(LayerSupportPoint{
|
near_points.add(LayerSupportPoint{
|
||||||
SupportPoint{
|
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,
|
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) {
|
for (const Peninsula& peninsula: peninsulas) {
|
||||||
SupportIslandPoints peninsula_supports =
|
SupportIslandPoints peninsula_supports =
|
||||||
uniform_support_peninsula(peninsula, cfg.island_configuration);
|
uniform_support_peninsula(peninsula, permanent, cfg.island_configuration);
|
||||||
for (const SupportIslandPointPtr &support : peninsula_supports)
|
for (const SupportIslandPointPtr &support : peninsula_supports)
|
||||||
near_points.add(LayerSupportPoint{
|
near_points.add(LayerSupportPoint{
|
||||||
SupportPoint{
|
SupportPoint{
|
||||||
@ -814,11 +813,9 @@ std::vector<Vec2f> load_curve_from_file() {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PERMANENT_SUPPORTS
|
|
||||||
// Processing permanent support points
|
// Processing permanent support points
|
||||||
// Permanent are manualy edited points by user
|
// Permanent are manualy edited points by user
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
size_t get_index_of_closest_part(const Point &coor, const LayerParts &parts, double max_allowed_distance_sq) {
|
size_t get_index_of_closest_part(const Point &coor, const LayerParts &parts, double max_allowed_distance_sq) {
|
||||||
size_t count_lines = 0;
|
size_t count_lines = 0;
|
||||||
std::vector<size_t> part_lines_ends;
|
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
|
// 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
|
// 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
|
// permanent supports MUST be sorted by z
|
||||||
assert(std::is_sorted(permanent_supports.begin(), permanent_supports.end(),
|
assert(std::is_sorted(permanent_supports.begin(), permanent_supports.end(),
|
||||||
[](const SupportPoint &a, const SupportPoint &b) { return a.pos.z() < b.pos.z(); }));
|
[](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>
|
/// <summary>
|
||||||
/// copy permanent supports into near points
|
/// copy permanent supports into near points
|
||||||
|
/// which has influence into current layer part
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="near_points">OUTPUT for all permanent supports for this layer and part</param>
|
/// <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="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="layer_index">current layer index</param>
|
||||||
/// <param name="part_index">current part index</param>
|
/// <param name="part_index">current part index</param>
|
||||||
void copy_permanent_supports(NearPoints& near_points, const PermanentSupports& supports, size_t& support_index,
|
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
|
/* 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)
|
/* current_radius */ calc_influence_radius(fabs(support.point_it->pos.z() - print_z), config)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// NOTE: increment index globaly
|
||||||
++support_index;
|
++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
|
} // namespace
|
||||||
#endif // PERMANENT_SUPPORTS
|
|
||||||
|
|
||||||
LayerSupportPoints Slic3r::sla::generate_support_points(
|
LayerSupportPoints Slic3r::sla::generate_support_points(
|
||||||
const SupportPointGeneratorData &data,
|
const SupportPointGeneratorData &data,
|
||||||
@ -1148,12 +1161,10 @@ LayerSupportPoints Slic3r::sla::generate_support_points(
|
|||||||
// Storage for support points used by grid
|
// Storage for support points used by grid
|
||||||
LayerSupportPoints result;
|
LayerSupportPoints result;
|
||||||
|
|
||||||
#ifdef PERMANENT_SUPPORTS
|
|
||||||
// Index into data.permanent_supports
|
// Index into data.permanent_supports
|
||||||
size_t permanent_index = 0;
|
size_t permanent_index = 0;
|
||||||
PermanentSupports permanent_supports =
|
PermanentSupports permanent_supports =
|
||||||
prepare_permanent_supports(data.permanent_supports, layers, config);
|
prepare_permanent_supports(data.permanent_supports, layers, config);
|
||||||
#endif // PERMANENT_SUPPORTS
|
|
||||||
|
|
||||||
// grid index == part in layer index
|
// grid index == part in layer index
|
||||||
std::vector<NearPoints> prev_grids; // same count as previous layer item size
|
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());
|
grids.reserve(layer.parts.size());
|
||||||
|
|
||||||
for (const LayerPart &part : layer.parts) {
|
for (const LayerPart &part : layer.parts) {
|
||||||
if (part.prev_parts.empty()) { // Island ?
|
size_t part_id = &part - &layer.parts.front();
|
||||||
// only island add new grid
|
if (part.prev_parts.empty()) { // Island ?
|
||||||
grids.emplace_back(&result);
|
grids.emplace_back(&result); // only island add new grid
|
||||||
// new island - needs support no doubt
|
Points permanent = get_permanents(permanent_supports, permanent_index, layer_id, part_id);
|
||||||
support_island(part, grids.back(), layer.print_z, config);
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1179,12 +1191,11 @@ LayerSupportPoints Slic3r::sla::generate_support_points(
|
|||||||
const LayerParts &prev_layer_parts = layers[layer_id - 1].parts;
|
const LayerParts &prev_layer_parts = layers[layer_id - 1].parts;
|
||||||
NearPoints near_points = create_near_points(prev_layer_parts, part, prev_grids);
|
NearPoints near_points = create_near_points(prev_layer_parts, part, prev_grids);
|
||||||
remove_supports_out_of_part(near_points, part, config);
|
remove_supports_out_of_part(near_points, part, config);
|
||||||
#ifdef PERMANENT_SUPPORTS
|
if (!part.peninsulas.empty()) {
|
||||||
size_t part_id = &part - &layer.parts.front();
|
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);
|
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);
|
support_part_overhangs(part, config, near_points, layer.print_z, maximal_radius);
|
||||||
grids.push_back(std::move(near_points));
|
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,
|
SupportIslandPoints test_island_sampling(const ExPolygon & island,
|
||||||
const SampleConfig &config)
|
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
|
Points chck_points = rasterize(island, config.head_radius); // TODO: Use resolution of printer
|
||||||
bool is_ok = true;
|
bool is_ok = true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user