From 69c58505cdb7adc3d198bf76b5b1de34bea6f438 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Wed, 21 Apr 2021 09:36:38 +0200 Subject: [PATCH] =?UTF-8?q?=EF=BB=BFCenter=20support=20point=20contain=20c?= =?UTF-8?q?onfiguration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SLA/SupportIslands/SampleConfig.hpp | 4 + .../SupportIslands/SampleConfigFactory.hpp | 2 + .../SLA/SupportIslands/SampleIslandUtils.cpp | 126 +++++++++++------- .../SLA/SupportIslands/SampleIslandUtils.hpp | 24 ++-- .../SLA/SupportIslands/SupportIslandPoint.cpp | 36 +++-- .../SLA/SupportIslands/SupportIslandPoint.hpp | 15 +-- .../SLA/SupportIslands/VoronoiGraphUtils.cpp | 32 ++--- tests/sla_print/sla_supptgen_tests.cpp | 7 +- 8 files changed, 148 insertions(+), 98 deletions(-) diff --git a/src/libslic3r/SLA/SupportIslands/SampleConfig.hpp b/src/libslic3r/SLA/SupportIslands/SampleConfig.hpp index 7896d6eb7e..d3627b91d5 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleConfig.hpp +++ b/src/libslic3r/SLA/SupportIslands/SampleConfig.hpp @@ -28,6 +28,10 @@ struct SampleConfig // MUST be bigger than minimal_distance_from_outline coord_t minimal_support_distance = 0; + // minimal length of side branch to be sampled + // it is used for sampling in center only + coord_t min_side_branch_length = 0; + // Maximal length of longest path in voronoi diagram to be island // supported only by one single support point this point will be in center of path. coord_t max_length_for_one_support_point = 1.; diff --git a/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp b/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp index 262ef9fc03..82a706bfee 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp +++ b/src/libslic3r/SLA/SupportIslands/SampleConfigFactory.hpp @@ -31,6 +31,8 @@ public: result.minimal_support_distance = result.minimal_distance_from_outline + result.half_distance; + result.min_side_branch_length = 2 * result.minimal_distance_from_outline; + result.max_length_for_one_support_point = 2 * result.minimal_distance_from_outline + head_diameter; diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp index d96e706a90..95aaa06503 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp @@ -139,13 +139,12 @@ std::unique_ptr SampleIslandUtils::create_point( { VoronoiGraph::Position position(neighbor, ratio); Slic3r::Point p = VoronoiGraphUtils::create_edge_point(position); - return std::make_unique(p, position, type); + return std::make_unique(p, type); } -std::unique_ptr SampleIslandUtils::create_point_on_path( + std::optional SampleIslandUtils::create_position_on_path( const VoronoiGraph::Nodes &path, - double distance, - SupportIslandPoint::Type type) + double distance) { const VoronoiGraph::Node *prev_node = nullptr; double actual_distance = 0.; @@ -162,20 +161,35 @@ std::unique_ptr SampleIslandUtils::create_point_on_path( double previous_distance = actual_distance - distance; double over_ratio = previous_distance / neighbor->length(); double ratio = 1. - over_ratio; - return create_point(neighbor, ratio, type); + return VoronoiGraph::Position(neighbor, ratio); } prev_node = node; } + // distance must be inside path // this means bad input params assert(false); - return nullptr; // unreachable + return {}; // unreachable +} + +SupportIslandPointPtr SampleIslandUtils::create_point_on_path( + const VoronoiGraph::Nodes &path, + double distance, + const SampleConfig & config, + SupportIslandPoint::Type type) +{ + auto position_opt = create_position_on_path(path, distance); + if (!position_opt.has_value()) return nullptr; + return std::make_unique(*position_opt, &config, type); } SupportIslandPointPtr SampleIslandUtils::create_middle_path_point( const VoronoiGraph::Path &path, SupportIslandPoint::Type type) { - return create_point_on_path(path.nodes, path.length / 2, type); + auto position_opt = create_position_on_path(path.nodes, path.length / 2); + if (!position_opt.has_value()) return nullptr; + + return create_point(position_opt->neighbor, position_opt->ratio, type); } SupportIslandPoints SampleIslandUtils::create_side_points( @@ -183,11 +197,16 @@ SupportIslandPoints SampleIslandUtils::create_side_points( { VoronoiGraph::Nodes reverse_path = path; // copy std::reverse(reverse_path.begin(), reverse_path.end()); - SupportIslandPoints result; + auto pos1 = create_position_on_path(path, side_distance); + auto pos2 = create_position_on_path(reverse_path, side_distance); + assert(pos1.has_value()); + assert(pos2.has_value()); + SupportIslandPoint::Type type = SupportIslandPoint::Type::two_points; + SupportIslandPoints result; result.reserve(2); - result.push_back(create_point_on_path(path, side_distance, SupportIslandPoint::Type::two_points)); - result.push_back(create_point_on_path(reverse_path, side_distance, SupportIslandPoint::Type::two_points)); - return std::move(result); + result.push_back(create_point(pos1->neighbor, pos1->ratio, type)); + result.push_back(create_point(pos2->neighbor, pos2->ratio, type)); + return result; } SupportIslandPoints SampleIslandUtils::sample_side_branch( @@ -196,22 +215,24 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch( double start_offset, const CenterLineConfiguration &cfg) { - assert(cfg.max_sample_distance > start_offset); - double distance = cfg.max_sample_distance - start_offset; - double length = side_path.length - cfg.side_distance - distance; + const double max_distance = cfg.sample_config.max_distance; + assert(max_distance > start_offset); + double distance = max_distance - start_offset; + const double side_distance = cfg.sample_config.minimal_distance_from_outline; + double length = side_path.length - side_distance - distance; if (length < 0.) { VoronoiGraph::Nodes reverse_path = side_path.nodes; std::reverse(reverse_path.begin(), reverse_path.end()); reverse_path.push_back(first_node); SupportIslandPoints result; result.push_back( - create_point_on_path(reverse_path, cfg.side_distance, + create_point_on_path(reverse_path, side_distance, cfg.sample_config, SupportIslandPoint::Type::center_line_end)); return std::move(result); } // count of segment between points on main path size_t segment_count = static_cast( - std::ceil(length / cfg.max_sample_distance)); + std::ceil(length / max_distance)); double sample_distance = length / segment_count; SupportIslandPoints result; result.reserve(segment_count + 1); @@ -225,7 +246,7 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch( distance : (sample_distance - distance); - if (side_item->second.top().length > cfg.min_length) { + if (side_item->second.top().length > cfg.sample_config.min_side_branch_length) { auto side_samples = sample_side_branches(side_item, start_offset, cfg); result.insert(result.end(), std::move_iterator(side_samples.begin()), @@ -269,7 +290,8 @@ SupportIslandPoints SampleIslandUtils::sample_side_branches( SupportIslandPoints result; VoronoiGraph::ExPath::SideBranches side_branches_cpy = side_branches; - while (side_branches_cpy.top().length > cfg.min_length) { + while (side_branches_cpy.top().length > + cfg.sample_config.min_side_branch_length) { auto samples = sample_side_branch(first_node, side_branches_cpy.top(), start_offset, cfg); result.insert(result.end(), @@ -405,7 +427,7 @@ SupportIslandPoints SampleIslandUtils::sample_center_line( // like side branch separate first node from path VoronoiGraph::Path main_path({nodes.begin() + 1, nodes.end()}, path.length); - double start_offset = cfg.max_sample_distance - cfg.side_distance; + double start_offset = cfg.sample_config.max_distance - cfg.sample_config.min_side_branch_length; SupportIslandPoints result = sample_side_branch(nodes.front(), main_path, start_offset, cfg); @@ -424,7 +446,8 @@ void SampleIslandUtils::sample_center_circle_end( SupportIslandPoints & result) { double distance = neighbor_distance + node_distance + neighbor.length(); - if (distance < cfg.max_sample_distance) { // no need add support point + double max_sample_distance = cfg.sample_config.max_distance; + if (distance < max_sample_distance) { // no need add support point if (neighbor_distance > node_distance + neighbor.length()) neighbor_distance = node_distance + neighbor.length(); if (node_distance > neighbor_distance + neighbor.length()) @@ -432,12 +455,13 @@ void SampleIslandUtils::sample_center_circle_end( return; } size_t count_supports = static_cast( - std::floor(distance / cfg.max_sample_distance)); + std::floor(distance / max_sample_distance)); // distance between support points double distance_between = distance / (count_supports + 1); if (distance_between < neighbor_distance) { // point is calculated to be in done path, SP will be on edge point - result.push_back(create_point(&neighbor, 1., SupportIslandPoint::Type::center_circle_end)); + result.push_back( + create_point(&neighbor, 1., SupportIslandPoint::Type::center_circle_end)); neighbor_distance = 0.; count_supports -= 1; if (count_supports == 0) { @@ -452,8 +476,11 @@ void SampleIslandUtils::sample_center_circle_end( nodes.insert(nodes.begin(), neighbor.node); for (int i = 1; i <= count_supports; ++i) { double distance_from_neighbor = i * (distance_between) - neighbor_distance; + auto position = create_position_on_path(nodes, distance_from_neighbor); + assert(position.has_value()); result.push_back( - create_point_on_path(nodes, distance_from_neighbor, SupportIslandPoint::Type::center_circle_end2)); + create_point(position->neighbor, position->ratio, + SupportIslandPoint::Type::center_circle_end2)); double distance_support_to_node = fabs(neighbor.length() - distance_from_neighbor); if (node_distance > distance_support_to_node) @@ -619,7 +646,7 @@ std::set create_path_set( void SampleIslandUtils::sample_center_circles( const VoronoiGraph::ExPath & path, const CenterLineConfiguration &cfg, - SupportIslandPoints& result) + SupportIslandPoints & result) { // vector of connected circle points // for detection path from circle @@ -627,8 +654,11 @@ void SampleIslandUtils::sample_center_circles( create_circles_sets(path.circles, path.connected_circle); std::set path_set = create_path_set(path); SupportDistanceMap support_distance_map = create_support_distance_map(result); + double half_sample_distance = cfg.sample_config.max_distance / 2.; for (const auto &circle_set : circles_sets) { - SupportDistanceMap path_distances = create_path_distances(circle_set, path_set, support_distance_map, cfg.max_sample_distance/2); + SupportDistanceMap path_distances = + create_path_distances(circle_set, path_set, support_distance_map, + half_sample_distance); SupportIslandPoints circle_result = sample_center_circle(circle_set, path_distances, cfg); result.insert(result.end(), std::make_move_iterator(circle_result.begin()), @@ -637,9 +667,9 @@ void SampleIslandUtils::sample_center_circles( } SupportIslandPoints SampleIslandUtils::sample_center_circle( - const std::set &circle_set, - std::map& path_distances, - const CenterLineConfiguration & cfg) + const std::set & circle_set, + std::map &path_distances, + const CenterLineConfiguration & cfg) { SupportIslandPoints result; // depth search @@ -699,15 +729,17 @@ SupportIslandPoints SampleIslandUtils::sample_center_circle( next_nd.nodes.insert(next_nd.nodes.begin(), neighbor.node); next_nd.distance_from_support_point += neighbor.length(); // exist place for sample: - while (next_nd.distance_from_support_point > - cfg.max_sample_distance) { + double max_sample_distance = cfg.sample_config.max_distance; + while (next_nd.distance_from_support_point > max_sample_distance) { double distance_from_node = next_nd .distance_from_support_point - nd.distance_from_support_point; - double ratio = distance_from_node / neighbor.length(); - result.push_back( - create_point(&neighbor, ratio, SupportIslandPoint::Type::center_circle)); - next_nd.distance_from_support_point -= cfg.max_sample_distance; + double ratio = distance_from_node / neighbor.length(); + result.push_back(std::make_unique( + VoronoiGraph::Position(&neighbor, ratio), + &cfg.sample_config, + SupportIslandPoint::Type::center_circle)); + next_nd.distance_from_support_point -= max_sample_distance; } process.push(next_nd); } @@ -762,10 +794,7 @@ SupportIslandPoints SampleIslandUtils::sample_expath( // othewise sample path CenterLineConfiguration - centerLineConfiguration(path.side_branches, - 2 * config.minimal_distance_from_outline, - config.max_distance, - config.minimal_distance_from_outline); + centerLineConfiguration(path.side_branches, config); SupportIslandPoints samples = sample_center_line(path, centerLineConfiguration); samples.front()->type = SupportIslandPoint::Type::center_line_end2; return std::move(samples); @@ -857,9 +886,9 @@ std::vector SampleIslandUtils::sample_center( double edge_length = neighbor->length(); while (edge_length >= support_in) { double ratio = support_in / edge_length; - results.push_back( - create_point(neighbor, ratio, - SupportIslandPoint::Type::center_line)); + VoronoiGraph::Position position(neighbor, ratio); + results.push_back(std::make_unique( + position, &config, SupportIslandPoint::Type::center_line)); support_in += config.max_distance; } support_in -= edge_length; @@ -882,9 +911,13 @@ std::vector SampleIslandUtils::sample_center( if ((config.max_distance - support_in) >= config.minimal_support_distance) { VoronoiGraph::Nodes path_reverse = path; // copy std::reverse(path_reverse.begin(), path_reverse.end()); - results.push_back(create_point_on_path( - path_reverse, config.minimal_distance_from_outline, - SupportCenterIslandPoint::Type::center_line_end3)); + auto position_opt = create_position_on_path( + path_reverse, config.minimal_distance_from_outline); + assert(position_opt.has_value()); + Point point = VoronoiGraphUtils::create_edge_point( + *position_opt); + results.push_back(std::make_unique( + point, SupportIslandPoint::Type::center_line_end3)); } if (new_starts.empty()) return {}; @@ -907,8 +940,9 @@ std::vector SampleIslandUtils::sample_center( double sample_length = edge_length * field_start->ratio; while (sample_length > support_in) { double ratio = support_in / edge_length; - results.push_back(create_point(neighbor, ratio, - SupportIslandPoint::Type::center_line)); + VoronoiGraph::Position position(neighbor, ratio); + results.push_back(std::make_unique( + position, &config,SupportIslandPoint::Type::center_line)); support_in += config.max_distance; } return new_starts; diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp index b7d77196d5..2a62a71786 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp @@ -57,10 +57,16 @@ public: /// /// Neighbor connected Nodes /// Distance to final point - /// Points with distance to first node + /// Position on VG with distance to first node when exists. + /// When distance is out of path return null optional + static std::optional create_position_on_path( + const VoronoiGraph::Nodes &path, + double distance); + static SupportIslandPointPtr create_point_on_path( const VoronoiGraph::Nodes &path, double distance, + const SampleConfig & config, SupportIslandPoint::Type type = SupportIslandPoint::Type::undefined); /// @@ -69,7 +75,7 @@ public: /// is same as distance to back of path /// /// Queue of neighbor nodes.(must be neighbor) - /// length of path + /// Type of result island point /// Point laying on voronoi diagram static SupportIslandPointPtr create_middle_path_point( const VoronoiGraph::Path &path, @@ -82,20 +88,16 @@ public: struct CenterLineConfiguration { const VoronoiGraph::ExPath::SideBranchesMap &branches_map; - double min_length; - double max_sample_distance; - double side_distance; + const SampleConfig & sample_config; + CenterLineConfiguration( const VoronoiGraph::ExPath::SideBranchesMap &branches_map, - double min_length, - double max_sample_distance, - double side_distance) + const SampleConfig & sample_config) : branches_map(branches_map) - , min_length(min_length) - , max_sample_distance(max_sample_distance) - , side_distance(side_distance) + , sample_config(sample_config) {} }; + // create points along path and its side branches(recursively) static SupportIslandPoints sample_side_branch( const VoronoiGraph::Node * first_node, diff --git a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp index a43d4603e4..678feaf206 100644 --- a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp +++ b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.cpp @@ -35,31 +35,39 @@ bool SupportIslandPoint::can_move(const Type &type) bool SupportIslandPoint::can_move() const { return can_move(type); } -SupportCenterIslandPoint::SupportCenterIslandPoint( - Point point, VoronoiGraph::Position position, Type type) - : SupportIslandPoint(point, type), position(position) -{} - coord_t SupportIslandPoint::move(const Point &destination) { Point diff = destination - point; - point = destination; + point = destination; // TODO: check move out of island !! // + need island ExPolygon return diff.x() + diff.y(); // Manhatn distance } -coord_t SupportCenterIslandPoint::move(const Point &destination) -{ - // TODO: For decide of move need information about - // + search distance for allowed move over VG(count or distance) - - // move only along VD - position = VoronoiGraphUtils::align(position, destination, max_distance); +/////////////// +// Point on VD +/////////////// +SupportCenterIslandPoint::SupportCenterIslandPoint( + VoronoiGraph::Position position, + const SampleConfig * configuration, + Type type) + : SupportIslandPoint(VoronoiGraphUtils::create_edge_point(position), type) + , configuration(configuration) + , position(position) +{} + +coord_t SupportCenterIslandPoint::move(const Point &destination) +{ + // move only along VD + // TODO: Start respect minimum distance from outline !! + position = + VoronoiGraphUtils::align(position, destination, + configuration->max_align_distance); Point new_point = VoronoiGraphUtils::create_edge_point(position); Point move = new_point - point; point = new_point; - return abs(move.x()) + abs(move.y()); + coord_t manhatn_distance = abs(move.x()) + abs(move.y()); + return manhatn_distance; } diff --git a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp index 1c7685ea48..5cb80adcdd 100644 --- a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp +++ b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp @@ -5,6 +5,7 @@ #include #include #include "VoronoiGraph.hpp" +#include "SampleConfig.hpp" namespace Slic3r::sla { @@ -83,17 +84,15 @@ class SupportCenterIslandPoint : public SupportIslandPoint { public: // Define position on voronoi graph - // Lose data when voronoi graph does NOT exist + // FYI: Lose data when voronoi graph does NOT exist VoronoiGraph::Position position; - // IMPROVE: not need ratio, only neighbor - // const VoronoiGraph::Node::Neighbor* neighbor; - - // TODO: should earn when created - const double max_distance = 1e6; // [in nm] --> 1 mm + // hold pointer to configuration + // FYI: Lose data when configuration destruct + const SampleConfig *configuration; public: - SupportCenterIslandPoint(Point point, - VoronoiGraph::Position position, + SupportCenterIslandPoint(VoronoiGraph::Position position, + const SampleConfig *configuration, Type type = Type::center_line); bool can_move() const override{ return true; } diff --git a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp index c493b07ebc..4690ff8b09 100644 --- a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp @@ -1055,22 +1055,22 @@ double VoronoiGraphUtils::get_distance(const VD::edge_type &edge, // TODO: find closest point on curve edge //if (edge.is_linear()) { - // get line foot point, inspired Geometry::foot_pt - Vec2d v0 = to_point_d(edge.vertex0()); - Vec2d v = point.cast() - v0; - Vec2d v1 = to_point_d(edge.vertex1()); - Vec2d edge_dir = v1 - v0; - double l2 = edge_dir.squaredNorm(); - edge_ratio = v.dot(edge_dir) / l2; - // IMPROVE: not neccesary to calculate point if (edge_ratio > 1 || edge_ratio < 0) - Point edge_point; - if (edge_ratio > 1.) edge_point = v1.cast(); - else if (edge_ratio < 0.) edge_point = v0.cast(); - else { // foot point - edge_point = (v0 + edge_dir * edge_ratio).cast(); - } - double distance = (point - edge_point).cast().norm(); - return distance; + // get line foot point, inspired Geometry::foot_pt + Vec2d v0 = to_point_d(edge.vertex0()); + Vec2d v = point.cast() - v0; + Vec2d v1 = to_point_d(edge.vertex1()); + Vec2d edge_dir = v1 - v0; + double l2 = edge_dir.squaredNorm(); + edge_ratio = v.dot(edge_dir) / l2; + // IMPROVE: not neccesary to calculate point if (edge_ratio > 1 || edge_ratio < 0) + Point edge_point; + if (edge_ratio > 1.) edge_point = v1.cast(); + else if (edge_ratio < 0.) edge_point = v0.cast(); + else { // foot point + edge_point = (v0 + edge_dir * edge_ratio).cast(); + } + double distance = (point - edge_point).cast().norm(); + return distance; } diff --git a/tests/sla_print/sla_supptgen_tests.cpp b/tests/sla_print/sla_supptgen_tests.cpp index b701e267cc..2cb95613d6 100644 --- a/tests/sla_print/sla_supptgen_tests.cpp +++ b/tests/sla_print/sla_supptgen_tests.cpp @@ -435,6 +435,7 @@ SampleConfig create_sample_config(double size) { cfg.half_distance = cfg.max_distance/2; cfg.head_radius = size / 4; cfg.minimal_distance_from_outline = cfg.head_radius + size/10; + cfg.min_side_branch_length = 2 * cfg.minimal_distance_from_outline; cfg.minimal_support_distance = cfg.minimal_distance_from_outline + cfg.half_distance; cfg.max_length_for_one_support_point = 2*size; cfg.max_length_for_two_support_points = 4*size; @@ -553,8 +554,8 @@ TEST_CASE("Small islands should be supported in center", "[SupGen][VoronoiSkelet // TODO: remove next 3 lines, debug sharp triangle auto triangle = PolygonUtils::create_isosceles_triangle(8. * size, 40. * size); islands = {ExPolygon(triangle)}; - auto test_island = create_tiny_wide_test_2(3 * size, 2 / 3. * size); - islands = {test_island}; + //auto test_island = create_tiny_wide_test_2(3 * size, 2 / 3. * size); + //islands = {test_island}; for (ExPolygon &island : islands) { size_t debug_index = &island - &islands.front(); @@ -647,7 +648,7 @@ TEST_CASE("Compare sampling test") enum class Sampling { old, filip - } sample_type = Sampling::old; + } sample_type = Sampling::filip; std::function(const ExPolygon &)> sample = (sample_type == Sampling::old) ? sample_old :