diff --git a/src/libslic3r/SLA/SupportIslands/LineUtils.cpp b/src/libslic3r/SLA/SupportIslands/LineUtils.cpp new file mode 100644 index 0000000000..31afc8c1a9 --- /dev/null +++ b/src/libslic3r/SLA/SupportIslands/LineUtils.cpp @@ -0,0 +1,20 @@ +#include "LineUtils.hpp" + +using namespace Slic3r::sla; + +// sort counter clock wise lines +void LineUtils::sort_CCW(Lines &lines, const Point& center) +{ + using namespace Slic3r; + std::sort(lines.begin(), lines.end(), [&](const Line &l1, const Line &l2) { + Point p1 = l1.a - center; + Point p2 = l2.a - center; + if (p1.y() < 0) { + if (p2.y() > 0) return false; + return p1.x() < p2.x(); + } else { + if (p2.y() < 0) return true; + return p1.x() > p2.x(); + } + }); +} diff --git a/src/libslic3r/SLA/SupportIslands/LineUtils.hpp b/src/libslic3r/SLA/SupportIslands/LineUtils.hpp new file mode 100644 index 0000000000..c904159356 --- /dev/null +++ b/src/libslic3r/SLA/SupportIslands/LineUtils.hpp @@ -0,0 +1,27 @@ +#ifndef slic3r_SLA_SuppotstIslands_LineUtils_hpp_ +#define slic3r_SLA_SuppotstIslands_LineUtils_hpp_ + +#include + +namespace Slic3r::sla { + +/// +/// Class which contain collection of static function +/// for work with Line and Lines. +/// QUESTION: Is it only for SLA? +/// +class LineUtils +{ +public: + LineUtils() = delete; + + /// + /// Sort lines to be in counter clock wise order + /// + /// Lines to sort + /// Center for order + static void sort_CCW(Lines &lines, const Point ¢er); +}; + +} // namespace Slic3r::sla +#endif // slic3r_SLA_SuppotstIslands_LineUtils_hpp_ diff --git a/src/libslic3r/SLA/SupportIslands/Parabola.hpp b/src/libslic3r/SLA/SupportIslands/Parabola.hpp index 7a7afd5cb3..d6b69a1d5f 100644 --- a/src/libslic3r/SLA/SupportIslands/Parabola.hpp +++ b/src/libslic3r/SLA/SupportIslands/Parabola.hpp @@ -21,5 +21,23 @@ struct Parabola {} }; + +/// +/// DTO store segment of parabola +/// Parabola with start(from) and end(to) point lay on parabola +/// +struct ParabolaSegment: public Parabola +{ + Point from; + Point to; + + ParabolaSegment(Parabola parabola, Point from, Point to) : + Parabola(std::move(parabola)), from(from), to(to) + {} + ParabolaSegment(Line directrix, Point focus, Point from, Point to) + : Parabola(directrix, focus), from(from), to(to) + {} +}; + } // namespace Slic3r::sla #endif // slic3r_SLA_SuppotstIslands_Parabola_hpp_ diff --git a/src/libslic3r/SLA/SupportIslands/ParabolaUtils.cpp b/src/libslic3r/SLA/SupportIslands/ParabolaUtils.cpp index c40d426c76..f8d4c24629 100644 --- a/src/libslic3r/SLA/SupportIslands/ParabolaUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/ParabolaUtils.cpp @@ -2,16 +2,15 @@ using namespace Slic3r::sla; -double ParabolaUtils::calculate_length_of_parabola( - const Parabola ¶bola, const Point &from, const Point &to) +double ParabolaUtils::length(const ParabolaSegment ¶bola) { const Point &point = parabola.focus; const Line & line = parabola.directrix; Line norm_line(point, point + line.normal()); // sign of distance is resolved by dot product in function is_over_zero() - double scaled_x1 = norm_line.perp_distance_to(from); - double scaled_x2 = norm_line.perp_distance_to(to); + double scaled_x1 = norm_line.perp_distance_to(parabola.from); + double scaled_x2 = norm_line.perp_distance_to(parabola.to); double parabola_scale = 1. / (4. * focal_length(parabola)); @@ -21,23 +20,21 @@ double ParabolaUtils::calculate_length_of_parabola( double length_x1 = parabola_arc_length(x1) / parabola_scale; double length_x2 = parabola_arc_length(x2) / parabola_scale; - return (is_over_zero(parabola, from, to)) ? + return (is_over_zero(parabola)) ? (length_x1 + length_x2) : // interval is over zero fabs(length_x1 - length_x2); // interval is on same side of parabola } - #include #include #include -double ParabolaUtils::calculate_length_of_parabola_by_sampling( - const Parabola ¶bola, - const Point & from, - const Point & to, +double ParabolaUtils::length_by_sampling( + const ParabolaSegment ¶bola, double discretization_step) { using VD = Slic3r::Geometry::VoronoiDiagram; - std::vector parabola_samples({from, to}); + std::vector parabola_samples( + {parabola.from, parabola.to}); VD::point_type source_point = parabola.focus; VD::segment_type source_segment(parabola.directrix.a, parabola.directrix.b); @@ -65,12 +62,19 @@ double ParabolaUtils::focal_length(const Parabola ¶bola) return f; } -bool ParabolaUtils::is_over_zero(const Parabola ¶bola, - const Point & from, - const Point & to) +bool ParabolaUtils::is_over_zero(const ParabolaSegment ¶bola) { Point line_direction = parabola.directrix.b - parabola.directrix.a; - bool is_positive_x1 = line_direction.dot(parabola.focus - from) > 0.; - bool is_positive_x2 = line_direction.dot(parabola.focus - to) > 0.; + Point focus_from = parabola.focus - parabola.from; + Point focus_to = parabola.focus - parabola.to; + bool is_positive_x1 = line_direction.dot(focus_from) > 0.; + bool is_positive_x2 = line_direction.dot(focus_to) > 0.; return is_positive_x1 != is_positive_x2; } + +// PRIVATE +double ParabolaUtils::parabola_arc_length(double x) +{ + double sqrtRes = sqrt(1 + 4 * x * x); + return 1 / 4. * log(2 * x + sqrtRes) + 1 / 2. * x * sqrtRes; +}; diff --git a/src/libslic3r/SLA/SupportIslands/ParabolaUtils.hpp b/src/libslic3r/SLA/SupportIslands/ParabolaUtils.hpp index f0c41397ef..a0912fff8a 100644 --- a/src/libslic3r/SLA/SupportIslands/ParabolaUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/ParabolaUtils.hpp @@ -17,27 +17,18 @@ public: /// /// Integrate length over interval defined by points from and to /// - /// Input parabola - /// Input point lay on parabola - /// Input point lay on parabola + /// Input segment of parabola /// Length of parabola arc - static double calculate_length_of_parabola(const Parabola ¶bola, - const Point & from, - const Point & to); + static double length(const ParabolaSegment ¶bola); /// /// Sample parabola between points from and to by step. /// - /// Input parabola - /// Input point lay on parabola - /// Input point lay on parabola + /// Input segment of parabola /// Define sampling /// Length of parabola arc - static double calculate_length_of_parabola_by_sampling( - const Parabola ¶bola, - const Point & from, - const Point & to, - double discretization_step = 0.0002 * 1e6); + static double length_by_sampling(const ParabolaSegment ¶bola, + double discretization_step = 200); /// /// calculate focal length of parabola @@ -49,13 +40,9 @@ public: /// /// Check if parabola interval (from, to) contains top of parabola /// - /// input parabola - /// Start of interval, point lay on parabola - /// End of interval, point lay on parabola + /// Input segment of parabola /// True when interval contain top of parabola otherwise False - static bool is_over_zero(const Parabola ¶bola, - const Point & from, - const Point & to); + static bool is_over_zero(const ParabolaSegment ¶bola); private: /// @@ -64,10 +51,7 @@ private: /// /// x coordinate of parabola, Positive number /// Length of parabola from zero to x - static double parabola_arc_length(double x) { - double sqrtRes = sqrt(1 + 4 * x * x); - return 1 / 4. * log(2 * x + sqrtRes) + 1 / 2. * x * sqrtRes; - }; + static double parabola_arc_length(double x); }; } // namespace Slic3r::sla diff --git a/src/libslic3r/SLA/SupportIslands/PointUtils.cpp b/src/libslic3r/SLA/SupportIslands/PointUtils.cpp new file mode 100644 index 0000000000..3876b1d063 --- /dev/null +++ b/src/libslic3r/SLA/SupportIslands/PointUtils.cpp @@ -0,0 +1,13 @@ +#include "PointUtils.hpp" + +using namespace Slic3r::sla; + +bool PointUtils::is_ccw(const Point &p1, const Point &p2, const Point ¢er) +{ + Slic3r::Point v1 = p1 - center; + Slic3r::Point v2 = p2 - center; + + double cross_product = v1.x() * (double) v2.y() - + v2.x() * (double) v1.y(); + return cross_product > 0; +} diff --git a/src/libslic3r/SLA/SupportIslands/PointUtils.hpp b/src/libslic3r/SLA/SupportIslands/PointUtils.hpp new file mode 100644 index 0000000000..5e7099cfed --- /dev/null +++ b/src/libslic3r/SLA/SupportIslands/PointUtils.hpp @@ -0,0 +1,23 @@ +#ifndef slic3r_SLA_SuppotstIslands_PointUtils_hpp_ +#define slic3r_SLA_SuppotstIslands_PointUtils_hpp_ + +#include + +namespace Slic3r::sla { + +/// +/// Class which contain collection of static function +/// for work with Point and Points. +/// QUESTION: Is it only for SLA? +/// +class PointUtils +{ +public: + PointUtils() = delete; + + // is point p1 to p2 in counter clock wise order against center? + static bool is_ccw(const Point &p1, const Point &p2, const Point ¢er); +}; + +} // namespace Slic3r::sla +#endif // slic3r_SLA_SuppotstIslands_PointUtils_hpp_ diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp index 1516c4f450..bec03040c7 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.cpp @@ -49,7 +49,9 @@ SupportIslandPoint SampleIslandUtils::create_point_on_path( // distance must be inside path // this means bad input params assert(false); - return Point(0, 0); + return SupportIslandPoint(Point(0, 0), + SupportIslandPoint::Type::undefined, + VoronoiGraph::Position(nullptr,0.)); } SupportIslandPoint SampleIslandUtils::create_middle_path_point( @@ -174,6 +176,31 @@ std::vector> create_circles_sets( return result; } +Slic3r::Points SampleIslandUtils::to_points(const SupportIslandPoints &support_points) +{ + Slic3r::Points points; + points.reserve(support_points.size()); + std::transform(support_points.begin(), support_points.end(), + std::back_inserter(points), + [](const SupportIslandPoint &p) { + return p.point; }); + return points; +} + +void SampleIslandUtils::align_samples(SupportIslandPoints &samples, double max_distance) +{ + using VD = Slic3r::Geometry::VoronoiDiagram; + VD vd; + Slic3r::Points points = SampleIslandUtils::to_points(samples); + construct_voronoi(points.begin(), points.end(), &vd); + for (const VD::cell_type &cell : vd.cells()) { + SupportIslandPoint& sample = samples[cell.source_index()]; + Polygon polygon = VoronoiGraphUtils::to_polygon(cell, points, max_distance); + + } + // create voronoi diagram with points +} + SupportIslandPoints SampleIslandUtils::sample_center_line( const VoronoiGraph::ExPath &path, const CenterLineConfiguration &cfg) { @@ -187,6 +214,8 @@ SupportIslandPoints SampleIslandUtils::sample_center_line( if (path.circles.empty()) return result; sample_center_circles(path, cfg, result); + + align_samples(result, cfg.max_sample_distance); return result; } diff --git a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp index fc31f9295d..da59c215b4 100644 --- a/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/SampleIslandUtils.hpp @@ -129,6 +129,15 @@ public: const SampleConfig & config, VoronoiGraph::ExPath &longest_path); + static Slic3r::Points to_points(const SupportIslandPoints &support_points); + + /// + /// keep same distances between support points + /// + /// In/Out vector of support points + /// Maximal distance between neighbor points + static void align_samples(SupportIslandPoints &samples, double max_distance); + static void draw(SVG & svg, const SupportIslandPoints &supportIslandPoints, double size, diff --git a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp index aee5d9bf5b..9789b4c46f 100644 --- a/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp +++ b/src/libslic3r/SLA/SupportIslands/SupportIslandPoint.hpp @@ -30,14 +30,10 @@ struct SupportIslandPoint Type type; SupportIslandPoint(Slic3r::Point point, - Type type = Type::undefined, - VoronoiGraph::Position position = {}) + Type type, + VoronoiGraph::Position position) : point(std::move(point)), type(type), position(position) - { - if (position.neighbor == nullptr) { - int i = 5; - } - } + {} }; using SupportIslandPoints = std::vector; diff --git a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp index 61117e846a..a1b2522844 100644 --- a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp +++ b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.cpp @@ -5,11 +5,193 @@ #include "IStackFunction.hpp" #include "EvaluateNeighbor.hpp" #include "ParabolaUtils.hpp" +#include "LineUtils.hpp" +#include "PointUtils.hpp" #include using namespace Slic3r::sla; +Slic3r::Line VoronoiGraphUtils::to_line(const VD::edge_type &edge) { + assert(edge.is_linear()); + assert(edge.is_finite()); + return Line(Point(edge.vertex0()->x(), edge.vertex0()->y()), + Point(edge.vertex1()->x(), edge.vertex1()->y())); +} + +// create line segment between (in the middle) points. With size depend on their distance +Slic3r::Line VoronoiGraphUtils::to_line(Point point1, + Point point2, + double maximal_distance) +{ + Point middle = (point1 + point2) / 2; + Point diff = point1 - point2; + double distance_2 = diff.x() * static_cast(diff.x()) + + diff.y() * static_cast(diff.y()); + double half_distance = sqrt(distance_2) / 2.; + double half_distance_2 = distance_2 / 4; + double size = sqrt(maximal_distance * maximal_distance - half_distance_2); + // normalized direction to side multiplied by size/2 + double scale = size / half_distance / 2; + Point side_dir(-diff.y() * scale, diff.x() * scale); + 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); +} + +Slic3r::Line VoronoiGraphUtils::to_line(const VD::edge_type & edge, + const Points &points, + double maximal_distance) +{ + assert(edge.is_linear()); + assert(edge.is_primary()); + + if (edge.is_finite()) return to_line(edge); + + const VD::cell_type &cell1 = *edge.cell(); + const VD::cell_type &cell2 = *edge.twin()->cell(); + assert(cell1.contains_point()); + assert(cell2.contains_point()); + Point p1 = retrieve_point(points, cell1); + Point p2 = retrieve_point(points, cell2); + if (edge.vertex0() == nullptr && edge.vertex1() == nullptr) + return to_line(p1, p2, maximal_distance); + + bool is_v0_null = edge.vertex0() == nullptr; + if (is_v0_null) std::swap(p1, p2); + Point direction(p1.y() - p2.y(), p2.x() - p1.x()); + + auto get_koef = [&](const Point &v)->double { + /*/ + // faster but less preciss version + double abs_max_dir = (std::max)(fabs(direction.x()), + fabs(direction.y())); + return 2 * maximal_distance / abs_max_dir; + + //*/ + + // slower but more precisse version + double dir_size = direction.cast().operatorNorm(); + Point middle = (p1 + p2) / 2; + Point to_middle = middle - v; + double to_middle_size = to_middle.cast().operatorNorm(); + double from_middle_size = sqrt(maximal_distance * maximal_distance - + to_middle_size * to_middle_size); + if (is_oposit_direction(direction, to_middle)) to_middle_size *= -1; + return (from_middle_size + to_middle_size)/dir_size; + }; + + if (is_v0_null) { + Point v1(edge.vertex1()->x(), edge.vertex1()->y()); + Point a = v1 + direction * get_koef(v1); + return Line(a, v1); + } else { + Point v0(edge.vertex0()->x(), edge.vertex0()->y()); + Point b = v0 + direction * get_koef(v0); + return Line(v0, b); + } +} + +Slic3r::Polygon VoronoiGraphUtils::to_polygon(const Lines &lines, + const Point ¢er, + double maximal_distance, + double minimal_distance, + size_t count_points) +{ + assert(lines.size() >= 1); + assert(minimal_distance > 0.); + assert(maximal_distance > minimal_distance); + assert(count_points >= 3); + Points points; + points.reserve(lines.size()); + const Line *prev_line = &lines.back(); + double max_angle = 2 * M_PI / count_points; + for (const Line &line : lines) { + const Point &p1 = prev_line->b; + const Point &p2 = line.a; + prev_line = &line; + Point diff = p1-p2; + if (abs(diff.x()) < minimal_distance && + abs(diff.y()) < minimal_distance) { + Point avg = (p1 + p2) / 2; + points.push_back(avg); + continue; + } + Point v1 = p1 - center; + Point v2 = p2 - center; + double a1 = std::atan2(v1.y(), v1.x()); + double a2 = std::atan2(v2.y(), v2.x()); + + double diff_angle = a2 - a1; + if(diff_angle < 0.) diff_angle += 2 * M_PI; + if(diff_angle > 2 * M_PI) diff_angle -= 2 * M_PI; + + size_t count_segment = std::floor(fabs(diff_angle) / max_angle) + 1; + double increase_angle = diff_angle / count_segment; + points.push_back(p1); + for (size_t i = 1; i < count_segment; i++) { + double angle = a1 + i*increase_angle; + Point direction( + static_cast(cos(angle) * maximal_distance), + static_cast(sin(angle) * maximal_distance)); + points.push_back(center + direction); + } + points.push_back(p2); + + } + return Polygon(points); +} + +Slic3r::Polygon VoronoiGraphUtils::to_polygon(const VD::cell_type & cell, + const Slic3r::Points &points, + double maximal_distance) +{ + const VD::edge_type *edge = cell.incident_edge(); + + Lines lines; + Point center = points[cell.source_index()]; + // Convenient way to iterate edges around Voronoi cell. + do { + assert(edge->is_linear()); + if (edge->is_primary()) { + Line line = to_line(*edge, points, maximal_distance); + if (!PointUtils::is_ccw(line.a, line.b, center)) std::swap(line.a, line.b); + lines.push_back(line); + } + edge = edge->next(); + } while (edge != cell.incident_edge()); + 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_SUPPORTPOINTGEN_DEBUG + { + std::cout << "cell " << cell.source_index() << " has " << lines.size() << "edges" << std::endl; + BoundingBox bbox(center - Point(maximal_distance, maximal_distance), + center + Point(maximal_distance, maximal_distance)); + static int counter = 0; + std::string filename = "polygon" + std::to_string(counter++) + ".svg"; + SVG svg(filename.c_str(), bbox); + svg.draw(center, "lightgreen", maximal_distance); + svg.draw(polygon, "lightblue"); + int index = 0; + for (auto &line : lines) { + svg.draw(line); + svg.draw_text(line.a, ("A"+std::to_string(++index)).c_str(), "green"); + svg.draw_text(line.b, ("B" + std::to_string(index)).c_str(), "blue"); + } + svg.draw(center, "red", maximal_distance / 100); + } +#endif /* SLA_SUPPORTPOINTGEN_DEBUG */ + return polygon; +} + VoronoiGraph::Node *VoronoiGraphUtils::getNode(VoronoiGraph & graph, const VD::vertex_type *vertex, const VD::edge_type * edge, @@ -39,16 +221,21 @@ VoronoiGraph::Node *VoronoiGraphUtils::getNode(VoronoiGraph & graph, Slic3r::Point VoronoiGraphUtils::retrieve_point(const Lines & lines, const VD::cell_type &cell) { - assert(cell.source_category() == - boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT || - cell.source_category() == - boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT); - return (cell.source_category() == - boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT) ? + using namespace boost::polygon; + assert(cell.source_category() == SOURCE_CATEGORY_SEGMENT_START_POINT || + cell.source_category() == SOURCE_CATEGORY_SEGMENT_END_POINT); + return (cell.source_category() == SOURCE_CATEGORY_SEGMENT_START_POINT) ? lines[cell.source_index()].a : lines[cell.source_index()].b; } +Slic3r::Point VoronoiGraphUtils::retrieve_point(const Points & points, + const VD::cell_type &cell) +{ + assert(cell.source_category() == boost::polygon::SOURCE_CATEGORY_SINGLE_POINT); + return points[cell.source_index()]; +} + Slic3r::Point VoronoiGraphUtils::get_parabola_point( const VD::edge_type ¶bola, const Slic3r::Lines &lines) { @@ -88,8 +275,8 @@ double VoronoiGraphUtils::calculate_length_of_parabola( { Point v0{edge.vertex0()->x(), edge.vertex0()->y()}; Point v1{edge.vertex1()->x(), edge.vertex1()->y()}; - Parabola parabola = get_parabola(edge, lines); - return ParabolaUtils::calculate_length_of_parabola(parabola, v0, v1); + ParabolaSegment parabola(get_parabola(edge, lines), v0, v1); + return ParabolaUtils::length(parabola); } double VoronoiGraphUtils::calculate_length( diff --git a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp index 1263678bd0..f7fb5818a8 100644 --- a/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp +++ b/src/libslic3r/SLA/SupportIslands/VoronoiGraphUtils.hpp @@ -26,6 +26,67 @@ class VoronoiGraphUtils public: VoronoiGraphUtils() = delete; + /// + /// Convert line edge segment to slicer line + /// only for line edge + /// only for finite line + /// + /// line edge + /// line + static Slic3r::Line to_line(const VD::edge_type &edge); + + /// + /// Private function to help convert edge without vertex to line + /// + /// VD Source point + /// VD Source point + /// Maximal distance from source point + /// Line segment between lines + static Slic3r::Line to_line(Point point1, + Point point2, + double maximal_distance); + /// + /// Convert edge to line + /// only for line edge + /// crop infinite edge by maximal distance from source point + /// inspiration in VoronoiVisualUtils::clip_infinite_edge + /// + /// + /// Source point for voronoi diagram + /// Maximal distance from source point + /// Croped line + static Slic3r::Line to_line(const VD::edge_type & edge, + const Points &points, + double maximal_distance); + /// + /// close polygon defined by lines + /// close points will convert to their center + /// Mainly for convert to polygon + /// + /// Border of polygon, sorted lines CCW + /// Center point of polygon + /// Radius around center point + /// Merge points closer than minimal_distance + /// Count checking points, create help points for result polygon + /// CCW polygon with center inside of polygon + static Slic3r::Polygon to_polygon(const Lines &lines, + const Point ¢er, + double maximal_distance, + double minimal_distance, + size_t count_points); + /// + /// Convert cell to polygon + /// Source for VD must be only point to create VD with only line segments + /// infinite cell are croped by maximal distance from source point + /// + /// cell from VD created only by points + /// source points for VD + /// maximal distance from source point - only for infinite edges(cells) + /// polygon created by cell + static Slic3r::Polygon to_polygon(const VD::cell_type & cell, + const Slic3r::Points &points, + double maximal_distance); + // return node from graph by vertex, when no exists create one static VoronoiGraph::Node *getNode(VoronoiGraph & graph, const VD::vertex_type *vertex, @@ -33,12 +94,26 @@ public: const Lines & lines); /// - /// extract parabola focus point from lines belongs to cell + /// Extract point from lines, belongs to cell + /// ! Source for VD must be only lines + /// Main purpose parabola focus point from lines belongs to cell + /// inspiration in VoronoiVisualUtils::retrieve_point /// - /// source of Voronoi diagram - /// cell inside of Voronoi diagram - /// Point from lines which create parabola. + /// Source of Voronoi diagram + /// Cell inside of Voronoi diagram + /// Point from source lines. static Point retrieve_point(const Lines &lines, const VD::cell_type &cell); + + /// + /// Extract point from lines + /// ! Source for VD must be only points + /// inspiration in VoronoiVisualUtils::retrieve_point + /// + /// Source of Voronoi diagram + /// Cell inside of Voronoi diagram + /// Point from source points. + static Point retrieve_point(const Points &points, const VD::cell_type &cell); + static Slic3r::Point get_parabola_point(const VD::edge_type ¶bola, const Slic3r::Lines &lines); static Slic3r::Line get_parabola_line(const VD::edge_type ¶bola, const Lines &lines); static Parabola get_parabola(const VD::edge_type &edge, const Lines &lines); diff --git a/tests/sla_print/CMakeLists.txt b/tests/sla_print/CMakeLists.txt index 655a2928c3..8ab44e5407 100644 --- a/tests/sla_print/CMakeLists.txt +++ b/tests/sla_print/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests_main.cpp sla_supptgen_tests.cpp sla_raycast_tests.cpp sla_parabola_tests.cpp + sla_voronoi_graph_tests.cpp sla_supptreeutils_tests.cpp sla_archive_readwrite_tests.cpp sla_zcorrection_tests.cpp) diff --git a/tests/sla_print/sla_parabola_tests.cpp b/tests/sla_print/sla_parabola_tests.cpp index 6774ae786d..f3ab2ca267 100644 --- a/tests/sla_print/sla_parabola_tests.cpp +++ b/tests/sla_print/sla_parabola_tests.cpp @@ -5,19 +5,14 @@ using namespace Slic3r; using namespace Slic3r::sla; -void parabola_check(const Parabola ¶bola, - const Point & from, - const Point & to) +void parabola_check_length(const ParabolaSegment ¶bola) { - auto diffPoint = to - from; + auto diffPoint = parabola.to - parabola.from; double min = sqrt(diffPoint.x() * diffPoint.x() + diffPoint.y() * diffPoint.y()); double max = static_cast(diffPoint.x()) + diffPoint.y(); - - double len = ParabolaUtils::calculate_length_of_parabola(parabola, from, to); - double len2 = ParabolaUtils::calculate_length_of_parabola_by_sampling( - parabola, from, to, 1.); - + double len = ParabolaUtils::length(parabola); + double len2 = ParabolaUtils::length_by_sampling(parabola, 1.); CHECK(fabs(len2 - len) < 1.); CHECK(len >= min); CHECK(len <= max); @@ -48,7 +43,8 @@ TEST_CASE("Parabola length", "[SupGen][Voronoi][Parabola]") double to_x = 3 * scale; Point from(from_x, getParabolaY(parabola_x2, from_x)); Point to(to_x, getParabolaY(parabola_x2, to_x)); - parabola_check(parabola_x2, from, to); + ParabolaSegment parabola_segment(parabola_x2, from, to); + parabola_check_length(parabola_segment); } diff --git a/tests/sla_print/sla_voronoi_graph_tests.cpp b/tests/sla_print/sla_voronoi_graph_tests.cpp new file mode 100644 index 0000000000..2d6692de8a --- /dev/null +++ b/tests/sla_print/sla_voronoi_graph_tests.cpp @@ -0,0 +1,46 @@ +#include "sla_test_utils.hpp" + +#include + +using namespace Slic3r; +using namespace Slic3r::sla; + +void check(Slic3r::Points points, double max_distance) { + using VD = Slic3r::Geometry::VoronoiDiagram; + VD vd; + construct_voronoi(points.begin(), points.end(), &vd); + double max_area = 3.15 * 4 * max_distance*max_distance; // circle + for (const VD::cell_type &cell : vd.cells()) { + Slic3r::Polygon polygon = VoronoiGraphUtils::to_polygon(cell, points, max_distance); + CHECK(polygon.area() < max_area); + } +} + +TEST_CASE("Polygon from cell", "[Voronoi]") +{ + double max_distance = 1e7; + coord_t size = (int) (4e6); + coord_t half_size = size/2; + + Slic3r::Points two_cols({Point(0, 0), Point(size, 0)}); + check(two_cols, max_distance); + + Slic3r::Points two_rows({Point(0, 0), Point(0, size)}); + check(two_rows, max_distance); + + Slic3r::Points two_diag({Point(0, 0), Point(size, size)}); + check(two_diag, max_distance); + + Slic3r::Points three({Point(0, 0), Point(size, 0), Point(half_size, size)}); + check(three, max_distance); + + Slic3r::Points middle_point({Point(0, 0), Point(size, half_size), + Point(-size, half_size), Point(0, -size)}); + check(middle_point, max_distance); + + Slic3r::Points middle_point2({Point(half_size, half_size), Point(-size, -size), Point(-size, size), + Point(size, -size), Point(size, size)}); + check(middle_point2, max_distance); +} + +