From 85984ca18961283eacea878a3e4dfefa3140f651 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Fri, 26 Mar 2021 16:57:03 +0100 Subject: [PATCH] =?UTF-8?q?=EF=BB=BFSupport=20island=20points=20are=20gene?= =?UTF-8?q?rated=20as=20unique=20ptr=20for=20option=20to=20move=20with=20t?= =?UTF-8?q?hem=20+=20add=20fix=20for=20cell=202=20polygon=20transformation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libslic3r/Geometry.hpp | 4 +- .../SLA/SupportIslands/LineUtils.cpp | 9 +- .../SLA/SupportIslands/LineUtils.hpp | 8 ++ .../SLA/SupportIslands/SampleIslandUtils.cpp | 115 +++++++++-------- .../SLA/SupportIslands/SampleIslandUtils.hpp | 6 +- .../SLA/SupportIslands/SupportIslandPoint.hpp | 118 ++++++++++++------ .../SLA/SupportIslands/VectorUtils.hpp | 1 + .../SLA/SupportIslands/VoronoiGraphUtils.cpp | 55 ++++---- tests/libslic3r/test_voronoi.cpp | 76 +++++++++++ tests/sla_print/sla_supptgen_tests.cpp | 14 +-- tests/sla_print/sla_voronoi_graph_tests.cpp | 2 +- 11 files changed, 270 insertions(+), 138 deletions(-) diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 8c69d55126..1043ae12b9 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -314,11 +314,11 @@ bool liang_barsky_line_clipping( template int ray_circle_intersections_r2_lv2_c(T r2, T a, T b, T lv2, T c, std::pair, Eigen::Matrix> &out) { - T x0 = - a * c / lv2; - T y0 = - b * c / lv2; T d = r2 - c * c / lv2; if (d < T(0)) return 0; + T x0 = - a * c / lv2; + T y0 = - b * c / lv2; T mult = sqrt(d / lv2); out.first.x() = x0 + b * mult; out.first.y() = y0 - a * mult; diff --git a/src/libslic3r/SLA/SupportIslands/LineUtils.cpp b/src/libslic3r/SLA/SupportIslands/LineUtils.cpp index 4a79906205..e081ddbaac 100644 --- a/src/libslic3r/SLA/SupportIslands/LineUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/LineUtils.cpp @@ -59,7 +59,7 @@ std::optional LineUtils::crop_ray(const Linef &ray, Vec2d center_d = center.cast(); if (is_parallel_y(ray)) { double x = ray.a.x(); - double diff = x - center.x(); + double diff = x - center_d.x(); double abs_diff = fabs(diff); if (abs_diff > radius) return {}; // create cross points @@ -247,6 +247,13 @@ void LineUtils::draw(SVG & svg, } } +double LineUtils::perp_distance(const Linef &line, Vec2d p) +{ + Vec2d v = line.b - line.a; // direction + Vec2d va = p - line.a; + return std::abs(cross2(v, va)) / v.norm(); +} + void LineUtils::draw(SVG & svg, const Lines &lines, const char * color, diff --git a/src/libslic3r/SLA/SupportIslands/LineUtils.hpp b/src/libslic3r/SLA/SupportIslands/LineUtils.hpp index 3e3a1102e7..6b2f7a8780 100644 --- a/src/libslic3r/SLA/SupportIslands/LineUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/LineUtils.hpp @@ -84,6 +84,14 @@ public: static std::tuple get_param(const Line &line); static std::tuple get_param(const Linef &line); + /// + /// Calculate distance between point and ray + /// + /// a and b are only for direction, not limit + /// Point in space + /// Euclid perpedicular distance + static double perp_distance(const Linef &line, Vec2d p); + static void draw(SVG & svg, const Line &line, const char *color = "gray", diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp index 06f2ce9399..84ce4d022c 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp @@ -19,18 +19,17 @@ using namespace Slic3r::sla; - -SupportIslandPoint SampleIslandUtils::create_point( +std::unique_ptr SampleIslandUtils::create_point( const VoronoiGraph::Node::Neighbor *neighbor, double ratio, SupportIslandPoint::Type type) { VoronoiGraph::Position position(neighbor, ratio); Slic3r::Point p = VoronoiGraphUtils::create_edge_point(position); - return SupportIslandPoint(p, type, position); + return std::make_unique(p, position, type); } -SupportIslandPoint SampleIslandUtils::create_point_on_path( +std::unique_ptr SampleIslandUtils::create_point_on_path( const VoronoiGraph::Nodes &path, double distance, SupportIslandPoint::Type type) @@ -57,12 +56,10 @@ SupportIslandPoint SampleIslandUtils::create_point_on_path( // distance must be inside path // this means bad input params assert(false); - return SupportIslandPoint(Point(0, 0), - SupportIslandPoint::Type::undefined, - VoronoiGraph::Position(nullptr,0.)); + return nullptr; // unreachable } -SupportIslandPoint SampleIslandUtils::create_middle_path_point( +SupportIslandPointPtr SampleIslandUtils::create_middle_path_point( const VoronoiGraph::Path &path, SupportIslandPoint::Type type) { return create_point_on_path(path.nodes, path.length / 2, type); @@ -73,10 +70,11 @@ SupportIslandPoints SampleIslandUtils::create_side_points( { VoronoiGraph::Nodes reverse_path = path; // copy std::reverse(reverse_path.begin(), reverse_path.end()); - return { - create_point_on_path(path, side_distance, SupportIslandPoint::Type::two_points), - create_point_on_path(reverse_path, side_distance, 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); } SupportIslandPoints SampleIslandUtils::sample_side_branch( @@ -92,7 +90,11 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch( VoronoiGraph::Nodes reverse_path = side_path.nodes; std::reverse(reverse_path.begin(), reverse_path.end()); reverse_path.push_back(first_node); - return {create_point_on_path(reverse_path, cfg.side_distance, SupportIslandPoint::Type::center_line_end)}; + SupportIslandPoints result; + result.push_back( + create_point_on_path(reverse_path, cfg.side_distance, + SupportIslandPoint::Type::center_line_end)); + return std::move(result); } // count of segment between points on main path size_t segment_count = static_cast( @@ -113,13 +115,13 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch( if (side_item->second.top().length > cfg.min_length) { auto side_samples = sample_side_branches(side_item, start_offset, cfg); - result.insert(result.end(), side_samples.begin(), - side_samples.end()); + result.insert(result.end(), std::move_iterator(side_samples.begin()), + std::move_iterator(side_samples.end())); } } while (distance < neighbor->edge_length) { double edge_ratio = distance / neighbor->edge_length; - result.emplace_back( + result.push_back( create_point(neighbor, edge_ratio, SupportIslandPoint::Type::center_line) ); distance += sample_distance; @@ -128,8 +130,8 @@ SupportIslandPoints SampleIslandUtils::sample_side_branch( prev_node = node; } assert(fabs(distance - (sample_distance - cfg.side_distance)) < 1e-5); - result.back().type = SupportIslandPoint::Type::center_line_end; - return result; + result.back()->type = SupportIslandPoint::Type::center_line_end; + return std::move(result); } SupportIslandPoints SampleIslandUtils::sample_side_branches( @@ -150,10 +152,12 @@ SupportIslandPoints SampleIslandUtils::sample_side_branches( while (side_branches_cpy.top().length > cfg.min_length) { auto samples = sample_side_branch(first_node, side_branches_cpy.top(), start_offset, cfg); - result.insert(result.end(), samples.begin(), samples.end()); + result.insert(result.end(), + std::move_iterator(samples.begin()), + std::move_iterator(samples.end())); side_branches_cpy.pop(); } - return result; + return std::move(result); } std::vector> create_circles_sets( @@ -187,14 +191,16 @@ std::vector> create_circles_sets( Slic3r::Points SampleIslandUtils::to_points(const SupportIslandPoints &support_points) { - std::function transform_func = &SupportIslandPoint::point; + std::function &)> transform_func = &SupportIslandPoint::point; return VectorUtils::transform(support_points, transform_func); } std::vector SampleIslandUtils::to_points_f(const SupportIslandPoints &support_points) { - std::function transform_func = - [](const SupportIslandPoint &p) { return p.point.cast(); }; + std::function &)> transform_func = + [](const std::unique_ptr &p) { + return p->point.cast(); + }; return VectorUtils::transform(support_points, transform_func); } @@ -246,13 +252,13 @@ coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples, construct_voronoi(points.begin(), points.end(), &vd); coord_t max_move = 0; for (const VD::cell_type &cell : vd.cells()) { - SupportIslandPoint &sample = samples[cell.source_index()]; - if (!sample.can_move()) continue; + SupportIslandPointPtr &sample = samples[cell.source_index()]; + if (!sample->can_move()) continue; Polygon polygon = VoronoiGraphUtils::to_polygon(cell, points, config.max_distance); Polygons intersections = Slic3r::intersection(island, ExPolygon(polygon)); const Polygon *island_cell = nullptr; for (const Polygon &intersection : intersections) { - if (intersection.contains(sample.point)) { + if (intersection.contains(sample->point)) { island_cell = &intersection; break; } @@ -265,27 +271,13 @@ coord_t SampleIslandUtils::align_once(SupportIslandPoints &samples, svg.draw(*island_cell, "gray"); svg.draw(sample.point, "black", config.head_radius); svg.draw(Line(sample.point, center), "blue", config.head_radius / 5); -#endif // VISUALIZE_SAMPLE_ISLAND_UTILS_ALIGN_ONCE - coord_t act_move = align_support(sample, center, config.max_align_distance); +#endif // VISUALIZE_SAMPLE_ISLAND_UTILS_ALIGN_ONCE + coord_t act_move = sample->move(center); if (max_move < act_move) max_move = act_move; } return max_move; } -coord_t SampleIslandUtils::align_support(SupportIslandPoint &support, - const Point & wanted, - double max_distance) -{ - //move only along VD - VoronoiGraph::Position position = - VoronoiGraphUtils::align(support.position, wanted, max_distance); - Point new_point = VoronoiGraphUtils::create_edge_point(position); - Point move = new_point - support.point; - support.position= position; - support.point = new_point; - return abs(move.x()) + abs(move.y()); -} - SupportIslandPoints SampleIslandUtils::sample_center_line( const VoronoiGraph::ExPath &path, const CenterLineConfiguration &cfg) { @@ -300,7 +292,7 @@ SupportIslandPoints SampleIslandUtils::sample_center_line( if (path.circles.empty()) return result; sample_center_circles(path, cfg, result); - return result; + return std::move(result); } void SampleIslandUtils::sample_center_circle_end( @@ -325,7 +317,7 @@ void SampleIslandUtils::sample_center_circle_end( 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.emplace_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) { @@ -340,7 +332,7 @@ 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; - result.emplace_back( + result.push_back( create_point_on_path(nodes, distance_from_neighbor, SupportIslandPoint::Type::center_circle_end2)); double distance_support_to_node = fabs(neighbor.edge_length - distance_from_neighbor); @@ -435,11 +427,13 @@ SupportDistanceMap create_path_distances( return path_distances; } +// do not use SupportDistanceMap create_support_distance_map(const SupportIslandPoints &support_points) { SupportDistanceMap support_distance_map; - for (const SupportIslandPoint &support_point : support_points) { - const VoronoiGraph::Position &position = support_point.position; + for (const SupportIslandPointPtr &support_point : support_points) { + auto ptr = dynamic_cast(support_point.get()); // bad use + const VoronoiGraph::Position &position = ptr->position; const VoronoiGraph::Node *node = position.neighbor->node; const VoronoiGraph::Node *twin_node = VoronoiGraphUtils::get_twin_node(position.neighbor); double distance = (1 - position.ratio) * position.neighbor->edge_length; @@ -516,7 +510,9 @@ void SampleIslandUtils::sample_center_circles( 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); SupportIslandPoints circle_result = sample_center_circle(circle_set, path_distances, cfg); - result.insert(result.end(), circle_result.begin(), circle_result.end()); + result.insert(result.end(), + std::make_move_iterator(circle_result.begin()), + std::make_move_iterator(circle_result.end())); } } @@ -589,7 +585,7 @@ SupportIslandPoints SampleIslandUtils::sample_center_circle( .distance_from_support_point - nd.distance_from_support_point; double ratio = distance_from_node / neighbor.edge_length; - result.emplace_back( + result.push_back( create_point(&neighbor, ratio, SupportIslandPoint::Type::center_circle)); next_nd.distance_from_support_point -= cfg.max_sample_distance; } @@ -605,9 +601,10 @@ SupportIslandPoints SampleIslandUtils::sample_expath( // 1) One support point if (path.length < config.max_length_for_one_support_point) { // create only one point in center - return { - create_middle_path_point(path, SupportIslandPoint::Type::one_center_point) - }; + SupportIslandPoints result; + result.push_back(create_middle_path_point( + path, SupportIslandPoint::Type::one_center_point)); + return std::move(result); } double max_width = VoronoiGraphUtils::get_max_width(path); @@ -624,8 +621,8 @@ SupportIslandPoints SampleIslandUtils::sample_expath( config.max_distance, config.minimal_distance_from_outline); SupportIslandPoints samples = sample_center_line(path, centerLineConfiguration); - samples.front().type = SupportIslandPoint::Type::center_line_end2; - return samples; + samples.front()->type = SupportIslandPoint::Type::center_line_end2; + return std::move(samples); } // line of zig zag points @@ -641,7 +638,7 @@ SupportIslandPoints SampleIslandUtils::sample_expath( SupportIslandPoints points; points.emplace_back(create_point_on_path(path.nodes, config.minimal_distance_from_outline)); - return points; + return std::move(points); } SupportIslandPoints SampleIslandUtils::sample_voronoi_graph( @@ -665,10 +662,10 @@ void SampleIslandUtils::draw(SVG & svg, bool write_type) { for (const auto &p : supportIslandPoints) { - svg.draw(p.point, color, size); - if (write_type && p.type != SupportIslandPoint::Type::undefined) { - auto type_name = magic_enum::enum_name(p.type); - Point start = p.point + Point(size, 0.); + svg.draw(p->point, color, size); + if (write_type && p->type != SupportIslandPoint::Type::undefined) { + auto type_name = magic_enum::enum_name(p->type); + Point start = p->point + Point(size, 0.); svg.draw_text(start, std::string(type_name).c_str(), color); } } diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp index edd51bc8f5..5404748638 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp @@ -28,7 +28,7 @@ public: /// Source distance ratio for position on edge /// Type of point /// created support island point - static SupportIslandPoint create_point( + static SupportIslandPointPtr create_point( const VoronoiGraph::Node::Neighbor *neighbor, double ratio, SupportIslandPoint::Type type = SupportIslandPoint::Type::undefined); @@ -39,7 +39,7 @@ public: /// Neighbor connected Nodes /// Distance to final point /// Points with distance to first node - static SupportIslandPoint create_point_on_path( + static SupportIslandPointPtr create_point_on_path( const VoronoiGraph::Nodes &path, double distance, SupportIslandPoint::Type type = SupportIslandPoint::Type::undefined); @@ -52,7 +52,7 @@ public: /// Queue of neighbor nodes.(must be neighbor) /// length of path /// Point laying on voronoi diagram - static SupportIslandPoint create_middle_path_point( + static SupportIslandPointPtr create_middle_path_point( const VoronoiGraph::Path &path, SupportIslandPoint::Type type = SupportIslandPoint::Type::undefined); diff --git a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp index 821f8af2ce..7506052602 100644 --- a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp +++ b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp @@ -2,6 +2,7 @@ #define slic3r_SLA_SuppotstIslands_SupportIslandPoint_hpp_ #include +#include #include #include "VoronoiGraph.hpp" @@ -12,59 +13,106 @@ namespace Slic3r::sla { /// struct SupportIslandPoint { - enum class Type : unsigned char { + enum class Type: unsigned char { one_center_point, two_points, center_line, - center_line_end, // end of branch + center_line_end, // end of branch center_line_end2, // start of main path(only one per VD) center_circle, - center_circle_end, // circle finish by one point (one end per circle - need allign) - center_circle_end2, // circle finish by multi points (one end per circle - need allign) + center_circle_end, // circle finish by one point (one end per circle - + // need allign) + center_circle_end2, // circle finish by multi points (one end per + // circle - need allign) + + outline, // keep position align with island outline undefined }; - Slic3r::Point point; // 2 point in layer coordinate + Type type; + Slic3r::Point point; // 2 coordinate point in a layer (in one slice) + //SupportIslandPoint() : point(0, 0), type(Type::undefined) {} + SupportIslandPoint(Slic3r::Point point, Type type = Type::undefined); + virtual ~SupportIslandPoint() = default; + + static bool can_move(const Type &type) + { + // use shorter list + /* + static const std::set can_move({ + Type::center_line, + Type::center_circle, + Type::center_circle_end, + Type::center_circle_end2}); + return can_move.find(type) != can_move.end(); + /*/ // switch comment center + static const std::set cant_move({ + Type::one_center_point, + Type::two_points, + Type::center_line_end, + Type::center_line_end2}); + return cant_move.find(type) == cant_move.end(); + //*/ + } + + virtual bool can_move() const { return can_move(type); } + + /// + /// Move position of support point close to destination + /// with support point restrictions + /// + /// Wanted position + /// Move distance + virtual coord_t move(const Point &destination); +}; + +using SupportIslandPointPtr = std::unique_ptr; +using SupportIslandPoints = std::vector; + +struct SupportCenterIslandPoint : public SupportIslandPoint +{ // Define position on voronoi graph // Lose data when voronoi graph does NOT exist VoronoiGraph::Position position; + // IMPROVE: not need ratio, only neighbor + // const VoronoiGraph::Node::Neighbor* neighbor; - Type type; + // TODO: should earn when created + const double max_distance = 1e6; // [in nm] --> 1 mm - SupportIslandPoint(Slic3r::Point point, - Type type, - VoronoiGraph::Position position) - : point(std::move(point)), type(type), position(position) + SupportCenterIslandPoint(Slic3r::Point point, + VoronoiGraph::Position position, + Type type = Type::center_line) + : SupportIslandPoint(point, type), position(position) {} - bool can_move() const{ - // use shorter list - /* - - static const std::set can_move({ - Type::center_line, - Type::center_circle, - Type::center_circle_end, - Type::center_circle_end2 - }); - return can_move.find(type) != can_move.end(); - - /*/ - - static const std::set cant_move({ - Type::one_center_point, - Type::two_points, - Type::center_line_end, - Type::center_line_end2 - }); - return cant_move.find(type) == cant_move.end(); - - //*/ + bool can_move() const override{ return true; } + coord_t move(const Point &destination) override; +}; + +struct SupportOutlineIslandPoint : public SupportIslandPoint +{ + // index of line form island outline + size_t index; + SupportOutlineIslandPoint(Slic3r::Point point, + size_t index, + Type type = Type::outline) + : SupportIslandPoint(point, type), index(index) + {} + + bool can_move() const override { return true; } + + coord_t move(const Point &destination) override + { + // TODO: For decide of move need information about + // + island outlines \ May be + // + distance from outline / offseted outlines + // + search distance for allowed move over outlines(count, distance) + assert(false); // Not implemented + return 0; } }; -using SupportIslandPoints = std::vector; - } // namespace Slic3r::sla #endif // slic3r_SLA_SuppotstIslands_SupportIslandPoint_hpp_ diff --git a/src/libslic3r/SLA/SupportIslands/VectorUtils.hpp b/src/libslic3r/SLA/SupportIslands/VectorUtils.hpp index 5b6319c0ca..e55184b495 100644 --- a/src/libslic3r/SLA/SupportIslands/VectorUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/VectorUtils.hpp @@ -26,6 +26,7 @@ public: template static void sort_by(std::vector &data, std::function &calc) { + assert(!data.empty()); // initialize original index locations std::vector idx(data.size()); iota(idx.begin(), idx.end(), 0); diff --git a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp index e41d7a1314..6c07445cc5 100644 --- a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp @@ -13,10 +13,10 @@ #include // comment definition of NDEBUG to enable assert() -// #define NDEBUG +//#define NDEBUG #include -//#define SLA_CELL_2_POLYGON_DEBUG +//#define SLA_SVG_VISUALIZATION_CELL_2_POLYGON using namespace Slic3r::sla; @@ -38,7 +38,7 @@ Slic3r::Point VoronoiGraphUtils::to_point(const VD::vertex_type *vertex) Slic3r::Vec2d VoronoiGraphUtils::to_point_d(const VD::vertex_type *vertex) { - return Vec2d(to_coord(vertex->x()), to_coord(vertex->y())); + return Vec2d(vertex->x(), vertex->y()); } bool VoronoiGraphUtils::is_coord_in_limits(const VD::coordinate_type &coord, @@ -78,13 +78,6 @@ Slic3r::Line VoronoiGraphUtils::create_line_between_source_points( return Line(middle - side_dir, middle + side_dir); } -bool is_oposit_direction(const Slic3r::Point &p1, const Slic3r::Point &p2) { - if (abs(p1.x()) > abs(p1.y())) { - return (p1.x() > 0) != (p2.x() > 0); - } - return (p1.y() > 0) != (p2.y() > 0); -} - std::optional VoronoiGraphUtils::to_line( const VD::edge_type &edge, const Points &points, double maximal_distance) { @@ -137,12 +130,22 @@ std::optional VoronoiGraphUtils::to_line( } std::optional segment; if (use_both) { - Linef edge_segment(Vec2d(v0->x(), v0->y()), Vec2d(v1->x(), v1->y())); + Linef edge_segment(to_point_d(v0), to_point_d(v1)); segment = LineUtils::crop_line(edge_segment, p1, maximal_distance); } else { - Vec2d ray_point(edge_vertex->x(), edge_vertex->y()); - Linef ray(ray_point, ray_point + direction.cast()); - segment = LineUtils::crop_half_ray(ray, p1, maximal_distance); + // Vertex can't be used as start point because data type limitation + // Explanation for shortening line is in Test::bad_vertex + Vec2d middle = (p1.cast() + p2.cast()) / 2.; + Vec2d vertex = to_point_d(edge_vertex); + Vec2d vertex_direction = (vertex - middle); + Vec2d vertex_dir_abs(fabs(vertex_direction.x()), fabs(vertex_direction.y())); + double divider = (vertex_dir_abs.x() > vertex_dir_abs.y()) ? + vertex_dir_abs.x() / maximal_distance : + vertex_dir_abs.y() / maximal_distance; + Vec2d vertex_dir_short = vertex_direction / divider; + Vec2d start_point = middle + vertex_dir_short; + Linef line_short(start_point, start_point + direction.cast()); + segment = LineUtils::crop_half_ray(line_short, p1, maximal_distance); } if (!segment.has_value()) return {}; return Line(segment->a.cast(), segment->b.cast()); @@ -218,32 +221,24 @@ Slic3r::Polygon VoronoiGraphUtils::to_polygon(const VD::cell_type & cell, const VD::edge_type *edge = cell.incident_edge(); do { assert(edge->is_linear()); - if (!edge->is_primary()) { - edge = edge->next(); - continue; - } + if (!edge->is_primary()) continue; std::optional line = to_line(*edge, points, maximal_distance); - if (!line.has_value()) { - edge = edge->next(); - continue; - } + if (!line.has_value()) continue; Geometry::Orientation orientation = Geometry::orient(center, line->a, line->b); - if (orientation == Geometry::Orientation::ORIENTATION_COLINEAR) - { // on circle over source point edge - edge = edge->next(); + // Can be rich on circle over source point edge + if (orientation == Geometry::Orientation::ORIENTATION_COLINEAR) continue; - } if (orientation == Geometry::Orientation::ORIENTATION_CW) std::swap(line->a, line->b); lines.push_back(line.value()); - edge = edge->next(); - } while (edge != cell.incident_edge()); + } while ((edge = edge->next()) && edge != cell.incident_edge()); + assert(!lines.empty()); LineUtils::sort_CCW(lines, center); // preccission to decide when not connect neighbor points double min_distance = maximal_distance / 1000.; size_t count_point = 6; // count added points Slic3r::Polygon polygon = to_polygon(lines, center, maximal_distance, min_distance, count_point); -#ifdef SLA_CELL_2_POLYGON_DEBUG +#ifdef SLA_SVG_VISUALIZATION_CELL_2_POLYGON { std::cout << "cell " << cell.source_index() << " has " << lines.size() << "edges" << std::endl; BoundingBox bbox(center - Point(maximal_distance, maximal_distance), @@ -261,7 +256,7 @@ Slic3r::Polygon VoronoiGraphUtils::to_polygon(const VD::cell_type & cell, } svg.draw(center, "red", maximal_distance / 100); } -#endif /* SLA_CELL_2_POLYGON_DEBUG */ +#endif /* SLA_SVG_VISUALIZATION_CELL_2_POLYGON */ return polygon; } diff --git a/tests/libslic3r/test_voronoi.cpp b/tests/libslic3r/test_voronoi.cpp index ce87071997..081744b098 100644 --- a/tests/libslic3r/test_voronoi.cpp +++ b/tests/libslic3r/test_voronoi.cpp @@ -2284,3 +2284,79 @@ TEST_CASE("Voronoi cell doesn't contain a source point - SPE-2298", "[VoronoiCel REQUIRE(vd.is_valid()); } // */ + +//#include +TEST_CASE("bad vertex cause overflow of data type precisin when use VD result", "[VoronoiDiagram]") +{ + // Points are almost in line + Points points = { + {-106641371, 61644934}, + {-56376476, 32588892}, + {0, 0} + }; + + //auto perp_distance = sla::LineUtils::perp_distance; + auto perp_distance = [](const Linef &line, Vec2d p) { + Vec2d v = line.b - line.a; // direction + Vec2d va = p - line.a; + return std::abs(cross2(v, va)) / v.norm(); + }; + + using VD = Slic3r::Geometry::VoronoiDiagram; + VD vd; + construct_voronoi(points.begin(), points.end(), &vd); + + // edge between source index 0 and 1 has bad vertex + size_t bad_index0 = 0; + size_t bad_index1 = 1; + for (auto &edge : vd.edges()) { + size_t i1 = edge.cell()->source_index(); + size_t i2 = edge.twin()->cell()->source_index(); + if (i1 == bad_index0 && i2 == bad_index1 || + i1 == bad_index1 && i2 == bad_index0) { + Vec2d p1 = points[bad_index0].cast(); + Vec2d p2 = points[bad_index1].cast(); + Vec2d middle = (p1 + p2) / 2; + // direction for edge is perpendicular point connection + Vec2d direction(p2.y() - p1.y(), p1.x() - p2.x()); + const VD::vertex_type *vrtx = (edge.vertex0() == nullptr) ? + edge.vertex1() : + edge.vertex0(); + if (vrtx == nullptr) continue; + Vec2d vertex(vrtx->x(), vrtx->y()); + + double point_distance = (p1 - p2).norm(); + double half_point_distance = point_distance/2; + + Linef line_from_middle(middle, middle + direction); // line between source points + double distance_vertex = perp_distance(line_from_middle, vertex); + double distance_p1 = perp_distance(line_from_middle, p1); + double distance_p2 = perp_distance(line_from_middle, p2); + + Linef line_from_vertex(vertex, vertex + direction); + double distance_middle = perp_distance(line_from_vertex, middle); + double distance_p1_ = perp_distance(line_from_vertex, p1); + double distance_p2_ = perp_distance(line_from_vertex, p2); + + double maximal_distance = 9e6; + Vec2d vertex_direction = (vertex - middle); + Vec2d vertex_dir_abs(fabs(vertex_direction.x()), + fabs(vertex_direction.y())); + double divider = (vertex_dir_abs.x() > vertex_dir_abs.y()) ? + vertex_dir_abs.x() / maximal_distance : + vertex_dir_abs.y() / maximal_distance; + Vec2d vertex_dir_short = vertex_direction / divider; + Vec2d start_point = middle + vertex_dir_short; + Linef line_short(start_point, start_point + direction); + double distance_short_vertex = perp_distance(line_short, vertex); + double distance_short_middle = perp_distance(line_short, middle); + double distance_p1_short = perp_distance(line_short, p1); + double distance_p2_short = perp_distance(line_short, p2); + + CHECK(distance_vertex < 10); + //CHECK(distance_middle < 10); // This is bad + CHECK(distance_short_vertex < 10); + CHECK(distance_short_middle < 10); + } + } +} diff --git a/tests/sla_print/sla_supptgen_tests.cpp b/tests/sla_print/sla_supptgen_tests.cpp index 1ba5209338..3a6d15aee7 100644 --- a/tests/sla_print/sla_supptgen_tests.cpp +++ b/tests/sla_print/sla_supptgen_tests.cpp @@ -331,8 +331,8 @@ SupportIslandPoints test_island_sampling(const ExPolygon & island, const Point &chck_point = chck_points[index]; double &min_distance = point_distances[index]; bool exist_close_support_point = false; - for (auto &island_point : points) { - Point& p = island_point.point; + for (const auto &island_point : points) { + const Point& p = island_point->point; Point abs_diff(fabs(p.x() - chck_point.x()), fabs(p.y() - chck_point.y())); if (abs_diff.x() < min_distance && abs_diff.y() < min_distance) { @@ -354,7 +354,7 @@ SupportIslandPoints test_island_sampling(const ExPolygon & island, SVG svg("Error" + std::to_string(++counter) + ".svg", bb); svg.draw(island, "blue", 0.5f); for (auto& p : points) - svg.draw(p.point, "lightgreen", config.head_radius); + svg.draw(p->point, "lightgreen", config.head_radius); for (size_t index = 0; index < chck_points.size(); ++index) { const Point &chck_point = chck_points[index]; double distance = point_distances[index]; @@ -367,7 +367,7 @@ SupportIslandPoints test_island_sampling(const ExPolygon & island, //CHECK(is_ok); // all points must be inside of island - for (const auto &point : points) { CHECK(island.contains(point.point)); } + for (const auto &point : points) { CHECK(island.contains(point->point)); } return points; } @@ -428,10 +428,10 @@ TEST_CASE("Speed align", "[VoronoiSkeleton]") Slic3r::Voronoi::annotate_inside_outside(vd, lines); VoronoiGraph::ExPath longest_path; VoronoiGraph skeleton = VoronoiGraphUtils::create_skeleton(vd, lines); - auto samples = SampleIslandUtils::sample_voronoi_graph(skeleton, cfg, longest_path); - for (int i = 0; i < 100; ++i) { auto sample_copy = samples; // copy - SampleIslandUtils::align_samples(sample_copy, island, cfg); + for (int i = 0; i < 100; ++i) { + auto samples = SampleIslandUtils::sample_voronoi_graph(skeleton, cfg, longest_path); + SampleIslandUtils::align_samples(samples, island, cfg); } } diff --git a/tests/sla_print/sla_voronoi_graph_tests.cpp b/tests/sla_print/sla_voronoi_graph_tests.cpp index ff7a4bc24d..4f0440b4e1 100644 --- a/tests/sla_print/sla_voronoi_graph_tests.cpp +++ b/tests/sla_print/sla_voronoi_graph_tests.cpp @@ -47,7 +47,7 @@ void check(Slic3r::Points points, double max_distance) { TEST_CASE("Polygon from cell", "[Voronoi]") { - // for debug #define SLA_CELL_2_POLYGON_DEBUG in VoronoiGraphUtils + // for debug #define SLA_SVG_VISUALIZATION_CELL_2_POLYGON in VoronoiGraphUtils double max_distance = 1e7; coord_t size = (int) (4e6); coord_t half_size = size/2;