diff --git a/src/libslic3r/Arachne/utils/VoronoiUtils.cpp b/src/libslic3r/Arachne/utils/VoronoiUtils.cpp index 033657e5a8..f06c15da64 100644 --- a/src/libslic3r/Arachne/utils/VoronoiUtils.cpp +++ b/src/libslic3r/Arachne/utils/VoronoiUtils.cpp @@ -7,6 +7,7 @@ #include "linearAlg2D.hpp" #include "VoronoiUtils.hpp" +#include "libslic3r/Geometry/VoronoiUtils.hpp" namespace Slic3r::Arachne { @@ -85,164 +86,95 @@ const VoronoiUtils::Segment &VoronoiUtils::getSourceSegment(const vd_t::cell_typ return segments[cell.source_index()]; } -class PointMatrix -{ -public: - double matrix[4]; - - PointMatrix() - { - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 1; - } - - PointMatrix(double rotation) - { - rotation = rotation / 180 * M_PI; - matrix[0] = cos(rotation); - matrix[1] = -sin(rotation); - matrix[2] = -matrix[1]; - matrix[3] = matrix[0]; - } - - PointMatrix(const Point p) - { - matrix[0] = p.x(); - matrix[1] = p.y(); - double f = sqrt((matrix[0] * matrix[0]) + (matrix[1] * matrix[1])); - matrix[0] /= f; - matrix[1] /= f; - matrix[2] = -matrix[1]; - matrix[3] = matrix[0]; - } - - static PointMatrix scale(double s) - { - PointMatrix ret; - ret.matrix[0] = s; - ret.matrix[3] = s; - return ret; - } - - Point apply(const Point p) const - { - return Point(coord_t(p.x() * matrix[0] + p.y() * matrix[1]), coord_t(p.x() * matrix[2] + p.y() * matrix[3])); - } - - Point unapply(const Point p) const - { - return Point(coord_t(p.x() * matrix[0] + p.y() * matrix[2]), coord_t(p.x() * matrix[1] + p.y() * matrix[3])); - } -}; -Points VoronoiUtils::discretizeParabola(const Point& p, const Segment& segment, Point s, Point e, coord_t approximate_step_size, float transitioning_angle) +Points VoronoiUtils::discretizeParabola(const Point &source_point, const Segment &source_segment, const Point &start, const Point &end, const coord_t approximate_step_size, float transitioning_angle) { Points discretized; // x is distance of point projected on the segment ab // xx is point projected on the segment ab - const Point a = segment.from(); - const Point b = segment.to(); - const Point ab = b - a; - const Point as = s - a; - const Point ae = e - a; + const Point a = source_segment.from(); + const Point b = source_segment.to(); + const Point ab = b - a; + const Point as = start - a; + const Point ae = end - a; const coord_t ab_size = ab.cast().norm(); - const coord_t sx = as.cast().dot(ab.cast()) / ab_size; - const coord_t ex = ae.cast().dot(ab.cast()) / ab_size; - const coord_t sxex = ex - sx; + const coord_t sx = as.cast().dot(ab.cast()) / ab_size; + const coord_t ex = ae.cast().dot(ab.cast()) / ab_size; + const coord_t sxex = ex - sx; - assert((as.cast().dot(ab.cast()) / int64_t(ab_size)) <= std::numeric_limits::max()); - assert((ae.cast().dot(ab.cast()) / int64_t(ab_size)) <= std::numeric_limits::max()); - - const Point ap = p - a; + const Point ap = source_point - a; const coord_t px = ap.cast().dot(ab.cast()) / ab_size; - assert((ap.cast().dot(ab.cast()) / int64_t(ab_size)) <= std::numeric_limits::max()); - Point pxx; - Line(a, b).distance_to_infinite_squared(p, &pxx); - const Point ppxx = pxx - p; - const coord_t d = ppxx.cast().norm(); - const PointMatrix rot = PointMatrix(perp(ppxx)); + Line(a, b).distance_to_infinite_squared(source_point, &pxx); + const Point ppxx = pxx - source_point; + const coord_t d = ppxx.cast().norm(); - if (d == 0) - { - discretized.emplace_back(s); - discretized.emplace_back(e); + const Vec2d rot = perp(ppxx).cast().normalized(); + const double rot_cos_theta = rot.x(); + const double rot_sin_theta = rot.y(); + + if (d == 0) { + discretized.emplace_back(start); + discretized.emplace_back(end); return discretized; } - - const float marking_bound = atan(transitioning_angle * 0.5); - int64_t msx = - marking_bound * int64_t(d); // projected marking_start - int64_t mex = marking_bound * int64_t(d); // projected marking_end - assert(msx <= std::numeric_limits::max()); - assert(double(msx) * double(msx) <= double(std::numeric_limits::max())); - assert(mex <= std::numeric_limits::max()); - assert(double(msx) * double(msx) / double(2 * d) + double(d / 2) <= std::numeric_limits::max()); + const double marking_bound = atan(transitioning_angle * 0.5); + int64_t msx = -marking_bound * int64_t(d); // projected marking_start + int64_t mex = marking_bound * int64_t(d); // projected marking_end const coord_t marking_start_end_h = msx * msx / (2 * d) + d / 2; - Point marking_start = rot.unapply(Point(coord_t(msx), marking_start_end_h)) + pxx; - Point marking_end = rot.unapply(Point(coord_t(mex), marking_start_end_h)) + pxx; - const int dir = (sx > ex) ? -1 : 1; - if (dir < 0) - { + Point marking_start = Point(coord_t(msx), marking_start_end_h).rotated(rot_cos_theta, rot_sin_theta) + pxx; + Point marking_end = Point(coord_t(mex), marking_start_end_h).rotated(rot_cos_theta, rot_sin_theta) + pxx; + const int dir = (sx > ex) ? -1 : 1; + if (dir < 0) { std::swap(marking_start, marking_end); std::swap(msx, mex); } - + bool add_marking_start = msx * int64_t(dir) > int64_t(sx - px) * int64_t(dir) && msx * int64_t(dir) < int64_t(ex - px) * int64_t(dir); - bool add_marking_end = mex * int64_t(dir) > int64_t(sx - px) * int64_t(dir) && mex * int64_t(dir) < int64_t(ex - px) * int64_t(dir); + bool add_marking_end = mex * int64_t(dir) > int64_t(sx - px) * int64_t(dir) && mex * int64_t(dir) < int64_t(ex - px) * int64_t(dir); - const Point apex = rot.unapply(Point(0, d / 2)) + pxx; - bool add_apex = int64_t(sx - px) * int64_t(dir) < 0 && int64_t(ex - px) * int64_t(dir) > 0; + const Point apex = Point(0, d / 2).rotated(rot_cos_theta, rot_sin_theta) + pxx; + bool add_apex = int64_t(sx - px) * int64_t(dir) < 0 && int64_t(ex - px) * int64_t(dir) > 0; - assert(!(add_marking_start && add_marking_end) || add_apex); - if(add_marking_start && add_marking_end && !add_apex) - { + assert(!add_marking_start || !add_marking_end || add_apex); + if (add_marking_start && add_marking_end && !add_apex) BOOST_LOG_TRIVIAL(warning) << "Failing to discretize parabola! Must add an apex or one of the endpoints."; - } - - const coord_t step_count = static_cast(static_cast(std::abs(ex - sx)) / approximate_step_size + 0.5); - - discretized.emplace_back(s); - for (coord_t step = 1; step < step_count; step++) - { - assert(double(sxex) * double(step) <= double(std::numeric_limits::max())); + + const coord_t step_count = lround(static_cast(std::abs(ex - sx)) / approximate_step_size); + discretized.emplace_back(start); + for (coord_t step = 1; step < step_count; ++step) { const int64_t x = int64_t(sx) + int64_t(sxex) * int64_t(step) / int64_t(step_count) - int64_t(px); - assert(double(x) * double(x) <= double(std::numeric_limits::max())); - assert(double(x) * double(x) / double(2 * d) + double(d / 2) <= double(std::numeric_limits::max())); const int64_t y = int64_t(x) * int64_t(x) / int64_t(2 * d) + int64_t(d / 2); - - if (add_marking_start && msx * int64_t(dir) < int64_t(x) * int64_t(dir)) - { + + if (add_marking_start && msx * int64_t(dir) < int64_t(x) * int64_t(dir)) { discretized.emplace_back(marking_start); add_marking_start = false; } - if (add_apex && int64_t(x) * int64_t(dir) > 0) - { + + if (add_apex && int64_t(x) * int64_t(dir) > 0) { discretized.emplace_back(apex); - add_apex = false; // only add the apex just before the + add_apex = false; // only add the apex just before the } - if (add_marking_end && mex * int64_t(dir) < int64_t(x) * int64_t(dir)) - { + + if (add_marking_end && mex * int64_t(dir) < int64_t(x) * int64_t(dir)) { discretized.emplace_back(marking_end); add_marking_end = false; } - assert(x <= std::numeric_limits::max() && x >= std::numeric_limits::lowest()); - assert(y <= std::numeric_limits::max() && y >= std::numeric_limits::lowest()); - const Point result = rot.unapply(Point(x, y)) + pxx; + + assert(Geometry::VoronoiUtils::is_in_range(x) && Geometry::VoronoiUtils::is_in_range(y)); + const Point result = Point(x, y).rotated(rot_cos_theta, rot_sin_theta) + pxx; discretized.emplace_back(result); } + if (add_apex) - { discretized.emplace_back(apex); - } + if (add_marking_end) - { discretized.emplace_back(marking_end); - } - discretized.emplace_back(e); + + discretized.emplace_back(end); return discretized; } diff --git a/src/libslic3r/Arachne/utils/VoronoiUtils.hpp b/src/libslic3r/Arachne/utils/VoronoiUtils.hpp index ea6a8495a1..6b6abeb041 100644 --- a/src/libslic3r/Arachne/utils/VoronoiUtils.hpp +++ b/src/libslic3r/Arachne/utils/VoronoiUtils.hpp @@ -34,7 +34,7 @@ public: * Discretize a parabola based on (approximate) step size. * The \p approximate_step_size is measured parallel to the \p source_segment, not along the parabola. */ - static Points discretizeParabola(const Point &source_point, const Segment &source_segment, Point start, Point end, coord_t approximate_step_size, float transitioning_angle); + static Points discretizeParabola(const Point &source_point, const Segment &source_segment, const Point& start, const Point &end, coord_t approximate_step_size, float transitioning_angle); static inline bool is_finite(const VoronoiUtils::vd_t::vertex_type &vertex) { diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index ce24457cd1..2cb2232864 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -214,6 +214,8 @@ set(SLIC3R_SOURCES Geometry/Voronoi.hpp Geometry/VoronoiOffset.cpp Geometry/VoronoiOffset.hpp + Geometry/VoronoiUtils.hpp + Geometry/VoronoiUtils.cpp Geometry/VoronoiVisualUtils.hpp Int128.hpp JumpPointSearch.cpp @@ -464,7 +466,6 @@ set(SLIC3R_SOURCES BranchingTree/BranchingTree.hpp BranchingTree/PointCloud.cpp BranchingTree/PointCloud.hpp - Arachne/BeadingStrategy/BeadingStrategy.hpp Arachne/BeadingStrategy/BeadingStrategy.cpp Arachne/BeadingStrategy/BeadingStrategyFactory.hpp diff --git a/src/libslic3r/Geometry/VoronoiUtils.cpp b/src/libslic3r/Geometry/VoronoiUtils.cpp new file mode 100644 index 0000000000..2b4846c627 --- /dev/null +++ b/src/libslic3r/Geometry/VoronoiUtils.cpp @@ -0,0 +1,10 @@ +#include "VoronoiUtils.hpp" + +namespace Slic3r::Geometry { + +bool VoronoiUtils::is_finite(const VD::vertex_type &vertex) +{ + return std::isfinite(vertex.x()) && std::isfinite(vertex.y()); +} + +} // namespace Slic3r::Geometry \ No newline at end of file diff --git a/src/libslic3r/Geometry/VoronoiUtils.hpp b/src/libslic3r/Geometry/VoronoiUtils.hpp new file mode 100644 index 0000000000..c0f821d2db --- /dev/null +++ b/src/libslic3r/Geometry/VoronoiUtils.hpp @@ -0,0 +1,36 @@ +#ifndef slic3r_VoronoiUtils_hpp_ +#define slic3r_VoronoiUtils_hpp_ + +#include "libslic3r/Geometry/Voronoi.hpp" + +using VD = Slic3r::Geometry::VoronoiDiagram; + +namespace Slic3r::Geometry { + +class VoronoiUtils +{ +public: + static bool is_finite(const VD::vertex_type &vertex); + + template static bool is_in_range(double value) + { + return double(std::numeric_limits::lowest()) <= value && value <= double(std::numeric_limits::max()); + } + + template static bool is_in_range(const VD::vertex_type &vertex) + { + return VoronoiUtils::is_finite(vertex) && is_in_range(vertex.x()) && is_in_range(vertex.y()); + } + + template static bool is_in_range(const VD::edge_type &edge) + { + if (edge.vertex0() == nullptr || edge.vertex1() == nullptr) + return false; + + return is_in_range(*edge.vertex0()) && is_in_range(*edge.vertex1()); + } +}; + +} // namespace Slic3r::Geometry + +#endif // slic3r_VoronoiUtils_hpp_