From 5a38e9b4b3807543f4b4ff2498d59a6b655fd33a Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Thu, 3 Oct 2024 14:41:47 +0200 Subject: [PATCH] Fix sampling selfconnected thiny part of island sampled on voronoi skelet --- .../SupportIslands/SampleConfigFactory.hpp | 17 +- .../SLA/SupportIslands/SampleIslandUtils.cpp | 428 ++++++++++++------ .../SLA/SupportIslands/SampleIslandUtils.hpp | 10 + src/libslic3r/SLA/SupportPointGenerator.cpp | 65 +-- 4 files changed, 342 insertions(+), 178 deletions(-) diff --git a/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp b/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp index c83e84c17f..0e3a213606 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp +++ b/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_SLA_SuppotstIslands_SampleConfigFactory_hpp_ #define slic3r_SLA_SuppotstIslands_SampleConfigFactory_hpp_ +#include "SampleConfig.hpp" #include "../SupportPointGenerator.hpp" namespace Slic3r::sla { @@ -14,16 +15,16 @@ public: SampleConfigFactory() = delete; // factory method to iniciate config - static SampleConfig create(const SupportPointGenerator::Config &config) + static SampleConfig create(const SupportPointGeneratorConfig &config) { - coord_t head_diameter = scale_(config.head_diameter); - coord_t min_distance = head_diameter/2 + scale_(config.minimal_distance); - coord_t max_distance = 3 * min_distance; - coord_t sample_multiplicator = 8; // allign is made by selecting from samples - + coord_t head_diameter = scale_((double)config.head_diameter.min); + coord_t minimal_distance = head_diameter * 7; + coord_t min_distance = head_diameter / 2 + minimal_distance; + coord_t max_distance = 3 * min_distance; + // TODO: find valid params !!!! SampleConfig result; - result.max_distance = max_distance / sample_multiplicator; + result.max_distance = max_distance; result.half_distance = result.max_distance / 2; result.head_radius = head_diameter / 2; result.minimal_distance_from_outline = result.head_radius; @@ -73,7 +74,7 @@ public: result.min_width_for_outline_support = result.max_width_for_center_support_line - 2 * head_diameter; assert(result.min_width_for_outline_support <= result.max_width_for_center_support_line); - result.outline_sample_distance = result.max_distance/20; + result.outline_sample_distance = result.max_distance/4; // Align support points // TODO: propagate print resolution diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp index ad10a342b1..cd3fbafaf2 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp @@ -23,14 +23,61 @@ //#define SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG //#define SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG //#define SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG -//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNE_VD_TO_SVG -//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG //#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNED_TO_SVG +//#define SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH "C:/data/temp/Align_once_<>.svg" +//#define SLA_SAMPLE_ISLAND_UTILS_DEBUG_CELL_DISTANCE_PATH "C:/data/temp/island_cell.svg" + #include +using namespace Slic3r; using namespace Slic3r::sla; +namespace { +const ExPolygon &get_expolygon_with_biggest_contour(const ExPolygons &expolygons) { + assert(!expolygons.empty()); + const ExPolygon *biggest = &expolygons.front(); + for (size_t index = 1; index < expolygons.size(); ++index) { + const ExPolygon *current = &expolygons[index]; + if (biggest->contour.size() < current->contour.size()) + biggest = current; + } + return *biggest; +} +} // namespace + +SupportIslandPoints SampleIslandUtils::uniform_cover_island( + const ExPolygon &island, const SampleConfig &config +) { + // closing similar to FDM arachne do before voronoi + // inspired by make_expolygons inside TriangleMeshSlicer + float closing_radius = scale_(0.0499f); + float offset_out = closing_radius; + float offset_in = -closing_radius; + ExPolygons closed_expolygons = offset2_ex({island}, offset_out, offset_in); // mitter + ExPolygon closed_expolygon = get_expolygon_with_biggest_contour(closed_expolygons); + + // "Close" operation create neighbor pixel for sharp triangle tip + double tolerance = scale_(0.05); + ExPolygons simplified_expolygons = island.simplify(tolerance); + ExPolygon simplified_expolygon = get_expolygon_with_biggest_contour(simplified_expolygons); + + Slic3r::Geometry::VoronoiDiagram vd; + Lines lines = to_lines(simplified_expolygon); + vd.construct_voronoi(lines.begin(), lines.end()); + Slic3r::Voronoi::annotate_inside_outside(vd, lines); + VoronoiGraph skeleton = VoronoiGraphUtils::create_skeleton(vd, lines); + VoronoiGraph::ExPath longest_path; + + SupportIslandPoints samples = + SampleIslandUtils::sample_voronoi_graph(skeleton, lines, config, longest_path); + + // allign samples + SampleIslandUtils::align_samples(samples, island, config); + + return samples; +} + std::vector SampleIslandUtils::sample_expolygon( const ExPolygon &expoly, float samples_per_mm2) { @@ -440,115 +487,145 @@ void SampleIslandUtils::align_samples(SupportIslandPoints &samples, } +namespace { +Polygons create_voronoi_cells_boost(const Points &points, coord_t max_distance) { + using VD = Slic3r::Geometry::VoronoiDiagram; + VD vd; + vd.construct_voronoi(points.begin(), points.end()); + assert(points.size() == vd.cells().size()); + Polygons cells(points.size()); + for (const VD::cell_type &cell : vd.cells()) + cells[cell.source_index()] = VoronoiGraphUtils::to_polygon(cell, points, max_distance); + return cells; +} + +std::string replace_first( + std::string s, + const std::string& toReplace, + const std::string& replaceWith +) { + std::size_t pos = s.find(toReplace); + if (pos == std::string::npos) return s; + s.replace(pos, toReplace.length(), replaceWith); + return s; +} + bool is_points_in_distance(const Slic3r::Point & p, const Slic3r::Points &points, double max_distance) { for (const auto &p2 : points) { double d = (p - p2).cast().norm(); - if (d > max_distance) return false; + if (d > max_distance) + return false; } return true; } +} // namespace -coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples, - const ExPolygon & island, - const SampleConfig & config) -{ - using VD = Slic3r::Geometry::VoronoiDiagram; - VD vd; +coord_t SampleIslandUtils::align_once( + SupportIslandPoints &samples, + const ExPolygon &island, + const SampleConfig &config) +{ + // IMPROVE1: add accessor to point coordinate do not copy points + // IMPROVE2: add filter for create cell polygon only for moveable samples Slic3r::Points points = SampleIslandUtils::to_points(samples); - coord_t max_move = 0; - -#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG - std::string color_of_island = "#FF8080"; // LightRed. Should not be visible - cell color should overlap - std::string color_point_cell = "lightgray"; // bigger than island but NOT self overlap - std::string color_island_cell_intersection = "gray"; // Should full overlap island !! - std::string color_old_point = "lightblue"; // Center of island cell intersection - std::string color_wanted_point = "darkblue"; // Center of island cell intersection - std::string color_new_point = "blue"; // Center of island cell intersection - std::string color_static_point = "black"; - static int counter = 0; - BoundingBox bbox(island.contour.points); - SVG svg(("align_" + std::to_string(counter++) + ".svg").c_str(), bbox); - svg.draw(island, color_of_island ); -#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG + Polygons cell_polygons = //* + create_voronoi_cells_boost + /*/ + create_voronoi_cells_cgal + //*/ + (points, config.max_distance); + +#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH + std::string color_of_island = "#FF8080"; // LightRed. Should not be visible - cell color should overlap + std::string color_point_cell = "lightgray"; // bigger than island but NOT self overlap + std::string color_island_cell_intersection = "gray"; // Should full overlap island !! + std::string color_old_point = "lightblue"; // Center of island cell intersection + std::string color_wanted_point = "darkblue"; // Center of island cell intersection + std::string color_new_point = "blue"; // Center of island cell intersection + std::string color_static_point = "black"; + BoundingBox bbox(island.contour.points); + static int counter = 0; + Slic3r::SVG svg(replace_first(SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH, + "<>", std::to_string(counter++)).c_str(), bbox); + svg.draw(island, color_of_island); +#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH - // create voronoi diagram with points - vd.construct_voronoi(points.begin(), points.end()); -#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNE_VD_TO_SVG - static int vd_counter = 0; - BoundingBox bbox(island); - std::string name = "align_VD_" + std::to_string(vd_counter++) + ".svg"; - SVG svg(name.c_str(), bbox); - svg.draw(island); - for (const Point &point : points) { - size_t index = &point - &points.front(); - svg.draw(point, "black", config.head_radius); - svg.draw_text(point + Point(config.head_radius,0), std::to_string(index).c_str(), "black"); - } - Lines island_lines = to_lines(island); - svg.draw(island_lines, "blue"); - for (const auto &edge: vd.edges()) { - std::optional line = - VoronoiGraphUtils::to_line(edge, points, config.max_distance); - if (!line.has_value()) continue; - svg.draw(*line, "green", 1e6); - } - svg.Close(); -#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNE_VD_TO_SVG - size_t max_move_index = -1; - for (const VD::cell_type &cell : vd.cells()) { - SupportIslandPointPtr &sample = samples[cell.source_index()]; + // Maximal move during align each loop of align it should decrease + coord_t max_move = 0; + for (size_t i = 0; i < points.size(); i++) { + const Polygon &cell_polygon = cell_polygons[i]; + SupportIslandPointPtr &sample = samples[i]; -#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG - if (!sample->can_move()) { +#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH + if (!sample->can_move()) { // draww freezed support points svg.draw(sample->point, color_static_point, config.head_radius); - svg.draw_text(sample->point+Point(config.head_radius,0), SupportIslandPoint::to_string(sample->type).c_str(), color_static_point.c_str()); + svg.draw_text(sample->point + Point(config.head_radius, 0), + SupportIslandPoint::to_string(sample->type).c_str(), color_static_point.c_str()); } -#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG - if (!sample->can_move()) continue; - Polygon cell_polygon = VoronoiGraphUtils::to_polygon(cell, points, config.max_distance); +#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH + if (!sample->can_move()) + continue; + + // polygon must be at least triangle + assert(cell_polygon.points.size() >= 3); + if (cell_polygon.points.size() < 3) + continue; // do not align point with invalid cell + + // IMPROVE: add intersection polygon with expolygon Polygons intersections = Slic3r::intersection(island, ExPolygon(cell_polygon)); - const Polygon *island_cell = nullptr; + const Polygon *island_cell = nullptr; for (const Polygon &intersection : intersections) { if (intersection.contains(sample->point)) { island_cell = &intersection; break; } } - assert(island_cell != nullptr); - Point center = island_cell->centroid(); - /*{ - SVG cell_svg("island_cell.svg", island_cell->points); - cell_svg.draw(cell_polygon, "lightgray"); - cell_svg.draw(points, "darkgray", config.head_radius); - cell_svg.draw(*island_cell, "gray"); - cell_svg.draw(sample->point, "green", config.head_radius); - cell_svg.draw(center, "black", config.head_radius); - }*/ - assert(is_points_in_distance(center, island_cell->points, config.max_distance)); -#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG + + // intersection island and cell made by suppot point + // must generate polygon containing initial source for voronoi cell + // otherwise it is invalid voronoi diagram + assert(island_cell != nullptr); + if (island_cell == nullptr) + continue; + + // new aligned position for sample + Point island_cell_center = island_cell->centroid(); + +#ifdef SLA_SAMPLE_ISLAND_UTILS_DEBUG_CELL_DISTANCE_PATH + {SVG cell_svg(SLA_SAMPLE_ISLAND_UTILS_DEBUG_CELL_DISTANCE_PATH, island_cell->points); + cell_svg.draw(island, "lightgreen"); + cell_svg.draw(cell_polygon, "lightgray"); + cell_svg.draw(points, "darkgray", config.head_radius); + cell_svg.draw(*island_cell, "gray"); + cell_svg.draw(sample->point, "green", config.head_radius); + cell_svg.draw(island_cell_center, "black", config.head_radius);} +#endif //SLA_SAMPLE_ISLAND_UTILS_DEBUG_CELL_DISTANCE_PATH + // Check that still points do not have bigger distance from each other + assert(is_points_in_distance(island_cell_center, island_cell->points, config.max_distance)); + +#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH svg.draw(cell_polygon, color_point_cell); svg.draw(*island_cell, color_island_cell_intersection); - svg.draw(Line(sample->point, center), color_wanted_point, config.head_radius / 5); + svg.draw(Line(sample->point, island_cell_center), color_wanted_point, config.head_radius / 5); svg.draw(sample->point, color_old_point, config.head_radius); - svg.draw(center, color_wanted_point, config.head_radius); // wanted position -#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG - coord_t act_move = sample->move(center); - if (max_move < act_move) { - max_move = act_move; - max_move_index = cell.source_index(); - } -#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG - svg.draw(sample->point, color_new_point, config.head_radius); - svg.draw_text(sample->point+Point(config.head_radius,0), SupportIslandPoint::to_string(sample->type).c_str(), color_new_point.c_str()); -#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG + svg.draw(island_cell_center, color_wanted_point, config.head_radius); // wanted position +#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH + + // say samples to use its restriction to change posion close to center + coord_t act_move = sample->move(island_cell_center); + if (max_move < act_move) + max_move = act_move; + +#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH + svg.draw(sample->point, color_new_point, config.head_radius); + svg.draw_text(sample->point + Point(config.head_radius, 0), + SupportIslandPoint::to_string(sample->type).c_str(), color_new_point.c_str()); +#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH } -#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG - svg.Close(); -#endif // SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG return max_move; } @@ -897,6 +974,7 @@ SupportIslandPoints SampleIslandUtils::sample_voronoi_graph( SVG svg("voronoiGraph" + std::to_string(counter++) + ".svg", LineUtils::create_bounding_box(lines)); VoronoiGraphUtils::draw(svg, graph, lines, config.head_radius / 10, true); + VoronoiGraphUtils::draw(svg, longest_path, config.head_radius / 10); } #endif // SLA_SAMPLE_ISLAND_UTILS_STORE_VORONOI_GRAPH_TO_SVG @@ -1031,6 +1109,83 @@ void SampleIslandUtils::sample_field(const VoronoiGraph::Position &field_start, }); } +namespace { +bool pop_start( + SampleIslandUtils::CenterStart &start, + SampleIslandUtils::CenterStarts &starts, + const std::set &done +) { + // skip done starts + if (starts.empty()) + return false; // no start + while (done.find(starts.back().neighbor->node) != done.end()) { + starts.pop_back(); + if (starts.empty()) + return false; + } + // fill new start + start = std::move(starts.back()); + starts.pop_back(); + return true; +} + +bool add_support_on_neighbor_edge( + const VoronoiGraph::Node::Neighbor *neighbor, + coord_t& support_in, + SupportIslandPoints &results, + const SampleConfig &config +) { + bool added = false; + coord_t edge_length = static_cast(neighbor->length()); + while (edge_length >= support_in) { + double ratio = support_in / neighbor->length(); + VoronoiGraph::Position position(neighbor, ratio); + results.push_back(std::make_unique( + position, &config, SupportIslandPoint::Type::center_line1 + )); + support_in += config.max_distance; + added = true; + } + support_in -= edge_length; + return added; +} + +/// +/// Solve place where loop ends in already sampled area of island +/// NOTE: still make a mistake in place of 2 ends +/// (example could be logo of anarchy with already sampled circle and process inner 'Y') +/// NOTE: do not count with supported distance in place of connect +/// +/// Last neighbor to sample +/// +/// +/// +/// +void sample_connection_into_sampled_area( + const VoronoiGraph::Node::Neighbor &node_neighbor, + coord_t support_in, + VoronoiGraph::Nodes path, // wanted copy + SupportIslandPoints &results, + const SampleConfig &config +) { + add_support_on_neighbor_edge(&node_neighbor, support_in, results, config); + return; // TODO: sample small rest part WRT distance on connected place + + if (support_in > config.max_distance / 2) + return; // no need to add new support + + // add last support before connection into already supported area + path.push_back(node_neighbor.node); + std::reverse(path.begin(), path.end()); + auto position_opt = SampleIslandUtils::create_position_on_path(path, 1 - support_in / 2); + if (position_opt.has_value()) { + results.push_back(std::make_unique( + *position_opt, &config, SupportIslandPoint::Type::center_line3 + )); + } +} +} // namespace + std::optional SampleIslandUtils::sample_center( CenterStarts & new_starts, std::set &done, @@ -1038,73 +1193,61 @@ std::optional SampleIslandUtils::sample_center( const Lines & lines, const SampleConfig & config) { + // Current place to sample CenterStart start(nullptr, {}, {}); - bool use_new_start = true; + if (!pop_start(start, new_starts, done)) return {}; + + // sign that there was added point on start.path + // used to distiquish whether add support point on island edge bool is_continous = false; - while (use_new_start || start.neighbor->max_width() <= config.max_width_for_center_support_line) { - // !! do not check max width for new start, it could be wide to tiny change - if (use_new_start) { - use_new_start = false; - // skip done starts - if (new_starts.empty()) return {}; // no start - while (done.find(new_starts.back().neighbor->node) != done.end()) { - new_starts.pop_back(); - if (new_starts.empty()) return {}; - } - // fill new start - start = std::move(new_starts.back()); - new_starts.pop_back(); - is_continous = false; - } - - // add support on actual neighbor edge - coord_t edge_length = static_cast(start.neighbor->length()); - while (edge_length >= start.support_in) { - double ratio = start.support_in / start.neighbor->length(); - VoronoiGraph::Position position(start.neighbor, ratio); - results.push_back(std::make_unique( - position, &config, SupportIslandPoint::Type::center_line1)); - start.support_in += config.max_distance; + // Loop over thin part of island which need to be sampled on the voronoi skeleton. + while (start.neighbor->max_width() <= config.max_width_for_center_support_line) { + assert(done.find(start.neighbor->node) == done.end()); // not proccessed only + // add support when it is in distance from last added + if (add_support_on_neighbor_edge(start.neighbor, start.support_in, results, config)) is_continous = true; - } - start.support_in -= edge_length; const VoronoiGraph::Node *node = start.neighbor->node; done.insert(node); // IMPROVE: A) limit length of path to config.minimal_support_distance // IMPROVE: B) store node in reverse order start.path.push_back(node); + + // next neighbor is short cut to not push back and pop new_starts const VoronoiGraph::Node::Neighbor *next_neighbor = nullptr; for (const auto &node_neighbor : node->neighbors) { - if (done.find(node_neighbor.node) != done.end()) continue; + // Check wheather node is not previous one + if (start.path.size() > 1 && + start.path[start.path.size() - 2] == node_neighbor.node) + continue; + // Check other nodes wheather they are already done + if (done.find(node_neighbor.node) != done.end()) { + sample_connection_into_sampled_area(node_neighbor, start.support_in, start.path, results, config); + continue; + } + if (next_neighbor == nullptr) { next_neighbor = &node_neighbor; continue; } - new_starts.emplace_back(&node_neighbor, start.support_in, start.path); // search in side branch + new_starts.emplace_back(&node_neighbor, start.support_in, start.path); // search in side branch } - if (next_neighbor == nullptr) { - if (start.neighbor->min_width() != 0) { - std::reverse(start.path.begin(), start.path.end()); - auto position_opt = create_position_on_path(start.path, start.support_in / 2); - if (position_opt.has_value()) { - results.push_back( - std::make_unique( - *position_opt, &config, - SupportIslandPoint::Type::center_line3)); - } - } else { - // no neighbor to continue - create_sample_center_end(*start.neighbor, is_continous, start.path, - start.support_in, lines, results, - new_starts, config); - } - use_new_start = true; - } else { + if (next_neighbor != nullptr) { start.neighbor = next_neighbor; + continue; } + + // no neighbor to continue so sample edge of island + if(start.neighbor->min_width() == 0) + create_sample_center_end(*start.neighbor, is_continous, start.path, + start.support_in, lines, results, + new_starts, config); + // select next start + if (!pop_start(start, new_starts, done)) + return {}; // finished + is_continous = false; // new branch for start was just selected } // create field start @@ -1136,6 +1279,7 @@ void SampleIslandUtils::create_sample_center_end( const SampleConfig & config) { // last neighbor? + assert(neighbor.min_width() == 0); if (neighbor.min_width() != 0) return; // sharp corner? @@ -1389,18 +1533,25 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( }; size_t source_indexe_for_change = lines.size(); + + /// + /// Insert change into + /// NOTE: separate functionality to be able force break from second loop + /// + /// island(ExPolygon) converted to lines + /// ... + /// False when change lead to close loop(into first change) otherwise True auto insert_changes = [&wide_tiny_changes, &lines, &source_indexes, source_indexe_for_change] (size_t &index, Points &points, std::set &done, size_t input_index)->bool { - bool is_first = points.empty(); auto change_item = wide_tiny_changes.find(index); while (change_item != wide_tiny_changes.end()) { const WideTinyChanges &changes = change_item->second; assert(!changes.empty()); size_t change_index = 0; - if (!is_first) { - const Point & last_point = points.back(); + if (!points.empty()) { // Not first point, could lead to termination + const Point &last_point = points.back(); LineUtils::SortFromAToB pred(lines[index]); - bool no_change = false; + bool no_change = false; while (pred.compare(changes[change_index].new_b, last_point)) { ++change_index; if (change_index >= changes.size()) { @@ -1445,7 +1596,7 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( outline_indexes.reserve(field_line_indexes.size()); size_t input_index1 = tiny_wide_neighbor->edge->cell()->source_index(); size_t input_index2 = tiny_wide_neighbor->edge->twin()->cell()->source_index(); - size_t input_index = std::min(input_index1, input_index2); + size_t input_index = std::min(input_index1, input_index2); // Why select min index? size_t outline_index = input_index; std::set done_indexes; do { @@ -1778,13 +1929,10 @@ bool SampleIslandUtils::is_visualization_disabled() #ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_INITIAL_SAMPLE_POSITION_TO_SVG return false; #endif -#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNE_VD_TO_SVG - return false; -#endif #ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_FIELD_TO_SVG return false; #endif -#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG +#ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGN_ONCE_TO_SVG_PATH return false; #endif #ifdef SLA_SAMPLE_ISLAND_UTILS_STORE_ALIGNED_TO_SVG diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp index 331874a80f..8efb79c94a 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp @@ -24,6 +24,16 @@ class SampleIslandUtils public: SampleIslandUtils() = delete; + /// + /// Main entry for sample island + /// + /// Shape of island + /// Configuration for sampler + /// List of support points + static SupportIslandPoints uniform_cover_island( + const ExPolygon &island, const SampleConfig &config + ); + /// /// Uniform sample expolygon area by points inside Equilateral triangle center /// diff --git a/src/libslic3r/SLA/SupportPointGenerator.cpp b/src/libslic3r/SLA/SupportPointGenerator.cpp index 0b60229ebc..99c8506a12 100644 --- a/src/libslic3r/SLA/SupportPointGenerator.cpp +++ b/src/libslic3r/SLA/SupportPointGenerator.cpp @@ -9,6 +9,10 @@ #include "libslic3r/Execution/Execution.hpp" #include "libslic3r/KDTreeIndirect.hpp" +// SupportIslands +#include "libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp" +#include "libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp" + using namespace Slic3r; using namespace Slic3r::sla; @@ -183,14 +187,14 @@ Point intersection(const Point &p1, const Point &p2, const Point &cnt, double r2 /// Current layer part to process /// Grids which will be moved to current grid /// Grid for given part -NearPoints create_part_grid( +NearPoints create_near_points( const LayerParts &prev_layer_parts, const LayerPart &part, std::vector &prev_grids ) { const LayerParts::const_iterator &prev_part_it = part.prev_parts.front().part_it; size_t index_of_prev_part = prev_part_it - prev_layer_parts.begin(); - NearPoints part_grid = (prev_part_it->next_parts.size() == 1)? + NearPoints near_points = (prev_part_it->next_parts.size() == 1)? std::move(prev_grids[index_of_prev_part]) : // Need a copy there are multiple parts above previus one prev_grids[index_of_prev_part]; // copy @@ -200,27 +204,27 @@ NearPoints create_part_grid( const LayerParts::const_iterator &prev_part_it = part.prev_parts[i].part_it; size_t index_of_prev_part = prev_part_it - prev_layer_parts.begin(); if (prev_part_it->next_parts.size() == 1) { - part_grid.merge(std::move(prev_grids[index_of_prev_part])); + near_points.merge(std::move(prev_grids[index_of_prev_part])); } else { // Need a copy there are multiple parts above previus one NearPoints grid_ = prev_grids[index_of_prev_part]; // copy - part_grid.merge(std::move(grid_)); + near_points.merge(std::move(grid_)); } } - return part_grid; + return near_points; } /// -/// Add support point to part_grid when it is neccessary +/// Add support point to near_points when it is neccessary /// /// Current part - keep samples /// Configuration to sample -/// Keep previous sampled suppport points +/// Keep previous sampled suppport points /// current z coordinate of part /// Max distance to seach support for sample void support_part_overhangs( const LayerPart &part, const SupportPointGeneratorConfig &config, - NearPoints &part_grid, + NearPoints &near_points, float part_z, coord_t maximal_radius ) { @@ -239,9 +243,9 @@ void support_part_overhangs( }; for (const Point &p : part.samples) { - if (!part_grid.exist_true_in_radius(p, maximal_radius, is_supported)) { + if (!near_points.exist_true_in_radius(p, maximal_radius, is_supported)) { // not supported sample, soo create new support point - part_grid.add(LayerSupportPoint{ + near_points.add(LayerSupportPoint{ SupportPoint{ Vec3f{unscale(p.x()), unscale(p.y()), part_z}, /* head_front_radius */ 0.4f, @@ -256,30 +260,31 @@ void support_part_overhangs( } } -Points uniformly_sample(const ExPolygon &island, const SupportPointGeneratorConfig &cfg) { - // TODO: Implement it - return Points{island.contour.centroid()}; -} - /// /// Sample part as Island /// Result store to grid /// /// Island to support -/// OUT place to store new supports +/// OUT place to store new supports /// z coordinate of part /// -void support_island(const LayerPart &part, NearPoints& part_grid, float part_z, - const SupportPointGeneratorConfig &cfg) { - Points pts = uniformly_sample(*part.shape, cfg); - for (const Point &pt : pts) - part_grid.add(LayerSupportPoint{ +void support_island(const LayerPart &part, NearPoints& near_points, float part_z, + const SupportPointGeneratorConfig &cfg) { + SampleConfig sample_cfg = SampleConfigFactory::create(cfg); + SupportIslandPoints samples = SampleIslandUtils::uniform_cover_island(*part.shape, sample_cfg); + //samples = {std::make_unique(island.contour.centroid())}; + for (const SupportIslandPointPtr &sample : samples) + near_points.add(LayerSupportPoint{ SupportPoint{ - Vec3f{unscale(pt.x()), unscale(pt.y()), part_z}, + Vec3f{ + unscale(sample->point.x()), + unscale(sample->point.y()), + part_z + }, /* head_front_radius */ 0.4f, SupportPointType::island }, - /* position_on_layer */ pt, + /* position_on_layer */ sample->point, /* direction_to_mass */ Point(0,0), // direction from bottom /* radius_curve_index */ 0, /* current_radius */ static_cast(scale_(cfg.support_curve.front().x())) @@ -471,15 +476,15 @@ void prepare_supports_for_layer(LayerSupportPoints &supports, float layer_z, /// Due to be able support in same area again(overhang above another overhang) /// Wanted Side effect, it supports thiny part of overhangs /// -/// +/// /// -void remove_supports_out_of_part(NearPoints& part_grid, const LayerPart &part) { +void remove_supports_out_of_part(NearPoints& near_points, const LayerPart &part) { // Must be greater than surface texture and lower than self supporting area // May be use maximal island distance float delta = scale_(5.); ExPolygons extend_shape = offset_ex(*part.shape, delta, ClipperLib::jtSquare); - part_grid.remove_out_of(extend_shape); + near_points.remove_out_of(extend_shape); } } // namespace @@ -651,10 +656,10 @@ LayerSupportPoints Slic3r::sla::generate_support_points( // first layer should have empty prev_part assert(layer_id != 0); const LayerParts &prev_layer_parts = layers[layer_id - 1].parts; - NearPoints part_grid = create_part_grid(prev_layer_parts, part, prev_grids); - remove_supports_out_of_part(part_grid, part); - support_part_overhangs(part, config, part_grid, layer.print_z, maximal_radius); - grids.push_back(std::move(part_grid)); + NearPoints near_points = create_near_points(prev_layer_parts, part, prev_grids); + remove_supports_out_of_part(near_points, part); + support_part_overhangs(part, config, near_points, layer.print_z, maximal_radius); + grids.push_back(std::move(near_points)); } } prev_grids = std::move(grids);