diff --git a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp index 587bdc9244..41ad104274 100644 --- a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp +++ b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp @@ -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 }; diff --git a/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp b/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp index 91d7732bce..3fbb0938e3 100644 --- a/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp +++ b/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.cpp @@ -3,11 +3,11 @@ #include #include #include -#include #include #include #include // allign +#include // closest point #include #include "libslic3r/Geometry/Voronoi.hpp" #include @@ -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 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(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()); +} + /// /// Separation of thin and thick part of island /// @@ -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( 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; } diff --git a/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.hpp b/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.hpp index b2b55d26f5..0a07385e71 100644 --- a/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.hpp +++ b/src/libslic3r/SLA/SupportIslands/UniformSupportIsland.hpp @@ -12,17 +12,21 @@ namespace Slic3r::sla { /// Distribute support points across island area defined by ExPolygon. /// /// Shape of island +/// Place supported by already existing supports /// Configuration of support density -/// Support points laying inside of island -SupportIslandPoints uniform_support_island(const ExPolygon &island, const SampleConfig &config); +/// Support points laying inside of the island +SupportIslandPoints uniform_support_island( + const ExPolygon &island, const Points &permanent, const SampleConfig &config); /// /// Distribute support points across peninsula /// /// half island with anotation of the coast and land outline +/// Place supported by already existing supports /// Density distribution parameters -/// -SupportIslandPoints uniform_support_peninsula(const Peninsula &peninsula, const SampleConfig &config); +/// Support points laying inside of the peninsula +SupportIslandPoints uniform_support_peninsula( + const Peninsula &peninsula, const Points& permanent, const SampleConfig &config); /// /// Check for tests that developer do not forget disable visualization after debuging. diff --git a/src/libslic3r/SLA/SupportPointGenerator.cpp b/src/libslic3r/SLA/SupportPointGenerator.cpp index 251e741aeb..d22dbfa73a 100644 --- a/src/libslic3r/SLA/SupportPointGenerator.cpp +++ b/src/libslic3r/SLA/SupportPointGenerator.cpp @@ -16,8 +16,6 @@ using namespace Slic3r; using namespace Slic3r::sla; -//#define PERMANENT_SUPPORTS - namespace { /// /// Struct to store support points in KD tree to fast search for nearest ones. @@ -274,10 +272,11 @@ void support_part_overhangs( /// Island to support /// OUT place to store new supports /// z coordinate of part +/// z coordinate of part /// 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 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 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 /// /// copy permanent supports into near points +/// which has influence into current layer part /// /// OUTPUT for all permanent supports for this layer and part -/// Copied from +/// source for Copy /// current index into supports +/// current layer index /// current layer index /// current part 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 /* 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 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)); } diff --git a/tests/sla_print/sla_supptgen_tests.cpp b/tests/sla_print/sla_supptgen_tests.cpp index 167af98a05..c43a1996b1 100644 --- a/tests/sla_print/sla_supptgen_tests.cpp +++ b/tests/sla_print/sla_supptgen_tests.cpp @@ -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;