From 688c614e47fa22ca6d343476b29e8693d0f172e1 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Thu, 24 Oct 2024 14:31:54 +0200 Subject: [PATCH] Fix for sampling and enhance visualization. --- .../SLA/SupportIslands/SampleIslandUtils.cpp | 98 ++++++++++++------- .../SLA/SupportIslands/SampleIslandUtils.hpp | 8 +- .../SLA/SupportIslands/VoronoiGraphUtils.cpp | 52 +++++++--- .../SLA/SupportIslands/VoronoiGraphUtils.hpp | 5 +- src/libslic3r/SLA/SupportPointGenerator.cpp | 21 ++-- src/libslic3r/SLA/SupportPointGenerator.hpp | 7 ++ 6 files changed, 126 insertions(+), 65 deletions(-) diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp index 69f9d3d70e..43cb525d38 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp @@ -124,9 +124,10 @@ SVG draw_island(const std::string &path, const ExPolygon &island, const ExPolygo } SVG draw_island_graph(const std::string &path, const ExPolygon &island, const ExPolygon &simplified_island, const VoronoiGraph& skeleton, - const VoronoiGraph::ExPath& longest_path, const Lines& lines, coord_t width) { + const VoronoiGraph::ExPath& longest_path, const Lines& lines, const SampleConfig &config) { SVG svg = draw_island(path, island, simplified_island); - VoronoiGraphUtils::draw(svg, skeleton, lines, width); + VoronoiGraphUtils::draw(svg, skeleton, lines, config, true /*print Pointer address*/); + coord_t width = config.head_radius / 10; VoronoiGraphUtils::draw(svg, longest_path.nodes, width, "orange"); return svg; } @@ -176,7 +177,7 @@ SupportIslandPoints SampleIslandUtils::uniform_cover_island( longest_path = VoronoiGraphUtils::create_longest_path(start_node); #ifdef OPTION_TO_STORE_ISLAND // add voronoi diagram with longest path into image - if (!path.empty()) draw_island_graph(path, island, simplified_island, skeleton, longest_path, lines, config.head_radius / 10); + if (!path.empty()) draw_island_graph(path, island, simplified_island, skeleton, longest_path, lines, config); #endif // OPTION_TO_STORE_ISLAND SupportIslandPoints samples = sample_expath(longest_path, lines, config); @@ -184,7 +185,7 @@ SupportIslandPoints SampleIslandUtils::uniform_cover_island( #ifdef OPTION_TO_STORE_ISLAND Points samples_before_align = to_points(samples); if (!path.empty()) { - SVG svg = draw_island_graph(path, island, simplified_island, skeleton, longest_path, lines, config.head_radius / 10); + SVG svg = draw_island_graph(path, island, simplified_island, skeleton, longest_path, lines, config); draw(svg, samples, config.head_radius); } #endif // OPTION_TO_STORE_ISLAND @@ -193,13 +194,17 @@ SupportIslandPoints SampleIslandUtils::uniform_cover_island( SampleIslandUtils::align_samples(samples, island, config); #ifdef OPTION_TO_STORE_ISLAND if (!path.empty()) { - SVG svg = draw_island_graph(path, island, simplified_island, skeleton, longest_path, lines, config.head_radius / 10); - draw(svg, samples, config.head_radius); + SVG svg = draw_island(path, island, simplified_island); + coord_t width = config.head_radius / 5; + VoronoiGraphUtils::draw(svg, longest_path.nodes, width, "darkorange"); + VoronoiGraphUtils::draw(svg, skeleton, lines, config, false /*print Pointer address*/); + Lines align_moves; align_moves.reserve(samples.size()); for (size_t i = 0; i < samples.size(); ++i) align_moves.push_back(Line(samples[i]->point, samples_before_align[i])); - svg.draw(align_moves, "lightgray"); + svg.draw(align_moves, "lightgray", width); + draw(svg, samples, config.head_radius); } #endif // OPTION_TO_STORE_ISLAND return samples; @@ -1130,7 +1135,6 @@ SupportIslandPoints SampleIslandUtils::sample_expath( coord_t support_in = config.max_distance + already_supported; center_starts.emplace_back(position->neighbor, support_in, start_path); } else { - assert(position.has_value()); done.insert(start_node); coord_t support_in = config.minimal_distance_from_outline; center_starts.emplace_back(neighbor, support_in); @@ -1263,16 +1267,15 @@ std::optional SampleIslandUtils::sample_center( std::set &done, SupportIslandPoints & results, const Lines & lines, - const SampleConfig & config) + const SampleConfig & config, + // sign that there was added point on start.path + // used to distiquish whether add support point on island edge + bool is_continous) { // Current place to sample CenterStart start(nullptr, {}, {}); 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; - // Loop over thin part of island which need to be sampled on the voronoi skeleton. while (!is_continous || start.neighbor->max_width() <= config.max_width_for_center_support_line) { assert(done.find(start.neighbor->node) == done.end()); // not proccessed only @@ -1489,16 +1492,16 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( // line index, vector std::map wide_tiny_changes; - coord_t minimal_edge_length = std::max(config.max_distance / 2, 2*config.minimal_distance_from_outline); - coord_t half_max_distance = config.max_distance / 2; - // cut lines at place where neighbor has width = min_width_for_outline_support - // neighbor must be in direction from wide part to tiny part of island - auto add_wide_tiny_change = - [minimal_edge_length, half_max_distance, &wide_tiny_changes, - &lines, &tiny_starts, &tiny_done] - (const VoronoiGraph::Position &position, const VoronoiGraph::Node *source_node)->bool{ - if (VoronoiGraphUtils::ends_in_distanace(position, minimal_edge_length)) - return false; // no change only rich outline + // Prepare data for field outline, + // when field transit into tiny part of island + auto add_wide_tiny_change_only = [&wide_tiny_changes, &lines, &tiny_done] + (const VoronoiGraph::Position &position){ + Point p1, p2; + std::tie(p1, p2) = VoronoiGraphUtils::point_on_lines(position, lines); + const VoronoiGraph::Node::Neighbor *neighbor = position.neighbor; + const VD::edge_type *edge = neighbor->edge; + size_t i1 = edge->cell()->source_index(); + size_t i2 = edge->twin()->cell()->source_index(); // function to add sorted change from wide to tiny // stored uder line index or line shorten in point b @@ -1513,13 +1516,6 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( } }; - Point p1, p2; - std::tie(p1, p2) = VoronoiGraphUtils::point_on_lines(position, lines); - const VoronoiGraph::Node::Neighbor *neighbor = position.neighbor; - const VD::edge_type *edge = neighbor->edge; - size_t i1 = edge->cell()->source_index(); - size_t i2 = edge->twin()->cell()->source_index(); - const Line &l1 = lines[i1]; if (VoronoiGraphUtils::is_opposit_direction(edge, l1)) { // line1 is shorten on side line1.a --> line2 is shorten on side line2.b @@ -1528,8 +1524,22 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( // line1 is shorten on side line1.b add(p1, p2, i1, i2); } - coord_t support_in = neighbor->length() * position.ratio + half_max_distance; - CenterStart tiny_start(neighbor, support_in, {source_node}); + }; + + coord_t minimal_edge_length = std::max(config.max_distance / 2, 2*config.minimal_distance_from_outline); + coord_t half_max_distance = config.max_distance / 2; + // cut lines at place where neighbor has width = min_width_for_outline_support + // neighbor must be in direction from wide part to tiny part of island + auto add_wide_tiny_change = [minimal_edge_length, half_max_distance, + add_wide_tiny_change_only, &tiny_starts, &tiny_done] + (const VoronoiGraph::Position &position, const VoronoiGraph::Node *source_node)->bool{ + if (VoronoiGraphUtils::ends_in_distanace(position, minimal_edge_length)) + return false; // no change only rich outline + + add_wide_tiny_change_only(position); + + coord_t support_in = position.neighbor->length() * position.ratio + half_max_distance; + CenterStart tiny_start(position.neighbor, support_in, {source_node}); tiny_starts.push_back(tiny_start); tiny_done.insert(source_node); return true; @@ -1543,6 +1553,7 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( std::set done; done.insert(wide_tiny_neighbor->node); + // prev node , node using ProcessItem = std::pair; // initial proccess item from tiny part to wide part of island @@ -1575,7 +1586,18 @@ SampleIslandUtils::Field SampleIslandUtils::create_field( if(add_wide_tiny_change(position, node)) continue; } - if (done.find(neighbor.node) != done.end()) continue; // loop back + if (done.find(neighbor.node) != done.end()) continue; // loop back into field + + // Detection that wide part do not continue over already sampled tiny part + // Caused by histereze of wide condition. + if (auto it = std::find_if(tiny_starts.begin(), tiny_starts.end(), + [twin=VoronoiGraphUtils::get_twin(neighbor)](const SampleIslandUtils::CenterStart& start)->bool{ + return twin == start.neighbor; }); + it != tiny_starts.end()) { + add_wide_tiny_change_only(VoronoiGraph::Position(&neighbor, 1.)); + tiny_starts.erase(it); + continue; + } if (next_node == nullptr) { next_node = neighbor.node; } else { @@ -1993,10 +2015,10 @@ void SampleIslandUtils::draw(SVG & svg, void SampleIslandUtils::draw(SVG & svg, const SupportIslandPoints &supportIslandPoints, - double size, - const char * color, + coord_t radius, bool write_type) { + const char *color = nullptr; for (const auto &p : supportIslandPoints) { switch (p->type) { case SupportIslandPoint::Type::center_line1: @@ -2016,11 +2038,11 @@ void SampleIslandUtils::draw(SVG & svg, case SupportIslandPoint::Type::two_points: default: color = "black"; } - svg.draw(p->point, color, size); + svg.draw(p->point, color, radius); if (write_type && p->type != SupportIslandPoint::Type::undefined) { auto type_name = SupportIslandPoint::to_string(p->type); - Point start = p->point + Point(size, 0.); - svg.draw_text(start, std::string(type_name).c_str(), color); + Point start = p->point + Point(radius, 0); + svg.draw_text(start, std::string(type_name).c_str(), color, 8); } } } diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp index 308b56a915..cbf0f0a69c 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp @@ -267,13 +267,16 @@ public: /// Result of sampling /// Source line for VD. To decide position of change from tiny to wide part /// Parameters for sampling + /// Already place sample on path /// Wide neighbor, start of field when exists static std::optional sample_center( CenterStarts & new_starts, std::set &done, SupportIslandPoints & results, const Lines & lines, - const SampleConfig & config); + const SampleConfig & config, + bool is_continous = false + ); private: /// @@ -390,8 +393,7 @@ public : static void draw(SVG & svg, const SupportIslandPoints &supportIslandPoints, - double size, - const char *color = "lightgreen", + coord_t radius, bool write_type = true); }; diff --git a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp index 66cdd4924f..dc5f1b7551 100644 --- a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp @@ -1301,20 +1301,45 @@ double VoronoiGraphUtils::outline_angle(const VoronoiGraph::Node::Neighbor &neig void VoronoiGraphUtils::draw(SVG & svg, const VoronoiGraph &graph, const Lines & lines, - coord_t width, + const SampleConfig &config, bool pointer_caption) { - LineUtils::draw(svg, lines, "black", 0., true); + coord_t width = config.head_radius / 10; + LineUtils::draw(svg, lines, "black", width, false); auto print_address = [&](const Point& p, const char* prefix, void * addr, const char* color){ if (pointer_caption) { std::stringstream ss; ss << prefix << std::hex << reinterpret_cast(addr); std::string s = ss.str(); - svg.draw_text(p, s.c_str(), color); + svg.draw_text(p, s.c_str(), color, 6); } }; + std::vector skeleton_colors{ + "yellow", // thin (min+max belowe thin) + "yellowgreen", // on way to thin (max is above thin) + "limegreen", // between (inside histerezis) + "forestgreen", // on way to thick (min is belove thick) + "darkgreen" // thick (min+max above thick) + }; + auto get_color = [&](const VoronoiGraph::Node::Neighbor &n) { + if (n.min_width() > config.max_width_for_center_support_line){ + return skeleton_colors[4]; + } else if (n.max_width() < config.min_width_for_outline_support){ + return skeleton_colors[0]; + } else if (n.min_width() < config.max_width_for_center_support_line && + n.max_width() > config.min_width_for_outline_support){ + return skeleton_colors[2]; + } else if (n.min_width() < config.min_width_for_outline_support){ + return skeleton_colors[1]; + } else if (n.max_width() > config.max_width_for_center_support_line) { + return skeleton_colors[3]; + } + assert(false); + return "gray"; + }; + for (const auto &[key, value] : graph.data) { Point p(key->x(), key->y()); svg.draw(p, "lightgray", width); @@ -1328,10 +1353,13 @@ void VoronoiGraphUtils::draw(SVG & svg, Point(0., 2e6)); print_address(p, "neighbor ptr ", (void *) &n, "gray"); if (is_second) continue; - std::string width_str = "width min=" + std::to_string(n.min_width()) + - " max=" + std::to_string(n.max_width()); - svg.draw_text(center + Point(-6e6, 0.), width_str.c_str(), "gray"); - draw(svg, *n.edge, lines, "gray", width); + const char *color = get_color(n); + if (pointer_caption) { + std::string width_str = "width min=" + std::to_string(n.min_width()) + + " max=" + std::to_string(n.max_width()); + svg.draw_text(center + Point(-6e6, 0.), width_str.c_str(), color, 6); + } + draw(svg, *n.edge, lines, color, width); } } } @@ -1358,7 +1386,8 @@ void VoronoiGraphUtils::draw(SVG & svg, const VoronoiGraph::Nodes &path, coord_t width, const char * color, - bool finish) + bool finish, + bool caption) { const VoronoiGraph::Node *prev_node = (finish) ? path.back() : nullptr; int index = 0; @@ -1372,9 +1401,10 @@ void VoronoiGraphUtils::draw(SVG & svg, Point from = to_point(prev_node->vertex); Point to = to_point(node->vertex); svg.draw(Line(from, to), color, width); - - svg.draw_text(from, std::to_string(index - 1).c_str(), color); - svg.draw_text(to, std::to_string(index).c_str(), color); + if (caption) { + svg.draw_text(from, std::to_string(index - 1).c_str(), color, 6); + svg.draw_text(to, std::to_string(index).c_str(), color, 6); + } prev_node = node; } } diff --git a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp index d7144c1389..d1c6f1f6cc 100644 --- a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp @@ -479,7 +479,7 @@ public: // draw function for debug static void draw(SVG & svg, const VoronoiGraph &graph, const Lines & lines, - coord_t width, + const SampleConfig &config, bool pointer_caption = false); static void draw(SVG & svg, const VD::edge_type &edge, @@ -490,7 +490,8 @@ public: // draw function for debug const VoronoiGraph::Nodes &path, coord_t width, const char * color, - bool finish = false); + bool finish = false, + bool caption = false); static void draw(SVG & svg, const VoronoiGraph::ExPath &path, coord_t width); diff --git a/src/libslic3r/SLA/SupportPointGenerator.cpp b/src/libslic3r/SLA/SupportPointGenerator.cpp index 66236df764..5f3f3746dd 100644 --- a/src/libslic3r/SLA/SupportPointGenerator.cpp +++ b/src/libslic3r/SLA/SupportPointGenerator.cpp @@ -60,6 +60,8 @@ public: return shape.contains(p); }); }); + if (it == indices.end()) + return; // no point to remove indices.erase(it, indices.end()); m_tree.clear(); m_tree.build(indices); // consume indices @@ -235,8 +237,7 @@ void support_part_overhangs( Point dp = support_point.position_on_layer - p; if (std::abs(dp.x()) > r) return false; if (std::abs(dp.y()) > r) return false; - double r2 = static_cast(r); - r2 *= r2; + double r2 = sqr(static_cast(r)); return dp.cast().squaredNorm() < r2; }; @@ -246,7 +247,7 @@ void support_part_overhangs( near_points.add(LayerSupportPoint{ SupportPoint{ Vec3f{unscale(p.x()), unscale(p.y()), part_z}, - /* head_front_radius */ 0.4f, + /* head_front_radius */ config.head_diameter / 2, SupportPointType::slope }, /* position_on_layer */ p, @@ -278,7 +279,7 @@ void support_island(const LayerPart &part, NearPoints& near_points, float part_z unscale(sample->point.y()), part_z }, - /* head_front_radius */ 0.4f, + /* head_front_radius */ cfg.head_diameter / 2, SupportPointType::island }, /* position_on_layer */ sample->point, @@ -481,12 +482,10 @@ void prepare_supports_for_layer(LayerSupportPoints &supports, float layer_z, /// /// /// -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); +/// +void remove_supports_out_of_part(NearPoints& near_points, const LayerPart &part, + const SupportPointGeneratorConfig &config) { + ExPolygons extend_shape = offset_ex(*part.shape, config.removing_delta, ClipperLib::jtSquare); near_points.remove_out_of(extend_shape); } @@ -660,7 +659,7 @@ LayerSupportPoints Slic3r::sla::generate_support_points( assert(layer_id != 0); 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); + remove_supports_out_of_part(near_points, part, config); support_part_overhangs(part, config, near_points, layer.print_z, maximal_radius); grids.push_back(std::move(near_points)); } diff --git a/src/libslic3r/SLA/SupportPointGenerator.hpp b/src/libslic3r/SLA/SupportPointGenerator.hpp index 96f16417c6..63f6ae56b1 100644 --- a/src/libslic3r/SLA/SupportPointGenerator.hpp +++ b/src/libslic3r/SLA/SupportPointGenerator.hpp @@ -51,6 +51,13 @@ struct SupportPointGeneratorConfig{ // Configuration for sampling island SampleConfig island_configuration = SampleConfigFactory::create(head_diameter); + + // To be able support same 2d area multipletimes, + // It is neccessary to remove support point form near KDTree structure + + // Must be greater than surface texture and lower than self supporting area + // May be use maximal island distance + float removing_delta = scale_(5.); }; struct LayerPart; // forward decl.