From e99cc427492f626f3301c7ae2efc66556aeb3ad5 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 14 Feb 2024 10:14:11 +0100 Subject: [PATCH 001/135] (WIP) Partially reworked Polygon/Polygons classes --- include/utils/ShapeType.h | 19 + include/utils/polygon.h | 1697 +++++++++------------------------ include/utils/polygons.h | 553 +++++++++++ src/utils/polygon.cpp | 1859 +++++++++---------------------------- src/utils/polygons.cpp | 1258 +++++++++++++++++++++++++ 5 files changed, 2696 insertions(+), 2690 deletions(-) create mode 100644 include/utils/ShapeType.h create mode 100644 include/utils/polygons.h create mode 100644 src/utils/polygons.cpp diff --git a/include/utils/ShapeType.h b/include/utils/ShapeType.h new file mode 100644 index 0000000000..99456c1691 --- /dev/null +++ b/include/utils/ShapeType.h @@ -0,0 +1,19 @@ +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef UTILS_SHAPE_TYPE_H +#define UTILS_SHAPE_TYPE_H + +namespace cura +{ + +enum class ShapeType +{ + Open, + Closed, + Filled +}; + +} // namespace cura + +#endif // UTILS_SHAPE_TYPE_H diff --git a/include/utils/polygon.h b/include/utils/polygon.h index 86f9a7aa22..01bed2a687 100644 --- a/include/utils/polygon.h +++ b/include/utils/polygon.h @@ -4,20 +4,20 @@ #ifndef UTILS_POLYGON_H #define UTILS_POLYGON_H -#include -#include // std::reverse, fill_n array #include -#include // fabs -#include -#include // int64_t.min +#include +#include #include +#include #include -#include #include -#include "../settings/types/Angle.h" //For angles between vertices. +#include "../settings/types/Angle.h" #include "../settings/types/Ratio.h" #include "Point2LL.h" +#include "utils/ListPolyIt.h" +#include "utils/ShapeType.h" +#include "utils/linearAlg2D.h" #define CHECK_POLY_ACCESS #ifdef CHECK_POLY_ACCESS @@ -32,6 +32,10 @@ namespace cura { +using point_t = ClipperLib::IntPoint; +using path_t = ClipperLib::Path; +using paths_t = ClipperLib::Paths; + template bool shorterThan(const T& shape, const coord_t check_length) { @@ -51,109 +55,181 @@ bool shorterThan(const T& shape, const coord_t check_length) class PartsView; class Polygons; -class Polygon; -class PolygonRef; - +class OpenPolyline; class ListPolyIt; -typedef std::list ListPolygon; //!< A polygon represented by a linked list instead of a vector -typedef std::vector ListPolygons; //!< Polygons represented by a vector of linked lists instead of a vector of vectors - const static int clipper_init = (0); #define NO_INDEX (std::numeric_limits::max()) -class ConstPolygonPointer; - -/*! - * Outer polygons should be counter-clockwise, - * inner hole polygons should be clockwise. - * (When negative X is to the left and negative Y is downward.) - */ -class ConstPolygonRef +class PointsSet : public std::vector { - friend class Polygons; - friend class Polygon; - friend class PolygonRef; - friend class ConstPolygonPointer; - -protected: - ClipperLib::Path* path; - public: - ConstPolygonRef(const ClipperLib::Path& polygon) - : path(const_cast(&polygon)) + PointsSet() = default; + + PointsSet(const std::initializer_list& initializer) + : std::vector(initializer) { } - ConstPolygonRef() = delete; // you cannot have a reference without an object! + PointsSet(const std::vector& points) + : std::vector(points) + { + } - virtual ~ConstPolygonRef() + PointsSet(std::vector&& points) + : std::vector(std::move(points)) { } - bool operator==(ConstPolygonRef& other) const = delete; // polygon comparison is expensive and probably not what you want when you use the equality operator + /*PointsSet& operator=(const PointsSet& other) + { + std::vector::operator=(other); + return *this; + }*/ + + Point2LL min() const; + + Point2LL max() const; - ConstPolygonRef& operator=(const ConstPolygonRef& other) = delete; // Cannot assign to a const object + Point2LL closestPointTo(Point2LL p) const; /*! - * Gets the number of vertices in this polygon. - * \return The number of vertices in this polygon. + * Translate the whole polygon in some direction. + * + * \param translation The direction in which to move the polygon */ - size_t size() const; + void translate(Point2LL translation) + { + for (Point2LL& p : *this) + { + p += translation; + } + } /*! - * Returns whether there are any vertices in this polygon. - * \return ``true`` if the polygon has no vertices at all, or ``false`` if - * it does have vertices. + * Apply a matrix to each vertex in this set */ - bool empty() const; + void applyMatrix(const PointMatrix& matrix); + void applyMatrix(const Point3Matrix& matrix); +}; + +// Transitory structure used to iterate over segments within a polygon/polyline +template +struct Segment +{ + using PointType = typename std::conditional::type; + + PointType& start; + PointType& end; +}; + +// Custom iterator to loop over the segments of an existing polygon/polyline +template +struct SegmentIterator +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = Segment; + using difference_type = std::ptrdiff_t; + using pointer = Segment*; + using reference = Segment&; + using source_iterator_type = typename std::conditional::const_iterator, typename std::vector::iterator>::type; + +private: + source_iterator_type current_pos_; + source_iterator_type begin_; + source_iterator_type before_end_; - const Point2LL& operator[](size_t index) const +public: + SegmentIterator(source_iterator_type pos, source_iterator_type begin, source_iterator_type end) + : current_pos_(pos) + , begin_(begin) + , before_end_(end != begin ? std::prev(end) : end) { - POLY_ASSERT(index < size()); - return (*path)[index]; } - const ClipperLib::Path& operator*() const + Segment operator*() const { - return *path; + if (current_pos_ == before_end_) + { + return Segment{ *current_pos_, *begin_ }; + } + else + { + return Segment{ *current_pos_, *std::next(current_pos_) }; + } } - ClipperLib::Path::const_iterator begin() const + SegmentIterator& operator++() { - return path->begin(); + current_pos_++; + return *this; } - ClipperLib::Path::const_iterator end() const + bool operator==(const SegmentIterator& other) const { - return path->end(); + return current_pos_ == other.current_pos_; } - ClipperLib::Path::const_reverse_iterator rbegin() const + bool operator!=(const SegmentIterator& other) const { - return path->rbegin(); + return ! (*this == other); } - ClipperLib::Path::const_reverse_iterator rend() const + friend difference_type operator-(const SegmentIterator& iterator1, const SegmentIterator& iterator2) { - return path->rend(); + return iterator1.current_pos_ - iterator2.current_pos_; } +}; + +template +class Polyline : public PointsSet +{ + friend class Polygons; + +public: + static constexpr ShapeType shape_type_ = ShapeTypeVal; + +public: + using segments_iterator = SegmentIterator; + using const_segments_iterator = SegmentIterator; - ClipperLib::Path::const_reference front() const + Polyline() = default; + + Polyline(const std::initializer_list& initializer) + : PointsSet(initializer) { - return path->front(); } - ClipperLib::Path::const_reference back() const + Polyline(const std::vector& points) + : PointsSet(points) { - return path->back(); } - const void* data() const + Polyline(std::vector&& points) + : PointsSet(points) { - return path->data(); } + /*Polyline& operator=(const Polyline& other) + { + std::vector::operator=(other); + return *this; + }*/ + + const_segments_iterator beginSegments() const; + + const_segments_iterator endSegments() const; + + segments_iterator beginSegments(); + + segments_iterator endSegments(); + + /*! + * Split these poly line objects into several line segment objects consisting of only two verts + * and store them in the \p result + */ + void splitIntoSegments(std::vector& result) const; + std::vector splitIntoSegments() const; /*! * On Y-axis positive upward displays, Orientation will return true if the polygon's orientation is counter-clockwise. @@ -162,122 +238,80 @@ class ConstPolygonRef */ bool orientation() const { - return ClipperLib::Orientation(*path); + return ClipperLib::Orientation(*this); } - Polygons offset(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; + coord_t length() const; - coord_t polygonLength() const - { - return polylineLength() + vSize(path->front() - path->back()); - } + bool shorterThan(const coord_t check_length) const; - coord_t polylineLength() const + void reverse() { - coord_t length = 0; - Point2LL p0 = path->front(); - for (size_t n = 1; n < path->size(); n++) - { - Point2LL p1 = (*path)[n]; - length += vSize(p0 - p1); - p0 = p1; - } - return length; + ClipperLib::ReversePath(*this); } + void removeColinearEdges(const AngleRadians max_deviation_angle); + /*! - * Split these poly line objects into several line segment objects consisting of only two verts - * and store them in the \p result + * Removes consecutive line segments with same orientation and changes this polygon. + * + * 1. Removes verts which are connected to line segments which are too small. + * 2. Removes verts which detour from a direct line from the previous and next vert by a too small amount. + * 3. Moves a vert when a small line segment is connected to a much longer one. in order to maintain the outline of the object. + * 4. Don't remove a vert when the impact on the outline of the object is too great. + * + * Note that the simplify is a best effort algorithm. It does not guarantee that no lines below the provided smallest_line_segment_squared are left. + * + * The following example (Two very long line segments (" & , respectively) that are connected by a very small line segment (i) is unsimplifable by this + * function, even though the actual area change of removing line segment i is very small. The reason for this is that in the case of long lines, even a small + * deviation from it's original direction is very noticeable in the final result, especially if the polygons above make a slightly different choice. + * + * """"""""""""""""""""""""""""""""i,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, + + * + * \param smallest_line_segment_squared maximal squared length of removed line segments + * \param allowed_error_distance_squared The square of the distance of the middle point to the line segment of the consecutive and previous point for which the middle point is + removed */ - void splitPolylineIntoSegments(Polygons& result) const; - Polygons splitPolylineIntoSegments() const; + void simplify(const coord_t smallest_line_segment_squared = MM2INT(0.01) * MM2INT(0.01), const coord_t allowed_error_distance_squared = 25); /*! - * Split these polygon objects into several line segment objects consisting of only two verts - * and store them in the \p result + * See simplify(.) */ - void splitPolygonIntoSegments(Polygons& result) const; - Polygons splitPolygonIntoSegments() const; +#warning This can probably be merge with simplify ? + void simplifyPolyline(const coord_t smallest_line_segment_squared = 100, const coord_t allowed_error_distance_squared = 25); - bool shorterThan(const coord_t check_length) const; +private: + /*! + * Private implementation for both simplify and simplifyPolygons. + * + * Made private to avoid accidental use of the wrong function. + */ + void _simplify(const coord_t smallest_line_segment_squared = 100, const coord_t allowed_error_distance_squared = 25, bool processing_polylines = false); +}; - Point2LL min() const - { - Point2LL ret = Point2LL(POINT_MAX, POINT_MAX); - for (Point2LL p : *path) - { - ret.X = std::min(ret.X, p.X); - ret.Y = std::min(ret.Y, p.Y); - } - return ret; - } +template +class _ClosedPolyline : public Polyline +{ + friend class Polygons; - Point2LL max() const - { - Point2LL ret = Point2LL(POINT_MIN, POINT_MIN); - for (Point2LL p : *path) - { - ret.X = std::max(ret.X, p.X); - ret.Y = std::max(ret.Y, p.Y); - } - return ret; - } +public: + _ClosedPolyline() = default; - double area() const + _ClosedPolyline(const std::initializer_list& initializer) + : Polyline(initializer) { - return ClipperLib::Area(*path); } - Point2LL centerOfMass() const + _ClosedPolyline(const std::vector& points) + : Polyline(points) { - if (path->size() > 0) - { - Point2LL p0 = (*path)[0]; - if (path->size() > 1) - { - double x = 0, y = 0; - for (size_t n = 1; n <= path->size(); n++) - { - Point2LL p1 = (*path)[n % path->size()]; - double second_factor = static_cast((p0.X * p1.Y) - (p1.X * p0.Y)); - - x += double(p0.X + p1.X) * second_factor; - y += double(p0.Y + p1.Y) * second_factor; - p0 = p1; - } - - double area = Area(*path); - - x = x / 6 / area; - y = y / 6 / area; - - return Point2LL(std::llrint(x), std::llrint(y)); - } - else - { - return p0; - } - } - else - { - return Point2LL(); - } } - Point2LL closestPointTo(Point2LL p) const + _ClosedPolyline& operator=(const _ClosedPolyline& other) { - Point2LL ret = p; - double bestDist = std::numeric_limits::max(); - for (size_t n = 0; n < path->size(); n++) - { - double dist = vSize2f(p - (*path)[n]); - if (dist < bestDist) - { - ret = (*path)[n]; - bestDist = dist; - } - } - return ret; + Polyline::operator=(other); + return *this; } /*! @@ -298,7 +332,7 @@ class ConstPolygonRef * \param border_result What to return when the point is exactly on the border * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) */ - bool _inside(Point2LL p, bool border_result = false) const; + // bool _inside(Point2LL p, bool border_result = false) const; /*! * Clipper function. @@ -308,7 +342,7 @@ class ConstPolygonRef */ bool inside(Point2LL p, bool border_result = false) const { - int res = ClipperLib::PointInPolygon(p, *path); + int res = ClipperLib::PointInPolygon(p, *this); if (res == -1) { return border_result; @@ -318,15 +352,64 @@ class ConstPolygonRef bool inside(const auto& polygon) const { - for (const auto& point : *path) + for (const auto& point : *this) { - if (! ClipperLib::PointInPolygon(point, *polygon.path)) + if (! ClipperLib::PointInPolygon(point, polygon)) { return false; } } return true; } +}; + +using ClosedPolyline = _ClosedPolyline; + +class Polygon : public _ClosedPolyline +{ + friend class Polygons; + +public: + Polygon() = default; + + Polygon(const Polygon& other) = default; + + Polygon(Polygon&& other) = default; + + Polygon(const std::initializer_list& initializer) + : _ClosedPolyline(initializer) + { + } + + Polygon(const std::vector& points) + : _ClosedPolyline(points) + { + } + + Polygon& operator=(const Polygon& other) + { + _ClosedPolyline::operator=(other); + return *this; + } + + /*! + * Compute the morphological intersection between this polygon and another. + * + * Note that the result may consist of multiple polygons, if you have bad + * luck. + * + * \param other The polygon with which to intersect this polygon. + */ + Polygons intersection(const Polygon& other) const; + + double area() const + { + return ClipperLib::Area(*this); + } + + Point2LL centerOfMass() const; + + Polygons offset(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; /*! * Smooth out small perpendicular segments and store the result in \p result. @@ -339,7 +422,7 @@ class ConstPolygonRef * \param remove_length The length of the largest segment removed * \param result (output) The result polygon, assumed to be empty */ - void smooth(int remove_length, PolygonRef result) const; + void smooth(int remove_length, Polygon& result) const; /*! * Smooth out sharp inner corners, by taking a shortcut which bypasses the corner @@ -348,7 +431,7 @@ class ConstPolygonRef * \param shortcut_length The desired length of the shortcut line segment introduced (shorter shortcuts may be unavoidable) * \param result The resulting polygon */ - void smooth_outward(const AngleDegrees angle, int shortcut_length, PolygonRef result) const; + void smooth_outward(const AngleDegrees angle, int shortcut_length, Polygon& result) const; /*! * Smooth out the polygon and store the result in \p result. @@ -357,20 +440,8 @@ class ConstPolygonRef * \param remove_length The length of the largest segment removed * \param result (output) The result polygon, assumed to be empty */ - void smooth2(int remove_length, PolygonRef result) const; - - /*! - * Compute the morphological intersection between this polygon and another. - * - * Note that the result may consist of multiple polygons, if you have bad - * luck. - * - * \param other The polygon with which to intersect this polygon. - */ - Polygons intersection(const ConstPolygonRef& other) const; - + void smooth2(int remove_length, Polygon& result) const; -private: /*! * Smooth out a simple corner consisting of two linesegments. * @@ -444,307 +515,281 @@ class ConstPolygonRef bool& backward_is_too_far); }; - -class PolygonPointer; - -class PolygonRef : public ConstPolygonRef +class OpenPolyline : public Polyline { - friend class PolygonPointer; - friend class Polygons; - friend class PolygonsPart; - public: - PolygonRef(ClipperLib::Path& polygon) - : ConstPolygonRef(polygon) - { - } + OpenPolyline() = default; - PolygonRef(const PolygonRef& other) - : ConstPolygonRef(*other.path) - { - } + OpenPolyline(const OpenPolyline& other) = default; - PolygonRef() = delete; // you cannot have a reference without an object! + OpenPolyline(OpenPolyline&& other) = default; - virtual ~PolygonRef() + OpenPolyline(const std::initializer_list& initializer) + : Polyline(initializer) { } - /*! - * Reserve a number of polygons to prevent reallocation and breakage of pointers. - * \param min_size The minimum size the new underlying array should have. - */ - void reserve(size_t min_size) + OpenPolyline(const std::vector& points) + : Polyline(points) { - path->reserve(min_size); } - template - ClipperLib::Path::iterator insert(ClipperLib::Path::const_iterator pos, iterator first, iterator last) + OpenPolyline(std::vector&& points) + : Polyline(points) { - return path->insert(pos, first, last); } - PolygonRef& operator=(const ConstPolygonRef& other) = delete; // polygon assignment is expensive and probably not what you want when you use the assignment operator - - PolygonRef& operator=(ConstPolygonRef& other) = delete; // polygon assignment is expensive and probably not what you want when you use the assignment operator - // { path = other.path; return *this; } - - PolygonRef& operator=(PolygonRef&& other) + OpenPolyline& operator=(const OpenPolyline& other) { - *path = std::move(*other.path); + Polyline::operator=(other); return *this; } - Point2LL& operator[](size_t index) - { - POLY_ASSERT(index < size()); - return (*path)[index]; - } - - const Point2LL& operator[](size_t index) const + OpenPolyline& operator=(OpenPolyline&& other) { - return ConstPolygonRef::operator[](index); + Polyline::operator=(other); + return *this; } +}; - ClipperLib::Path::iterator begin() - { - return path->begin(); - } +#if 0 +/*! + * Outer polygons should be counter-clockwise, + * inner hole polygons should be clockwise. + * (When negative X is to the left and negative Y is downward.) + */ +class ConstPolygonRef +{ - ClipperLib::Path::iterator end() - { - return path->end(); - } +}; - ClipperLib::Path::reference front() - { - return path->front(); - } +class PolygonsPart; - ClipperLib::Path::reference back() - { - return path->back(); - } +class Polygons +{ - void* data() + Polygons& operator=(const Polygons& other) { - return path->data(); + paths = other.paths; + return *this; } - - void add(const Point2LL p) + Polygons& operator=(Polygons&& other) { - path->push_back(p); - } + if (this != &other) + { + paths = std::move(other.paths); + } + return *this; + } +}; +#endif - ClipperLib::Path& operator*() +// ########################################################### +// Definitions of templated methods +// ########################################################### +#if 0 +seems to be unused +template +bool SurfaceContainer::_inside(Point2LL p, bool border_result) const +{ + if (size() < 1) { - return *path; + return false; } - template - void emplace_back(Args&&... args) + int crossings = 0; + Point2LL p0 = back(); + for (unsigned int n = 0; n < size(); n++) { - path->emplace_back(args...); + Point2LL p1 = (*this)[n]; + // no tests unless the segment p0-p1 is at least partly at, or to right of, p.X + short comp = LinearAlg2D::pointLiesOnTheRightOfLine(p, p0, p1); + if (comp == 1) + { + crossings++; + } + else if (comp == 0) + { + return border_result; + } + p0 = p1; } + return (crossings % 2) == 1; +} +#endif - void remove(size_t index) - { - POLY_ASSERT(index < size() && index <= static_cast(std::numeric_limits::max())); - path->erase(path->begin() + static_cast(index)); - } +template +void Polyline::removeColinearEdges(const AngleRadians max_deviation_angle) +{ + // TODO: Can be made more efficient (for example, use pointer-types for process-/skip-indices, so we can swap them without copy). - void insert(size_t index, Point2LL p) + size_t num_removed_in_iteration = 0; + do { - POLY_ASSERT(index < size() && index <= static_cast(std::numeric_limits::max())); - path->insert(path->begin() + static_cast(index), p); - } + num_removed_in_iteration = 0; - void clear() - { - path->clear(); - } + std::vector process_indices(size(), true); - void reverse() - { - ClipperLib::ReversePath(*path); - } + bool go = true; + while (go) + { + go = false; - /*! - * Translate the whole polygon in some direction. - * - * \param translation The direction in which to move the polygon - */ - void translate(Point2LL translation) - { - for (Point2LL& p : *this) - { - p += translation; - } - } + const path_t& rpath = *this; + const size_t pathlen = rpath.size(); + if (pathlen <= 3) + { + return; + } - void removeColinearEdges(const AngleRadians max_deviation_angle); + std::vector skip_indices(size(), false); - /*! - * Removes consecutive line segments with same orientation and changes this polygon. - * - * 1. Removes verts which are connected to line segments which are too small. - * 2. Removes verts which detour from a direct line from the previous and next vert by a too small amount. - * 3. Moves a vert when a small line segment is connected to a much longer one. in order to maintain the outline of the object. - * 4. Don't remove a vert when the impact on the outline of the object is too great. - * - * Note that the simplify is a best effort algorithm. It does not guarantee that no lines below the provided smallest_line_segment_squared are left. - * - * The following example (Two very long line segments (" & , respectively) that are connected by a very small line segment (i) is unsimplifable by this - * function, even though the actual area change of removing line segment i is very small. The reason for this is that in the case of long lines, even a small - * deviation from it's original direction is very noticeable in the final result, especially if the polygons above make a slightly different choice. - * - * """"""""""""""""""""""""""""""""i,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, + Polyline new_path; + for (size_t point_idx = 0; point_idx < pathlen; ++point_idx) + { + // Don't iterate directly over process-indices, but do it this way, because there are points _in_ process-indices that should nonetheless be skipped: + if (! process_indices[point_idx]) + { + new_path.push_back(rpath[point_idx]); + continue; + } - * - * \param smallest_line_segment_squared maximal squared length of removed line segments - * \param allowed_error_distance_squared The square of the distance of the middle point to the line segment of the consecutive and previous point for which the middle point is - removed - */ - void simplify(const coord_t smallest_line_segment_squared = MM2INT(0.01) * MM2INT(0.01), const coord_t allowed_error_distance_squared = 25); + // Should skip the last point for this iteration if the old first was removed (which can be seen from the fact that the new first was skipped): + if (point_idx == (pathlen - 1) && skip_indices[0]) + { + skip_indices[new_path.size()] = true; + go = true; + new_path.push_back(rpath[point_idx]); + break; + } - /*! - * See simplify(.) - */ - void simplifyPolyline(const coord_t smallest_line_segment_squared = 100, const coord_t allowed_error_distance_squared = 25); + const Point2LL& prev = rpath[(point_idx - 1 + pathlen) % pathlen]; + const Point2LL& pt = rpath[point_idx]; + const Point2LL& next = rpath[(point_idx + 1) % pathlen]; -protected: - /*! - * Private implementation for both simplify and simplifyPolygons. - * - * Made private to avoid accidental use of the wrong function. - */ - void _simplify(const coord_t smallest_line_segment_squared = 100, const coord_t allowed_error_distance_squared = 25, bool processing_polylines = false); + double angle = LinearAlg2D::getAngleLeft(prev, pt, next); // [0 : 2 * pi] + if (angle >= std::numbers::pi) + { + angle -= std::numbers::pi; + } // map [pi : 2 * pi] to [0 : pi] -public: - void pop_back() - { - path->pop_back(); - } + // Check if the angle is within limits for the point to 'make sense', given the maximum deviation. + // If the angle indicates near-parallel segments ignore the point 'pt' + if (angle > max_deviation_angle && angle < std::numbers::pi - max_deviation_angle) + { + new_path.push_back(pt); + } + else if (point_idx != (pathlen - 1)) + { + // Skip the next point, since the current one was removed: + skip_indices[new_path.size()] = true; + go = true; + new_path.push_back(next); + ++point_idx; + } + } + (*this) = new_path; + num_removed_in_iteration += pathlen - size(); - /*! - * Apply a matrix to each vertex in this polygon - */ - void applyMatrix(const PointMatrix& matrix); - void applyMatrix(const Point3Matrix& matrix); -}; + process_indices.clear(); + process_indices.insert(process_indices.end(), skip_indices.begin(), skip_indices.end()); + } + } while (num_removed_in_iteration > 0); +} -class ConstPolygonPointer +template +Polyline::const_segments_iterator Polyline::beginSegments() const { -protected: - const ClipperLib::Path* path; - -public: - ConstPolygonPointer() - : path(nullptr) - { - } - ConstPolygonPointer(const ConstPolygonRef* ref) - : path(ref->path) - { - } - ConstPolygonPointer(const ConstPolygonRef& ref) - : path(ref.path) - { - } - - ConstPolygonRef operator*() const - { - assert(path); - return ConstPolygonRef(*path); - } - const ClipperLib::Path* operator->() const - { - assert(path); - return path; - } + return const_segments_iterator(begin(), begin(), end()); +} - operator bool() const +template +Polyline::const_segments_iterator Polyline::endSegments() const +{ + if constexpr (shape_type_ == ShapeType::Closed || shape_type_ == ShapeType::Filled) { - return path; + return const_segments_iterator(end(), begin(), end()); } - - bool operator==(const ConstPolygonPointer& rhs) const + else { - return path == rhs.path; + return const_segments_iterator(size() > 1 ? std::prev(end()) : end(), begin(), end()); } -}; +} -class PolygonPointer : public ConstPolygonPointer +template +Polyline::segments_iterator Polyline::beginSegments() { -public: - PolygonPointer() - : ConstPolygonPointer(nullptr) - { - } - PolygonPointer(PolygonRef* ref) - : ConstPolygonPointer(ref) - { - } + return segments_iterator(begin(), begin(), end()); +} - PolygonPointer(PolygonRef& ref) - : ConstPolygonPointer(ref) +template +Polyline::segments_iterator Polyline::endSegments() +{ + if constexpr (shape_type_ == ShapeType::Closed || shape_type_ == ShapeType::Filled) { + return segments_iterator(end(), begin(), end()); } - - PolygonRef operator*() + else { - assert(path); - return PolygonRef(*const_cast(path)); + return segments_iterator(size() > 1 ? std::prev(end()) : end(), begin(), end()); } +} - ConstPolygonRef operator*() const - { - assert(path); - return ConstPolygonRef(*path); - } +template +coord_t Polyline::length() const +{ + return std::accumulate( + beginSegments(), + endSegments(), + 0, + [](coord_t total, const const_segments_iterator::value_type& segment) + { + return total + vSize(segment.end - segment.start); + }); +} - ClipperLib::Path* operator->() - { - assert(path); - return const_cast(path); - } +template +bool Polyline::shorterThan(const coord_t check_length) const +{ + coord_t length = 0; + auto iterator_segment = std::find_if( + beginSegments(), + endSegments(), + [&length, &check_length](const const_segments_iterator::value_type& segment) + { + length += vSize(segment.end - segment.start); + if (length >= check_length) + { + return true; + } + }); + return iterator_segment == endSegments(); +} - const ClipperLib::Path* operator->() const +template +void Polyline::splitIntoSegments(std::vector& result) const +{ + for (auto it = beginSegments(); it != endSegments(); ++it) { - assert(path); - return path; + result.emplace_back(std::initializer_list{ (*it).start, (*it).end }); } +} - operator bool() const - { - return path; - } -}; +template +std::vector Polyline::splitIntoSegments() const +{ + std::vector result; + splitIntoSegments(result); + return result; +} } // namespace cura - namespace std { +#if 0 template<> -struct hash -{ - size_t operator()(const cura::ConstPolygonRef& poly) const - { - return std::hash()(&*poly); - } -}; -template<> -struct hash -{ - size_t operator()(const cura::ConstPolygonPointer& poly) const - { - return std::hash()(&**poly); - } -}; -template<> -struct hash +struct hash { size_t operator()(const cura::PolygonPointer& poly) const { @@ -752,855 +797,7 @@ struct hash return std::hash()(&*ref); } }; +#endif } // namespace std -namespace cura -{ - -class Polygon : public PolygonRef -{ -public: - ClipperLib::Path poly; - - Polygon() - : PolygonRef(poly) - { - } - - Polygon(const ConstPolygonRef& other) - : PolygonRef(poly) - , poly(*other.path) - { - } - - Polygon(const Polygon& other) - : PolygonRef(poly) - , poly(*other.path) - { - } - - Polygon(Polygon&& moved) - : PolygonRef(poly) - , poly(std::move(moved.poly)) - { - } - - virtual ~Polygon() - { - } - - Polygon& operator=(const ConstPolygonRef& other) = delete; // copying a single polygon is generally not what you want - // { - // path = other.path; - // poly = *other.path; - // return *this; - // } - - Polygon& operator=(Polygon&& other) //!< move assignment - { - poly = std::move(other.poly); - return *this; - } -}; - -class PolygonsPart; - -class Polygons -{ - friend class Polygon; - friend class PolygonRef; - friend class ConstPolygonRef; - friend class PolygonUtils; - -public: - ClipperLib::Paths paths; - - size_t size() const - { - return paths.size(); - } - - void reserve(size_t new_cap) - { - paths.reserve(new_cap); - } - - /*! - * Convenience function to check if the polygon has no points. - * - * \return `true` if the polygon has no points, or `false` if it does. - */ - bool empty() const; - - size_t pointCount() const; //!< Return the amount of points in all polygons - - PolygonRef operator[](size_t index) - { - POLY_ASSERT(index < size()); - return paths[index]; - } - ConstPolygonRef operator[](size_t index) const - { - POLY_ASSERT(index < size()); - return paths[index]; - } - ClipperLib::Paths::iterator begin() - { - return paths.begin(); - } - ClipperLib::Paths::const_iterator begin() const - { - return paths.begin(); - } - ClipperLib::Paths::iterator end() - { - return paths.end(); - } - ClipperLib::Paths::const_iterator end() const - { - return paths.end(); - } - /*! - * Remove a polygon from the list and move the last polygon to its place - * - * \warning changes the order of the polygons! - */ - void remove(size_t index) - { - POLY_ASSERT(index < size()); - if (index < paths.size() - 1) - { - paths[index] = std::move(paths.back()); - } - paths.resize(paths.size() - 1); - } - - void pop_back() - { - paths.pop_back(); - } - - /*! - * Remove a range of polygons - */ - void erase(ClipperLib::Paths::iterator start, ClipperLib::Paths::iterator end) - { - paths.erase(start, end); - } - void clear() - { - paths.clear(); - } - void add(ConstPolygonRef& poly) - { - paths.push_back(*poly.path); - } - void add(const ConstPolygonRef& poly) - { - paths.push_back(*poly.path); - } - void add(Polygon&& other_poly) - { - paths.emplace_back(std::move(*other_poly)); - } - void add(const Polygons& other) - { - std::copy(other.paths.begin(), other.paths.end(), std::back_inserter(paths)); - } - void addIfNotEmpty(ConstPolygonRef& poly) - { - if (! poly.empty()) - { - paths.push_back(*poly.path); - } - } - void addIfNotEmpty(const ConstPolygonRef& poly) - { - if (! poly.empty()) - { - paths.push_back(*poly.path); - } - } - void addIfNotEmpty(Polygon&& other_poly) - { - if (! other_poly.empty()) - { - paths.emplace_back(std::move(*other_poly)); - } - } - /*! - * Add a 'polygon' consisting of two points - */ - void addLine(const Point2LL from, const Point2LL to) - { - paths.emplace_back(ClipperLib::Path{ from, to }); - } - - void emplace_back(const Polygon& poly) - { - paths.emplace_back(*poly.path); - } - - void emplace_back(const ConstPolygonRef& poly) - { - paths.emplace_back(*poly.path); - } - - void emplace_back(const PolygonRef& poly) - { - paths.emplace_back(*poly.path); - } - - template - void emplace_back(Args... args) - { - paths.emplace_back(args...); - } - - PolygonRef newPoly() - { - paths.emplace_back(); - return PolygonRef(paths.back()); - } - PolygonRef front() - { - return PolygonRef(paths.front()); - } - ConstPolygonRef front() const - { - return ConstPolygonRef(paths.front()); - } - PolygonRef back() - { - return PolygonRef(paths.back()); - } - ConstPolygonRef back() const - { - return ConstPolygonRef(paths.back()); - } - - Polygons() - { - } - - Polygons(const Polygons& other) - { - paths = other.paths; - } - Polygons(Polygons&& other) - { - paths = std::move(other.paths); - } - Polygons& operator=(const Polygons& other) - { - paths = other.paths; - return *this; - } - Polygons& operator=(Polygons&& other) - { - if (this != &other) - { - paths = std::move(other.paths); - } - return *this; - } - - bool operator==(const Polygons& other) const = delete; - - /*! - * Convert ClipperLib::PolyTree to a Polygons object, - * which uses ClipperLib::Paths instead of ClipperLib::PolyTree - */ - static Polygons toPolygons(ClipperLib::PolyTree& poly_tree); - - Polygons difference(const Polygons& other) const - { - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(paths, ClipperLib::ptSubject, true); - clipper.AddPaths(other.paths, ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctDifference, ret.paths); - return ret; - } - Polygons unionPolygons(const Polygons& other, ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero) const - { - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(paths, ClipperLib::ptSubject, true); - clipper.AddPaths(other.paths, ClipperLib::ptSubject, true); - clipper.Execute(ClipperLib::ctUnion, ret.paths, fill_type, fill_type); - return ret; - } - /*! - * Union all polygons with each other (When polygons.add(polygon) has been called for overlapping polygons) - */ - Polygons unionPolygons() const - { - return unionPolygons(Polygons()); - } - Polygons intersection(const Polygons& other) const - { - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(paths, ClipperLib::ptSubject, true); - clipper.AddPaths(other.paths, ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctIntersection, ret.paths); - return ret; - } - - - /*! - * Intersect polylines with this area Polygons object. - * - * \note Due to a clipper bug with polylines with nearly collinear segments, the polylines are cut up into separate polylines, and restitched back together at the end. - * - * \param polylines The (non-closed!) polylines to limit to the area of this Polygons object - * \param restitch Whether to stitch the resulting segments into longer polylines, or leave every segment as a single segment - * \param max_stitch_distance The maximum distance for two polylines to be stitched together with a segment - * \return The resulting polylines limited to the area of this Polygons object - */ - Polygons intersectionPolyLines(const Polygons& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; - - /*! - * Add the front to each polygon so that the polygon is represented as a polyline - */ - void toPolylines(); - - /*! - * Split this poly line object into several line segment objects - * and store them in the \p result - */ - void splitPolylinesIntoSegments(Polygons& result) const; - Polygons splitPolylinesIntoSegments() const; - - /*! - * Split this polygon object into several line segment objects - * and store them in the \p result - */ - void splitPolygonsIntoSegments(Polygons& result) const; - Polygons splitPolygonsIntoSegments() const; - - Polygons xorPolygons(const Polygons& other, ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const - { - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(paths, ClipperLib::ptSubject, true); - clipper.AddPaths(other.paths, ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctXor, ret.paths, pft); - return ret; - } - - Polygons execute(ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const - { - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(paths, ClipperLib::ptSubject, true); - clipper.Execute(ClipperLib::ctXor, ret.paths, pft); - return ret; - } - - Polygons offset(coord_t distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; - - Polygons offsetPolyLine(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, bool inputPolyIsClosed = false) const - { - Polygons ret; - double miterLimit = 1.2; - ClipperLib::EndType end_type; - if (inputPolyIsClosed) - { - end_type = ClipperLib::etClosedLine; - } - else if (joinType == ClipperLib::jtMiter) - { - end_type = ClipperLib::etOpenSquare; - } - else - { - end_type = ClipperLib::etOpenRound; - } - ClipperLib::ClipperOffset clipper(miterLimit, 10.0); - clipper.AddPaths(paths, joinType, end_type); - clipper.MiterLimit = miterLimit; - clipper.Execute(ret.paths, distance); - return ret; - } - - /*! - * Check if we are inside the polygon. - * - * We do this by counting the number of polygons inside which this point lies. - * An odd number is inside, while an even number is outside. - * - * Returns false if outside, true if inside; if the point lies exactly on the border, will return \p border_result. - * - * \param p The point for which to check if it is inside this polygon - * \param border_result What to return when the point is exactly on the border - * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) - */ - bool inside(Point2LL p, bool border_result = false) const; - - /*! - * Check if we are inside the polygon. We do this by tracing from the point towards the positive X direction, - * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. - * Care needs to be taken, if p.Y exactly matches a vertex to the right of p, then we need to count 1 intersect if the - * outline passes vertically past; and 0 (or 2) intersections if that point on the outline is a 'top' or 'bottom' vertex. - * The easiest way to do this is to break out two cases for increasing and decreasing Y ( from p0 to p1 ). - * A segment is tested if pa.Y <= p.Y < pb.Y, where pa and pb are the points (from p0,p1) with smallest & largest Y. - * When both have the same Y, no intersections are counted but there is a special test to see if the point falls - * exactly on the line. - * - * Returns false if outside, true if inside; if the point lies exactly on the border, will return \p border_result. - * - * \deprecated This function is old and no longer used. instead use \ref Polygons::inside - * - * \param p The point for which to check if it is inside this polygon - * \param border_result What to return when the point is exactly on the border - * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) - */ - bool insideOld(Point2LL p, bool border_result = false) const; - - /*! - * Find the polygon inside which point \p p resides. - * - * We do this by tracing from the point towards the positive X direction, - * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. - * We then find the polygon with an uneven number of crossings which is closest to \p p. - * - * If \p border_result, we return the first polygon which is exactly on \p p. - * - * \param p The point for which to check in which polygon it is. - * \param border_result Whether a point exactly on a polygon counts as inside - * \return The index of the polygon inside which the point \p p resides - */ - size_t findInside(Point2LL p, bool border_result = false); - - /*! - * Approximates the convex hull of the polygons. - * \p extra_outset Extra offset outward - * \return the convex hull (approximately) - * - */ - Polygons approxConvexHull(int extra_outset = 0); - - /*! - * Make each of the polygons convex - */ - void makeConvex(); - - /*! - * Compute the area enclosed within the polygons (minus holes) - * - * \return The area in square micron - */ - double area() const; - - /*! - * Smooth out small perpendicular segments - * Smoothing is performed by removing the inner most vertex of a line segment smaller than \p remove_length - * which has an angle with the next and previous line segment smaller than roughly 150* - * - * Note that in its current implementation this function doesn't remove line segments with an angle smaller than 30* - * Such would be the case for an N shape. - * - * \param remove_length The length of the largest segment removed - * \return The smoothed polygon - */ - Polygons smooth(int remove_length) const; - - /*! - * Smooth out sharp inner corners, by taking a shortcut which bypasses the corner - * - * \param angle The maximum angle of inner corners to be smoothed out - * \param shortcut_length The desired length of the shortcut line segment introduced (shorter shortcuts may be unavoidable) - * \return The resulting polygons - */ - Polygons smooth_outward(const AngleDegrees angle, int shortcut_length); - - Polygons smooth2(int remove_length, int min_area) const; //!< removes points connected to small lines - - void removeColinearEdges(const AngleRadians max_deviation_angle = AngleRadians(0.0005)) - { - Polygons& thiss = *this; - for (size_t p = 0; p < size(); p++) - { - thiss[p].removeColinearEdges(max_deviation_angle); - if (thiss[p].size() < 3) - { - remove(p); - p--; - } - } - } - -public: - void scale(const Ratio& ratio) - { - if (ratio == 1.) - { - return; - } - - for (auto& points : *this) - { - for (auto& pt : points) - { - pt = pt * static_cast(ratio); - } - } - } - - void translate(const Point2LL vec) - { - if (vec.X == 0 && vec.Y == 0) - { - return; - } - - for (PolygonRef poly : *this) - { - poly.translate(vec); - } - } - - /*! - * Remove all but the polygons on the very outside. - * Exclude holes and parts within holes. - * \return the resulting polygons. - */ - Polygons getOutsidePolygons() const; - - /*! - * Exclude holes which have no parts inside of them. - * \return the resulting polygons. - */ - Polygons removeEmptyHoles() const; - - /*! - * Return hole polygons which have no parts inside of them. - * \return the resulting polygons. - */ - Polygons getEmptyHoles() const; - - /*! - * Split up the polygons into groups according to the even-odd rule. - * Each PolygonsPart in the result has an outline as first polygon, whereas the rest are holes. - */ - std::vector splitIntoParts(bool unionAll = false) const; - - /*! - * Sort the polygons into bins where each bin has polygons which are contained within one of the polygons in the previous bin. - * - * \warning When polygons are crossing each other the result is undefined. - */ - std::vector sortByNesting() const; - - /*! - * Utility method for creating the tube (or 'donut') of a shape. - * \param inner_offset Offset relative to the original shape-outline towards the inside of the shape. Sort-of like a negative normal offset, except it's the offset part that's - * kept, not the shape. \param outer_offset Offset relative to the original shape-outline towards the outside of the shape. Comparable to normal offset. \return The resulting - * polygons. - */ - Polygons tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; - -private: - /*! - * recursive part of \ref Polygons::removeEmptyHoles and \ref Polygons::getEmptyHoles - * \param node The node of the polygons part to process - * \param remove_holes Whether to remove empty holes or everything but the empty holes - * \param ret Where to store polygons which are not empty holes - */ - void removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Polygons& ret) const; - void splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const; - void sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const; - -public: - /*! - * Split up the polygons into groups according to the even-odd rule. - * Each vector in the result has the index to an outline as first index, whereas the rest are indices to holes. - * - * \warning Note that this function reorders the polygons! - */ - PartsView splitIntoPartsView(bool unionAll = false); - -private: - void splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Polygons& reordered, ClipperLib::PolyNode* node) const; - -public: - /*! - * Removes polygons with area smaller than \p min_area_size (note that min_area_size is in mm^2, not in micron^2). - * Unless \p remove_holes is true, holes are not removed even if their area is below \p min_area_size. - * However, holes that are contained within outlines whose area is below the threshold are removed though. - */ - void removeSmallAreas(const double min_area_size, const bool remove_holes = false); - - /*! - * Removes polygons with circumference smaller than \p min_circumference_size (in micron). - * Unless \p remove_holes is true, holes are not removed even if their circumference is below \p min_circumference_size. - * However, holes that are contained within outlines whose circumference is below the threshold are removed though. - */ - [[maybe_unused]] void removeSmallCircumference(const coord_t min_circumference_size, const bool remove_holes = false); - - /*! - * Removes polygons with circumference smaller than \p min_circumference_size (in micron) _and_ - * an area smaller then \p min_area_size (note that min_area_size is in mm^2, not in micron^2). - * Unless \p remove_holes is true, holes are not removed even if their circumference is - * below \p min_circumference_size and their area smaller then \p min_area_size. - * However, holes that are contained within outlines whose circumference is below the threshold are removed though. - */ - [[maybe_unused]] void removeSmallAreaCircumference(const double min_area_size, const coord_t min_circumference_size, const bool remove_holes = false); - - /*! - * Removes overlapping consecutive line segments which don't delimit a - * positive area. - * - * This function is meant to work on polygons, not polylines. When misused - * on polylines, it may cause too many vertices to be removed. - * See \ref removeDegenerateVertsPolyline for a version that works on - * polylines. - */ - void removeDegenerateVerts(); - - /*! - * Removes overlapping consecutive line segments which don't delimit a - * positive area. - * - * This version is meant to work on polylines, not polygons. It leaves the - * endpoints of the polyline untouched. When misused on polygons, it may - * leave some degenerate vertices in. - * See \ref removeDegenerateVerts for a version that works on polygons. - */ - void removeDegenerateVertsPolyline(); - - /*! - * Removes overlapping consecutive line segments which don't delimit a - * positive area. - * \param for_polyline Indicate that we're removing degenerate vertices from - * a polyline, causing the endpoints of the polyline to be left untouched. - * When removing vertices from a polygon, the start and end can be - * considered for removal too, but when processing a polyline, removing - * those would cause the polyline to become shorter. - */ - void _removeDegenerateVerts(const bool for_polyline = false); - - /*! - * Removes the same polygons from this set (and also empty polygons). - * Polygons are considered the same if all points lie within [same_distance] of their counterparts. - */ - Polygons remove(const Polygons& to_be_removed, int same_distance = 0) const - { - Polygons result; - for (size_t poly_keep_idx = 0; poly_keep_idx < size(); poly_keep_idx++) - { - ConstPolygonRef poly_keep = (*this)[poly_keep_idx]; - bool should_be_removed = false; - if (poly_keep.size() > 0) - // for (int hole_poly_idx = 0; hole_poly_idx < to_be_removed.size(); hole_poly_idx++) - for (ConstPolygonRef poly_rem : to_be_removed) - { - // PolygonRef poly_rem = to_be_removed[hole_poly_idx]; - if (poly_rem.size() != poly_keep.size() || poly_rem.size() == 0) - continue; - - // find closest point, supposing this point aligns the two shapes in the best way - size_t closest_point_idx = 0; - coord_t smallestDist2 = -1; - for (size_t point_rem_idx = 0; point_rem_idx < poly_rem.size(); point_rem_idx++) - { - coord_t dist2 = vSize2(poly_rem[point_rem_idx] - poly_keep[0]); - if (dist2 < smallestDist2 || smallestDist2 < 0) - { - smallestDist2 = dist2; - closest_point_idx = point_rem_idx; - } - } - bool poly_rem_is_poly_keep = true; - // compare the two polygons on all points - if (smallestDist2 > same_distance * same_distance) - continue; - for (size_t point_idx = 0; point_idx < poly_rem.size(); point_idx++) - { - coord_t dist2 = vSize2(poly_rem[(closest_point_idx + point_idx) % poly_rem.size()] - poly_keep[point_idx]); - if (dist2 > same_distance * same_distance) - { - poly_rem_is_poly_keep = false; - break; - } - } - if (poly_rem_is_poly_keep) - { - should_be_removed = true; - break; - } - } - if (! should_be_removed) - result.add(poly_keep); - } - return result; - } - - Polygons processEvenOdd(ClipperLib::PolyFillType poly_fill_type = ClipperLib::PolyFillType::pftEvenOdd) const - { - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(paths, ClipperLib::ptSubject, true); - clipper.Execute(ClipperLib::ctUnion, ret.paths, poly_fill_type); - return ret; - } - - /*! - * Ensure the polygon is manifold, by removing small areas where the polygon touches itself. - * ____ ____ - * | | | | - * | |____ ==> | / ____ - * """"| | """ / | - * |____| |____| - * - */ - void ensureManifold(); - - coord_t polygonLength() const - { - coord_t length = 0; - for (ConstPolygonRef poly : *this) - { - length += poly.polygonLength(); - } - return length; - } - - coord_t polyLineLength() const; - - Point2LL min() const - { - Point2LL ret = Point2LL(POINT_MAX, POINT_MAX); - for (const ClipperLib::Path& polygon : paths) - { - for (Point2LL p : polygon) - { - ret.X = std::min(ret.X, p.X); - ret.Y = std::min(ret.Y, p.Y); - } - } - return ret; - } - - Point2LL max() const - { - Point2LL ret = Point2LL(POINT_MIN, POINT_MIN); - for (const ClipperLib::Path& polygon : paths) - { - for (Point2LL p : polygon) - { - ret.X = std::max(ret.X, p.X); - ret.Y = std::max(ret.Y, p.Y); - } - } - return ret; - } - - void applyMatrix(const PointMatrix& matrix) - { - for (size_t i = 0; i < paths.size(); i++) - { - for (size_t j = 0; j < paths[i].size(); j++) - { - paths[i][j] = matrix.apply(paths[i][j]); - } - } - } - - void applyMatrix(const Point3Matrix& matrix) - { - for (size_t i = 0; i < paths.size(); i++) - { - for (size_t j = 0; j < paths[i].size(); j++) - { - paths[i][j] = matrix.apply(paths[i][j]); - } - } - } - - Polygons offset(const std::vector& offset_dists) const; - - /*! - * @brief Export the polygon to a WKT string - * - * @param stream The stream to write to - */ - [[maybe_unused]] void writeWkt(std::ostream& stream) const; - - /*! - * @brief Import the polygon from a WKT string - * - * @param wkt The WKT string to read from - * @return Polygons The polygons read from the stream - */ - [[maybe_unused]] static Polygons fromWkt(const std::string& wkt); -}; - -/*! - * A single area with holes. The first polygon is the outline, while the rest are holes within this outline. - * - * This class has little more functionality than Polygons, but serves to show that a specific instance is ordered such that the first Polygon is the outline and the rest are holes. - */ -class PolygonsPart : public Polygons -{ -public: - PolygonRef outerPolygon() - { - return paths[0]; - } - ConstPolygonRef outerPolygon() const - { - return paths[0]; - } - - /*! - * Tests whether the given point is inside this polygon part. - * \param p The point to test whether it is inside. - * \param border_result If the point is exactly on the border, this will be - * returned instead. - */ - bool inside(Point2LL p, bool border_result = false) const; -}; - -/*! - * Extension of vector> which is similar to a vector of PolygonParts, except the base of the container is indices to polygons into the original Polygons, - * instead of the polygons themselves - */ -class PartsView : public std::vector> -{ -public: - Polygons& polygons_; - PartsView(Polygons& polygons) - : polygons_(polygons) - { - } - /*! - * Get the index of the PolygonsPart of which the polygon with index \p poly_idx is part. - * - * \param poly_idx The index of the polygon in \p polygons - * \param boundary_poly_idx Optional output parameter: The index of the boundary polygon of the part in \p polygons - * \return The PolygonsPart containing the polygon with index \p poly_idx - */ - size_t getPartContaining(size_t poly_idx, size_t* boundary_poly_idx = nullptr) const; - /*! - * Assemble the PolygonsPart of which the polygon with index \p poly_idx is part. - * - * \param poly_idx The index of the polygon in \p polygons - * \param boundary_poly_idx Optional output parameter: The index of the boundary polygon of the part in \p polygons - * \return The PolygonsPart containing the polygon with index \p poly_idx - */ - PolygonsPart assemblePartContaining(size_t poly_idx, size_t* boundary_poly_idx = nullptr) const; - /*! - * Assemble the PolygonsPart of which the polygon with index \p poly_idx is part. - * - * \param part_idx The index of the part - * \return The PolygonsPart with index \p poly_idx - */ - PolygonsPart assemblePart(size_t part_idx) const; -}; - -} // namespace cura - #endif // UTILS_POLYGON_H diff --git a/include/utils/polygons.h b/include/utils/polygons.h new file mode 100644 index 0000000000..3991bf4afc --- /dev/null +++ b/include/utils/polygons.h @@ -0,0 +1,553 @@ +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef UTILS_POLYGONS_H +#define UTILS_POLYGONS_H + +#include +#include +#include +#include +#include +#include +#include + +#include "../settings/types/Angle.h" +#include "../settings/types/Ratio.h" +#include "Point2LL.h" +#include "utils/ListPolyIt.h" +#include "utils/linearAlg2D.h" + +#define CHECK_POLY_ACCESS +#ifdef CHECK_POLY_ACCESS +#define POLY_ASSERT(e) assert(e) +#else +#define POLY_ASSERT(e) \ + do \ + { \ + } while (0) +#endif + +namespace cura +{ + +using point_t = ClipperLib::IntPoint; +using path_t = ClipperLib::Path; +using paths_t = ClipperLib::Paths; + +class OpenPolyline; +class Polygon; +class Polygons; +class PolygonsPart; +class PartsView; + +template +class LinesSet : public std::vector +{ +public: + LinesSet() = default; + + LinesSet(const LinesSet& other) = default; + + LinesSet(LinesSet&& other) = default; + + LinesSet(const std::vector& lines) + : std::vector(lines) + { + } + + LinesSet(std::vector&& lines) + : std::vector(std::move(lines)) + { + } + + LinesSet(const std::vector& paths) + : std::vector(*reinterpret_cast*>(&paths)) + { + } + + LinesSet& operator=(const LinesSet& other) + { + std::vector::operator=(other); + return *this; + } + + LinesSet& operator=(LinesSet&& other) + { + std::vector::operator=(other); + return *this; + } + + void splitIntoSegments(std::vector& result) const; + std::vector splitIntoSegments() const; + + /*! + * Removes overlapping consecutive line segments which don't delimit a + * positive area. + * + * This function is meant to work on polygons, not polylines. When misused + * on polylines, it may cause too many vertices to be removed. + * See \ref removeDegenerateVertsPolyline for a version that works on + * polylines. + */ +#warning rename this to removeDegenerateVerts + void removeDegenerateVertsForEveryone(); + + Polygons offset(coord_t distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; + // Polygons offsetPolyLine(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, bool inputPolyIsClosed = false) const; + + const std::vector>& getCallable() const + { + // This does work as long as we don't add any attribute to the Polygon class or any of its + // parent until std::vector + return *reinterpret_cast>*>(this); + } + + std::vector>& getCallable() + { + // This does work as long as we don't add any attribute to the Polygon class or any of its + // parent until std::vector + return *reinterpret_cast>*>(this); + } +}; + +class Polygons : public LinesSet +{ + friend class Polygon; + +public: + Polygons() = default; + + Polygons(const Polygons& other) = default; + + Polygons(Polygons&& other) = default; + + Polygons(const std::initializer_list& initializer) + : LinesSet(initializer) + { + } + + Polygons(const std::vector& paths) + : LinesSet(paths) + { + } + + Polygons& operator=(const Polygons& other) + { + LinesSet::operator=(other); + return *this; + } + + Polygons& operator=(Polygons&& polygons); + + //!< Return the amount of points in all polygons + size_t pointCount() const; + + /*! + * Remove a polygon from the list and move the last polygon to its place + * + * \warning changes the order of the polygons! + */ + void remove(size_t index); + + void add(const Polygons& other); + + void addIfNotEmpty(const Polygon& polygon); + + void addIfNotEmpty(Polygon&& polygon); + + /*! + * Add a 'polygon' consisting of two points + */ + void addLine(const point_t& from, const point_t& to); + + Polygon& newPoly(); + + /*! + * Convert ClipperLib::PolyTree to a Polygons object, + * which uses ClipperLib::Paths instead of ClipperLib::PolyTree + */ + static Polygons toPolygons(ClipperLib::PolyTree& poly_tree); + + Polygons difference(const Polygons& other) const; + + Polygons unionPolygons(const Polygons& other, ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero) const; + + /*! + * Union all polygons with each other (When polygons.add(polygon) has been called for overlapping polygons) + */ + Polygons unionPolygons() const + { + return unionPolygons(Polygons()); + } + + Polygons intersection(const Polygons& other) const; + + + /*! + * Intersect polylines with this area Polygons object. + * + * \note Due to a clipper bug with polylines with nearly collinear segments, the polylines are cut up into separate polylines, and restitched back together at the end. + * + * \param polylines The (non-closed!) polylines to limit to the area of this Polygons object + * \param restitch Whether to stitch the resulting segments into longer polylines, or leave every segment as a single segment + * \param max_stitch_distance The maximum distance for two polylines to be stitched together with a segment + * \return The resulting polylines limited to the area of this Polygons object + */ + std::vector intersectionPolyLines(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; + + /*! + * Add the front to each polygon so that the polygon is represented as a polyline + */ + void toPolylines(); + + /*! + * Split this poly line object into several line segment objects + * and store them in the \p result + */ + void splitPolylinesIntoSegments(Polygons& result) const; + Polygons splitPolylinesIntoSegments() const; + + /*! + * Split this polygon object into several line segment objects + * and store them in the \p result + */ + void splitPolygonsIntoSegments(Polygons& result) const; + Polygons splitPolygonsIntoSegments() const; + + Polygons xorPolygons(const Polygons& other, ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const; + + Polygons execute(ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const; + + /*! + * Check if we are inside the polygon. + * + * We do this by counting the number of polygons inside which this point lies. + * An odd number is inside, while an even number is outside. + * + * Returns false if outside, true if inside; if the point lies exactly on the border, will return \p border_result. + * + * \param p The point for which to check if it is inside this polygon + * \param border_result What to return when the point is exactly on the border + * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) + */ + bool inside(Point2LL p, bool border_result = false) const; + + /*! + * Check if we are inside the polygon. We do this by tracing from the point towards the positive X direction, + * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. + * Care needs to be taken, if p.Y exactly matches a vertex to the right of p, then we need to count 1 intersect if the + * outline passes vertically past; and 0 (or 2) intersections if that point on the outline is a 'top' or 'bottom' vertex. + * The easiest way to do this is to break out two cases for increasing and decreasing Y ( from p0 to p1 ). + * A segment is tested if pa.Y <= p.Y < pb.Y, where pa and pb are the points (from p0,p1) with smallest & largest Y. + * When both have the same Y, no intersections are counted but there is a special test to see if the point falls + * exactly on the line. + * + * Returns false if outside, true if inside; if the point lies exactly on the border, will return \p border_result. + * + * \deprecated This function is old and no longer used. instead use \ref Polygons::inside + * + * \param p The point for which to check if it is inside this polygon + * \param border_result What to return when the point is exactly on the border + * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) + */ + bool insideOld(Point2LL p, bool border_result = false) const; + + /*! + * Find the polygon inside which point \p p resides. + * + * We do this by tracing from the point towards the positive X direction, + * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. + * We then find the polygon with an uneven number of crossings which is closest to \p p. + * + * If \p border_result, we return the first polygon which is exactly on \p p. + * + * \param p The point for which to check in which polygon it is. + * \param border_result Whether a point exactly on a polygon counts as inside + * \return The index of the polygon inside which the point \p p resides + */ + size_t findInside(Point2LL p, bool border_result = false) const; + + /*! + * Approximates the convex hull of the polygons. + * \p extra_outset Extra offset outward + * \return the convex hull (approximately) + * + */ + Polygons approxConvexHull(int extra_outset = 0) const; + + /*! + * Make each of the polygons convex + */ + void makeConvex(); + + /*! + * Compute the area enclosed within the polygons (minus holes) + * + * \return The area in square micron + */ + double area() const; + + /*! + * Smooth out small perpendicular segments + * Smoothing is performed by removing the inner most vertex of a line segment smaller than \p remove_length + * which has an angle with the next and previous line segment smaller than roughly 150* + * + * Note that in its current implementation this function doesn't remove line segments with an angle smaller than 30* + * Such would be the case for an N shape. + * + * \param remove_length The length of the largest segment removed + * \return The smoothed polygon + */ + Polygons smooth(int remove_length) const; + + /*! + * Smooth out sharp inner corners, by taking a shortcut which bypasses the corner + * + * \param angle The maximum angle of inner corners to be smoothed out + * \param shortcut_length The desired length of the shortcut line segment introduced (shorter shortcuts may be unavoidable) + * \return The resulting polygons + */ + Polygons smooth_outward(const AngleDegrees angle, int shortcut_length) const; + + Polygons smooth2(int remove_length, int min_area) const; //!< removes points connected to small lines + + void removeColinearEdges(const AngleRadians max_deviation_angle = AngleRadians(0.0005)); + + void scale(const Ratio& ratio); + + void translate(const point_t& delta); + + /*! + * Remove all but the polygons on the very outside. + * Exclude holes and parts within holes. + * \return the resulting polygons. + */ + Polygons getOutsidePolygons() const; + + /*! + * Exclude holes which have no parts inside of them. + * \return the resulting polygons. + */ + Polygons removeEmptyHoles() const; + + /*! + * Return hole polygons which have no parts inside of them. + * \return the resulting polygons. + */ + Polygons getEmptyHoles() const; + + /*! + * Split up the polygons into groups according to the even-odd rule. + * Each PolygonsPart in the result has an outline as first polygon, whereas the rest are holes. + */ + std::vector splitIntoParts(bool unionAll = false) const; + + /*! + * Sort the polygons into bins where each bin has polygons which are contained within one of the polygons in the previous bin. + * + * \warning When polygons are crossing each other the result is undefined. + */ + std::vector sortByNesting() const; + + /*! + * Utility method for creating the tube (or 'donut') of a shape. + * \param inner_offset Offset relative to the original shape-outline towards the inside of the shape. Sort-of like a negative normal offset, except it's the offset part that's + * kept, not the shape. \param outer_offset Offset relative to the original shape-outline towards the outside of the shape. Comparable to normal offset. \return The resulting + * polygons. + */ + Polygons tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; + + /*! + * Split up the polygons into groups according to the even-odd rule. + * Each vector in the result has the index to an outline as first index, whereas the rest are indices to holes. + * + * \warning Note that this function reorders the polygons! + */ + PartsView splitIntoPartsView(bool unionAll = false); + + /*! + * Removes polygons with area smaller than \p min_area_size (note that min_area_size is in mm^2, not in micron^2). + * Unless \p remove_holes is true, holes are not removed even if their area is below \p min_area_size. + * However, holes that are contained within outlines whose area is below the threshold are removed though. + */ + void removeSmallAreas(const double min_area_size, const bool remove_holes = false); + + /*! + * Removes polygons with circumference smaller than \p min_circumference_size (in micron). + * Unless \p remove_holes is true, holes are not removed even if their circumference is below \p min_circumference_size. + * However, holes that are contained within outlines whose circumference is below the threshold are removed though. + */ + [[maybe_unused]] void removeSmallCircumference(const coord_t min_circumference_size, const bool remove_holes = false); + + /*! + * Removes polygons with circumference smaller than \p min_circumference_size (in micron) _and_ + * an area smaller then \p min_area_size (note that min_area_size is in mm^2, not in micron^2). + * Unless \p remove_holes is true, holes are not removed even if their circumference is + * below \p min_circumference_size and their area smaller then \p min_area_size. + * However, holes that are contained within outlines whose circumference is below the threshold are removed though. + */ + [[maybe_unused]] void removeSmallAreaCircumference(const double min_area_size, const coord_t min_circumference_size, const bool remove_holes = false); + + /*! + * Removes the same polygons from this set (and also empty polygons). + * Polygons are considered the same if all points lie within [same_distance] of their counterparts. + */ + Polygons remove(const Polygons& to_be_removed, int same_distance = 0) const; + + Polygons processEvenOdd(ClipperLib::PolyFillType poly_fill_type = ClipperLib::PolyFillType::pftEvenOdd) const; + + /*! + * Ensure the polygon is manifold, by removing small areas where the polygon touches itself. + * ____ ____ + * | | | | + * | |____ ==> | / ____ + * """"| | """ / | + * |____| |____| + * + */ + void ensureManifold(); + + coord_t length() const; + + point_t min() const; + + point_t max() const; + + void applyMatrix(const PointMatrix& matrix); + + void applyMatrix(const Point3Matrix& matrix); + +#warning If this is to be used, rename it + // Polygons offset(const std::vector& offset_dists) const; + + /*! + * @brief Export the polygon to a WKT string + * + * @param stream The stream to write to + */ + [[maybe_unused]] void writeWkt(std::ostream& stream) const; + + /*! + * @brief Import the polygon from a WKT string + * + * @param wkt The WKT string to read from + * @return Polygons The polygons read from the stream + */ + [[maybe_unused]] static Polygons fromWkt(const std::string& wkt); + +private: + /*! + * recursive part of \ref Polygons::removeEmptyHoles and \ref Polygons::getEmptyHoles + * \param node The node of the polygons part to process + * \param remove_holes Whether to remove empty holes or everything but the empty holes + * \param ret Where to store polygons which are not empty holes + */ + void removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Polygons& ret) const; + void splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const; + void sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const; + void splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Polygons& reordered, ClipperLib::PolyNode* node) const; +}; + +/*! + * A single area with holes. The first polygon is the outline, while the rest are holes within this outline. + * + * This class has little more functionality than Polygons, but serves to show that a specific instance is ordered such that the first Polygon is the outline and the rest are holes. + */ +class PolygonsPart : public Polygons +{ +public: + Polygon& outerPolygon() + { + return front(); + } + + const Polygon& outerPolygon() const + { + return front(); + } + + /*! + * Tests whether the given point is inside this polygon part. + * \param p The point to test whether it is inside. + * \param border_result If the point is exactly on the border, this will be + * returned instead. + */ + bool inside(Point2LL p, bool border_result = false) const; +}; + +/*! + * Extension of vector> which is similar to a vector of PolygonParts, except the base of the container is indices to polygons into the original Polygons, + * instead of the polygons themselves + */ +class PartsView : public std::vector> +{ +public: + Polygons& polygons_; + PartsView(Polygons& polygons) + : polygons_(polygons) + { + } + /*! + * Get the index of the PolygonsPart of which the polygon with index \p poly_idx is part. + * + * \param poly_idx The index of the polygon in \p polygons + * \param boundary_poly_idx Optional output parameter: The index of the boundary polygon of the part in \p polygons + * \return The PolygonsPart containing the polygon with index \p poly_idx + */ + size_t getPartContaining(size_t poly_idx, size_t* boundary_poly_idx = nullptr) const; + /*! + * Assemble the PolygonsPart of which the polygon with index \p poly_idx is part. + * + * \param poly_idx The index of the polygon in \p polygons + * \param boundary_poly_idx Optional output parameter: The index of the boundary polygon of the part in \p polygons + * \return The PolygonsPart containing the polygon with index \p poly_idx + */ + PolygonsPart assemblePartContaining(size_t poly_idx, size_t* boundary_poly_idx = nullptr) const; + /*! + * Assemble the PolygonsPart of which the polygon with index \p poly_idx is part. + * + * \param part_idx The index of the part + * \return The PolygonsPart with index \p poly_idx + */ + PolygonsPart assemblePart(size_t part_idx) const; +}; + +template +void LinesSet::splitIntoSegments(std::vector& result) const +{ + for (const LineType& line : (*this)) + { + line.splitIntoSegments(result); + } +} + +template +std::vector LinesSet::splitIntoSegments() const +{ + std::vector result; + for (const LineType& line : (*this)) + { + line.splitIntoSegments(result); + } + return result; +} + +} // namespace cura + +namespace std +{ +#if 0 +template<> +struct hash +{ + size_t operator()(const cura::PolygonPointer& poly) const + { + const cura::ConstPolygonRef ref = *static_cast(poly); + return std::hash()(&*ref); + } +}; +#endif +} // namespace std + +#endif // UTILS_POLYGONS_H diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp index decaeb582c..292b2bf1bb 100644 --- a/src/utils/polygon.cpp +++ b/src/utils/polygon.cpp @@ -21,1095 +21,211 @@ #include #include -#include "utils/ListPolyIt.h" #include "utils/PolylineStitcher.h" -#include "utils/linearAlg2D.h" // pointLiesOnTheRightOfLine +#include "utils/polygons.h" namespace cura { -size_t ConstPolygonRef::size() const -{ - return path->size(); -} - -bool ConstPolygonRef::empty() const -{ - return path->empty(); -} - -bool ConstPolygonRef::shorterThan(const coord_t check_length) const -{ - return cura::shorterThan(*this, check_length); -} - -bool ConstPolygonRef::_inside(Point2LL p, bool border_result) const -{ - const ConstPolygonRef thiss = *this; - if (size() < 1) - { - return false; - } - - int crossings = 0; - Point2LL p0 = back(); - for (unsigned int n = 0; n < size(); n++) - { - Point2LL p1 = thiss[n]; - // no tests unless the segment p0-p1 is at least partly at, or to right of, p.X - short comp = LinearAlg2D::pointLiesOnTheRightOfLine(p, p0, p1); - if (comp == 1) - { - crossings++; - } - else if (comp == 0) - { - return border_result; - } - p0 = p1; - } - return (crossings % 2) == 1; -} - - -Polygons ConstPolygonRef::intersection(const ConstPolygonRef& other) const +Polygons Polygon::intersection(const Polygon& other) const { Polygons ret; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPath(*path, ClipperLib::ptSubject, true); - clipper.AddPath(*other.path, ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctIntersection, ret.paths); + clipper.AddPath(*this, ClipperLib::ptSubject, true); + clipper.AddPath(other, ClipperLib::ptClip, true); + clipper.Execute(ClipperLib::ctIntersection, ret.getCallable()); return ret; } -bool Polygons::empty() const -{ - return paths.empty(); -} - -Polygons Polygons::approxConvexHull(int extra_outset) -{ - constexpr int overshoot = MM2INT(100); // 10cm (hard-coded value). - - Polygons convex_hull; - // Perform the offset for each polygon one at a time. - // This is necessary because the polygons may overlap, in which case the offset could end up in an infinite loop. - // See http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperOffset/_Body.htm - for (const ClipperLib::Path& path : paths) - { - Polygons offset_result; - ClipperLib::ClipperOffset offsetter(1.2, 10.0); - offsetter.AddPath(path, ClipperLib::jtRound, ClipperLib::etClosedPolygon); - offsetter.Execute(offset_result.paths, overshoot); - convex_hull.add(offset_result); - } - return convex_hull.unionPolygons().offset(-overshoot + extra_outset, ClipperLib::jtRound); -} - -void Polygons::makeConvex() +void Polygon::smooth2(int remove_length, Polygon& result) const { - // early out if there is nothing to do - if (empty()) - { - return; - } - - // Andrew’s Monotone Chain Convex Hull Algorithm - std::vector points; - - for (const auto& poly : this->paths) + if (size() > 0) { - points.insert(points.end(), poly.begin(), poly.end()); + result.push_back(front()); } - ClipperLib::Path convexified; - auto make_sorted_poly_convex = [&convexified](std::vector& poly) + for (unsigned int poly_idx = 1; poly_idx < size(); poly_idx++) { - convexified.push_back(poly[0]); - - for (const auto window : poly | ranges::views::sliding(2)) + const Point2LL& last = (*this)[poly_idx - 1]; + const Point2LL& now = (*this)[poly_idx]; + const Point2LL& next = (*this)[(poly_idx + 1) % size()]; + if (shorterThen(last - now, remove_length) && shorterThen(now - next, remove_length)) { - const Point2LL& current = window[0]; - const Point2LL& after = window[1]; - - if (LinearAlg2D::pointIsLeftOfLine(current, convexified.back(), after) < 0) + poly_idx++; // skip the next line piece (dont escalate the removal of edges) + if (poly_idx < size()) { - // Track backwards to make sure we haven't been in a concave pocket for multiple vertices already. - while (convexified.size() >= 2 - && (LinearAlg2D::pointIsLeftOfLine(convexified.back(), convexified[convexified.size() - 2], current) >= 0 - || LinearAlg2D::pointIsLeftOfLine(convexified.back(), convexified[convexified.size() - 2], convexified.front()) > 0)) - { - convexified.pop_back(); - } - convexified.push_back(current); + result.push_back((*this)[poly_idx]); } } - }; - - std::sort( - points.begin(), - points.end(), - [](Point2LL a, Point2LL b) - { - return a.X == b.X ? a.Y < b.Y : a.X < b.X; - }); - make_sorted_poly_convex(points); - std::reverse(points.begin(), points.end()); - make_sorted_poly_convex(points); - - this->paths = { convexified }; -} - -size_t Polygons::pointCount() const -{ - size_t count = 0; - for (const ClipperLib::Path& path : paths) - { - count += path.size(); - } - return count; -} - -bool Polygons::inside(Point2LL p, bool border_result) const -{ - int poly_count_inside = 0; - for (const ClipperLib::Path& poly : *this) - { - const int is_inside_this_poly = ClipperLib::PointInPolygon(p, poly); - if (is_inside_this_poly == -1) + else { - return border_result; + result.push_back((*this)[poly_idx]); } - poly_count_inside += is_inside_this_poly; } - return (poly_count_inside % 2) == 1; } -bool PolygonsPart::inside(Point2LL p, bool border_result) const +void Polygon::smooth(int remove_length, Polygon& result) const { - if (size() < 1) - { - return false; - } - if (! (*this)[0].inside(p, border_result)) + // a typical zigzag with the middle part to be removed by removing (1) : + // + // 3 + // ^ + // | + // | + // inside | outside + // 1--->2 + // ^ + // | + // | + // | + // 0 + if (size() > 0) { - return false; + result.push_back(front()); } - for (unsigned int n = 1; n < paths.size(); n++) + auto is_zigzag = [remove_length](const int64_t v02_size, const int64_t v12_size, const int64_t v13_size, const int64_t dot1, const int64_t dot2) { - if ((*this)[n].inside(p, border_result)) - { + if (v12_size > remove_length) + { // v12 or v13 is too long return false; } - } - return true; -} - -bool Polygons::insideOld(Point2LL p, bool border_result) const -{ - const Polygons& thiss = *this; - if (size() < 1) - { - return false; - } - - int crossings = 0; - for (const ClipperLib::Path& poly : thiss) - { - Point2LL p0 = poly.back(); - for (const Point2LL& p1 : poly) - { - short comp = LinearAlg2D::pointLiesOnTheRightOfLine(p, p0, p1); - if (comp == 1) - { - crossings++; - } - else if (comp == 0) - { - return border_result; - } - p0 = p1; + const bool p1_is_left_of_v02 = dot1 < 0; + if (! p1_is_left_of_v02) + { // removing p1 wouldn't smooth outward + return false; } - } - return (crossings % 2) == 1; -} - -size_t Polygons::findInside(Point2LL p, bool border_result) -{ - Polygons& thiss = *this; - if (size() < 1) - { - return false; - } - - // NOTE: Keep these vectors fixed-size, they replace an (non-standard, sized at runtime) arrays. - std::vector min_x(size(), std::numeric_limits::max()); - std::vector crossings(size()); - - for (size_t poly_idx = 0; poly_idx < size(); poly_idx++) - { - PolygonRef poly = thiss[poly_idx]; - Point2LL p0 = poly.back(); - for (Point2LL& p1 : poly) - { - short comp = LinearAlg2D::pointLiesOnTheRightOfLine(p, p0, p1); - if (comp == 1) - { - crossings[poly_idx]++; - int64_t x; - if (p1.Y == p0.Y) - { - x = p0.X; - } - else - { - x = p0.X + (p1.X - p0.X) * (p.Y - p0.Y) / (p1.Y - p0.Y); - } - if (x < min_x[poly_idx]) - { - min_x[poly_idx] = x; - } - } - else if (border_result && comp == 0) - { - return poly_idx; - } - p0 = p1; + const bool p2_is_left_of_v13 = dot2 > 0; + if (p2_is_left_of_v13) + { // l0123 doesn't constitute a zigzag ''|,, + return false; } - } - - int64_t min_x_uneven = std::numeric_limits::max(); - size_t ret = NO_INDEX; - size_t n_unevens = 0; - for (size_t array_idx = 0; array_idx < size(); array_idx++) - { - if (crossings[array_idx] % 2 == 1) - { - n_unevens++; - if (min_x[array_idx] < min_x_uneven) - { - min_x_uneven = min_x[array_idx]; - ret = array_idx; - } + if (-dot1 <= v02_size * v12_size / 2) + { // angle at p1 isn't sharp enough + return false; } - } - if (n_unevens % 2 == 0) + if (-dot2 <= v13_size * v12_size / 2) + { // angle at p2 isn't sharp enough + return false; + } + return true; + }; + Point2LL v02 = (*this)[2] - (*this)[0]; + Point2LL v02T = turn90CCW(v02); + int64_t v02_size = vSize(v02); + bool force_push = false; + for (unsigned int poly_idx = 1; poly_idx < size(); poly_idx++) { - ret = NO_INDEX; - } - return ret; -} - -Polygons Polygons::intersectionPolyLines(const Polygons& polylines, bool restitch, const coord_t max_stitch_distance) const -{ - Polygons split_polylines = polylines.splitPolylinesIntoSegments(); - - ClipperLib::PolyTree result; - ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(split_polylines.paths, ClipperLib::ptSubject, false); - clipper.AddPaths(paths, ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctIntersection, result); - Polygons ret; - ClipperLib::OpenPathsFromPolyTree(result, ret.paths); + const Point2LL& p1 = (*this)[poly_idx]; + const Point2LL& p2 = (*this)[(poly_idx + 1) % size()]; + const Point2LL& p3 = (*this)[(poly_idx + 2) % size()]; + // v02 computed in last iteration + // v02_size as well + const Point2LL v12 = p2 - p1; + const int64_t v12_size = vSize(v12); + const Point2LL v13 = p3 - p1; + const int64_t v13_size = vSize(v13); - if (restitch) - { - Polygons result_lines, result_polygons; - const coord_t snap_distance = 10_mu; - PolylineStitcher::stitch(ret, result_lines, result_polygons, max_stitch_distance, snap_distance); - ret = result_lines; - // if polylines got stitched into polygons, split them back up into a polyline again, because the result only admits polylines - for (PolygonRef poly : result_polygons) + // v02T computed in last iteration + const int64_t dot1 = dot(v02T, v12); + const Point2LL v13T = turn90CCW(v13); + const int64_t dot2 = dot(v13T, v12); + bool push_point = force_push || ! is_zigzag(v02_size, v12_size, v13_size, dot1, dot2); + force_push = false; + if (push_point) { - if (poly.empty()) - continue; - if (poly.size() > 2) - { - poly.emplace_back(poly[0]); - } - ret.add(poly); + result.push_back(p1); } + else + { + // do not add the current one to the result + force_push = true; // ensure the next point is added; it cannot also be a zigzag + } + v02T = v13T; + v02 = v13; + v02_size = v13_size; } - - return ret; -} - -void Polygons::toPolylines() -{ - for (PolygonRef poly : *this) - { - if (poly.empty()) - continue; - poly.emplace_back(poly.front()); - } -} - -void Polygons::splitPolylinesIntoSegments(Polygons& result) const -{ - for (ConstPolygonRef poly : *this) - { - poly.splitPolylineIntoSegments(result); - } -} -Polygons Polygons::splitPolylinesIntoSegments() const -{ - Polygons ret; - splitPolylinesIntoSegments(ret); - return ret; -} - -void Polygons::splitPolygonsIntoSegments(Polygons& result) const -{ - for (ConstPolygonRef poly : *this) - { - poly.splitPolygonIntoSegments(result); - } -} -Polygons Polygons::splitPolygonsIntoSegments() const -{ - Polygons ret; - splitPolygonsIntoSegments(ret); - return ret; -} - -coord_t Polygons::polyLineLength() const -{ - coord_t length = 0; - for (ConstPolygonRef poly : *this) - { - length += poly.polylineLength(); - } - return length; -} - -Polygons Polygons::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const -{ - if (distance == 0) - { - return *this; - } - Polygons ret; - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - clipper.AddPaths(unionPolygons().paths, join_type, ClipperLib::etClosedPolygon); - clipper.MiterLimit = miter_limit; - clipper.Execute(ret.paths, distance); - return ret; } -Polygons Polygons::offset(const std::vector& offset_dists) const +void Polygon::smooth_outward(const AngleDegrees min_angle, int shortcut_length, Polygon& result) const { - // we need as many offset-dists as points - assert(this->pointCount() == offset_dists.size()); + // example of smoothed out corner: + // + // 6 + // ^ + // | + // inside | outside + // 2>3>4>5 + // ^ / . + // | / . + // 1 / . + // ^ / . + // |/ . + // | + // | + // 0 - Polygons ret; - int i = 0; - for (auto& poly_line : this->paths - | ranges::views::filter( - [](const auto& path) - { - return ! path.empty(); - })) - { - std::vector ret_poly_line; + int shortcut_length2 = shortcut_length * shortcut_length; + double cos_min_angle = cos(min_angle / 180 * std::numbers::pi); - auto prev_p = poly_line.back(); - auto prev_dist = offset_dists[i + poly_line.size() - 1]; + ListPolygon poly; + ListPolyIt::convertPolygonToList(*this, poly); - for (const auto& p : poly_line) + { // remove duplicate vertices + ListPolyIt p1_it(poly, poly.begin()); + do { - auto offset_dist = offset_dists[i]; - - auto vec_dir = prev_p - p; - - constexpr coord_t min_vec_len = 10; - if (vSize2(vec_dir) > min_vec_len * min_vec_len) + ListPolyIt next = p1_it.next(); + if (vSize2(p1_it.p() - next.p()) < 10 * 10) { - auto offset_p1 = turn90CCW(normal(vec_dir, prev_dist)); - auto offset_p2 = turn90CCW(normal(vec_dir, offset_dist)); - - ret_poly_line.emplace_back(prev_p + offset_p1); - ret_poly_line.emplace_back(p + offset_p2); + p1_it.remove(); } - - prev_p = p; - prev_dist = offset_dist; - i++; - } - - ret.add(ret_poly_line); + p1_it = next; + } while (p1_it != ListPolyIt(poly, poly.begin())); } - ClipperLib::SimplifyPolygons(ret.paths, ClipperLib::PolyFillType::pftPositive); - - return ret; -} - -Polygons ConstPolygonRef::offset(int distance, ClipperLib::JoinType join_type, double miter_limit) const -{ - if (distance == 0) - { - Polygons ret; - ret.add(*this); - return ret; - } - Polygons ret; - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - clipper.AddPath(*path, join_type, ClipperLib::etClosedPolygon); - clipper.MiterLimit = miter_limit; - clipper.Execute(ret.paths, distance); - return ret; -} - -void PolygonRef::removeColinearEdges(const AngleRadians max_deviation_angle) -{ - // TODO: Can be made more efficient (for example, use pointer-types for process-/skip-indices, so we can swap them without copy). - - size_t num_removed_in_iteration = 0; - do - { - num_removed_in_iteration = 0; - - std::vector process_indices(path->size(), true); - - bool go = true; - while (go) - { - go = false; - - const auto& rpath = *path; - const size_t pathlen = rpath.size(); - if (pathlen <= 3) - { - return; - } - - std::vector skip_indices(path->size(), false); - - ClipperLib::Path new_path; - for (size_t point_idx = 0; point_idx < pathlen; ++point_idx) - { - // Don't iterate directly over process-indices, but do it this way, because there are points _in_ process-indices that should nonetheless be skipped: - if (! process_indices[point_idx]) - { - new_path.push_back(rpath[point_idx]); - continue; - } - - // Should skip the last point for this iteration if the old first was removed (which can be seen from the fact that the new first was skipped): - if (point_idx == (pathlen - 1) && skip_indices[0]) - { - skip_indices[new_path.size()] = true; - go = true; - new_path.push_back(rpath[point_idx]); - break; - } - - const Point2LL& prev = rpath[(point_idx - 1 + pathlen) % pathlen]; - const Point2LL& pt = rpath[point_idx]; - const Point2LL& next = rpath[(point_idx + 1) % pathlen]; - - double angle = LinearAlg2D::getAngleLeft(prev, pt, next); // [0 : 2 * pi] - if (angle >= std::numbers::pi) - { - angle -= std::numbers::pi; - } // map [pi : 2 * pi] to [0 : pi] - - // Check if the angle is within limits for the point to 'make sense', given the maximum deviation. - // If the angle indicates near-parallel segments ignore the point 'pt' - if (angle > max_deviation_angle && angle < std::numbers::pi - max_deviation_angle) - { - new_path.push_back(pt); - } - else if (point_idx != (pathlen - 1)) - { - // Skip the next point, since the current one was removed: - skip_indices[new_path.size()] = true; - go = true; - new_path.push_back(next); - ++point_idx; - } - } - *path = new_path; - num_removed_in_iteration += pathlen - path->size(); - - process_indices.clear(); - process_indices.insert(process_indices.end(), skip_indices.begin(), skip_indices.end()); - } - } while (num_removed_in_iteration > 0); -} - -void PolygonRef::applyMatrix(const PointMatrix& matrix) -{ - for (unsigned int path_idx = 0; path_idx < path->size(); path_idx++) - { - (*path)[path_idx] = matrix.apply((*path)[path_idx]); - } -} -void PolygonRef::applyMatrix(const Point3Matrix& matrix) -{ - for (unsigned int path_idx = 0; path_idx < path->size(); path_idx++) - { - (*path)[path_idx] = matrix.apply((*path)[path_idx]); - } -} - -Polygons Polygons::getOutsidePolygons() const -{ - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree poly_tree; - constexpr bool paths_are_closed_polys = true; - clipper.AddPaths(paths, ClipperLib::ptSubject, paths_are_closed_polys); - clipper.Execute(ClipperLib::ctUnion, poly_tree); - - for (int outer_poly_idx = 0; outer_poly_idx < poly_tree.ChildCount(); outer_poly_idx++) - { - ClipperLib::PolyNode* child = poly_tree.Childs[outer_poly_idx]; - ret.emplace_back(child->Contour); - } - return ret; -} - -Polygons Polygons::removeEmptyHoles() const -{ - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree poly_tree; - constexpr bool paths_are_closed_polys = true; - clipper.AddPaths(paths, ClipperLib::ptSubject, paths_are_closed_polys); - clipper.Execute(ClipperLib::ctUnion, poly_tree); - - bool remove_holes = true; - removeEmptyHoles_processPolyTreeNode(poly_tree, remove_holes, ret); - return ret; -} - -Polygons Polygons::getEmptyHoles() const -{ - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree poly_tree; - constexpr bool paths_are_closed_polys = true; - clipper.AddPaths(paths, ClipperLib::ptSubject, paths_are_closed_polys); - clipper.Execute(ClipperLib::ctUnion, poly_tree); - - bool remove_holes = false; - removeEmptyHoles_processPolyTreeNode(poly_tree, remove_holes, ret); - return ret; -} - -void Polygons::removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Polygons& ret) const -{ - for (int outer_poly_idx = 0; outer_poly_idx < node.ChildCount(); outer_poly_idx++) - { - ClipperLib::PolyNode* child = node.Childs[outer_poly_idx]; - if (remove_holes) - { - ret.emplace_back(child->Contour); - } - for (int hole_node_idx = 0; hole_node_idx < child->ChildCount(); hole_node_idx++) - { - ClipperLib::PolyNode& hole_node = *child->Childs[hole_node_idx]; - if ((hole_node.ChildCount() > 0) == remove_holes) - { - ret.emplace_back(hole_node.Contour); - removeEmptyHoles_processPolyTreeNode(hole_node, remove_holes, ret); - } - } - } -} - -void Polygons::removeSmallAreas(const double min_area_size, const bool remove_holes) -{ - auto new_end = paths.end(); - if (remove_holes) - { - for (auto it = paths.begin(); it < new_end;) - { - // All polygons smaller than target are removed by replacing them with a polygon from the back of the vector - if (std::abs(INT2MM2(ClipperLib::Area(*it))) < min_area_size) - { - *it = std::move(*--new_end); - continue; - } - it++; // Skipped on removal such that the polygon just swaped in is checked next - } - } - else - { - // For each polygon, computes the signed area, move small outlines at the end of the vector and keep references on small holes - std::vector small_holes; - for (auto it = paths.begin(); it < new_end;) - { - double area = INT2MM2(ClipperLib::Area(*it)); - if (std::abs(area) < min_area_size) - { - if (area >= 0) - { - --new_end; - if (it < new_end) - { - std::swap(*new_end, *it); - continue; - } - else - { // Don't self-swap the last Path - break; - } - } - else - { - small_holes.push_back(*it); - } - } - it++; // Skipped on removal such that the polygon just swaped in is checked next - } - - // Removes small holes that have their first point inside one of the removed outlines - // Iterating in reverse ensures that unprocessed small holes won't be moved - const auto removed_outlines_start = new_end; - for (auto hole_it = small_holes.rbegin(); hole_it < small_holes.rend(); hole_it++) - { - for (auto outline_it = removed_outlines_start; outline_it < paths.end(); outline_it++) - { - if (PolygonRef(*outline_it).inside(*hole_it->begin())) - { - **hole_it = std::move(*--new_end); - break; - } - } - } - } - paths.resize(new_end - paths.begin()); -} - -void Polygons::removeSmallCircumference(const coord_t min_circumference_size, const bool remove_holes) -{ - removeSmallAreaCircumference(0.0, min_circumference_size, remove_holes); -} - -void Polygons::removeSmallAreaCircumference(const double min_area_size, const coord_t min_circumference_size, const bool remove_holes) -{ - Polygons new_polygon; - - bool outline_is_removed = false; - for (ConstPolygonRef poly : paths) - { - double area = poly.area(); - auto circumference = poly.polygonLength(); - bool is_outline = area >= 0; - - if (is_outline) - { - if (circumference >= min_circumference_size && std::abs(area) >= min_area_size) - { - new_polygon.add(poly); - outline_is_removed = false; - } - else - { - outline_is_removed = true; - } - } - else if (outline_is_removed) - { - // containing parent outline is removed; hole should be removed as well - } - else if (! remove_holes || (circumference >= min_circumference_size && std::abs(area) >= min_area_size)) - { - // keep hole-polygon if we do not remove holes, or if its - // circumference is bigger then the minimum circumference size - new_polygon.add(poly); - } - } - - *this = new_polygon; -} - -void Polygons::removeDegenerateVerts() -{ - _removeDegenerateVerts(false); -} - -void Polygons::removeDegenerateVertsPolyline() -{ - _removeDegenerateVerts(true); -} - -void Polygons::_removeDegenerateVerts(const bool for_polyline) -{ - Polygons& thiss = *this; - for (size_t poly_idx = 0; poly_idx < size(); poly_idx++) - { - PolygonRef poly = thiss[poly_idx]; - Polygon result; - - auto isDegenerate = [](const Point2LL& last, const Point2LL& now, const Point2LL& next) - { - Point2LL last_line = now - last; - Point2LL next_line = next - now; - return dot(last_line, next_line) == -1 * vSize(last_line) * vSize(next_line); - }; - - // With polylines, skip the first and last vertex. - const size_t start_vertex = for_polyline ? 1 : 0; - const size_t end_vertex = for_polyline ? poly.size() - 1 : poly.size(); - for (size_t i = 0; i < start_vertex; ++i) - { - result.add(poly[i]); // Add everything before the start vertex. - } - - bool isChanged = false; - for (size_t idx = start_vertex; idx < end_vertex; idx++) - { - const Point2LL& last = (result.size() == 0) ? poly.back() : result.back(); - if (idx + 1 >= poly.size() && result.size() == 0) - { - break; - } - const Point2LL& next = (idx + 1 >= poly.size()) ? result[0] : poly[idx + 1]; - if (isDegenerate(last, poly[idx], next)) - { // lines are in the opposite direction - // don't add vert to the result - isChanged = true; - while (result.size() > 1 && isDegenerate(result[result.size() - 2], result.back(), next)) - { - result.pop_back(); - } - } - else - { - result.add(poly[idx]); - } - } - - for (size_t i = end_vertex; i < poly.size(); ++i) - { - result.add(poly[i]); // Add everything after the end vertex. - } - - if (isChanged) - { - if (for_polyline || result.size() > 2) - { - *poly = *result; - } - else - { - thiss.remove(poly_idx); - poly_idx--; // effectively the next iteration has the same poly_idx (referring to a new poly which is not yet processed) - } - } - } -} - -Polygons Polygons::toPolygons(ClipperLib::PolyTree& poly_tree) -{ - Polygons ret; - ClipperLib::PolyTreeToPaths(poly_tree, ret.paths); - return ret; -} - -[[maybe_unused]] Polygons Polygons::fromWkt(const std::string& wkt) -{ - typedef boost::geometry::model::d2::point_xy point_type; - typedef boost::geometry::model::polygon polygon_type; - - polygon_type poly; - boost::geometry::read_wkt(wkt, poly); - - Polygons ret; - - Polygon outer; - for (const auto& point : poly.outer()) - { - outer.add(Point2LL(point.x(), point.y())); - } - ret.add(outer); - - for (const auto& hole : poly.inners()) - { - Polygon inner; - for (const auto& point : hole) - { - inner.add(Point2LL(point.x(), point.y())); - } - ret.add(inner); - } - - return ret; -} - -[[maybe_unused]] void Polygons::writeWkt(std::ostream& stream) const -{ - stream << "POLYGON ("; - const auto paths_str = paths - | ranges::views::transform( - [](const auto& path) - { - const auto line_string = ranges::views::concat(path, path | ranges::views::take(1)) - | ranges::views::transform( - [](const auto& point) - { - return fmt::format("{} {}", point.X, point.Y); - }) - | ranges::views::join(ranges::views::c_str(", ")) | ranges::to(); - return "(" + line_string + ")"; - }) - | ranges::views::join(ranges::views::c_str(", ")) | ranges::to(); - stream << paths_str; - stream << ")"; -} - -bool ConstPolygonRef::smooth_corner_complex(const Point2LL p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length) -{ - // walk away from the corner until the shortcut > shortcut_length or it would smooth a piece inward - // - walk in both directions untill shortcut > shortcut_length - // - stop walking in one direction if it would otherwise cut off a corner in that direction - // - same in the other direction - // - stop if both are cut off - // walk by updating p0_it and p2_it - int64_t shortcut_length2 = shortcut_length * shortcut_length; - bool forward_is_blocked = false; - bool forward_is_too_far = false; - bool backward_is_blocked = false; - bool backward_is_too_far = false; - while (true) - { - const bool forward_has_converged = forward_is_blocked || forward_is_too_far; - const bool backward_has_converged = backward_is_blocked || backward_is_too_far; - if (forward_has_converged && backward_has_converged) - { - if (forward_is_too_far && backward_is_too_far && vSize2(p0_it.prev().p() - p2_it.next().p()) < shortcut_length2) - { - // o - // / \ . - // o o - // | | - // \ / . - // | | - // \ / . - // | | - // o o - --p0_it; - ++p2_it; - forward_is_too_far = false; // invalidate data - backward_is_too_far = false; // invalidate data - continue; - } - else - { - break; - } - } - smooth_outward_step(p1, shortcut_length2, p0_it, p2_it, forward_is_blocked, backward_is_blocked, forward_is_too_far, backward_is_too_far); - if (p0_it.prev() == p2_it || p0_it == p2_it) - { // stop if we went all the way around the polygon - // this should only be the case for hole polygons (?) - if (forward_is_too_far && backward_is_too_far) - { - // in case p0_it.prev() == p2_it : - // / . - // / /| - // | becomes | | - // \ \| - // \ . - // in case p0_it == p2_it : - // / . - // / becomes /| - // \ \| - // \ . - break; - } - else - { - // this whole polygon can be removed - return true; - } - } - } - - const Point2LL v02 = p2_it.p() - p0_it.p(); - const int64_t v02_size2 = vSize2(v02); - // set the following: - // p0_it = start point of line - // p2_it = end point of line - if (std::abs(v02_size2 - shortcut_length2) < shortcut_length * 10) // i.e. if (size2 < l * (l+10) && size2 > l * (l-10)) - { // v02 is approximately shortcut length - // handle this separately to avoid rounding problems below in the getPointOnLineWithDist function - // p0_it and p2_it are already correct - } - else if (! backward_is_blocked && ! forward_is_blocked) - { // introduce two new points - // 1----b---->2 - // ^ / - // | / - // | / - // |/ - // |a - // | - // 0 - const int64_t v02_size = sqrt(v02_size2); - - const ListPolyIt p0_2_it = p0_it.prev(); - const ListPolyIt p2_2_it = p2_it.next(); - const Point2LL p2_2 = p2_2_it.p(); - const Point2LL p0_2 = p0_2_it.p(); - const Point2LL v02_2 = p0_2 - p2_2; - const int64_t v02_2_size = vSize(v02_2); - double progress - = std::min(1.0, INT2MM(shortcut_length - v02_size) / INT2MM(v02_2_size - v02_size)); // account for rounding error when v02_2_size is approx equal to v02_size - assert(progress >= 0.0f && progress <= 1.0f && "shortcut length must be between last length and new length"); - const Point2LL new_p0 = p0_it.p() + (p0_2 - p0_it.p()) * progress; - p0_it = ListPolyIt::insertPointNonDuplicate(p0_2_it, p0_it, new_p0); - const Point2LL new_p2 = p2_it.p() + (p2_2 - p2_it.p()) * progress; - p2_it = ListPolyIt::insertPointNonDuplicate(p2_it, p2_2_it, new_p2); - } - else if (! backward_is_blocked) - { // forward is blocked, back is open - // | - // 1->b - // ^ : - // | / - // 0 : - // |/ - // |a - // | - // 0_2 - const ListPolyIt p0_2_it = p0_it.prev(); - const Point2LL p0 = p0_it.p(); - const Point2LL p0_2 = p0_2_it.p(); - const Point2LL p2 = p2_it.p(); - Point2LL new_p0; - bool success = LinearAlg2D::getPointOnLineWithDist(p2, p0, p0_2, shortcut_length, new_p0); - // shortcut length must be possible given that last length was ok and new length is too long - if (success) - { -#ifdef ASSERT_INSANE_OUTPUT - assert(new_p0.X < 400000 && new_p0.Y < 400000); -#endif // #ifdef ASSERT_INSANE_OUTPUT - p0_it = ListPolyIt::insertPointNonDuplicate(p0_2_it, p0_it, new_p0); - } - else - { // if not then a rounding error occured - if (vSize(p2 - p0_2) < vSize2(p2 - p0)) - { - p0_it = p0_2_it; // start shortcut at 0 - } - } - } - else if (! forward_is_blocked) - { // backward is blocked, front is open - // 1----2----b----------->2_2 - // ^ ,-' - // | ,-' - //--0.-' - // a - const ListPolyIt p2_2_it = p2_it.next(); - const Point2LL p0 = p0_it.p(); - const Point2LL p2 = p2_it.p(); - const Point2LL p2_2 = p2_2_it.p(); - Point2LL new_p2; - bool success = LinearAlg2D::getPointOnLineWithDist(p0, p2, p2_2, shortcut_length, new_p2); - // shortcut length must be possible given that last length was ok and new length is too long - if (success) - { -#ifdef ASSERT_INSANE_OUTPUT - assert(new_p2.X < 400000 && new_p2.Y < 400000); -#endif // #ifdef ASSERT_INSANE_OUTPUT - p2_it = ListPolyIt::insertPointNonDuplicate(p2_it, p2_2_it, new_p2); - } - else - { // if not then a rounding error occured - if (vSize(p2_2 - p0) < vSize2(p2 - p0)) - { - p2_it = p2_2_it; // start shortcut at 0 - } - } - } - else - { - // | - // __|2 - // | / > shortcut cannot be of the desired length - // ___|/ . - // 0 - // both are blocked and p0_it and p2_it are already correct - } - // delete all cut off points - while (p0_it.next() != p2_it) - { - p0_it.next().remove(); - } - return false; -} - -void ConstPolygonRef::smooth_outward_step( - const Point2LL p1, - const int64_t shortcut_length2, - ListPolyIt& p0_it, - ListPolyIt& p2_it, - bool& forward_is_blocked, - bool& backward_is_blocked, - bool& forward_is_too_far, - bool& backward_is_too_far) -{ - const bool forward_has_converged = forward_is_blocked || forward_is_too_far; - const bool backward_has_converged = backward_is_blocked || backward_is_too_far; - const Point2LL p0 = p0_it.p(); - const Point2LL p2 = p2_it.p(); - bool walk_forward - = ! forward_has_converged && (backward_has_converged || (vSize2(p2 - p1) < vSize2(p0 - p1))); // whether to walk along the p1-p2 direction or in the p1-p0 direction - - if (walk_forward) - { - const ListPolyIt p2_2_it = p2_it.next(); - const Point2LL p2_2 = p2_2_it.p(); - bool p2_is_left = LinearAlg2D::pointIsLeftOfLine(p2, p0, p2_2) >= 0; - if (! p2_is_left) - { - forward_is_blocked = true; - return; - } - - const Point2LL v02_2 = p2_2 - p0_it.p(); - if (vSize2(v02_2) > shortcut_length2) - { - forward_is_too_far = true; - return; - } - - p2_it = p2_2_it; // make one step in the forward direction - backward_is_blocked = false; // invalidate data about backward walking - backward_is_too_far = false; - return; - } - else + ListPolyIt p1_it(poly, poly.begin()); + do { - const ListPolyIt p0_2_it = p0_it.prev(); - const Point2LL p0_2 = p0_2_it.p(); - bool p0_is_left = LinearAlg2D::pointIsLeftOfLine(p0, p0_2, p2) >= 0; - if (! p0_is_left) + const Point2LL p1 = p1_it.p(); + ListPolyIt p0_it = p1_it.prev(); + ListPolyIt p2_it = p1_it.next(); + const Point2LL p0 = p0_it.p(); + const Point2LL p2 = p2_it.p(); + + const Point2LL v10 = p0 - p1; + const Point2LL v12 = p2 - p1; + double cos_angle = INT2MM(INT2MM(dot(v10, v12))) / vSizeMM(v10) / vSizeMM(v12); + bool is_left_angle = LinearAlg2D::pointIsLeftOfLine(p1, p0, p2) > 0; + if (cos_angle > cos_min_angle && is_left_angle) { - backward_is_blocked = true; - return; + // angle is so sharp that it can be removed + Point2LL v02 = p2_it.p() - p0_it.p(); + if (vSize2(v02) >= shortcut_length2) + { + smooth_corner_simple(p0, p1, p2, p0_it, p1_it, p2_it, v10, v12, v02, shortcut_length, cos_angle); + } + else + { + bool remove_poly = smooth_corner_complex(p1, p0_it, p2_it, shortcut_length); // edits p0_it and p2_it! + if (remove_poly) + { + // don't convert ListPolygon into result + return; + } + } + // update: + p1_it = p2_it; // next point to consider for whether it's an internal corner } - - const Point2LL v02_2 = p2_it.p() - p0_2; - if (vSize2(v02_2) > shortcut_length2) + else { - backward_is_too_far = true; - return; + ++p1_it; } + } while (p1_it != ListPolyIt(poly, poly.begin())); - p0_it = p0_2_it; // make one step in the backward direction - forward_is_blocked = false; // invalidate data about forward walking - forward_is_too_far = false; - return; - } + ListPolyIt::convertListPolygonToPolygon(poly, result); } -void ConstPolygonRef::smooth_corner_simple( +void Polygon::smooth_corner_simple( const Point2LL p0, const Point2LL p1, const Point2LL p2, @@ -1210,493 +326,356 @@ void ConstPolygonRef::smooth_corner_simple( } } -void ConstPolygonRef::smooth_outward(const AngleDegrees min_angle, int shortcut_length, PolygonRef result) const +void Polygon::smooth_outward_step( + const Point2LL p1, + const int64_t shortcut_length2, + ListPolyIt& p0_it, + ListPolyIt& p2_it, + bool& forward_is_blocked, + bool& backward_is_blocked, + bool& forward_is_too_far, + bool& backward_is_too_far) { - // example of smoothed out corner: - // - // 6 - // ^ - // | - // inside | outside - // 2>3>4>5 - // ^ / . - // | / . - // 1 / . - // ^ / . - // |/ . - // | - // | - // 0 - - int shortcut_length2 = shortcut_length * shortcut_length; - double cos_min_angle = cos(min_angle / 180 * std::numbers::pi); - - ListPolygon poly; - ListPolyIt::convertPolygonToList(*this, poly); - - { // remove duplicate vertices - ListPolyIt p1_it(poly, poly.begin()); - do - { - ListPolyIt next = p1_it.next(); - if (vSize2(p1_it.p() - next.p()) < 10 * 10) - { - p1_it.remove(); - } - p1_it = next; - } while (p1_it != ListPolyIt(poly, poly.begin())); - } - - ListPolyIt p1_it(poly, poly.begin()); - do - { - const Point2LL p1 = p1_it.p(); - ListPolyIt p0_it = p1_it.prev(); - ListPolyIt p2_it = p1_it.next(); - const Point2LL p0 = p0_it.p(); - const Point2LL p2 = p2_it.p(); - - const Point2LL v10 = p0 - p1; - const Point2LL v12 = p2 - p1; - double cos_angle = INT2MM(INT2MM(dot(v10, v12))) / vSizeMM(v10) / vSizeMM(v12); - bool is_left_angle = LinearAlg2D::pointIsLeftOfLine(p1, p0, p2) > 0; - if (cos_angle > cos_min_angle && is_left_angle) - { - // angle is so sharp that it can be removed - Point2LL v02 = p2_it.p() - p0_it.p(); - if (vSize2(v02) >= shortcut_length2) - { - smooth_corner_simple(p0, p1, p2, p0_it, p1_it, p2_it, v10, v12, v02, shortcut_length, cos_angle); - } - else - { - bool remove_poly = smooth_corner_complex(p1, p0_it, p2_it, shortcut_length); // edits p0_it and p2_it! - if (remove_poly) - { - // don't convert ListPolygon into result - return; - } - } - // update: - p1_it = p2_it; // next point to consider for whether it's an internal corner - } - else - { - ++p1_it; - } - } while (p1_it != ListPolyIt(poly, poly.begin())); - - ListPolyIt::convertListPolygonToPolygon(poly, result); -} + const bool forward_has_converged = forward_is_blocked || forward_is_too_far; + const bool backward_has_converged = backward_is_blocked || backward_is_too_far; + const Point2LL p0 = p0_it.p(); + const Point2LL p2 = p2_it.p(); + bool walk_forward + = ! forward_has_converged && (backward_has_converged || (vSize2(p2 - p1) < vSize2(p0 - p1))); // whether to walk along the p1-p2 direction or in the p1-p0 direction -Polygons Polygons::smooth_outward(const AngleDegrees max_angle, int shortcut_length) -{ - Polygons ret; - for (unsigned int p = 0; p < size(); p++) + if (walk_forward) { - PolygonRef poly(paths[p]); - if (poly.size() < 3) - { - continue; - } - if (poly.size() == 3) - { - ret.add(poly); - continue; - } - poly.smooth_outward(max_angle, shortcut_length, ret.newPoly()); - if (ret.back().size() < 3) + const ListPolyIt p2_2_it = p2_it.next(); + const Point2LL p2_2 = p2_2_it.p(); + bool p2_is_left = LinearAlg2D::pointIsLeftOfLine(p2, p0, p2_2) >= 0; + if (! p2_is_left) { - ret.paths.resize(ret.paths.size() - 1); - } - } - return ret; -} - - -void ConstPolygonRef::splitPolylineIntoSegments(Polygons& result) const -{ - Point2LL last = front(); - for (size_t idx = 1; idx < size(); idx++) - { - Point2LL p = (*this)[idx]; - result.addLine(last, p); - last = p; - } -} - -Polygons ConstPolygonRef::splitPolylineIntoSegments() const -{ - Polygons ret; - splitPolylineIntoSegments(ret); - return ret; -} - -void ConstPolygonRef::splitPolygonIntoSegments(Polygons& result) const -{ - splitPolylineIntoSegments(result); - result.addLine(back(), front()); -} - -Polygons ConstPolygonRef::splitPolygonIntoSegments() const -{ - Polygons ret; - splitPolygonIntoSegments(ret); - return ret; -} - -void ConstPolygonRef::smooth(int remove_length, PolygonRef result) const -{ - // a typical zigzag with the middle part to be removed by removing (1) : - // - // 3 - // ^ - // | - // | - // inside | outside - // 1--->2 - // ^ - // | - // | - // | - // 0 - const ConstPolygonRef& thiss = *path; - ClipperLib::Path* poly = result.path; - if (size() > 0) - { - poly->push_back(thiss[0]); - } - auto is_zigzag = [remove_length](const int64_t v02_size, const int64_t v12_size, const int64_t v13_size, const int64_t dot1, const int64_t dot2) - { - if (v12_size > remove_length) - { // v12 or v13 is too long - return false; - } - const bool p1_is_left_of_v02 = dot1 < 0; - if (! p1_is_left_of_v02) - { // removing p1 wouldn't smooth outward - return false; - } - const bool p2_is_left_of_v13 = dot2 > 0; - if (p2_is_left_of_v13) - { // l0123 doesn't constitute a zigzag ''|,, - return false; - } - if (-dot1 <= v02_size * v12_size / 2) - { // angle at p1 isn't sharp enough - return false; - } - if (-dot2 <= v13_size * v12_size / 2) - { // angle at p2 isn't sharp enough - return false; + forward_is_blocked = true; + return; } - return true; - }; - Point2LL v02 = thiss[2] - thiss[0]; - Point2LL v02T = turn90CCW(v02); - int64_t v02_size = vSize(v02); - bool force_push = false; - for (unsigned int poly_idx = 1; poly_idx < size(); poly_idx++) - { - const Point2LL& p1 = thiss[poly_idx]; - const Point2LL& p2 = thiss[(poly_idx + 1) % size()]; - const Point2LL& p3 = thiss[(poly_idx + 2) % size()]; - // v02 computed in last iteration - // v02_size as well - const Point2LL v12 = p2 - p1; - const int64_t v12_size = vSize(v12); - const Point2LL v13 = p3 - p1; - const int64_t v13_size = vSize(v13); - // v02T computed in last iteration - const int64_t dot1 = dot(v02T, v12); - const Point2LL v13T = turn90CCW(v13); - const int64_t dot2 = dot(v13T, v12); - bool push_point = force_push || ! is_zigzag(v02_size, v12_size, v13_size, dot1, dot2); - force_push = false; - if (push_point) - { - poly->push_back(p1); - } - else + const Point2LL v02_2 = p2_2 - p0_it.p(); + if (vSize2(v02_2) > shortcut_length2) { - // do not add the current one to the result - force_push = true; // ensure the next point is added; it cannot also be a zigzag + forward_is_too_far = true; + return; } - v02T = v13T; - v02 = v13; - v02_size = v13_size; - } -} -Polygons Polygons::smooth(int remove_length) const -{ - Polygons ret; - for (unsigned int p = 0; p < size(); p++) + p2_it = p2_2_it; // make one step in the forward direction + backward_is_blocked = false; // invalidate data about backward walking + backward_is_too_far = false; + return; + } + else { - ConstPolygonRef poly(paths[p]); - if (poly.size() < 3) - { - continue; - } - if (poly.size() == 3) + const ListPolyIt p0_2_it = p0_it.prev(); + const Point2LL p0_2 = p0_2_it.p(); + bool p0_is_left = LinearAlg2D::pointIsLeftOfLine(p0, p0_2, p2) >= 0; + if (! p0_is_left) { - ret.add(poly); - continue; + backward_is_blocked = true; + return; } - poly.smooth(remove_length, ret.newPoly()); - PolygonRef back = ret.back(); - if (back.size() < 3) + + const Point2LL v02_2 = p2_it.p() - p0_2; + if (vSize2(v02_2) > shortcut_length2) { - back.path->resize(back.path->size() - 1); + backward_is_too_far = true; + return; } + + p0_it = p0_2_it; // make one step in the backward direction + forward_is_blocked = false; // invalidate data about forward walking + forward_is_too_far = false; + return; } - return ret; } -void ConstPolygonRef::smooth2(int remove_length, PolygonRef result) const +bool Polygon::smooth_corner_complex(const Point2LL p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length) { - const ConstPolygonRef& thiss = *this; - ClipperLib::Path* poly = result.path; - if (thiss.size() > 0) - { - poly->push_back(thiss[0]); - } - for (unsigned int poly_idx = 1; poly_idx < thiss.size(); poly_idx++) + // walk away from the corner until the shortcut > shortcut_length or it would smooth a piece inward + // - walk in both directions untill shortcut > shortcut_length + // - stop walking in one direction if it would otherwise cut off a corner in that direction + // - same in the other direction + // - stop if both are cut off + // walk by updating p0_it and p2_it + int64_t shortcut_length2 = shortcut_length * shortcut_length; + bool forward_is_blocked = false; + bool forward_is_too_far = false; + bool backward_is_blocked = false; + bool backward_is_too_far = false; + while (true) { - const Point2LL& last = thiss[poly_idx - 1]; - const Point2LL& now = thiss[poly_idx]; - const Point2LL& next = thiss[(poly_idx + 1) % thiss.size()]; - if (shorterThen(last - now, remove_length) && shorterThen(now - next, remove_length)) + const bool forward_has_converged = forward_is_blocked || forward_is_too_far; + const bool backward_has_converged = backward_is_blocked || backward_is_too_far; + if (forward_has_converged && backward_has_converged) { - poly_idx++; // skip the next line piece (dont escalate the removal of edges) - if (poly_idx < thiss.size()) + if (forward_is_too_far && backward_is_too_far && vSize2(p0_it.prev().p() - p2_it.next().p()) < shortcut_length2) + { + // o + // / \ . + // o o + // | | + // \ / . + // | | + // \ / . + // | | + // o o + --p0_it; + ++p2_it; + forward_is_too_far = false; // invalidate data + backward_is_too_far = false; // invalidate data + continue; + } + else { - poly->push_back(thiss[poly_idx]); + break; } } - else - { - poly->push_back(thiss[poly_idx]); + smooth_outward_step(p1, shortcut_length2, p0_it, p2_it, forward_is_blocked, backward_is_blocked, forward_is_too_far, backward_is_too_far); + if (p0_it.prev() == p2_it || p0_it == p2_it) + { // stop if we went all the way around the polygon + // this should only be the case for hole polygons (?) + if (forward_is_too_far && backward_is_too_far) + { + // in case p0_it.prev() == p2_it : + // / . + // / /| + // | becomes | | + // \ \| + // \ . + // in case p0_it == p2_it : + // / . + // / becomes /| + // \ \| + // \ . + break; + } + else + { + // this whole polygon can be removed + return true; + } } } -} -Polygons Polygons::smooth2(int remove_length, int min_area) const -{ - Polygons ret; - for (unsigned int p = 0; p < size(); p++) - { - ConstPolygonRef poly(paths[p]); - if (poly.size() == 0) + const Point2LL v02 = p2_it.p() - p0_it.p(); + const int64_t v02_size2 = vSize2(v02); + // set the following: + // p0_it = start point of line + // p2_it = end point of line + if (std::abs(v02_size2 - shortcut_length2) < shortcut_length * 10) // i.e. if (size2 < l * (l+10) && size2 > l * (l-10)) + { // v02 is approximately shortcut length + // handle this separately to avoid rounding problems below in the getPointOnLineWithDist function + // p0_it and p2_it are already correct + } + else if (! backward_is_blocked && ! forward_is_blocked) + { // introduce two new points + // 1----b---->2 + // ^ / + // | / + // | / + // |/ + // |a + // | + // 0 + const int64_t v02_size = sqrt(v02_size2); + + const ListPolyIt p0_2_it = p0_it.prev(); + const ListPolyIt p2_2_it = p2_it.next(); + const Point2LL p2_2 = p2_2_it.p(); + const Point2LL p0_2 = p0_2_it.p(); + const Point2LL v02_2 = p0_2 - p2_2; + const int64_t v02_2_size = vSize(v02_2); + double progress + = std::min(1.0, INT2MM(shortcut_length - v02_size) / INT2MM(v02_2_size - v02_size)); // account for rounding error when v02_2_size is approx equal to v02_size + assert(progress >= 0.0f && progress <= 1.0f && "shortcut length must be between last length and new length"); + const Point2LL new_p0 = p0_it.p() + (p0_2 - p0_it.p()) * progress; + p0_it = ListPolyIt::insertPointNonDuplicate(p0_2_it, p0_it, new_p0); + const Point2LL new_p2 = p2_it.p() + (p2_2 - p2_it.p()) * progress; + p2_it = ListPolyIt::insertPointNonDuplicate(p2_it, p2_2_it, new_p2); + } + else if (! backward_is_blocked) + { // forward is blocked, back is open + // | + // 1->b + // ^ : + // | / + // 0 : + // |/ + // |a + // | + // 0_2 + const ListPolyIt p0_2_it = p0_it.prev(); + const Point2LL p0 = p0_it.p(); + const Point2LL p0_2 = p0_2_it.p(); + const Point2LL p2 = p2_it.p(); + Point2LL new_p0; + bool success = LinearAlg2D::getPointOnLineWithDist(p2, p0, p0_2, shortcut_length, new_p0); + // shortcut length must be possible given that last length was ok and new length is too long + if (success) { - continue; +#ifdef ASSERT_INSANE_OUTPUT + assert(new_p0.X < 400000 && new_p0.Y < 400000); +#endif // #ifdef ASSERT_INSANE_OUTPUT + p0_it = ListPolyIt::insertPointNonDuplicate(p0_2_it, p0_it, new_p0); } - if (poly.area() < min_area || poly.size() <= 5) // when optimally removing, a poly with 5 pieces results in a triangle. Smaller polys dont have area! - { - ret.add(poly); - continue; + else + { // if not then a rounding error occured + if (vSize(p2 - p0_2) < vSize2(p2 - p0)) + { + p0_it = p0_2_it; // start shortcut at 0 + } } - if (poly.size() < 4) + } + else if (! forward_is_blocked) + { // backward is blocked, front is open + // 1----2----b----------->2_2 + // ^ ,-' + // | ,-' + //--0.-' + // a + const ListPolyIt p2_2_it = p2_it.next(); + const Point2LL p0 = p0_it.p(); + const Point2LL p2 = p2_it.p(); + const Point2LL p2_2 = p2_2_it.p(); + Point2LL new_p2; + bool success = LinearAlg2D::getPointOnLineWithDist(p0, p2, p2_2, shortcut_length, new_p2); + // shortcut length must be possible given that last length was ok and new length is too long + if (success) { - ret.add(poly); +#ifdef ASSERT_INSANE_OUTPUT + assert(new_p2.X < 400000 && new_p2.Y < 400000); +#endif // #ifdef ASSERT_INSANE_OUTPUT + p2_it = ListPolyIt::insertPointNonDuplicate(p2_it, p2_2_it, new_p2); } else - { - poly.smooth2(remove_length, ret.newPoly()); + { // if not then a rounding error occured + if (vSize(p2_2 - p0) < vSize2(p2 - p0)) + { + p2_it = p2_2_it; // start shortcut at 0 + } } } - return ret; -} - -double Polygons::area() const -{ - double area = 0.0; - for (unsigned int poly_idx = 0; poly_idx < size(); poly_idx++) + else + { + // | + // __|2 + // | / > shortcut cannot be of the desired length + // ___|/ . + // 0 + // both are blocked and p0_it and p2_it are already correct + } + // delete all cut off points + while (p0_it.next() != p2_it) { - area += operator[](poly_idx).area(); - // note: holes already have negative area + p0_it.next().remove(); } - return area; -} - -std::vector Polygons::splitIntoParts(bool unionAll) const -{ - std::vector ret; - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree resultPolyTree; - clipper.AddPaths(paths, ClipperLib::ptSubject, true); - if (unionAll) - clipper.Execute(ClipperLib::ctUnion, resultPolyTree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - else - clipper.Execute(ClipperLib::ctUnion, resultPolyTree); - - splitIntoParts_processPolyTreeNode(&resultPolyTree, ret); - return ret; + return false; } -void Polygons::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const +Point2LL Polygon::centerOfMass() const { - for (int n = 0; n < node->ChildCount(); n++) + if (size() > 0) { - ClipperLib::PolyNode* child = node->Childs[n]; - PolygonsPart part; - part.add(child->Contour); - for (int i = 0; i < child->ChildCount(); i++) + Point2LL p0 = (*this)[0]; + if (size() > 1) { - part.add(child->Childs[i]->Contour); - splitIntoParts_processPolyTreeNode(child->Childs[i], ret); - } - ret.push_back(part); - } -} + double x = 0, y = 0; + for (size_t n = 1; n <= size(); n++) + { + Point2LL p1 = (*this)[n % size()]; + double second_factor = static_cast((p0.X * p1.Y) - (p1.X * p0.Y)); -std::vector Polygons::sortByNesting() const -{ - std::vector ret; - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree resultPolyTree; - clipper.AddPaths(paths, ClipperLib::ptSubject, true); - clipper.Execute(ClipperLib::ctUnion, resultPolyTree); + x += double(p0.X + p1.X) * second_factor; + y += double(p0.Y + p1.Y) * second_factor; + p0 = p1; + } - sortByNesting_processPolyTreeNode(&resultPolyTree, 0, ret); - return ret; -} + double current_area = area(); -void Polygons::sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const -{ - for (int n = 0; n < node->ChildCount(); n++) - { - ClipperLib::PolyNode* child = node->Childs[n]; - if (nesting_idx >= ret.size()) + x = x / 6 / current_area; + y = y / 6 / current_area; + + return Point2LL(std::llrint(x), std::llrint(y)); + } + else { - ret.resize(nesting_idx + 1); + return p0; } - ret[nesting_idx].add(child->Contour); - sortByNesting_processPolyTreeNode(child, nesting_idx + 1, ret); + } + else + { + return Point2LL(); } } -Polygons Polygons::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const +Polygons Polygon::offset(int distance, ClipperLib::JoinType join_type, double miter_limit) const { - return this->offset(outer_offset).difference(this->offset(-inner_offset)); + if (distance == 0) + { + return Polygons({ *this }); + } + Polygons ret; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + clipper.AddPath(*this, join_type, ClipperLib::etClosedPolygon); + clipper.MiterLimit = miter_limit; + clipper.Execute(ret.getCallable(), distance); + return ret; } -size_t PartsView::getPartContaining(size_t poly_idx, size_t* boundary_poly_idx) const +void PointsSet::applyMatrix(const PointMatrix& matrix) { - const PartsView& partsView = *this; - for (size_t part_idx_now = 0; part_idx_now < partsView.size(); part_idx_now++) + for (point_t& point : (*this)) { - const std::vector& partView = partsView[part_idx_now]; - if (partView.size() == 0) - { - continue; - } - std::vector::const_iterator result = std::find(partView.begin(), partView.end(), poly_idx); - if (result != partView.end()) - { - if (boundary_poly_idx) - { - *boundary_poly_idx = partView[0]; - } - return part_idx_now; - } + point = matrix.apply(point); } - return NO_INDEX; } -PolygonsPart PartsView::assemblePart(size_t part_idx) const +void PointsSet::applyMatrix(const Point3Matrix& matrix) { - const PartsView& partsView = *this; - PolygonsPart ret; - if (part_idx != NO_INDEX) + for (point_t& point : (*this)) { - for (size_t poly_idx_ff : partsView[part_idx]) - { - ret.add(polygons_[poly_idx_ff]); - } + point = matrix.apply(point); } - return ret; } -PolygonsPart PartsView::assemblePartContaining(size_t poly_idx, size_t* boundary_poly_idx) const +Point2LL PointsSet::min() const { - PolygonsPart ret; - size_t part_idx = getPartContaining(poly_idx, boundary_poly_idx); - if (part_idx != NO_INDEX) + Point2LL ret = Point2LL(POINT_MAX, POINT_MAX); + for (Point2LL p : *this) { - return assemblePart(part_idx); + ret.X = std::min(ret.X, p.X); + ret.Y = std::min(ret.Y, p.Y); } return ret; } -PartsView Polygons::splitIntoPartsView(bool unionAll) -{ - Polygons reordered; - PartsView partsView(*this); - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree resultPolyTree; - clipper.AddPaths(paths, ClipperLib::ptSubject, true); - if (unionAll) - clipper.Execute(ClipperLib::ctUnion, resultPolyTree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - else - clipper.Execute(ClipperLib::ctUnion, resultPolyTree); - - splitIntoPartsView_processPolyTreeNode(partsView, reordered, &resultPolyTree); - - (*this) = reordered; - return partsView; -} - -void Polygons::splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Polygons& reordered, ClipperLib::PolyNode* node) const +Point2LL PointsSet::max() const { - for (int n = 0; n < node->ChildCount(); n++) + Point2LL ret = Point2LL(POINT_MIN, POINT_MIN); + for (Point2LL p : *this) { - ClipperLib::PolyNode* child = node->Childs[n]; - partsView.emplace_back(); - size_t pos = partsView.size() - 1; - partsView[pos].push_back(reordered.size()); - reordered.add(child->Contour); // TODO: should this steal the internal representation for speed? - for (int i = 0; i < child->ChildCount(); i++) - { - partsView[pos].push_back(reordered.size()); - reordered.add(child->Childs[i]->Contour); - splitIntoPartsView_processPolyTreeNode(partsView, reordered, child->Childs[i]); - } + ret.X = std::max(ret.X, p.X); + ret.Y = std::max(ret.Y, p.Y); } + return ret; } -void Polygons::ensureManifold() +Point2LL PointsSet::closestPointTo(Point2LL p) const { - const Polygons& polys = *this; - std::vector duplicate_locations; - std::unordered_set poly_locations; - for (size_t poly_idx = 0; poly_idx < polys.size(); poly_idx++) + Point2LL ret = p; + double bestDist = std::numeric_limits::max(); + for (size_t n = 0; n < size(); n++) { - ConstPolygonRef poly = polys[poly_idx]; - for (size_t point_idx = 0; point_idx < poly.size(); point_idx++) + double dist = vSize2f(p - (*this)[n]); + if (dist < bestDist) { - Point2LL p = poly[point_idx]; - if (poly_locations.find(p) != poly_locations.end()) - { - duplicate_locations.push_back(p); - } - poly_locations.emplace(p); + ret = (*this)[n]; + bestDist = dist; } } - Polygons removal_dots; - for (Point2LL p : duplicate_locations) - { - PolygonRef dot = removal_dots.newPoly(); - dot.add(p + Point2LL(0, 5)); - dot.add(p + Point2LL(5, 0)); - dot.add(p + Point2LL(0, -5)); - dot.add(p + Point2LL(-5, 0)); - } - if (! removal_dots.empty()) - { - *this = polys.difference(removal_dots); - } + return ret; } } // namespace cura diff --git a/src/utils/polygons.cpp b/src/utils/polygons.cpp new file mode 100644 index 0000000000..76887a48a9 --- /dev/null +++ b/src/utils/polygons.cpp @@ -0,0 +1,1258 @@ +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#include "utils/polygons.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils/OpenPolylineStitcher.h" + +namespace cura +{ + +Polygons Polygon::intersection(const Polygon& other) const +{ + Polygons ret; + ClipperLib::Clipper clipper(clipper_init); + clipper.AddPath(*this, ClipperLib::ptSubject, true); + clipper.AddPath(other, ClipperLib::ptClip, true); + clipper.Execute(ClipperLib::ctIntersection, ret.getCallable()); + return ret; +} + +Polygons Polygons::approxConvexHull(int extra_outset) const +{ + constexpr int overshoot = MM2INT(100); // 10cm (hard-coded value). + + Polygons convex_hull; + // Perform the offset for each polygon one at a time. + // This is necessary because the polygons may overlap, in which case the offset could end up in an infinite loop. + // See http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperOffset/_Body.htm + for (const path_t& path : (*this)) + { + Polygons offset_result; + ClipperLib::ClipperOffset offsetter(1.2, 10.0); + offsetter.AddPath(path, ClipperLib::jtRound, ClipperLib::etClosedPolygon); + offsetter.Execute(offset_result.getCallable(), overshoot); + convex_hull.add(offset_result); + } + + return convex_hull.unionPolygons().offset(-overshoot + extra_outset, ClipperLib::jtRound); +} + +void Polygons::makeConvex() +{ + // early out if there is nothing to do + if (empty()) + { + return; + } + + // Andrew’s Monotone Chain Convex Hull Algorithm + std::vector points; + for (const path_t& poly : (*this)) + { + points.insert(points.end(), poly.begin(), poly.end()); + } + + Polygon convexified; + auto make_sorted_poly_convex = [&convexified](std::vector& poly) + { + convexified.push_back(poly[0]); + + for (const auto window : poly | ranges::views::sliding(2)) + { + const point_t& current = window[0]; + const point_t& after = window[1]; + + if (LinearAlg2D::pointIsLeftOfLine(current, convexified.back(), after) < 0) + { + // Track backwards to make sure we haven't been in a concave pocket for multiple vertices already. + while (convexified.size() >= 2 + && (LinearAlg2D::pointIsLeftOfLine(convexified.back(), convexified[convexified.size() - 2], current) >= 0 + || LinearAlg2D::pointIsLeftOfLine(convexified.back(), convexified[convexified.size() - 2], convexified.front()) > 0)) + { + convexified.pop_back(); + } + convexified.push_back(current); + } + } + }; + + std::sort( + points.begin(), + points.end(), + [](point_t a, point_t b) + { + return a.X == b.X ? a.Y < b.Y : a.X < b.X; + }); + make_sorted_poly_convex(points); + std::reverse(points.begin(), points.end()); + make_sorted_poly_convex(points); + + *this = { convexified }; +} + +Polygons Polygons::difference(const Polygons& other) const +{ + Polygons ret; + ClipperLib::Clipper clipper(clipper_init); + clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); + clipper.AddPaths(other.getCallable(), ClipperLib::ptClip, true); + clipper.Execute(ClipperLib::ctDifference, ret.getCallable()); + return ret; +} + +Polygons Polygons::unionPolygons(const Polygons& other, ClipperLib::PolyFillType fill_type) const +{ + Polygons ret; + ClipperLib::Clipper clipper(clipper_init); + clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); + clipper.AddPaths(other.getCallable(), ClipperLib::ptSubject, true); + clipper.Execute(ClipperLib::ctUnion, ret.getCallable(), fill_type, fill_type); + return ret; +} + +Polygons Polygons::intersection(const Polygons& other) const +{ + Polygons ret; + ClipperLib::Clipper clipper(clipper_init); + clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); + clipper.AddPaths(other.getCallable(), ClipperLib::ptClip, true); + clipper.Execute(ClipperLib::ctIntersection, ret.getCallable()); + return ret; +} + +Polygons& Polygons::operator=(Polygons&& polygons) +{ + if (this != &polygons) + { + (*this) = std::move(polygons); + } + return *this; +} + +size_t Polygons::pointCount() const +{ + return std::accumulate( + begin(), + end(), + size_t(0), + [](size_t total, const Polygon& polygon) + { + return total + polygon.size(); + }); +} + +void Polygons::remove(size_t index) +{ + if (size() == 1) + { + clear(); + } + else if (size() > 1) + { + POLY_ASSERT(index < size()); + if (index < size() - 1) + { + (*this)[index] = std::move(back()); + } + resize(size() - 1); + } +} + +void Polygons::add(const Polygons& other) +{ + std::copy(other.begin(), other.end(), std::back_inserter(*this)); +} + +void Polygons::addIfNotEmpty(const Polygon& polygon) +{ + if (! polygon.empty()) + { + push_back(polygon); + } +} + +void Polygons::addIfNotEmpty(Polygon&& polygon) +{ + if (! polygon.empty()) + { + emplace_back(std::move(polygon)); + } +} + +void Polygons::addLine(const point_t& from, const point_t& to) +{ + emplace_back(Polygon{ from, to }); +} + +Polygon& Polygons::newPoly() +{ + emplace_back(); + return back(); +} + +bool Polygons::inside(Point2LL p, bool border_result) const +{ + int poly_count_inside = 0; + for (const ClipperLib::Path& poly : *this) + { + const int is_inside_this_poly = ClipperLib::PointInPolygon(p, poly); + if (is_inside_this_poly == -1) + { + return border_result; + } + poly_count_inside += is_inside_this_poly; + } + return (poly_count_inside % 2) == 1; +} + +bool PolygonsPart::inside(Point2LL p, bool border_result) const +{ + if (size() < 1) + { + return false; + } + + if (! (*this)[0].inside(p, border_result)) + { + return false; + } + + for (unsigned int n = 1; n < size(); n++) + { + if ((*this)[n].inside(p, border_result)) + { + return false; + } + } + return true; +} + +bool Polygons::insideOld(Point2LL p, bool border_result) const +{ + const Polygons& thiss = *this; + if (size() < 1) + { + return false; + } + + int crossings = 0; + for (const ClipperLib::Path& poly : thiss) + { + Point2LL p0 = poly.back(); + for (const Point2LL& p1 : poly) + { + short comp = LinearAlg2D::pointLiesOnTheRightOfLine(p, p0, p1); + if (comp == 1) + { + crossings++; + } + else if (comp == 0) + { + return border_result; + } + p0 = p1; + } + } + return (crossings % 2) == 1; +} + +size_t Polygons::findInside(Point2LL p, bool border_result) const +{ + if (size() < 1) + { + return false; + } + + // NOTE: Keep these vectors fixed-size, they replace an (non-standard, sized at runtime) arrays. + std::vector min_x(size(), std::numeric_limits::max()); + std::vector crossings(size()); + + for (size_t poly_idx = 0; poly_idx < size(); poly_idx++) + { + const Polygon poly = (*this)[poly_idx]; + Point2LL p0 = poly.back(); + for (const Point2LL& p1 : poly) + { + short comp = LinearAlg2D::pointLiesOnTheRightOfLine(p, p0, p1); + if (comp == 1) + { + crossings[poly_idx]++; + int64_t x; + if (p1.Y == p0.Y) + { + x = p0.X; + } + else + { + x = p0.X + (p1.X - p0.X) * (p.Y - p0.Y) / (p1.Y - p0.Y); + } + if (x < min_x[poly_idx]) + { + min_x[poly_idx] = x; + } + } + else if (border_result && comp == 0) + { + return poly_idx; + } + p0 = p1; + } + } + + int64_t min_x_uneven = std::numeric_limits::max(); + size_t ret = NO_INDEX; + size_t n_unevens = 0; + for (size_t array_idx = 0; array_idx < size(); array_idx++) + { + if (crossings[array_idx] % 2 == 1) + { + n_unevens++; + if (min_x[array_idx] < min_x_uneven) + { + min_x_uneven = min_x[array_idx]; + ret = array_idx; + } + } + } + if (n_unevens % 2 == 0) + { + ret = NO_INDEX; + } + return ret; +} + +std::vector Polygons::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const +{ + LinesSet split_polylines = polylines.splitIntoSegments(); + + ClipperLib::PolyTree result; + ClipperLib::Clipper clipper(clipper_init); + clipper.AddPaths(split_polylines.getCallable(), ClipperLib::ptSubject, false); + clipper.AddPaths(getCallable(), ClipperLib::ptClip, true); + clipper.Execute(ClipperLib::ctIntersection, result); + LinesSet ret; + ClipperLib::OpenPathsFromPolyTree(result, ret.getCallable()); + + if (restitch) + { + std::vector result_lines; + Polygons result_polygons; + const coord_t snap_distance = 10_mu; + OpenPolylineStitcher::stitch(ret, result_lines, result_polygons, max_stitch_distance, snap_distance); + ret = std::move(result_lines); + // if polylines got stitched into polygons, split them back up into a polyline again, because the result only admits polylines + for (const Polygon& poly : result_polygons) + { + if (! poly.empty()) + { + ret.push_back(poly); + } + } + } + + return ret; +} + +Polygons Polygons::xorPolygons(const Polygons& other, ClipperLib::PolyFillType pft) const +{ + Polygons ret; + ClipperLib::Clipper clipper(clipper_init); + clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); + clipper.AddPaths(other.getCallable(), ClipperLib::ptClip, true); + clipper.Execute(ClipperLib::ctXor, ret.getCallable(), pft); + return ret; +} + +Polygons Polygons::execute(ClipperLib::PolyFillType pft) const +{ + Polygons ret; + ClipperLib::Clipper clipper(clipper_init); + clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); + clipper.Execute(ClipperLib::ctXor, ret.getCallable(), pft); + return ret; +} +/* +void Polygons::toPolylines() +{ + for (PolygonRef poly : *this) + { + if (poly.empty()) + continue; + poly.emplace_back(poly.front()); + } +} + +void Polygons::splitPolylinesIntoSegments(Polygons& result) const +{ +for (ConstPolygonRef poly : *this) +{ + poly.splitPolylineIntoSegments(result); + } +} +Polygons Polygons::splitPolylinesIntoSegments() const +{ + Polygons ret; + splitPolylinesIntoSegments(ret); + return ret; +} + +void Polygons::splitPolygonsIntoSegments(Polygons& result) const +{ + for (ConstPolygonRef poly : *this) + { + poly.splitPolygonIntoSegments(result); + } +} +Polygons Polygons::splitPolygonsIntoSegments() const +{ + Polygons ret; + splitPolygonsIntoSegments(ret); + return ret; +} + +coord_t Polygons::polyLineLength() const +{ + coord_t length = 0; + for (ConstPolygonRef poly : *this) + { + length += poly.polylineLength(); + } + return length; +} +*/ + +template +Polygons LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const +{ + if (distance == 0) + { + return Polygons(getCallable()); + } + + Polygons temp; + const paths_t* actual_polygons = &getCallable(); + Polygons ret; + ClipperLib::EndType end_type; + if constexpr (LineType::shape_type_ == ShapeType::Filled) + { + temp = Polygons(getCallable()).unionPolygons(); + actual_polygons = &temp.getCallable(); + end_type = ClipperLib::etClosedPolygon; + } + else if constexpr (LineType::shape_type_ == ShapeType::Closed) + { + end_type = ClipperLib::etClosedLine; + } + else if (joinType == ClipperLib::jtMiter) + { + end_type = ClipperLib::etOpenSquare; + } + else + { + end_type = ClipperLib::etOpenRound; + } + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + clipper.AddPaths(*actual_polygons, joinType, end_type); + clipper.MiterLimit = miter_limit; + clipper.Execute(ret.getCallable(), distance); + return ret; +} +/* +Polygons Polygons::offset(const std::vector& offset_dists) const +{ + // we need as many offset-dists as points + assert(pointCount() == offset_dists.size()); + + Polygons ret; + size_t i = 0; + for (const path_t& poly_line : (*this) + | ranges::views::filter( + [](const path_t& path) + { + return ! path.empty(); + })) + { + Polygon ret_poly_line; + + auto prev_p = poly_line.back(); + auto prev_dist = offset_dists[i + poly_line.size() - 1]; + + for (const point_t& p : poly_line) + { + auto offset_dist = offset_dists[i]; + + auto vec_dir = prev_p - p; + + constexpr coord_t min_vec_len = 10; + if (vSize2(vec_dir) > min_vec_len * min_vec_len) + { + auto offset_p1 = turn90CCW(normal(vec_dir, prev_dist)); + auto offset_p2 = turn90CCW(normal(vec_dir, offset_dist)); + + ret_poly_line.emplace_back(prev_p + offset_p1); + ret_poly_line.emplace_back(p + offset_p2); + } + + prev_p = p; + prev_dist = offset_dist; + i++; + } + + ret.push_back(ret_poly_line); + } + + ClipperLib::SimplifyPolygons(ret.getCallable(), ClipperLib::PolyFillType::pftPositive); + + return ret; +} +*/ +Polygons Polygons::getOutsidePolygons() const +{ + Polygons ret; + ClipperLib::Clipper clipper(clipper_init); + ClipperLib::PolyTree poly_tree; + constexpr bool paths_are_closed_polys = true; + clipper.AddPaths(getCallable(), ClipperLib::ptSubject, paths_are_closed_polys); + clipper.Execute(ClipperLib::ctUnion, poly_tree); + + for (int outer_poly_idx = 0; outer_poly_idx < poly_tree.ChildCount(); outer_poly_idx++) + { + ClipperLib::PolyNode* child = poly_tree.Childs[outer_poly_idx]; + ret.emplace_back(child->Contour); + } + return ret; +} + +Polygons Polygons::removeEmptyHoles() const +{ + Polygons ret; + ClipperLib::Clipper clipper(clipper_init); + ClipperLib::PolyTree poly_tree; + constexpr bool paths_are_closed_polys = true; + clipper.AddPaths(getCallable(), ClipperLib::ptSubject, paths_are_closed_polys); + clipper.Execute(ClipperLib::ctUnion, poly_tree); + + bool remove_holes = true; + removeEmptyHoles_processPolyTreeNode(poly_tree, remove_holes, ret); + return ret; +} + +Polygons Polygons::getEmptyHoles() const +{ + Polygons ret; + ClipperLib::Clipper clipper(clipper_init); + ClipperLib::PolyTree poly_tree; + constexpr bool paths_are_closed_polys = true; + clipper.AddPaths(getCallable(), ClipperLib::ptSubject, paths_are_closed_polys); + clipper.Execute(ClipperLib::ctUnion, poly_tree); + + bool remove_holes = false; + removeEmptyHoles_processPolyTreeNode(poly_tree, remove_holes, ret); + return ret; +} + +void Polygons::removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Polygons& ret) const +{ + for (int outer_poly_idx = 0; outer_poly_idx < node.ChildCount(); outer_poly_idx++) + { + ClipperLib::PolyNode* child = node.Childs[outer_poly_idx]; + if (remove_holes) + { + ret.emplace_back(child->Contour); + } + for (int hole_node_idx = 0; hole_node_idx < child->ChildCount(); hole_node_idx++) + { + ClipperLib::PolyNode& hole_node = *child->Childs[hole_node_idx]; + if ((hole_node.ChildCount() > 0) == remove_holes) + { + ret.emplace_back(hole_node.Contour); + removeEmptyHoles_processPolyTreeNode(hole_node, remove_holes, ret); + } + } + } +} + +void Polygons::removeSmallAreas(const double min_area_size, const bool remove_holes) +{ + auto new_end = end(); + if (remove_holes) + { + for (auto it = begin(); it < new_end;) + { + // All polygons smaller than target are removed by replacing them with a polygon from the back of the vector + if (std::abs(INT2MM2(ClipperLib::Area(*it))) < min_area_size) + { + *it = std::move(*--new_end); + continue; + } + it++; // Skipped on removal such that the polygon just swaped in is checked next + } + } + else + { + // For each polygon, computes the signed area, move small outlines at the end of the vector and keep references on small holes + std::vector small_holes; + for (auto it = begin(); it < new_end;) + { + double area = INT2MM2(ClipperLib::Area(*it)); + if (std::abs(area) < min_area_size) + { + if (area >= 0) + { + --new_end; + if (it < new_end) + { + std::swap(*new_end, *it); + continue; + } + else + { // Don't self-swap the last Path + break; + } + } + else + { + small_holes.push_back(&(*it)); + } + } + it++; // Skipped on removal such that the polygon just swaped in is checked next + } + + // Removes small holes that have their first point inside one of the removed outlines + // Iterating in reverse ensures that unprocessed small holes won't be moved + const auto removed_outlines_start = new_end; + for (auto hole_it = small_holes.rbegin(); hole_it < small_holes.rend(); hole_it++) + { + for (auto outline_it = removed_outlines_start; outline_it < end(); outline_it++) + { + if (outline_it->inside((*hole_it)->front())) + { + **hole_it = std::move(*--new_end); + break; + } + } + } + } + resize(new_end - begin()); +} + +void Polygons::removeSmallCircumference(const coord_t min_circumference_size, const bool remove_holes) +{ + removeSmallAreaCircumference(0.0, min_circumference_size, remove_holes); +} + +void Polygons::removeSmallAreaCircumference(const double min_area_size, const coord_t min_circumference_size, const bool remove_holes) +{ + Polygons new_polygon; + + bool outline_is_removed = false; + for (const Polygon& poly : (*this)) + { + double area = poly.area(); + auto circumference = poly.length(); + bool is_outline = area >= 0; + + if (is_outline) + { + if (circumference >= min_circumference_size && std::abs(area) >= min_area_size) + { + new_polygon.push_back(poly); + outline_is_removed = false; + } + else + { + outline_is_removed = true; + } + } + else if (outline_is_removed) + { + // containing parent outline is removed; hole should be removed as well + } + else if (! remove_holes || (circumference >= min_circumference_size && std::abs(area) >= min_area_size)) + { + // keep hole-polygon if we do not remove holes, or if its + // circumference is bigger then the minimum circumference size + new_polygon.push_back(poly); + } + } + + *this = new_polygon; +} + +template +void LinesSet::removeDegenerateVertsForEveryone() +{ + constexpr bool for_polyline = LineType::shape_type_ == ShapeType::Open; + for (size_t poly_idx = 0; poly_idx < this->size(); poly_idx++) + { + Polygon& poly = (*this)[poly_idx]; + Polygon result; + + auto isDegenerate = [](const Point2LL& last, const Point2LL& now, const Point2LL& next) + { + Point2LL last_line = now - last; + Point2LL next_line = next - now; + return dot(last_line, next_line) == -1 * vSize(last_line) * vSize(next_line); + }; + + // With polylines, skip the first and last vertex. + const size_t start_vertex = for_polyline ? 1 : 0; + const size_t end_vertex = for_polyline ? poly.size() - 1 : poly.size(); + for (size_t i = 0; i < start_vertex; ++i) + { + result.push_back(poly[i]); // Add everything before the start vertex. + } + + bool isChanged = false; + for (size_t idx = start_vertex; idx < end_vertex; idx++) + { + const Point2LL& last = (result.size() == 0) ? poly.back() : result.back(); + if (idx + 1 >= poly.size() && result.size() == 0) + { + break; + } + const Point2LL& next = (idx + 1 >= poly.size()) ? result[0] : poly[idx + 1]; + if (isDegenerate(last, poly[idx], next)) + { // lines are in the opposite direction + // don't add vert to the result + isChanged = true; + while (result.size() > 1 && isDegenerate(result[result.size() - 2], result.back(), next)) + { + result.pop_back(); + } + } + else + { + result.push_back(poly[idx]); + } + } + + for (size_t i = end_vertex; i < poly.size(); ++i) + { + result.push_back(poly[i]); // Add everything after the end vertex. + } + + if (isChanged) + { + if (for_polyline || result.size() > 2) + { + poly = result; + } + else + { + remove(poly_idx); + poly_idx--; // effectively the next iteration has the same poly_idx (referring to a new poly which is not yet processed) + } + } + } +} + +Polygons Polygons::remove(const Polygons& to_be_removed, int same_distance) const +{ + Polygons result; + for (size_t poly_keep_idx = 0; poly_keep_idx < size(); poly_keep_idx++) + { + const Polygon& poly_keep = (*this)[poly_keep_idx]; + bool should_be_removed = false; + if (poly_keep.size() > 0) + // for (int hole_poly_idx = 0; hole_poly_idx < to_be_removed.size(); hole_poly_idx++) + for (const Polygon& poly_rem : to_be_removed) + { + // PolygonRef poly_rem = to_be_removed[hole_poly_idx]; + if (poly_rem.size() != poly_keep.size() || poly_rem.size() == 0) + continue; + + // find closest point, supposing this point aligns the two shapes in the best way + size_t closest_point_idx = 0; + coord_t smallestDist2 = -1; + for (size_t point_rem_idx = 0; point_rem_idx < poly_rem.size(); point_rem_idx++) + { + coord_t dist2 = vSize2(poly_rem[point_rem_idx] - poly_keep[0]); + if (dist2 < smallestDist2 || smallestDist2 < 0) + { + smallestDist2 = dist2; + closest_point_idx = point_rem_idx; + } + } + bool poly_rem_is_poly_keep = true; + // compare the two polygons on all points + if (smallestDist2 > same_distance * same_distance) + continue; + for (size_t point_idx = 0; point_idx < poly_rem.size(); point_idx++) + { + coord_t dist2 = vSize2(poly_rem[(closest_point_idx + point_idx) % poly_rem.size()] - poly_keep[point_idx]); + if (dist2 > same_distance * same_distance) + { + poly_rem_is_poly_keep = false; + break; + } + } + if (poly_rem_is_poly_keep) + { + should_be_removed = true; + break; + } + } + if (! should_be_removed) + result.push_back(poly_keep); + } + return result; +} + +Polygons Polygons::processEvenOdd(ClipperLib::PolyFillType poly_fill_type) const +{ + Polygons ret; + ClipperLib::Clipper clipper(clipper_init); + clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); + clipper.Execute(ClipperLib::ctUnion, ret.getCallable(), poly_fill_type); + return ret; +} + +Polygons Polygons::toPolygons(ClipperLib::PolyTree& poly_tree) +{ + Polygons ret; + ClipperLib::PolyTreeToPaths(poly_tree, ret.getCallable()); + return ret; +} + +[[maybe_unused]] Polygons Polygons::fromWkt(const std::string& wkt) +{ + typedef boost::geometry::model::d2::point_xy point_type; + typedef boost::geometry::model::polygon polygon_type; + + polygon_type poly; + boost::geometry::read_wkt(wkt, poly); + + Polygons ret; + + Polygon outer; + for (const auto& point : poly.outer()) + { + outer.push_back(point_t(point.x(), point.y())); + } + ret.push_back(outer); + + for (const auto& hole : poly.inners()) + { + Polygon inner; + for (const auto& point : hole) + { + inner.push_back(point_t(point.x(), point.y())); + } + ret.push_back(inner); + } + + return ret; +} + +[[maybe_unused]] void Polygons::writeWkt(std::ostream& stream) const +{ + stream << "POLYGON ("; + const auto paths_str = (*this) + | ranges::views::transform( + [](const auto& path) + { + const auto line_string = ranges::views::concat(path, path | ranges::views::take(1)) + | ranges::views::transform( + [](const auto& point) + { + return fmt::format("{} {}", point.X, point.Y); + }) + | ranges::views::join(ranges::views::c_str(", ")) | ranges::to(); + return "(" + line_string + ")"; + }) + | ranges::views::join(ranges::views::c_str(", ")) | ranges::to(); + stream << paths_str; + stream << ")"; +} + +Polygons Polygons::smooth_outward(const AngleDegrees max_angle, int shortcut_length) const +{ + Polygons ret; + for (const Polygon& poly : (*this)) + { + if (poly.size() < 3) + { + continue; + } + if (poly.size() == 3) + { + ret.push_back(poly); + continue; + } + poly.smooth_outward(max_angle, shortcut_length, ret.newPoly()); + if (ret.back().size() < 3) + { + ret.resize(ret.size() - 1); + } + } + return ret; +} + +Polygons Polygons::smooth(int remove_length) const +{ + Polygons ret; + for (const Polygon& poly : (*this)) + { + if (poly.size() < 3) + { + continue; + } + if (poly.size() == 3) + { + ret.push_back(poly); + continue; + } + poly.smooth(remove_length, ret.newPoly()); + Polygon& back = ret.back(); + if (back.size() < 3) + { + back.resize(back.size() - 1); + } + } + return ret; +} + +Polygons Polygons::smooth2(int remove_length, int min_area) const +{ + Polygons ret; + for (const Polygon& poly : (*this)) + { + if (poly.size() == 0) + { + continue; + } + if (poly.area() < min_area || poly.size() <= 5) // when optimally removing, a poly with 5 pieces results in a triangle. Smaller polys dont have area! + { + ret.push_back(poly); + continue; + } + if (poly.size() < 4) + { + ret.push_back(poly); + } + else + { + poly.smooth2(remove_length, ret.newPoly()); + } + } + return ret; +} + +void Polygons::removeColinearEdges(const AngleRadians max_deviation_angle) +{ + Polygons& thiss = *this; + for (size_t p = 0; p < size(); p++) + { + thiss[p].removeColinearEdges(max_deviation_angle); + if (thiss[p].size() < 3) + { + remove(p); + p--; + } + } +} + +void Polygons::scale(const Ratio& ratio) +{ + if (ratio == 1.) + { + return; + } + + for (auto& points : *this) + { + for (auto& pt : points) + { + pt = pt * static_cast(ratio); + } + } +} + +void Polygons::translate(const point_t& delta) +{ + if (delta.X != 0 || delta.Y != 0) + { + for (Polygon& polygon : *this) + { + polygon.translate(delta); + } + } +} + +double Polygons::area() const +{ + return std::accumulate( + begin(), + end(), + 0.0, + [](double total, const Polygon& poly) + { + return total + poly.area(); + }); + + double area = 0.0; + for (unsigned int poly_idx = 0; poly_idx < size(); poly_idx++) + { + area += operator[](poly_idx).area(); + // note: holes already have negative area + } + return area; +} + +std::vector Polygons::splitIntoParts(bool unionAll) const +{ + std::vector ret; + ClipperLib::Clipper clipper(clipper_init); + ClipperLib::PolyTree resultPolyTree; + clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); + if (unionAll) + clipper.Execute(ClipperLib::ctUnion, resultPolyTree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + else + clipper.Execute(ClipperLib::ctUnion, resultPolyTree); + + splitIntoParts_processPolyTreeNode(&resultPolyTree, ret); + return ret; +} + +void Polygons::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const +{ + for (int n = 0; n < node->ChildCount(); n++) + { + ClipperLib::PolyNode* child = node->Childs[n]; + PolygonsPart part; + part.emplace_back(child->Contour); + for (int i = 0; i < child->ChildCount(); i++) + { + part.emplace_back(child->Childs[i]->Contour); + splitIntoParts_processPolyTreeNode(child->Childs[i], ret); + } + ret.push_back(part); + } +} + +std::vector Polygons::sortByNesting() const +{ + std::vector ret; + ClipperLib::Clipper clipper(clipper_init); + ClipperLib::PolyTree resultPolyTree; + clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); + clipper.Execute(ClipperLib::ctUnion, resultPolyTree); + + sortByNesting_processPolyTreeNode(&resultPolyTree, 0, ret); + return ret; +} + +void Polygons::sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const +{ + for (int n = 0; n < node->ChildCount(); n++) + { + ClipperLib::PolyNode* child = node->Childs[n]; + if (nesting_idx >= ret.size()) + { + ret.resize(nesting_idx + 1); + } + ret[nesting_idx].emplace_back(child->Contour); + sortByNesting_processPolyTreeNode(child, nesting_idx + 1, ret); + } +} + +Polygons Polygons::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const +{ + return this->offset(outer_offset).difference(this->offset(-inner_offset)); +} + +size_t PartsView::getPartContaining(size_t poly_idx, size_t* boundary_poly_idx) const +{ + const PartsView& partsView = *this; + for (size_t part_idx_now = 0; part_idx_now < partsView.size(); part_idx_now++) + { + const std::vector& partView = partsView[part_idx_now]; + if (partView.size() == 0) + { + continue; + } + std::vector::const_iterator result = std::find(partView.begin(), partView.end(), poly_idx); + if (result != partView.end()) + { + if (boundary_poly_idx) + { + *boundary_poly_idx = partView[0]; + } + return part_idx_now; + } + } + return NO_INDEX; +} + +PolygonsPart PartsView::assemblePart(size_t part_idx) const +{ + const PartsView& partsView = *this; + PolygonsPart ret; + if (part_idx != NO_INDEX) + { + for (size_t poly_idx_ff : partsView[part_idx]) + { + ret.push_back(polygons_[poly_idx_ff]); + } + } + return ret; +} + +PolygonsPart PartsView::assemblePartContaining(size_t poly_idx, size_t* boundary_poly_idx) const +{ + PolygonsPart ret; + size_t part_idx = getPartContaining(poly_idx, boundary_poly_idx); + if (part_idx != NO_INDEX) + { + return assemblePart(part_idx); + } + return ret; +} + +PartsView Polygons::splitIntoPartsView(bool unionAll) +{ + Polygons reordered; + PartsView partsView(*this); + ClipperLib::Clipper clipper(clipper_init); + ClipperLib::PolyTree resultPolyTree; + clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); + if (unionAll) + clipper.Execute(ClipperLib::ctUnion, resultPolyTree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + else + clipper.Execute(ClipperLib::ctUnion, resultPolyTree); + + splitIntoPartsView_processPolyTreeNode(partsView, reordered, &resultPolyTree); + + (*this) = reordered; + return partsView; +} + +void Polygons::splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Polygons& reordered, ClipperLib::PolyNode* node) const +{ + for (int n = 0; n < node->ChildCount(); n++) + { + ClipperLib::PolyNode* child = node->Childs[n]; + partsView.emplace_back(); + size_t pos = partsView.size() - 1; + partsView[pos].push_back(reordered.size()); + reordered.emplace_back(child->Contour); // TODO: should this steal the internal representation for speed? + for (int i = 0; i < child->ChildCount(); i++) + { + partsView[pos].push_back(reordered.size()); + reordered.emplace_back(child->Childs[i]->Contour); + splitIntoPartsView_processPolyTreeNode(partsView, reordered, child->Childs[i]); + } + } +} + +void Polygons::ensureManifold() +{ + std::vector duplicate_locations; + std::unordered_set poly_locations; + for (const Polygon& poly : (*this)) + { + for (const point_t& p : poly) + { + if (poly_locations.find(p) != poly_locations.end()) + { + duplicate_locations.push_back(p); + } + poly_locations.emplace(p); + } + } + Polygons removal_dots; + for (Point2LL p : duplicate_locations) + { + Polygon& dot = removal_dots.newPoly(); + dot.push_back(p + Point2LL(0, 5)); + dot.push_back(p + Point2LL(5, 0)); + dot.push_back(p + Point2LL(0, -5)); + dot.push_back(p + Point2LL(-5, 0)); + } + if (! removal_dots.empty()) + { + *this = difference(removal_dots); + } +} + +coord_t Polygons::length() const +{ + return std::accumulate( + begin(), + end(), + 0, + [](coord_t total, const Polygon& polygon) + { + return total += polygon.length(); + }); +} + +point_t Polygons::min() const +{ + point_t ret = point_t(POINT_MAX, POINT_MAX); + + for (const Polygon& polygon : *this) + { + for (const point_t& p : polygon) + { + ret.X = std::min(ret.X, p.X); + ret.Y = std::min(ret.Y, p.Y); + } + } + + return ret; +} + +point_t Polygons::max() const +{ + point_t ret = point_t(POINT_MIN, POINT_MIN); + + for (const Polygon& polygon : *this) + { + for (const point_t& p : polygon) + { + ret.X = std::max(ret.X, p.X); + ret.Y = std::max(ret.Y, p.Y); + } + } + + return ret; +} + +void Polygons::applyMatrix(const PointMatrix& matrix) +{ + for (Polygon& polygon : *this) + { + polygon.applyMatrix(matrix); + } +} + +void Polygons::applyMatrix(const Point3Matrix& matrix) +{ + for (Polygon& polygon : *this) + { + polygon.applyMatrix(matrix); + } +} + +} // namespace cura From 5b8027acd4ba65a82382b731b4b2a0c95c9da798 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 16 Feb 2024 11:35:19 +0100 Subject: [PATCH 002/135] New geometric architecture, only builds --- CMakeLists.txt | 11 +- benchmark/wall_benchmark.h | 2 +- include/BeadingStrategy/BeadingStrategy.h | 2 +- include/BoostInterface.hpp | 4 +- include/ExtruderPlan.h | 2 +- include/InsetOrderOptimizer.h | 2 +- include/InterlockingGenerator.h | 3 +- include/LayerPlan.h | 28 +- include/PathOrderMonotonic.h | 2 +- include/PathOrderOptimizer.h | 6 +- include/PathOrdering.h | 4 +- include/PrimeTower.h | 4 +- include/SkeletalTrapezoidation.h | 2 +- include/SkeletalTrapezoidationJoint.h | 2 +- include/SupportInfillPart.h | 7 +- include/TopSurface.h | 2 +- include/TreeModelVolumes.h | 2 +- include/TreeSupport.h | 2 +- include/TreeSupportBaseCircle.h | 10 +- include/TreeSupportElement.h | 4 +- include/TreeSupportSettings.h | 2 + include/TreeSupportTipGenerator.h | 8 +- include/TreeSupportUtils.h | 64 +- include/WallToolPaths.h | 2 +- include/communication/ArcusCommunication.h | 4 +- include/communication/CommandLine.h | 2 +- include/communication/Communication.h | 6 +- include/gcodeExport.h | 2 +- include/geometry/closed_polyline.h | 16 + include/geometry/generic_closed_polyline.h | 98 +++ include/geometry/lines_set.h | 137 +++ include/geometry/open_polyline.h | 51 ++ include/geometry/parts_view.h | 58 ++ .../{utils/Point2LL.h => geometry/point2ll.h} | 203 +---- include/geometry/point3_matrix.h | 95 +++ .../{utils/Point3LL.h => geometry/point3ll.h} | 9 +- include/geometry/point_matrix.h | 84 ++ include/geometry/points_set.h | 86 ++ include/geometry/polygon.h | 183 ++++ include/{utils => geometry}/polygons.h | 269 +----- include/geometry/polyline.h | 130 +++ .../ShapeType.h => geometry/polyline_type.h} | 8 +- include/geometry/segment_iterator.h | 81 ++ include/geometry/single_shape.h | 38 + include/infill.h | 42 +- include/infill/GyroidInfill.h | 14 +- include/infill/LightningDistanceField.h | 2 +- include/infill/LightningLayer.h | 4 +- include/infill/LightningTreeNode.h | 9 +- include/infill/NoZigZagConnectorProcessor.h | 7 +- include/infill/SubDivCube.h | 18 +- include/infill/ZigzagConnectorProcessor.h | 46 +- include/pathPlanning/Comb.h | 18 +- include/pathPlanning/CombPath.h | 2 +- include/pathPlanning/GCodePath.h | 2 +- include/pathPlanning/LinePolygonsCrossings.h | 5 +- include/plugins/converters.h | 21 +- include/plugins/slots.h | 6 +- include/plugins/types.h | 4 +- include/settings/ZSeamConfig.h | 2 +- include/sliceDataStorage.h | 22 +- include/slicer.h | 23 +- include/support.h | 2 +- include/utils/AABB.h | 13 +- include/utils/AABB3D.h | 2 +- include/utils/ExtrusionJunction.h | 2 +- include/utils/ExtrusionLine.h | 15 +- include/utils/ExtrusionLineStitcher.h | 16 + include/utils/ExtrusionSegment.h | 4 +- include/utils/HalfEdge.h | 2 +- include/utils/HalfEdgeNode.h | 2 +- include/utils/ImplicitSharedDataContainer.h | 188 ++++ include/utils/ListPolyIt.h | 13 +- include/utils/MinimumSpanningTree.h | 2 +- include/utils/OpenPolylineStitcher.h | 18 + include/utils/Point3D.h | 2 +- include/utils/Point3F.h | 2 +- include/utils/PolygonConnector.h | 5 +- include/utils/PolygonsPointIndex.h | 16 +- include/utils/PolylineStitcher.h | 192 +---- include/utils/SVG.h | 10 +- include/utils/Simplify.h | 11 +- include/utils/SparseGrid.h | 2 +- include/utils/SparseLineGrid.h | 2 +- include/utils/SparsePointGrid.h | 2 +- include/utils/SparsePointGridInclusive.h | 2 +- include/utils/SquareGrid.h | 2 +- include/utils/ToolpathVisualizer.h | 2 +- include/utils/VoxelUtils.h | 4 +- include/utils/linearAlg2D.h | 44 +- include/utils/orderOptimizer.h | 2 +- include/utils/polygon.h | 803 ------------------ include/utils/polygonUtils.h | 97 +-- src/ConicalOverhang.cpp | 5 +- src/FffGcodeWriter.cpp | 77 +- src/FffPolygonGenerator.cpp | 25 +- src/GCodePathConfig.cpp | 2 +- src/InsetOrderOptimizer.cpp | 4 +- src/InterlockingGenerator.cpp | 7 +- src/LayerPlan.cpp | 98 +-- src/Mold.cpp | 5 +- src/PathOrderPath.cpp | 26 +- src/PrimeTower.cpp | 6 +- src/SkeletalTrapezoidation.cpp | 2 +- src/SkirtBrim.cpp | 37 +- src/SupportInfillPart.cpp | 2 +- src/TopSurface.cpp | 2 +- src/TreeModelVolumes.cpp | 2 +- src/TreeSupport.cpp | 14 +- src/TreeSupportTipGenerator.cpp | 63 +- src/WallToolPaths.cpp | 12 +- src/WallsComputation.cpp | 4 +- src/bridge.cpp | 21 +- src/communication/ArcusCommunication.cpp | 11 +- src/communication/CommandLine.cpp | 2 +- src/geometry/lines_set.cpp | 239 ++++++ src/geometry/parts_view.cpp | 59 ++ src/geometry/points_set.cpp | 90 ++ src/{utils => geometry}/polygon.cpp | 102 +-- src/{utils => geometry}/polygons.cpp | 412 +-------- src/geometry/polyline.cpp | 211 +++++ src/geometry/single_shape.cpp | 41 + src/infill.cpp | 103 ++- src/infill/GyroidInfill.cpp | 20 +- src/infill/LightningDistanceField.cpp | 2 +- src/infill/LightningLayer.cpp | 10 +- src/infill/LightningTreeNode.cpp | 21 +- src/infill/SierpinskiFill.cpp | 16 +- src/infill/SierpinskiFillProvider.cpp | 2 +- src/infill/SubDivCube.cpp | 18 +- src/infill/ZigzagConnectorProcessor.cpp | 24 +- src/layerPart.cpp | 10 +- src/multiVolumes.cpp | 19 +- src/pathPlanning/Comb.cpp | 40 +- src/pathPlanning/LinePolygonsCrossings.cpp | 6 +- src/plugins/converters.cpp | 28 +- src/settings/Settings.cpp | 6 +- src/skin.cpp | 2 +- src/sliceDataStorage.cpp | 20 +- src/slicer.cpp | 113 ++- src/support.cpp | 22 +- src/utils/AABB.cpp | 32 +- src/utils/ExtrusionLine.cpp | 2 +- src/utils/ExtrusionSegment.cpp | 8 +- src/utils/ListPolyIt.cpp | 9 +- src/utils/Matrix4x3D.cpp | 2 +- src/utils/Point3LL.cpp | 2 +- src/utils/PolygonConnector.cpp | 10 +- src/utils/PolygonsPointIndex.cpp | 13 +- src/utils/PolylineStitcher.cpp | 217 ++++- src/utils/SVG.cpp | 21 +- src/utils/Simplify.cpp | 32 +- src/utils/ToolpathVisualizer.cpp | 2 +- src/utils/VoronoiUtils.cpp | 1 + src/utils/VoxelUtils.cpp | 2 +- .../{LinearAlg2D.cpp => linearAlg2D.cpp} | 43 +- src/utils/polygonUtils.cpp | 237 +++--- stress_benchmark/stress_benchmark.cpp | 2 +- tests/ClipperTest.cpp | 2 +- tests/InfillTest.cpp | 93 +- tests/PathOrderMonotonicTest.cpp | 2 +- tests/ReadTestPolygons.h | 2 +- tests/WallsComputationTest.cpp | 4 +- tests/arcus/ArcusCommunicationTest.cpp | 2 +- tests/arcus/MockCommunication.h | 6 +- tests/integration/SlicePhaseTest.cpp | 2 +- tests/utils/AABB3DTest.cpp | 2 +- tests/utils/AABBTest.cpp | 2 +- tests/utils/IntPointTest.cpp | 2 +- tests/utils/PolygonConnectorTest.cpp | 2 +- tests/utils/PolygonTest.cpp | 45 +- tests/utils/PolygonUtilsTest.cpp | 34 +- tests/utils/SmoothTest.cpp | 4 +- tests/utils/StringTest.cpp | 2 +- 174 files changed, 3441 insertions(+), 2926 deletions(-) create mode 100644 include/geometry/closed_polyline.h create mode 100644 include/geometry/generic_closed_polyline.h create mode 100644 include/geometry/lines_set.h create mode 100644 include/geometry/open_polyline.h create mode 100644 include/geometry/parts_view.h rename include/{utils/Point2LL.h => geometry/point2ll.h} (60%) create mode 100644 include/geometry/point3_matrix.h rename include/{utils/Point3LL.h => geometry/point3ll.h} (97%) create mode 100644 include/geometry/point_matrix.h create mode 100644 include/geometry/points_set.h create mode 100644 include/geometry/polygon.h rename include/{utils => geometry}/polygons.h (55%) create mode 100644 include/geometry/polyline.h rename include/{utils/ShapeType.h => geometry/polyline_type.h} (60%) create mode 100644 include/geometry/segment_iterator.h create mode 100644 include/geometry/single_shape.h create mode 100644 include/utils/ExtrusionLineStitcher.h create mode 100644 include/utils/ImplicitSharedDataContainer.h create mode 100644 include/utils/OpenPolylineStitcher.h delete mode 100644 include/utils/polygon.h create mode 100644 src/geometry/lines_set.cpp create mode 100644 src/geometry/parts_view.cpp create mode 100644 src/geometry/points_set.cpp rename src/{utils => geometry}/polygon.cpp (92%) rename src/{utils => geometry}/polygons.cpp (72%) create mode 100644 src/geometry/polyline.cpp create mode 100644 src/geometry/single_shape.cpp rename src/utils/{LinearAlg2D.cpp => linearAlg2D.cpp} (81%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62dab2e03d..5c62445789 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,7 +133,7 @@ set(engine_SRCS # Except main.cpp. src/utils/ExtrusionLine.cpp src/utils/ExtrusionSegment.cpp src/utils/gettime.cpp - src/utils/LinearAlg2D.cpp + src/utils/linearAlg2D.cpp src/utils/ListPolyIt.cpp src/utils/Matrix4x3D.cpp src/utils/MinimumSpanningTree.cpp @@ -142,7 +142,6 @@ set(engine_SRCS # Except main.cpp. src/utils/PolygonsPointIndex.cpp src/utils/PolygonsSegmentIndex.cpp src/utils/polygonUtils.cpp - src/utils/polygon.cpp src/utils/PolylineStitcher.cpp src/utils/Simplify.cpp src/utils/SVG.cpp @@ -151,6 +150,14 @@ set(engine_SRCS # Except main.cpp. src/utils/ToolpathVisualizer.cpp src/utils/VoronoiUtils.cpp src/utils/VoxelUtils.cpp + + src/geometry/polygon.cpp + src/geometry/polygons.cpp + src/geometry/points_set.cpp + src/geometry/single_shape.cpp + src/geometry/parts_view.cpp + src/geometry/lines_set.cpp + src/geometry/polyline.cpp ) add_library(_CuraEngine STATIC ${engine_SRCS} ${engine_PB_SRCS}) diff --git a/benchmark/wall_benchmark.h b/benchmark/wall_benchmark.h index 13f2021ceb..d91f9d5831 100644 --- a/benchmark/wall_benchmark.h +++ b/benchmark/wall_benchmark.h @@ -13,7 +13,7 @@ #include "WallsComputation.h" #include "settings/Settings.h" #include "sliceDataStorage.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" #include #include diff --git a/include/BeadingStrategy/BeadingStrategy.h b/include/BeadingStrategy/BeadingStrategy.h index d72645592f..76d53cf677 100644 --- a/include/BeadingStrategy/BeadingStrategy.h +++ b/include/BeadingStrategy/BeadingStrategy.h @@ -8,7 +8,7 @@ #include "../settings/types/Angle.h" #include "../settings/types/Ratio.h" //For the wall transition threshold. -#include "../utils/Point2LL.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/BoostInterface.hpp b/include/BoostInterface.hpp index a294450a11..3b584aba8f 100644 --- a/include/BoostInterface.hpp +++ b/include/BoostInterface.hpp @@ -7,9 +7,9 @@ #include #include -#include "utils/Point2LL.h" +#include "geometry/point2ll.h" +#include "geometry/polygon.h" #include "utils/PolygonsSegmentIndex.h" -#include "utils/polygon.h" using CSegment = cura::PolygonsSegmentIndex; diff --git a/include/ExtruderPlan.h b/include/ExtruderPlan.h index e5fc1dd11d..89cbf5cf03 100644 --- a/include/ExtruderPlan.h +++ b/include/ExtruderPlan.h @@ -12,7 +12,7 @@ #include "pathPlanning/TimeMaterialEstimates.h" #include "settings/types/LayerIndex.h" #include "settings/types/Ratio.h" -#include "utils/Point2LL.h" +#include "geometry/point2ll.h" #ifdef BUILD_TESTS #include //Friend tests, so that they can inspect the privates. diff --git a/include/InsetOrderOptimizer.h b/include/InsetOrderOptimizer.h index 7ff5300090..808abb99d6 100644 --- a/include/InsetOrderOptimizer.h +++ b/include/InsetOrderOptimizer.h @@ -107,7 +107,7 @@ class InsetOrderOptimizer const std::vector& paths_; const LayerIndex layer_nr_; - std::vector> inset_polys_; // vector of vectors holding the inset polygons + std::vector> inset_polys_; // vector of vectors holding the inset polygons Polygons retraction_region_; // After printing an outer wall, move into this region so that retractions do not leave visible blobs. Calculated lazily if needed (see // retraction_region_calculated). diff --git a/include/InterlockingGenerator.h b/include/InterlockingGenerator.h index da37b66e53..14fd39ec9e 100644 --- a/include/InterlockingGenerator.h +++ b/include/InterlockingGenerator.h @@ -8,8 +8,9 @@ #include #include +#include "geometry/point_matrix.h" +#include "geometry/polygon.h" #include "utils/VoxelUtils.h" -#include "utils/polygon.h" namespace cura { diff --git a/include/LayerPlan.h b/include/LayerPlan.h index de831d00a2..21006d9d1f 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -17,7 +17,7 @@ #include "settings/PathConfigStorage.h" #include "settings/types/LayerIndex.h" #include "utils/ExtrusionJunction.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" #ifdef BUILD_TESTS #include //Friend tests, so that they can inspect the privates. @@ -349,7 +349,7 @@ class LayerPlan : public NoCopy * \param always_retract Whether to force a retraction when moving to the start of the polygon (used for outer walls) */ void addPolygon( - ConstPolygonRef polygon, + const Polygon& polygon, int startIdx, const bool reverse, const GCodePathConfig& config, @@ -448,7 +448,7 @@ class LayerPlan : public NoCopy * start of the wall (used for outer walls). */ void addWall( - ConstPolygonRef wall, + const Polygon& wall, int start_idx, const Settings& settings, const GCodePathConfig& default_config, @@ -529,7 +529,7 @@ class LayerPlan : public NoCopy /*! * Add lines to the gcode with optimized order. - * \param polygons The lines + * \param lines The lines * \param config The config of the lines * \param space_fill_type The type of space filling used to generate the line segments (should be either Lines or PolyLines!) * \param enable_travel_optimization Whether to enable some potentially time consuming optimization of order the lines are printed to reduce the travel time required. @@ -538,10 +538,10 @@ class LayerPlan : public NoCopy * \param near_start_location Optional: Location near where to add the first line. If not provided the last position is used. * \param fan_speed optional fan speed override for this path * \param reverse_print_direction Whether to reverse the optimized order and their printing direction. - * \param order_requirements Pairs where first needs to be printed before second. Pointers are pointing to elements of \p polygons + * \param order_requirements Pairs where first needs to be printed before second. Pointers are pointing to elements of \p lines */ void addLinesByOptimizer( - const Polygons& polygons, + const std::vector& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const bool enable_travel_optimization = false, @@ -550,11 +550,11 @@ class LayerPlan : public NoCopy const std::optional near_start_location = std::optional(), const double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT, const bool reverse_print_direction = false, - const std::unordered_multimap& order_requirements = PathOrderOptimizer::no_order_requirements_); + const std::unordered_multimap& order_requirements = PathOrderOptimizer::no_order_requirements_); /*! - * Add polygons to the g-code with monotonic order. - * \param polygons The lines to add. + * Add lines to the g-code with monotonic order. + * \param lines The lines to add. * \param config The settings to print those lines with. * \param space_fill_type The type of space filling used to generate the * line segments (should be either Lines or PolyLines!) @@ -575,7 +575,7 @@ class LayerPlan : public NoCopy */ void addLinesMonotonic( const Polygons& area, - const Polygons& polygons, + const std::vector& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const AngleRadians monotonic_direction, @@ -588,7 +588,7 @@ class LayerPlan : public NoCopy protected: /*! * Add order optimized lines to the gcode. - * \param paths The paths in order + * \param lines The lines in order * \param config The config of the lines * \param space_fill_type The type of space filling used to generate the line segments (should be either Lines or PolyLines!) * \param wipe_dist (optional) the distance wiped without extruding after laying down a line. @@ -596,7 +596,7 @@ class LayerPlan : public NoCopy * \param fan_speed optional fan speed override for this path */ void addLinesInGivenOrder( - const std::vector>& paths, + const std::vector>& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const coord_t wipe_dist, @@ -619,8 +619,8 @@ class LayerPlan : public NoCopy */ void spiralizeWallSlice( const GCodePathConfig& config, - ConstPolygonRef wall, - ConstPolygonRef last_wall, + const Polygon& wall, + const Polygon& last_wall, int seam_vertex_idx, int last_seam_vertex_idx, const bool is_top_layer, diff --git a/include/PathOrderMonotonic.h b/include/PathOrderMonotonic.h index 2b8aa5dfc1..9ecf3e8713 100644 --- a/include/PathOrderMonotonic.h +++ b/include/PathOrderMonotonic.h @@ -62,7 +62,7 @@ class PathOrderMonotonic : public PathOrder // Get the vertex data and store it in the paths. for (Path& path : this->paths_) { - path.converted_ = path.getVertexData(); + path.converted_ = &path.getVertexData(); } std::vector reordered; // To store the result in. At the end, we'll std::swap with the real paths. diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index df1cc07c7e..1a7e3ed2e7 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -157,7 +157,7 @@ class PathOrderOptimizer // Get the vertex data and store it in the paths. for (auto& path : paths_) { - path.converted_ = path.getVertexData(); + path.converted_ = &path.getVertexData(); vertices_to_paths_.emplace(path.vertices_, &path); } @@ -661,7 +661,7 @@ class PathOrderOptimizer size_t best_i; double best_score = std::numeric_limits::infinity(); - for (const auto& [i, here] : **path.converted_ | ranges::views::drop_last(1) | ranges::views::enumerate) + for (const auto& [i, here] : *path.converted_ | ranges::views::drop_last(1) | ranges::views::enumerate) { // For most seam types, the shortest distance matters. Not for SHARPEST_CORNER though. // For SHARPEST_CORNER, use a fixed starting score of 0. @@ -884,7 +884,7 @@ class PathOrderOptimizer * \param polygon A polygon to get a random vertex of. * \return A random index in that polygon. */ - size_t getRandomPointInPolygon(ConstPolygonRef const& polygon) const + size_t getRandomPointInPolygon(const Polygon& polygon) const { return rand() % polygon.size(); } diff --git a/include/PathOrdering.h b/include/PathOrdering.h index 0ec185e700..a143d7d165 100644 --- a/include/PathOrdering.h +++ b/include/PathOrdering.h @@ -50,7 +50,7 @@ struct PathOrdering * Vertex data, converted into a Polygon so that the orderer knows how * to deal with this data. */ - ConstPolygonPointer converted_; + const Polygon* converted_{ nullptr }; /*! * Which vertex along the path to start printing with. @@ -89,7 +89,7 @@ struct PathOrdering * for each different type that this class is used with. See the .cpp file * for examples and where to add a new specialization. */ - ConstPolygonRef getVertexData(); + const Polygon& getVertexData(); protected: /*! diff --git a/include/PrimeTower.h b/include/PrimeTower.h index a4a31a26b9..62c92c5f86 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -7,7 +7,7 @@ #include #include "settings/types/LayerIndex.h" -#include "utils/polygon.h" // Polygons +#include "geometry/polygon.h" // Polygons #include "utils/polygonUtils.h" @@ -36,7 +36,7 @@ class PrimeTower Point2LL post_wipe_point_; //!< Location to post-wipe the unused nozzle off on - std::vector prime_tower_start_locations_; //!< The differernt locations where to pre-wipe the active nozzle + std::vector prime_tower_start_locations_; //!< The differernt locations where to pre-wipe the active nozzle const unsigned int number_of_prime_tower_start_locations_ = 21; //!< The required size of \ref PrimeTower::wipe_locations MovesByExtruder prime_moves_; //!< For each extruder, the moves to be processed for actual priming. diff --git a/include/SkeletalTrapezoidation.h b/include/SkeletalTrapezoidation.h index 86f13f2782..9ed382c5db 100644 --- a/include/SkeletalTrapezoidation.h +++ b/include/SkeletalTrapezoidation.h @@ -19,7 +19,7 @@ #include "utils/ExtrusionLine.h" #include "utils/HalfEdgeGraph.h" #include "utils/PolygonsSegmentIndex.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" #include "utils/section_type.h" namespace cura diff --git a/include/SkeletalTrapezoidationJoint.h b/include/SkeletalTrapezoidationJoint.h index daa9087cdf..43101b03fb 100644 --- a/include/SkeletalTrapezoidationJoint.h +++ b/include/SkeletalTrapezoidationJoint.h @@ -7,7 +7,7 @@ #include // smart pointers #include "BeadingStrategy/BeadingStrategy.h" -#include "utils/Point2LL.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/SupportInfillPart.h b/include/SupportInfillPart.h index 23a983276a..d35d3e3462 100644 --- a/include/SupportInfillPart.h +++ b/include/SupportInfillPart.h @@ -6,9 +6,10 @@ #include +#include "geometry/polygon.h" +#include "geometry/single_shape.h" #include "utils/AABB.h" #include "utils/ExtrusionLine.h" -#include "utils/polygon.h" namespace cura @@ -25,7 +26,7 @@ namespace cura class SupportInfillPart { public: - PolygonsPart outline_; //!< The outline of the support infill area + SingleShape outline_; //!< The outline of the support infill area AABB outline_boundary_box_; //!< The boundary box for the infill area coord_t support_line_width_; //!< The support line width int inset_count_to_generate_; //!< The number of insets need to be generated from the outline. This is not the actual insets that will be generated. @@ -36,7 +37,7 @@ class SupportInfillPart coord_t custom_line_distance_; //!< The distance between support infill lines. 0 means use the default line distance instead. bool use_fractional_config_; //!< Request to use the configuration used to fill a partial layer height here, instead of the normal full layer height configuration. - SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, bool use_fractional_config, int inset_count_to_generate = 0, coord_t custom_line_distance = 0); + SupportInfillPart(const SingleShape& outline, coord_t support_line_width, bool use_fractional_config, int inset_count_to_generate = 0, coord_t custom_line_distance = 0); const Polygons& getInfillArea() const; }; diff --git a/include/TopSurface.h b/include/TopSurface.h index 77505bfa94..cdeb9b4a1b 100644 --- a/include/TopSurface.h +++ b/include/TopSurface.h @@ -5,7 +5,7 @@ #define TOPSURFACE_H #include "GCodePathConfig.h" -#include "utils/polygon.h" //For the polygon areas. +#include "geometry/polygons.h" namespace cura { diff --git a/include/TreeModelVolumes.h b/include/TreeModelVolumes.h index 9c9013888d..3a8a44b69e 100644 --- a/include/TreeModelVolumes.h +++ b/include/TreeModelVolumes.h @@ -14,7 +14,7 @@ #include "settings/types/LayerIndex.h" //Part of the RadiusLayerPair. #include "sliceDataStorage.h" #include "utils/Simplify.h" -#include "utils/polygon.h" //For polygon parameters. +#include "geometry/polygon.h" //For polygon parameters. namespace cura { diff --git a/include/TreeSupport.h b/include/TreeSupport.h index 6ad2a5fac4..26f2e32757 100644 --- a/include/TreeSupport.h +++ b/include/TreeSupport.h @@ -14,7 +14,7 @@ #include "settings/EnumSettings.h" #include "sliceDataStorage.h" #include "utils/Coord_t.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" namespace cura { diff --git a/include/TreeSupportBaseCircle.h b/include/TreeSupportBaseCircle.h index ac9410bfbd..d802d11a9e 100644 --- a/include/TreeSupportBaseCircle.h +++ b/include/TreeSupportBaseCircle.h @@ -1,14 +1,16 @@ -//CuraEngine is released under the terms of the AGPLv3 or higher. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef TREESUPPORTCIRCLE_H #define TREESUPPORTCIRCLE_H -#include "utils/Coord_t.h" -#include "utils/polygon.h" - #include + #include +#include "geometry/polygon.h" +#include "settings/types/Angle.h" +#include "utils/Coord_t.h" + namespace cura { diff --git a/include/TreeSupportElement.h b/include/TreeSupportElement.h index 83b47ba3fb..d5c11181f0 100644 --- a/include/TreeSupportElement.h +++ b/include/TreeSupportElement.h @@ -12,7 +12,7 @@ #include "TreeSupportEnums.h" #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" -#include "utils/polygon.h" +#include "geometry/polygons.h" namespace cura { @@ -402,7 +402,7 @@ struct TreeSupportElement Polygon circle; for (Point2LL corner : TreeSupportBaseCircle::getBaseCircle()) { - circle.add(p + corner * influence_area_limit_range_ / double(TreeSupportBaseCircle::base_radius)); + circle.push_back(p + corner * influence_area_limit_range_ / double(TreeSupportBaseCircle::base_radius)); } if (influence_area_limit_area_.empty()) { diff --git a/include/TreeSupportSettings.h b/include/TreeSupportSettings.h index 1fe47514ca..2d66d15695 100644 --- a/include/TreeSupportSettings.h +++ b/include/TreeSupportSettings.h @@ -10,9 +10,11 @@ #include "settings/EnumSettings.h" #include "settings/Settings.h" #include "settings/types/Angle.h" +#include "settings/types/Ratio.h" #include "utils/Coord_t.h" #include "utils/Simplify.h" + namespace cura { diff --git a/include/TreeSupportTipGenerator.h b/include/TreeSupportTipGenerator.h index a6e04b0a1b..a20e7a8618 100644 --- a/include/TreeSupportTipGenerator.h +++ b/include/TreeSupportTipGenerator.h @@ -15,7 +15,7 @@ #include "settings/EnumSettings.h" #include "sliceDataStorage.h" #include "utils/Coord_t.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" namespace cura { @@ -63,7 +63,7 @@ class TreeSupportTipGenerator * \param layer_idx[in] The current layer. * \return All lines of the \p polylines object, with information for each point regarding in which avoidance it is currently valid in. */ - std::vector convertLinesToInternal(Polygons polylines, LayerIndex layer_idx); + std::vector convertLinesToInternal(const LinesSet& polylines, LayerIndex layer_idx); /*! * \brief Converts lines in internal format into a Polygons object representing these lines. @@ -71,7 +71,7 @@ class TreeSupportTipGenerator * \param lines[in] The lines that will be converted. * \return All lines of the \p lines object as a Polygons object. */ - Polygons convertInternalToLines(std::vector lines); + LinesSet convertInternalToLines(std::vector lines); /*! * \brief Returns a function, evaluating if a point has to be added now. Required for a splitLines call in generateInitialAreas. @@ -102,7 +102,7 @@ class TreeSupportTipGenerator * \param enforce_distance[in] If points should not be added if they are closer than distance to other points. * \return A Polygons object containing the evenly spaced points. Does not represent an area, more a collection of points on lines. */ - Polygons ensureMaximumDistancePolyline(const Polygons& input, coord_t distance, size_t min_points, bool enforce_distance) const; + LinesSet ensureMaximumDistancePolyline(const LinesSet& input, coord_t distance, size_t min_points, bool enforce_distance) const; /*! * \brief Creates a valid CrossInfillProvider diff --git a/include/TreeSupportUtils.h b/include/TreeSupportUtils.h index ca301b6ad4..5b393fe330 100644 --- a/include/TreeSupportUtils.h +++ b/include/TreeSupportUtils.h @@ -17,7 +17,7 @@ #include "settings/EnumSettings.h" #include "sliceDataStorage.h" #include "utils/Coord_t.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" namespace cura { @@ -29,20 +29,17 @@ class TreeSupportUtils * \brief Adds the implicit line from the last vertex of a Polygon to the first one. * * \param poly[in] The Polygons object, of which its lines should be extended. - * \return A Polygons object with implicit line from the last vertex of a Polygon to the first one added. + * \return A Polygons object with explicit line from the last vertex of a Polygon to the first one added. */ - static Polygons toPolylines(const Polygons& poly) + static LinesSet toPolylines(const Polygons& poly) { - Polygons result; +#warning We should just cast it to a LineSet instead, but that's running for trouble yet + LinesSet result; for (const auto& path : poly) { - Polygon part; - for (const auto& p : path) - { - part.add(p); - } - part.add(path[0]); - result.add(part); + Polygon part(path); + part.push_back(path[0]); + result.push_back(part); } return result; } @@ -54,29 +51,30 @@ class TreeSupportUtils * \param toolpaths[in] The toolpaths. * \return A Polygons object. */ - [[nodiscard]] static Polygons toPolylines(const std::vector toolpaths) + [[nodiscard]] static LinesSet toPolylines(const std::vector toolpaths) { - Polygons result; - for (VariableWidthLines lines : toolpaths) + LinesSet result; + for (const VariableWidthLines& lines : toolpaths) { - for (ExtrusionLine line : lines) + for (const ExtrusionLine& line : lines) { - if (line.size() == 0) + if (line.empty()) { continue; } - Polygon result_line; - for (ExtrusionJunction junction : line) + + OpenPolyline result_line; + for (const ExtrusionJunction& junction : line) { - result_line.add(junction.p_); + result_line.push_back(junction.p_); } if (line.is_closed_) { - result_line.add(line[0].p_); + result_line.push_back(line[0].p_); } - result.add(result_line); + result.push_back(result_line); } } return result; @@ -96,7 +94,7 @@ class TreeSupportUtils * todo doku * \return A Polygons object that represents the resulting infill lines. */ - [[nodiscard]] static Polygons generateSupportInfillLines( + [[nodiscard]] static LinesSet generateSupportInfillLines( const Polygons& area, const TreeSupportSettings& config, bool roof, @@ -159,7 +157,7 @@ class TreeSupportUtils pocket_size); Polygons areas; - Polygons lines; + LinesSet lines; roof_computation.generate(toolpaths, areas, lines, config.settings, layer_idx, SectionType::SUPPORT, cross_fill_provider); lines.add(toPolylines(areas)); lines.add(toPolylines(toolpaths)); @@ -194,7 +192,7 @@ class TreeSupportUtils spdlog::warn("Caught an area destroying union, enlarging areas a bit."); // Just take the few lines we have, and offset them a tiny bit. Needs to be offsetPolylines, as offset may already have problems with the area. - return toPolylines(first).offsetPolyLine(2).unionPolygons(toPolylines(second).offsetPolyLine(2)); + return toPolylines(first).offset(2).unionPolygons(toPolylines(second).offset(2)); } return result; } @@ -291,14 +289,14 @@ class TreeSupportUtils * \param max_allowed_distance[in] The maximum distance a point may be moved. If not possible the point will be moved as far as possible in the direction of the outside of the * provided area. \return A Polyline object containing the moved points. */ - [[nodiscard]] static Polygons movePointsOutside(const Polygons& polylines, const Polygons& area, coord_t max_allowed_distance) + [[nodiscard]] static LinesSet movePointsOutside(const LinesSet& polylines, const Polygons& area, coord_t max_allowed_distance) { - Polygons result; + LinesSet result; - for (auto line : polylines) + for (const OpenPolyline& line : polylines) { - Polygon next_line; - for (Point2LL p : line) + OpenPolyline next_line; + for (const Point2LL& p : line) { if (area.inside(p)) { @@ -306,23 +304,23 @@ class TreeSupportUtils PolygonUtils::moveOutside(area, next_outside); if (vSize2(p - next_outside) < max_allowed_distance * max_allowed_distance) { - next_line.add(next_outside); + next_line.push_back(next_outside); } else // move point as far as allowed. { double max_partial_move_proportion = double(max_allowed_distance) / double(vSize(p - next_outside)); next_outside = p + (next_outside - p) * max_partial_move_proportion; - next_line.add(next_outside); + next_line.push_back(next_outside); } } else { - next_line.add(p); + next_line.push_back(p); } } if (next_line.size() > 0) { - result.add(next_line); + result.push_back(next_line); } } diff --git a/include/WallToolPaths.h b/include/WallToolPaths.h index 07b67ebfcd..08ee7b091c 100644 --- a/include/WallToolPaths.h +++ b/include/WallToolPaths.h @@ -9,7 +9,7 @@ #include "BeadingStrategy/BeadingStrategyFactory.h" #include "settings/Settings.h" #include "utils/ExtrusionLine.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" #include "utils/section_type.h" namespace cura diff --git a/include/communication/ArcusCommunication.h b/include/communication/ArcusCommunication.h index 6a1fa1c3f0..c83c475205 100644 --- a/include/communication/ArcusCommunication.h +++ b/include/communication/ArcusCommunication.h @@ -22,6 +22,8 @@ class Socket; namespace cura { +class Polygon; + /* * \brief Communication class that connects via libArcus to Cura's front-end. */ @@ -152,7 +154,7 @@ class ArcusCommunication : public Communication * \param line_thickness The thickness (in the Z direction) of the polygon. * \param velocity The velocity of printing this polygon. */ - void sendPolygon(const PrintFeatureType& type, const ConstPolygonRef& polygon, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity) override; + void sendPolygon(const PrintFeatureType& type, const Polygon& polygon, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity) override; /* * \brief Send polygons to the front-end to display in layer view. diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index ac7c1ccda7..416182ac0e 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -107,7 +107,7 @@ class CommandLine : public Communication * * The command line doesn't show any layer view so this is ignored. */ - void sendPolygon(const PrintFeatureType&, const ConstPolygonRef&, const coord_t&, const coord_t&, const Velocity&) override; + void sendPolygon(const PrintFeatureType&, const Polygon&, const coord_t&, const coord_t&, const Velocity&) override; /* * \brief Send a polygon to show it in layer view. diff --git a/include/communication/Communication.h b/include/communication/Communication.h index 0b8a509a5b..dab6af1530 100644 --- a/include/communication/Communication.h +++ b/include/communication/Communication.h @@ -6,14 +6,14 @@ #include "settings/types/LayerIndex.h" #include "settings/types/Velocity.h" -#include "utils/Point2LL.h" +#include "geometry/point2ll.h" namespace cura { // Some forward declarations to increase compilation speed. enum class PrintFeatureType : unsigned char; class Polygons; -class ConstPolygonRef; +class Polygon; class ExtruderTrain; /* @@ -90,7 +90,7 @@ class Communication * \param line_thickness The thickness (in the Z direction) of the polygon. * \param velocity The velocity of printing this polygon. */ - virtual void sendPolygon(const PrintFeatureType& type, const ConstPolygonRef& polygon, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity) = 0; + virtual void sendPolygon(const PrintFeatureType& type, const Polygon& polygon, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity) = 0; /* * \brief Send a line to the user to visualise. diff --git a/include/gcodeExport.h b/include/gcodeExport.h index 950fe50824..804b992609 100644 --- a/include/gcodeExport.h +++ b/include/gcodeExport.h @@ -20,7 +20,7 @@ #include "timeEstimate.h" #include "utils/AABB3D.h" //To track the used build volume for the Griffin header. #include "utils/NoCopy.h" -#include "utils/Point2LL.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/geometry/closed_polyline.h b/include/geometry/closed_polyline.h new file mode 100644 index 0000000000..49ca7af908 --- /dev/null +++ b/include/geometry/closed_polyline.h @@ -0,0 +1,16 @@ +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_CLOSED_POLYLINE_H +#define GEOMETRY_CLOSED_POLYLINE_H + +#include "geometry/generic_closed_polyline.h" + +namespace cura +{ + +using ClosedPolyline = GenericClosedPolyline; + +} // namespace cura + +#endif // GEOMETRY_CLOSED_POLYLINE_H diff --git a/include/geometry/generic_closed_polyline.h b/include/geometry/generic_closed_polyline.h new file mode 100644 index 0000000000..55ff0fd5a4 --- /dev/null +++ b/include/geometry/generic_closed_polyline.h @@ -0,0 +1,98 @@ +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_GENERIC_CLOSED_POLYLINE_H +#define GEOMETRY_GENERIC_CLOSED_POLYLINE_H + +#include "geometry/point2ll.h" +#include "geometry/polyline.h" +#include "geometry/polyline_type.h" + +namespace cura +{ + +template +class GenericClosedPolyline : public Polyline +{ + friend class Polygons; + +public: + GenericClosedPolyline() = default; + + GenericClosedPolyline(const std::initializer_list& initializer) + : Polyline(initializer) + { + } + + GenericClosedPolyline(const std::vector& points) + : Polyline(points) + { + } + + GenericClosedPolyline& operator=(const GenericClosedPolyline& other) + { + Polyline::operator=(other); + return *this; + } + + /*! + * Check if we are inside the polygon. We do this by tracing from the point towards the positive X direction, + * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. + * Care needs to be taken, if p.Y exactly matches a vertex to the right of p, then we need to count 1 intersect if the + * outline passes vertically past; and 0 (or 2) intersections if that point on the outline is a 'top' or 'bottom' vertex. + * The easiest way to do this is to break out two cases for increasing and decreasing Y ( from p0 to p1 ). + * A segment is tested if pa.Y <= p.Y < pb.Y, where pa and pb are the points (from p0,p1) with smallest & largest Y. + * When both have the same Y, no intersections are counted but there is a special test to see if the point falls + * exactly on the line. + * + * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. + * + * \deprecated This function is no longer used, since the Clipper function is used by the function PolygonRef::inside(.) + * + * \param p The point for which to check if it is inside this polygon + * \param border_result What to return when the point is exactly on the border + * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) + */ + // bool _inside(Point2LL p, bool border_result = false) const; + + /*! + * Clipper function. + * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. + * + * http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/PointInPolygon.htm + */ + bool inside(Point2LL p, bool border_result = false) const; + + bool inside(const auto& polygon) const; +}; + +// ########################################################### +// Definitions of templated methods +// ########################################################### +template +bool GenericClosedPolyline::inside(Point2LL p, bool border_result) const +{ + int res = ClipperLib::PointInPolygon(p, *this); + if (res == -1) + { + return border_result; + } + return res == 1; +} + +template +bool GenericClosedPolyline::inside(const auto& polygon) const +{ + for (const auto& point : *this) + { + if (! ClipperLib::PointInPolygon(point, polygon)) + { + return false; + } + } + return true; +} + +} // namespace cura + +#endif // GEOMETRY_GENERIC_CLOSED_POLYLINE_H diff --git a/include/geometry/lines_set.h b/include/geometry/lines_set.h new file mode 100644 index 0000000000..1cdcb78e11 --- /dev/null +++ b/include/geometry/lines_set.h @@ -0,0 +1,137 @@ +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_LINES_SET_H +#define GEOMETRY_LINES_SET_H + +#include + +#include "geometry/point2ll.h" + +namespace cura +{ + +class Polygons; +class OpenPolyline; +template +class LinesSet; + +template +class LinesSet : public std::vector +{ +public: + LinesSet() = default; + + LinesSet(const LinesSet& other) = default; + + LinesSet(LinesSet&& other) = default; + + LinesSet(const std::vector& lines) + : std::vector(lines) + { + } + + LinesSet(std::vector&& lines) + : std::vector(std::move(lines)) + { + } + + LinesSet(const std::vector>& paths) + : std::vector(*reinterpret_cast*>(&paths)) + { + } + + LinesSet& operator=(const LinesSet& other) + { + std::vector::operator=(other); + return *this; + } + + LinesSet& operator=(LinesSet&& other) + { + std::vector::operator=(other); + return *this; + } + + template + const LinesSet& toType() const + { + return *reinterpret_cast*>(this); + } + + const std::vector>& getCallable() const + { + // This does work as long as we don't add any attribute to the Polygon class or any of its + // parent until std::vector + return *reinterpret_cast>*>(this); + } + + std::vector>& getCallable() + { + // This does work as long as we don't add any attribute to the Polygon class or any of its + // parent until std::vector + return *reinterpret_cast>*>(this); + } + + void add(const LinesSet& other) + { + this->insert(this->end(), other.begin(), other.end()); + } + + void addIfNotEmpty(const LineType& line); + + void addIfNotEmpty(LineType&& line); + + LineType& newLine() + { + this->emplace_back(); + return this->back(); + } + + //!< Return the amount of points in all lines + size_t pointCount() const; + + /*! + * Remove a line from the list and move the last line to its place + * + * \warning changes the order of the lines! + */ + void removeAt(size_t index); + + /*! + * Add a simple line consisting of two points + */ + void addLine(const Point2LL& from, const Point2LL& to); + + coord_t length() const; + + void splitIntoSegments(LinesSet& result) const; + LinesSet splitIntoSegments() const; + + /*! + * Removes overlapping consecutive line segments which don't delimit a + * positive area. + * + * This function is meant to work on polygons, not polylines. When misused + * on polylines, it may cause too many vertices to be removed. + * See \ref removeDegenerateVertsPolyline for a version that works on + * polylines. + */ +#warning rename this to removeDegenerateVerts + void removeDegenerateVertsForEveryone(); + + Polygons offset(coord_t distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; + // Polygons offsetPolyLine(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, bool inputPolyIsClosed = false) const; + + /*! + * Utility method for creating the tube (or 'donut') of a shape. + * \param inner_offset Offset relative to the original shape-outline towards the inside of the shape. Sort-of like a negative normal offset, except it's the offset part that's + * kept, not the shape. \param outer_offset Offset relative to the original shape-outline towards the outside of the shape. Comparable to normal offset. \return The resulting + * polygons. + */ + Polygons tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +}; + +} // namespace cura + +#endif // GEOMETRY_LINES_SET_H diff --git a/include/geometry/open_polyline.h b/include/geometry/open_polyline.h new file mode 100644 index 0000000000..b6d8008509 --- /dev/null +++ b/include/geometry/open_polyline.h @@ -0,0 +1,51 @@ +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_OPEN_POLYLINE_H +#define GEOMETRY_OPEN_POLYLINE_H + +#include "geometry/polyline.h" + +namespace cura +{ + +class OpenPolyline : public Polyline +{ +public: + OpenPolyline() = default; + + OpenPolyline(const OpenPolyline& other) = default; + + OpenPolyline(OpenPolyline&& other) = default; + + OpenPolyline(const std::initializer_list& initializer) + : Polyline(initializer) + { + } + + OpenPolyline(const std::vector& points) + : Polyline(points) + { + } + + OpenPolyline(std::vector&& points) + : Polyline(points) + { + } + + OpenPolyline& operator=(const OpenPolyline& other) + { + Polyline::operator=(other); + return *this; + } + + OpenPolyline& operator=(OpenPolyline&& other) + { + Polyline::operator=(other); + return *this; + } +}; + +} // namespace cura + +#endif // GEOMETRY_OPEN_POLYLINE_H diff --git a/include/geometry/parts_view.h b/include/geometry/parts_view.h new file mode 100644 index 0000000000..458ce956f8 --- /dev/null +++ b/include/geometry/parts_view.h @@ -0,0 +1,58 @@ +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_PARTS_VIEW_H +#define GEOMETRY_PARTS_VIEW_H + +#include + +namespace cura +{ + +class Polygons; +class SingleShape; + +/*! + * Extension of vector> which is similar to a vector of PolygonParts, except the base of the container is indices to polygons into the original Polygons, + * instead of the polygons themselves + */ +class PartsView : public std::vector> +{ +public: + Polygons& polygons_; + + PartsView(Polygons& polygons) + : polygons_(polygons) + { + } + + /*! + * Get the index of the SingleShape of which the polygon with index \p poly_idx is part. + * + * \param poly_idx The index of the polygon in \p polygons + * \param boundary_poly_idx Optional output parameter: The index of the boundary polygon of the part in \p polygons + * \return The SingleShape containing the polygon with index \p poly_idx + */ + size_t getPartContaining(size_t poly_idx, size_t* boundary_poly_idx = nullptr) const; + + /*! + * Assemble the SingleShape of which the polygon with index \p poly_idx is part. + * + * \param poly_idx The index of the polygon in \p polygons + * \param boundary_poly_idx Optional output parameter: The index of the boundary polygon of the part in \p polygons + * \return The SingleShape containing the polygon with index \p poly_idx + */ + SingleShape assemblePartContaining(size_t poly_idx, size_t* boundary_poly_idx = nullptr) const; + + /*! + * Assemble the SingleShape of which the polygon with index \p poly_idx is part. + * + * \param part_idx The index of the part + * \return The SingleShape with index \p poly_idx + */ + SingleShape assemblePart(size_t part_idx) const; +}; + +} // namespace cura + +#endif // GEOMETRY_PARTS_VIEW_H diff --git a/include/utils/Point2LL.h b/include/geometry/point2ll.h similarity index 60% rename from include/utils/Point2LL.h rename to include/geometry/point2ll.h index 8623282fc2..393e43ea93 100644 --- a/include/utils/Point2LL.h +++ b/include/geometry/point2ll.h @@ -10,16 +10,13 @@ Integer points are used to avoid floating point rounding errors, and because Cli */ #define INLINE static inline -// Include Clipper to get the ClipperLib::IntPoint definition, which we reuse as Point definition. -#include -#include // for hash function object -#include // auto-serialization / auto-toString() +//#include // for hash function object +//#include // auto-serialization / auto-toString() #include #include -#include +//#include -#include "../utils/math.h" // for PI. Use relative path to avoid pulling -#include "Point3LL.h" //For applying Point3Matrices. +#include "point3ll.h" #ifdef __GNUC__ #define DEPRECATED(func) func __attribute__((deprecated)) @@ -35,7 +32,7 @@ namespace cura { /* 64bit Points are used mostly throughout the code, these are the 2D points from ClipperLib */ -typedef ClipperLib::IntPoint Point2LL; +using Point2LL = ClipperLib::IntPoint; #define POINT_MIN std::numeric_limits::min() #define POINT_MAX std::numeric_limits::max() @@ -197,179 +194,6 @@ INLINE const Point2LL& make_point(const Point2LL& p) return p; } -} // namespace cura - -namespace std -{ -template<> -struct hash -{ - size_t operator()(const cura::Point2LL& pp) const - { - static int prime = 31; - int result = 89; - result = static_cast(result * prime + pp.X); - result = static_cast(result * prime + pp.Y); - return static_cast(result); - } -}; -} // namespace std - -namespace cura -{ - -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 * std::numbers::pi; - matrix[0] = cos(rotation); - matrix[1] = -sin(rotation); - matrix[2] = -matrix[1]; - matrix[3] = matrix[0]; - } - - PointMatrix(const Point2LL p) - { - matrix[0] = static_cast(p.X); - matrix[1] = static_cast(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; - } - - Point2LL apply(const Point2LL p) const - { - const double x = static_cast(p.X); - const double y = static_cast(p.Y); - return Point2LL(std::llrint(x * matrix[0] + y * matrix[1]), std::llrint(x * matrix[2] + y * matrix[3])); - } - - /*! - * \warning only works on a rotation matrix! Output is incorrect for other types of matrix - */ - Point2LL unapply(const Point2LL p) const - { - const double x = static_cast(p.X); - const double y = static_cast(p.Y); - return Point2LL(std::llrint(x * matrix[0] + y * matrix[2]), std::llrint(x * matrix[1] + y * matrix[3])); - } - - PointMatrix inverse() const - { - PointMatrix ret; - double det = matrix[0] * matrix[3] - matrix[1] * matrix[2]; - ret.matrix[0] = matrix[3] / det; - ret.matrix[1] = -matrix[1] / det; - ret.matrix[2] = -matrix[2] / det; - ret.matrix[3] = matrix[0] / det; - return ret; - } -}; - -class Point3Matrix -{ -public: - double matrix[9]; - - Point3Matrix() - { - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 1; - matrix[5] = 0; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 1; - } - - /*! - * Initializes the top left corner with the values of \p b - * and the rest as if it's a unit matrix - */ - Point3Matrix(const PointMatrix& b) - { - matrix[0] = b.matrix[0]; - matrix[1] = b.matrix[1]; - matrix[2] = 0; - matrix[3] = b.matrix[2]; - matrix[4] = b.matrix[3]; - matrix[5] = 0; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 1; - } - - Point3LL apply(const Point3LL p) const - { - const double x = static_cast(p.x_); - const double y = static_cast(p.y_); - const double z = static_cast(p.z_); - return Point3LL( - std::llrint(x * matrix[0] + y * matrix[1] + z * matrix[2]), - std::llrint(x * matrix[3] + y * matrix[4] + z * matrix[5]), - std::llrint(x * matrix[6] + y * matrix[7] + z * matrix[8])); - } - - /*! - * Apply matrix to vector as homogeneous coordinates. - */ - Point2LL apply(const Point2LL p) const - { - Point3LL result = apply(Point3LL(p.X, p.Y, 1)); - return Point2LL(result.x_ / result.z_, result.y_ / result.z_); - } - - static Point3Matrix translate(const Point2LL p) - { - Point3Matrix ret; // uniform matrix - ret.matrix[2] = static_cast(p.X); - ret.matrix[5] = static_cast(p.Y); - return ret; - } - - Point3Matrix compose(const Point3Matrix& b) - { - Point3Matrix ret; - for (int outx = 0; outx < 3; outx++) - { - for (int outy = 0; outy < 3; outy++) - { - ret.matrix[outy * 3 + outx] = 0; - for (int in = 0; in < 3; in++) - { - ret.matrix[outy * 3 + outx] += matrix[outy * 3 + in] * b.matrix[in * 3 + outx]; - } - } - } - return ret; - } -}; - - inline Point3LL operator+(const Point3LL& p3, const Point2LL& p2) { return Point3LL(p3.x_ + p2.X, p3.y_ + p2.Y, p3.z_); @@ -404,4 +228,21 @@ inline Point2LL operator-(const Point2LL& p2, const Point3LL& p3) } } // namespace cura + +namespace std +{ +template<> +struct hash +{ + size_t operator()(const cura::Point2LL& pp) const + { + static int prime = 31; + int result = 89; + result = static_cast(result * prime + pp.X); + result = static_cast(result * prime + pp.Y); + return static_cast(result); + } +}; +} // namespace std + #endif // UTILS_INT_POINT_H diff --git a/include/geometry/point3_matrix.h b/include/geometry/point3_matrix.h new file mode 100644 index 0000000000..ce7447cd61 --- /dev/null +++ b/include/geometry/point3_matrix.h @@ -0,0 +1,95 @@ +// Copyright (c) 2020 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#ifndef GEOMETRY_POINT3_MATRIX_H +#define GEOMETRY_POINT3_MATRIX_H + +#include "point3ll.h" +#include "point_matrix.h" + +namespace cura +{ + +class Point3Matrix +{ +public: + double matrix[9]; + + Point3Matrix() + { + matrix[0] = 1; + matrix[1] = 0; + matrix[2] = 0; + matrix[3] = 0; + matrix[4] = 1; + matrix[5] = 0; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 1; + } + + /*! + * Initializes the top left corner with the values of \p b + * and the rest as if it's a unit matrix + */ + Point3Matrix(const PointMatrix& b) + { + matrix[0] = b.matrix[0]; + matrix[1] = b.matrix[1]; + matrix[2] = 0; + matrix[3] = b.matrix[2]; + matrix[4] = b.matrix[3]; + matrix[5] = 0; + matrix[6] = 0; + matrix[7] = 0; + matrix[8] = 1; + } + + Point3LL apply(const Point3LL p) const + { + const double x = static_cast(p.x_); + const double y = static_cast(p.y_); + const double z = static_cast(p.z_); + return Point3LL( + std::llrint(x * matrix[0] + y * matrix[1] + z * matrix[2]), + std::llrint(x * matrix[3] + y * matrix[4] + z * matrix[5]), + std::llrint(x * matrix[6] + y * matrix[7] + z * matrix[8])); + } + + /*! + * Apply matrix to vector as homogeneous coordinates. + */ + Point2LL apply(const Point2LL p) const + { + Point3LL result = apply(Point3LL(p.X, p.Y, 1)); + return Point2LL(result.x_ / result.z_, result.y_ / result.z_); + } + + static Point3Matrix translate(const Point2LL p) + { + Point3Matrix ret; // uniform matrix + ret.matrix[2] = static_cast(p.X); + ret.matrix[5] = static_cast(p.Y); + return ret; + } + + Point3Matrix compose(const Point3Matrix& b) + { + Point3Matrix ret; + for (int outx = 0; outx < 3; outx++) + { + for (int outy = 0; outy < 3; outy++) + { + ret.matrix[outy * 3 + outx] = 0; + for (int in = 0; in < 3; in++) + { + ret.matrix[outy * 3 + outx] += matrix[outy * 3 + in] * b.matrix[in * 3 + outx]; + } + } + } + return ret; + } +}; + +} // namespace cura +#endif // GEOMETRY_POINT3_MATRIX_H diff --git a/include/utils/Point3LL.h b/include/geometry/point3ll.h similarity index 97% rename from include/utils/Point3LL.h rename to include/geometry/point3ll.h index c992bcb3d5..9dfb91c544 100644 --- a/include/utils/Point3LL.h +++ b/include/geometry/point3ll.h @@ -1,17 +1,16 @@ // Copyright (c) 2018 Ultimaker B.V. // CuraEngine is released under the terms of the AGPLv3 or higher. -#ifndef UTILS_POINT3_H -#define UTILS_POINT3_H +#ifndef GEOMETRY_POINT3LL_H +#define GEOMETRY_POINT3LL_H #include #include //For sqrt. #include //Auto-serialization. #include //For numeric_limits::min and max. -#include //For int32_t and int64_t. #include // for operations on any arithmetic number type -#include "Coord_t.h" +#include "utils/Coord_t.h" namespace cura @@ -180,4 +179,4 @@ struct hash } // namespace std -#endif // UTILS_POINT3_H +#endif // GEOMETRY_POINT3LL_H diff --git a/include/geometry/point_matrix.h b/include/geometry/point_matrix.h new file mode 100644 index 0000000000..4f3c348414 --- /dev/null +++ b/include/geometry/point_matrix.h @@ -0,0 +1,84 @@ +// Copyright (c) 2020 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#ifndef GEOMETRY_POINT_MATRIX_H +#define GEOMETRY_POINT_MATRIX_H + +#include "point2ll.h" + + +namespace cura +{ + +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 * std::numbers::pi; + matrix[0] = cos(rotation); + matrix[1] = -sin(rotation); + matrix[2] = -matrix[1]; + matrix[3] = matrix[0]; + } + + PointMatrix(const Point2LL p) + { + matrix[0] = static_cast(p.X); + matrix[1] = static_cast(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; + } + + Point2LL apply(const Point2LL p) const + { + const double x = static_cast(p.X); + const double y = static_cast(p.Y); + return Point2LL(std::llrint(x * matrix[0] + y * matrix[1]), std::llrint(x * matrix[2] + y * matrix[3])); + } + + /*! + * \warning only works on a rotation matrix! Output is incorrect for other types of matrix + */ + Point2LL unapply(const Point2LL p) const + { + const double x = static_cast(p.X); + const double y = static_cast(p.Y); + return Point2LL(std::llrint(x * matrix[0] + y * matrix[2]), std::llrint(x * matrix[1] + y * matrix[3])); + } + + PointMatrix inverse() const + { + PointMatrix ret; + double det = matrix[0] * matrix[3] - matrix[1] * matrix[2]; + ret.matrix[0] = matrix[3] / det; + ret.matrix[1] = -matrix[1] / det; + ret.matrix[2] = -matrix[2] / det; + ret.matrix[3] = matrix[0] / det; + return ret; + } +}; + +} // namespace cura +#endif // GEOMETRY_POINT_MATRIX_H diff --git a/include/geometry/points_set.h b/include/geometry/points_set.h new file mode 100644 index 0000000000..7fd1e81caf --- /dev/null +++ b/include/geometry/points_set.h @@ -0,0 +1,86 @@ +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_POINTS_SET_H +#define GEOMETRY_POINTS_SET_H + +#include "geometry/point2ll.h" +#include "utils/Coord_t.h" + +namespace cura +{ + +class PointMatrix; +class Point3Matrix; + +const static int clipper_init = (0); +#define NO_INDEX (std::numeric_limits::max()) + +#warning Move this somewhere else, or remove it... +template +bool shorterThan(const T& shape, const coord_t check_length) +{ + const auto* p0 = &shape.back(); + int64_t length = 0; + for (const auto& p1 : shape) + { + length += vSize(*p0 - p1); + if (length >= check_length) + { + return false; + } + p0 = &p1; + } + return true; +} + +class PointsSet : public std::vector +{ +public: + PointsSet() = default; + + PointsSet(const std::initializer_list& initializer); + + PointsSet(const std::vector& points); + + PointsSet(std::vector&& points); + + /*PointsSet& operator=(const PointsSet& other) + { + std::vector::operator=(other); + return *this; + }*/ + + const std::vector& asRawVector() const + { + return *reinterpret_cast*>(this); + } + + std::vector& asRawVector() + { + return *reinterpret_cast*>(this); + } + + Point2LL min() const; + + Point2LL max() const; + + Point2LL closestPointTo(const Point2LL& p) const; + + /*! + * Translate the whole polygon in some direction. + * + * \param translation The direction in which to move the polygon + */ + void translate(const Point2LL& translation); + + /*! + * Apply a matrix to each vertex in this set + */ + void applyMatrix(const PointMatrix& matrix); + void applyMatrix(const Point3Matrix& matrix); +}; + +} // namespace cura + +#endif // GEOMETRY_POINTS_SET_H diff --git a/include/geometry/polygon.h b/include/geometry/polygon.h new file mode 100644 index 0000000000..80159f7f56 --- /dev/null +++ b/include/geometry/polygon.h @@ -0,0 +1,183 @@ +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_POLYGON_H +#define GEOMETRY_POLYGON_H + +#include "generic_closed_polyline.h" + +namespace cura +{ + +class Polygons; +class ListPolyIt; +class AngleDegrees; + +class Polygon : public GenericClosedPolyline +{ + friend class Polygons; + +public: + Polygon() = default; + + Polygon(const Polygon& other) = default; + + Polygon(Polygon&& other) = default; + + Polygon(const std::initializer_list& initializer) + : GenericClosedPolyline(initializer) + { + } + + Polygon(const std::vector& points) + : GenericClosedPolyline(points) + { + } + + Polygon& operator=(const Polygon& other) + { + GenericClosedPolyline::operator=(other); + return *this; + } + + /*! + * Compute the morphological intersection between this polygon and another. + * + * Note that the result may consist of multiple polygons, if you have bad + * luck. + * + * \param other The polygon with which to intersect this polygon. + */ + Polygons intersection(const Polygon& other) const; + + double area() const + { + return ClipperLib::Area(*this); + } + + Point2LL centerOfMass() const; + + Polygons offset(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; + + /*! + * Smooth out small perpendicular segments and store the result in \p result. + * Smoothing is performed by removing the inner most vertex of a line segment smaller than \p remove_length + * which has an angle with the next and previous line segment smaller than roughly 150* + * + * Note that in its current implementation this function doesn't remove line segments with an angle smaller than 30* + * Such would be the case for an N shape. + * + * \param remove_length The length of the largest segment removed + * \param result (output) The result polygon, assumed to be empty + */ + void smooth(int remove_length, Polygon& result) const; + + /*! + * Smooth out sharp inner corners, by taking a shortcut which bypasses the corner + * + * \param angle The maximum angle of inner corners to be smoothed out + * \param shortcut_length The desired length of the shortcut line segment introduced (shorter shortcuts may be unavoidable) + * \param result The resulting polygon + */ + void smooth_outward(const AngleDegrees angle, int shortcut_length, Polygon& result) const; + + /*! + * Smooth out the polygon and store the result in \p result. + * Smoothing is performed by removing vertices for which both connected line segments are smaller than \p remove_length + * + * \param remove_length The length of the largest segment removed + * \param result (output) The result polygon, assumed to be empty + */ + void smooth2(int remove_length, Polygon& result) const; + + /*! + * Smooth out a simple corner consisting of two linesegments. + * + * Auxiliary function for \ref smooth_outward + * + * \param p0 The point before the corner + * \param p1 The corner + * \param p2 The point after the corner + * \param p0_it Iterator to the point before the corner + * \param p1_it Iterator to the corner + * \param p2_it Iterator to the point after the corner + * \param v10 Vector from \p p1 to \p p0 + * \param v12 Vector from \p p1 to \p p2 + * \param v02 Vector from \p p0 to \p p2 + * \param shortcut_length The desired length ofthe shortcutting line + * \param cos_angle The cosine on the angle in L 012 + */ + static void smooth_corner_simple( + const Point2LL p0, + const Point2LL p1, + const Point2LL p2, + const ListPolyIt p0_it, + const ListPolyIt p1_it, + const ListPolyIt p2_it, + const Point2LL v10, + const Point2LL v12, + const Point2LL v02, + const int64_t shortcut_length, + double cos_angle); + + /*! + * Smooth out a complex corner where the shortcut bypasses more than two line segments + * + * Auxiliary function for \ref smooth_outward + * + * \warning This function might try to remove the whole polygon + * Error code -1 means the whole polygon should be removed (which means it is a hole polygon) + * + * \param p1 The corner point + * \param[in,out] p0_it Iterator to the last point checked before \p p1 to consider cutting off + * \param[in,out] p2_it Iterator to the last point checked after \p p1 to consider cutting off + * \param shortcut_length The desired length ofthe shortcutting line + * \return Whether this whole polygon whould be removed by the smoothing + */ + static bool smooth_corner_complex(const Point2LL p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length); + + /*! + * Try to take a step away from the corner point in order to take a bigger shortcut. + * + * Try to take the shortcut from a place as far away from the corner as the place we are taking the shortcut to. + * + * Auxiliary function for \ref smooth_outward + * + * \param[in] p1 The corner point + * \param[in] shortcut_length2 The square of the desired length ofthe shortcutting line + * \param[in,out] p0_it Iterator to the previously checked point somewhere beyond \p p1. Updated for the next iteration. + * \param[in,out] p2_it Iterator to the previously checked point somewhere before \p p1. Updated for the next iteration. + * \param[in,out] forward_is_blocked Whether trying another step forward is blocked by the smoothing outward condition. Updated for the next iteration. + * \param[in,out] backward_is_blocked Whether trying another step backward is blocked by the smoothing outward condition. Updated for the next iteration. + * \param[in,out] forward_is_too_far Whether trying another step forward is blocked by the shortcut length condition. Updated for the next iteration. + * \param[in,out] backward_is_too_far Whether trying another step backward is blocked by the shortcut length condition. Updated for the next iteration. + */ + static void smooth_outward_step( + const Point2LL p1, + const int64_t shortcut_length2, + ListPolyIt& p0_it, + ListPolyIt& p2_it, + bool& forward_is_blocked, + bool& backward_is_blocked, + bool& forward_is_too_far, + bool& backward_is_too_far); +}; + +} // namespace cura + +namespace std +{ +#if 0 +template<> +struct hash +{ + size_t operator()(const cura::PolygonPointer& poly) const + { + const cura::ConstPolygonRef ref = *static_cast(poly); + return std::hash()(&*ref); + } +}; +#endif +} // namespace std + +#endif // GEOMETRY_POLYGON_H diff --git a/include/utils/polygons.h b/include/geometry/polygons.h similarity index 55% rename from include/utils/polygons.h rename to include/geometry/polygons.h index 3991bf4afc..6e85f8a3b5 100644 --- a/include/utils/polygons.h +++ b/include/geometry/polygons.h @@ -1,116 +1,21 @@ // Copyright (c) 2023 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher -#ifndef UTILS_POLYGONS_H -#define UTILS_POLYGONS_H - -#include -#include -#include -#include -#include -#include -#include - -#include "../settings/types/Angle.h" -#include "../settings/types/Ratio.h" -#include "Point2LL.h" -#include "utils/ListPolyIt.h" -#include "utils/linearAlg2D.h" - -#define CHECK_POLY_ACCESS -#ifdef CHECK_POLY_ACCESS -#define POLY_ASSERT(e) assert(e) -#else -#define POLY_ASSERT(e) \ - do \ - { \ - } while (0) -#endif +#ifndef GEOMETRY_POLYGONS_H +#define GEOMETRY_POLYGONS_H + +#include "geometry/lines_set.h" +#include "geometry/polygon.h" +#include "settings/types/Angle.h" namespace cura { -using point_t = ClipperLib::IntPoint; -using path_t = ClipperLib::Path; -using paths_t = ClipperLib::Paths; - -class OpenPolyline; class Polygon; -class Polygons; -class PolygonsPart; +class Ratio; +class SingleShape; class PartsView; -template -class LinesSet : public std::vector -{ -public: - LinesSet() = default; - - LinesSet(const LinesSet& other) = default; - - LinesSet(LinesSet&& other) = default; - - LinesSet(const std::vector& lines) - : std::vector(lines) - { - } - - LinesSet(std::vector&& lines) - : std::vector(std::move(lines)) - { - } - - LinesSet(const std::vector& paths) - : std::vector(*reinterpret_cast*>(&paths)) - { - } - - LinesSet& operator=(const LinesSet& other) - { - std::vector::operator=(other); - return *this; - } - - LinesSet& operator=(LinesSet&& other) - { - std::vector::operator=(other); - return *this; - } - - void splitIntoSegments(std::vector& result) const; - std::vector splitIntoSegments() const; - - /*! - * Removes overlapping consecutive line segments which don't delimit a - * positive area. - * - * This function is meant to work on polygons, not polylines. When misused - * on polylines, it may cause too many vertices to be removed. - * See \ref removeDegenerateVertsPolyline for a version that works on - * polylines. - */ -#warning rename this to removeDegenerateVerts - void removeDegenerateVertsForEveryone(); - - Polygons offset(coord_t distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; - // Polygons offsetPolyLine(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, bool inputPolyIsClosed = false) const; - - const std::vector>& getCallable() const - { - // This does work as long as we don't add any attribute to the Polygon class or any of its - // parent until std::vector - return *reinterpret_cast>*>(this); - } - - std::vector>& getCallable() - { - // This does work as long as we don't add any attribute to the Polygon class or any of its - // parent until std::vector - return *reinterpret_cast>*>(this); - } -}; - class Polygons : public LinesSet { friend class Polygon; @@ -127,7 +32,7 @@ class Polygons : public LinesSet { } - Polygons(const std::vector& paths) + Polygons(const std::vector& paths) : LinesSet(paths) { } @@ -140,29 +45,8 @@ class Polygons : public LinesSet Polygons& operator=(Polygons&& polygons); - //!< Return the amount of points in all polygons - size_t pointCount() const; - - /*! - * Remove a polygon from the list and move the last polygon to its place - * - * \warning changes the order of the polygons! - */ - void remove(size_t index); - void add(const Polygons& other); - void addIfNotEmpty(const Polygon& polygon); - - void addIfNotEmpty(Polygon&& polygon); - - /*! - * Add a 'polygon' consisting of two points - */ - void addLine(const point_t& from, const point_t& to); - - Polygon& newPoly(); - /*! * Convert ClipperLib::PolyTree to a Polygons object, * which uses ClipperLib::Paths instead of ClipperLib::PolyTree @@ -194,7 +78,7 @@ class Polygons : public LinesSet * \param max_stitch_distance The maximum distance for two polylines to be stitched together with a segment * \return The resulting polylines limited to the area of this Polygons object */ - std::vector intersectionPolyLines(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; + LinesSet intersectionPolyLines(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; /*! * Add the front to each polygon so that the polygon is represented as a polyline @@ -233,26 +117,6 @@ class Polygons : public LinesSet */ bool inside(Point2LL p, bool border_result = false) const; - /*! - * Check if we are inside the polygon. We do this by tracing from the point towards the positive X direction, - * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. - * Care needs to be taken, if p.Y exactly matches a vertex to the right of p, then we need to count 1 intersect if the - * outline passes vertically past; and 0 (or 2) intersections if that point on the outline is a 'top' or 'bottom' vertex. - * The easiest way to do this is to break out two cases for increasing and decreasing Y ( from p0 to p1 ). - * A segment is tested if pa.Y <= p.Y < pb.Y, where pa and pb are the points (from p0,p1) with smallest & largest Y. - * When both have the same Y, no intersections are counted but there is a special test to see if the point falls - * exactly on the line. - * - * Returns false if outside, true if inside; if the point lies exactly on the border, will return \p border_result. - * - * \deprecated This function is old and no longer used. instead use \ref Polygons::inside - * - * \param p The point for which to check if it is inside this polygon - * \param border_result What to return when the point is exactly on the border - * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) - */ - bool insideOld(Point2LL p, bool border_result = false) const; - /*! * Find the polygon inside which point \p p resides. * @@ -316,7 +180,7 @@ class Polygons : public LinesSet void scale(const Ratio& ratio); - void translate(const point_t& delta); + void translate(const Point2LL& delta); /*! * Remove all but the polygons on the very outside. @@ -339,9 +203,9 @@ class Polygons : public LinesSet /*! * Split up the polygons into groups according to the even-odd rule. - * Each PolygonsPart in the result has an outline as first polygon, whereas the rest are holes. + * Each SingleShape in the result has an outline as first polygon, whereas the rest are holes. */ - std::vector splitIntoParts(bool unionAll = false) const; + std::vector splitIntoParts(bool unionAll = false) const; /*! * Sort the polygons into bins where each bin has polygons which are contained within one of the polygons in the previous bin. @@ -350,14 +214,6 @@ class Polygons : public LinesSet */ std::vector sortByNesting() const; - /*! - * Utility method for creating the tube (or 'donut') of a shape. - * \param inner_offset Offset relative to the original shape-outline towards the inside of the shape. Sort-of like a negative normal offset, except it's the offset part that's - * kept, not the shape. \param outer_offset Offset relative to the original shape-outline towards the outside of the shape. Comparable to normal offset. \return The resulting - * polygons. - */ - Polygons tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; - /*! * Split up the polygons into groups according to the even-odd rule. * Each vector in the result has the index to an outline as first index, whereas the rest are indices to holes. @@ -393,7 +249,7 @@ class Polygons : public LinesSet * Removes the same polygons from this set (and also empty polygons). * Polygons are considered the same if all points lie within [same_distance] of their counterparts. */ - Polygons remove(const Polygons& to_be_removed, int same_distance = 0) const; + Polygons removePolygon(const Polygons& to_be_removed, int same_distance = 0) const; Polygons processEvenOdd(ClipperLib::PolyFillType poly_fill_type = ClipperLib::PolyFillType::pftEvenOdd) const; @@ -408,18 +264,15 @@ class Polygons : public LinesSet */ void ensureManifold(); - coord_t length() const; + Point2LL min() const; - point_t min() const; - - point_t max() const; + Point2LL max() const; void applyMatrix(const PointMatrix& matrix); void applyMatrix(const Point3Matrix& matrix); -#warning If this is to be used, rename it - // Polygons offset(const std::vector& offset_dists) const; + Polygons offsetMulti(const std::vector& offset_dists) const; /*! * @brief Export the polygon to a WKT string @@ -444,95 +297,11 @@ class Polygons : public LinesSet * \param ret Where to store polygons which are not empty holes */ void removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Polygons& ret) const; - void splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const; + void splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const; void sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const; void splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Polygons& reordered, ClipperLib::PolyNode* node) const; }; -/*! - * A single area with holes. The first polygon is the outline, while the rest are holes within this outline. - * - * This class has little more functionality than Polygons, but serves to show that a specific instance is ordered such that the first Polygon is the outline and the rest are holes. - */ -class PolygonsPart : public Polygons -{ -public: - Polygon& outerPolygon() - { - return front(); - } - - const Polygon& outerPolygon() const - { - return front(); - } - - /*! - * Tests whether the given point is inside this polygon part. - * \param p The point to test whether it is inside. - * \param border_result If the point is exactly on the border, this will be - * returned instead. - */ - bool inside(Point2LL p, bool border_result = false) const; -}; - -/*! - * Extension of vector> which is similar to a vector of PolygonParts, except the base of the container is indices to polygons into the original Polygons, - * instead of the polygons themselves - */ -class PartsView : public std::vector> -{ -public: - Polygons& polygons_; - PartsView(Polygons& polygons) - : polygons_(polygons) - { - } - /*! - * Get the index of the PolygonsPart of which the polygon with index \p poly_idx is part. - * - * \param poly_idx The index of the polygon in \p polygons - * \param boundary_poly_idx Optional output parameter: The index of the boundary polygon of the part in \p polygons - * \return The PolygonsPart containing the polygon with index \p poly_idx - */ - size_t getPartContaining(size_t poly_idx, size_t* boundary_poly_idx = nullptr) const; - /*! - * Assemble the PolygonsPart of which the polygon with index \p poly_idx is part. - * - * \param poly_idx The index of the polygon in \p polygons - * \param boundary_poly_idx Optional output parameter: The index of the boundary polygon of the part in \p polygons - * \return The PolygonsPart containing the polygon with index \p poly_idx - */ - PolygonsPart assemblePartContaining(size_t poly_idx, size_t* boundary_poly_idx = nullptr) const; - /*! - * Assemble the PolygonsPart of which the polygon with index \p poly_idx is part. - * - * \param part_idx The index of the part - * \return The PolygonsPart with index \p poly_idx - */ - PolygonsPart assemblePart(size_t part_idx) const; -}; - -template -void LinesSet::splitIntoSegments(std::vector& result) const -{ - for (const LineType& line : (*this)) - { - line.splitIntoSegments(result); - } -} - -template -std::vector LinesSet::splitIntoSegments() const -{ - std::vector result; - for (const LineType& line : (*this)) - { - line.splitIntoSegments(result); - } - return result; -} - } // namespace cura namespace std @@ -550,4 +319,4 @@ struct hash #endif } // namespace std -#endif // UTILS_POLYGONS_H +#endif // GEOMETRY_POLYGONS_H diff --git a/include/geometry/polyline.h b/include/geometry/polyline.h new file mode 100644 index 0000000000..7cbc4ec51b --- /dev/null +++ b/include/geometry/polyline.h @@ -0,0 +1,130 @@ +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_POLYLINE_H +#define GEOMETRY_POLYLINE_H + +#include "geometry/points_set.h" +#include "geometry/polyline_type.h" +#include "geometry/segment_iterator.h" + +namespace cura +{ + +class OpenPolyline; +template +class LinesSet; +class AngleRadians; + +template +class Polyline : public PointsSet +{ + friend class Polygons; + +public: + static constexpr PolylineType type_ = PolylineTypeVal; + +public: + using segments_iterator = SegmentIterator; + using const_segments_iterator = SegmentIterator; + + Polyline() = default; + + Polyline(const std::initializer_list& initializer) + : PointsSet(initializer) + { + } + + Polyline(const std::vector& points) + : PointsSet(points) + { + } + + Polyline(std::vector&& points) + : PointsSet(points) + { + } + + /*Polyline& operator=(const Polyline& other) + { + std::vector::operator=(other); + return *this; + }*/ + + const_segments_iterator beginSegments() const; + + const_segments_iterator endSegments() const; + + segments_iterator beginSegments(); + + segments_iterator endSegments(); + + /*! + * Split these poly line objects into several line segment objects consisting of only two verts + * and store them in the \p result + */ + void splitIntoSegments(LinesSet& result) const; + LinesSet splitIntoSegments() const; + + /*! + * On Y-axis positive upward displays, Orientation will return true if the polygon's orientation is counter-clockwise. + * + * from http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/Orientation.htm + */ + bool orientation() const + { + return ClipperLib::Orientation(*this); + } + + coord_t length() const; + + bool shorterThan(const coord_t check_length) const; + + void reverse() + { + ClipperLib::ReversePath(*this); + } + + void removeColinearEdges(const AngleRadians max_deviation_angle); + + /*! + * Removes consecutive line segments with same orientation and changes this polygon. + * + * 1. Removes verts which are connected to line segments which are too small. + * 2. Removes verts which detour from a direct line from the previous and next vert by a too small amount. + * 3. Moves a vert when a small line segment is connected to a much longer one. in order to maintain the outline of the object. + * 4. Don't remove a vert when the impact on the outline of the object is too great. + * + * Note that the simplify is a best effort algorithm. It does not guarantee that no lines below the provided smallest_line_segment_squared are left. + * + * The following example (Two very long line segments (" & , respectively) that are connected by a very small line segment (i) is unsimplifable by this + * function, even though the actual area change of removing line segment i is very small. The reason for this is that in the case of long lines, even a small + * deviation from it's original direction is very noticeable in the final result, especially if the polygons above make a slightly different choice. + * + * """"""""""""""""""""""""""""""""i,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, + + * + * \param smallest_line_segment_squared maximal squared length of removed line segments + * \param allowed_error_distance_squared The square of the distance of the middle point to the line segment of the consecutive and previous point for which the middle point is + removed + */ + void simplify(const coord_t smallest_line_segment_squared = MM2INT(0.01) * MM2INT(0.01), const coord_t allowed_error_distance_squared = 25); + + /*! + * See simplify(.) + */ +#warning This can probably be merge with simplify ? + void simplifyPolyline(const coord_t smallest_line_segment_squared = 100, const coord_t allowed_error_distance_squared = 25); + +private: + /*! + * Private implementation for both simplify and simplifyPolygons. + * + * Made private to avoid accidental use of the wrong function. + */ + void _simplify(const coord_t smallest_line_segment_squared = 100, const coord_t allowed_error_distance_squared = 25, bool processing_polylines = false); +}; + +} // namespace cura + +#endif // GEOMETRY_POLYLINE_H diff --git a/include/utils/ShapeType.h b/include/geometry/polyline_type.h similarity index 60% rename from include/utils/ShapeType.h rename to include/geometry/polyline_type.h index 99456c1691..0042b5d943 100644 --- a/include/utils/ShapeType.h +++ b/include/geometry/polyline_type.h @@ -1,13 +1,13 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher -#ifndef UTILS_SHAPE_TYPE_H -#define UTILS_SHAPE_TYPE_H +#ifndef UTILS_POLYLINE_TYPE_H +#define UTILS_POLYLINE_TYPE_H namespace cura { -enum class ShapeType +enum class PolylineType { Open, Closed, @@ -16,4 +16,4 @@ enum class ShapeType } // namespace cura -#endif // UTILS_SHAPE_TYPE_H +#endif // UTILS_POLYLINE_TYPE_H diff --git a/include/geometry/segment_iterator.h b/include/geometry/segment_iterator.h new file mode 100644 index 0000000000..8da9c21eb4 --- /dev/null +++ b/include/geometry/segment_iterator.h @@ -0,0 +1,81 @@ +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_SEGMENT_ITERATOR_H +#define GEOMETRY_SEGMENT_ITERATOR_H + +#include "geometry/point2ll.h" + +namespace cura +{ + +// Custom iterator to loop over the segments of an existing polygon/polyline +template +struct SegmentIterator +{ + // Transitory structure used to iterate over segments within a polygon/polyline + struct Segment + { + using PointType = typename std::conditional::type; + + PointType& start; + PointType& end; + }; + + using iterator_category = std::random_access_iterator_tag; + using value_type = Segment; + using difference_type = std::ptrdiff_t; + using pointer = Segment*; + using reference = Segment&; + using source_iterator_type = typename std::conditional::const_iterator, typename std::vector::iterator>::type; + +private: + source_iterator_type current_pos_; + source_iterator_type begin_; + source_iterator_type before_end_; + +public: + SegmentIterator(source_iterator_type pos, source_iterator_type begin, source_iterator_type end) + : current_pos_(pos) + , begin_(begin) + , before_end_(end != begin ? std::prev(end) : end) + { + } + + Segment operator*() const + { + if (current_pos_ == before_end_) + { + return Segment{ *current_pos_, *begin_ }; + } + else + { + return Segment{ *current_pos_, *std::next(current_pos_) }; + } + } + + SegmentIterator& operator++() + { + current_pos_++; + return *this; + } + + bool operator==(const SegmentIterator& other) const + { + return current_pos_ == other.current_pos_; + } + + bool operator!=(const SegmentIterator& other) const + { + return ! (*this == other); + } + + friend difference_type operator-(const SegmentIterator& iterator1, const SegmentIterator& iterator2) + { + return iterator1.current_pos_ - iterator2.current_pos_; + } +}; + +} // namespace cura + +#endif // GEOMETRY_SEGMENT_ITERATOR_H diff --git a/include/geometry/single_shape.h b/include/geometry/single_shape.h new file mode 100644 index 0000000000..e4e232dddd --- /dev/null +++ b/include/geometry/single_shape.h @@ -0,0 +1,38 @@ +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_SINGLE_SHAPE_H +#define GEOMETRY_SINGLE_SHAPE_H + +#include "point2ll.h" +#include "geometry/polygons.h" + +namespace cura +{ + +class Polygon; + +/*! + * A single area with holes. The first polygon is the outline, while the rest are holes within this outline. + * + * This class has little more functionality than Polygons, but serves to show that a specific instance is ordered such that the first Polygon is the outline and the rest are holes. + */ +class SingleShape : public Polygons +{ +public: + Polygon& outerPolygon(); + + const Polygon& outerPolygon() const; + + /*! + * Tests whether the given point is inside this polygon part. + * \param p The point to test whether it is inside. + * \param border_result If the point is exactly on the border, this will be + * returned instead. + */ + bool inside(const Point2LL& p, bool border_result = false) const; +}; + +} // namespace cura + +#endif // GEOMETRY_MONO_SHAPE_H diff --git a/include/infill.h b/include/infill.h index 3f0cc19943..0f6495d472 100644 --- a/include/infill.h +++ b/include/infill.h @@ -15,7 +15,7 @@ #include "settings/types/Angle.h" #include "utils/AABB.h" #include "utils/ExtrusionLine.h" -#include "utils/Point2LL.h" +#include "geometry/point2ll.h" #include "utils/section_type.h" namespace cura @@ -203,7 +203,7 @@ class Infill void generate( std::vector& toolpaths, Polygons& result_polygons, - Polygons& result_lines, + LinesSet& result_lines, const Settings& settings, int layer_idx, SectionType section_type, @@ -358,7 +358,7 @@ class Infill * * \param include_start Wether to include the start point or not, useful when tracing a poly-line. */ - void appendTo(PolygonRef& result_polyline, const bool include_start = true); + void appendTo(OpenPolyline& result_polyline, const bool include_start = true); }; /*! @@ -374,7 +374,7 @@ class Infill void _generate( std::vector& toolpaths, Polygons& result_polygons, - Polygons& result_lines, + LinesSet& result_lines, const Settings& settings, const std::shared_ptr& cross_fill_pattern = nullptr, const std::shared_ptr& lightning_layer = nullptr, @@ -391,21 +391,21 @@ class Infill * \param[in,out] result_polygons The polygons to be multiplied (input and output) * \param[in,out] result_lines The lines to be multiplied (input and output) */ - void multiplyInfill(Polygons& result_polygons, Polygons& result_lines); + void multiplyInfill(Polygons& result_polygons, LinesSet& result_lines); /*! * Generate gyroid infill * \param result_polylines (output) The resulting polylines * \param result_polygons (output) The resulting polygons, if zigzagging accidentally happened to connect gyroid lines in a circle. */ - void generateGyroidInfill(Polygons& result_polylines, Polygons& result_polygons); + void generateGyroidInfill(LinesSet& result_polylines, Polygons& result_polygons); /*! * Generate lightning fill aka minfill aka 'Ribbed Support Vault Infill', see Tricard,Claux,Lefebvre/'Ribbed Support Vaults for 3D Printing of Hollowed Objects' * see https://hal.archives-ouvertes.fr/hal-02155929/document * \param result (output) The resulting polygons */ - void generateLightningInfill(const std::shared_ptr& lightning_layer, Polygons& result_lines); + void generateLightningInfill(const std::shared_ptr& lightning_layer, LinesSet& result_lines); /*! * Generate sparse concentric infill @@ -419,25 +419,25 @@ class Infill * Generate a rectangular grid of infill lines * \param[out] result (output) The resulting lines */ - void generateGridInfill(Polygons& result); + void generateGridInfill(LinesSet& result); /*! * Generate a shifting triangular grid of infill lines, which combine with consecutive layers into a cubic pattern * \param[out] result (output) The resulting lines */ - void generateCubicInfill(Polygons& result); + void generateCubicInfill(LinesSet& result); /*! * Generate a double shifting square grid of infill lines, which combine with consecutive layers into a tetrahedral pattern * \param[out] result (output) The resulting lines */ - void generateTetrahedralInfill(Polygons& result); + void generateTetrahedralInfill(LinesSet& result); /*! * Generate a double shifting square grid of infill lines, which combine with consecutive layers into a quarter cubic pattern * \param[out] result (output) The resulting lines */ - void generateQuarterCubicInfill(Polygons& result); + void generateQuarterCubicInfill(LinesSet& result); /*! * Generate a single shifting square grid of infill lines. @@ -447,26 +447,26 @@ class Infill * \param angle_shift The angle to add to the infill_angle * \param[out] result (output) The resulting lines */ - void generateHalfTetrahedralInfill(double pattern_z_shift, int angle_shift, Polygons& result); + void generateHalfTetrahedralInfill(double pattern_z_shift, int angle_shift, LinesSet& result); /*! * Generate a triangular grid of infill lines * \param[out] result (output) The resulting lines */ - void generateTriangleInfill(Polygons& result); + void generateTriangleInfill(LinesSet& result); /*! * Generate a triangular grid of infill lines * \param[out] result (output) The resulting lines */ - void generateTrihexagonInfill(Polygons& result); + void generateTrihexagonInfill(LinesSet& result); /*! * Generate a 3d pattern of subdivided cubes on their points * \param[out] result The resulting lines * \param[in] mesh Where the Cubic Subdivision Infill precomputation is stored */ - void generateCubicSubDivInfill(Polygons& result, const SliceMeshStorage& mesh); + void generateCubicSubDivInfill(LinesSet& result, const SliceMeshStorage& mesh); /*! * Generate a 3d pattern of subdivided cubes on their points @@ -474,7 +474,7 @@ class Infill * \param[out] result_polygons The resulting polygons * \param[out] result_lines The resulting lines */ - void generateCrossInfill(const SierpinskiFillProvider& cross_fill_provider, Polygons& result_polygons, Polygons& result_lines); + void generateCrossInfill(const SierpinskiFillProvider& cross_fill_provider, Polygons& result_polygons, LinesSet& result_lines); /*! * Convert a mapping from scanline to line_segment-scanline-intersections (\p cut_list) into line segments, using the even-odd rule @@ -487,7 +487,7 @@ class Infill * \param total_shift total shift of the scanlines in the direction perpendicular to the fill_angle. */ void addLineInfill( - Polygons& result, + LinesSet& result, const PointMatrix& rotation_matrix, const int scanline_min_idx, const int line_distance, @@ -506,7 +506,7 @@ class Infill * \param infill_rotation The angle of the generated lines * \param extra_shift extra shift of the scanlines in the direction perpendicular to the infill_rotation */ - void generateLineInfill(Polygons& result, int line_distance, const double& infill_rotation, coord_t extra_shift); + void generateLineInfill(LinesSet& result, int line_distance, const double& infill_rotation, coord_t extra_shift); /*! * Function for creating linear based infill types (Lines, ZigZag). @@ -524,7 +524,7 @@ class Infill * \param extra_shift extra shift of the scanlines in the direction perpendicular to the fill_angle */ void generateLinearBasedInfill( - Polygons& result, + LinesSet& result, const int line_distance, const PointMatrix& rotation_matrix, ZigzagConnectorProcessor& zigzag_connector_processor, @@ -578,7 +578,7 @@ class Infill * \param line_distance The distance between two lines which are in the same direction * \param infill_rotation The angle of the generated lines */ - void generateZigZagInfill(Polygons& result, const coord_t line_distance, const double& infill_rotation); + void generateZigZagInfill(LinesSet& result, const coord_t line_distance, const double& infill_rotation); /*! * determine how far the infill pattern should be shifted based on the values of infill_origin and \p infill_rotation @@ -620,7 +620,7 @@ class Infill * border of the infill area, similar to the zigzag pattern. * \param[in/out] result_lines The lines to connect together. */ - void connectLines(Polygons& result_lines); + void connectLines(LinesSet& result_lines); }; static_assert(concepts::semiregular, "Infill should be semiregular"); diff --git a/include/infill/GyroidInfill.h b/include/infill/GyroidInfill.h index 697ee26bc1..e19018c0af 100644 --- a/include/infill/GyroidInfill.h +++ b/include/infill/GyroidInfill.h @@ -1,5 +1,5 @@ -//Copyright (c) 2020 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2020 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #include "../utils/Coord_t.h" @@ -7,6 +7,10 @@ namespace cura { class Polygons; +class OpenPolyline; + +template +class LinesSet; class GyroidInfill { @@ -33,11 +37,9 @@ class GyroidInfill * \param z The Z coordinate of this layer. Different Z coordinates cause the pattern to vary, producing a 3D * pattern. */ - static void generateTotalGyroidInfill(Polygons& result_lines, bool zig_zaggify, coord_t line_distance, const Polygons& in_outline, coord_t z); - -private: + static void generateTotalGyroidInfill(LinesSet& result_lines, bool zig_zaggify, coord_t line_distance, const Polygons& in_outline, coord_t z); +private: }; } // namespace cura - diff --git a/include/infill/LightningDistanceField.h b/include/infill/LightningDistanceField.h index 3624fd72c7..728910ee5a 100644 --- a/include/infill/LightningDistanceField.h +++ b/include/infill/LightningDistanceField.h @@ -5,7 +5,7 @@ #define LIGHTNING_DISTANCE_FIELD_H #include "../utils/SquareGrid.h" //Tracking for each location the distance to overhang. -#include "../utils/polygon.h" //Using outlines to fill and tracking overhang. +#include "geometry/polygon.h" //Using outlines to fill and tracking overhang. namespace cura { diff --git a/include/infill/LightningLayer.h b/include/infill/LightningLayer.h index fe5a079e43..597c232ba6 100644 --- a/include/infill/LightningLayer.h +++ b/include/infill/LightningLayer.h @@ -21,7 +21,7 @@ using SparseLightningTreeNodeGrid = SparsePointGridInclusive boundary_location; //!< in case the gounding location is on the boundary + std::optional boundary_location; //!< in case the gounding location is on the boundary Point2LL p() const; }; @@ -68,7 +68,7 @@ class LightningLayer const coord_t supporting_radius, const coord_t wall_supporting_radius); - Polygons convertToLines(const Polygons& limit_to_outline, const coord_t line_width) const; + LinesSet convertToLines(const Polygons& limit_to_outline, const coord_t line_width) const; coord_t getWeightedDistance(const Point2LL& boundary_loc, const Point2LL& unsupported_location); diff --git a/include/infill/LightningTreeNode.h b/include/infill/LightningTreeNode.h index 0ebd5503a8..dc5cb89f83 100644 --- a/include/infill/LightningTreeNode.h +++ b/include/infill/LightningTreeNode.h @@ -9,8 +9,9 @@ #include #include -#include "../utils/polygon.h" +#include "geometry/polygon.h" #include "../utils/polygonUtils.h" +#include "geometry/polygons.h" namespace cura { @@ -239,7 +240,7 @@ class LightningTreeNode : public std::enable_shared_from_this * * \param output all branches in this tree connected into polylines */ - void convertToPolylines(Polygons& output, const coord_t line_width) const; + void convertToPolylines(LinesSet& output, const coord_t line_width) const; /*! If this was ever a direct child of the root, it'll have a previous grounding location. * @@ -258,9 +259,9 @@ class LightningTreeNode : public std::enable_shared_from_this * \param long_line a reference to a polyline in \p output which to continue building on in the recursion * \param output all branches in this tree connected into polylines */ - void convertToPolylines(size_t long_line_idx, Polygons& output) const; + void convertToPolylines(size_t long_line_idx, LinesSet& output) const; - void removeJunctionOverlap(Polygons& polylines, const coord_t line_width) const; + void removeJunctionOverlap(LinesSet& polylines, const coord_t line_width) const; bool is_root_; Point2LL p_; diff --git a/include/infill/NoZigZagConnectorProcessor.h b/include/infill/NoZigZagConnectorProcessor.h index 002fb0fb7b..8279205763 100644 --- a/include/infill/NoZigZagConnectorProcessor.h +++ b/include/infill/NoZigZagConnectorProcessor.h @@ -9,7 +9,10 @@ namespace cura { -class Polygons; +class OpenPolyline; + +template +class LinesSet; /*! * This processor adds no connection. This is for line infill pattern. @@ -17,7 +20,7 @@ class Polygons; class NoZigZagConnectorProcessor : public ZigzagConnectorProcessor { public: - NoZigZagConnectorProcessor(const PointMatrix& rotation_matrix, Polygons& result) + NoZigZagConnectorProcessor(const PointMatrix& rotation_matrix, LinesSet& result) : ZigzagConnectorProcessor( rotation_matrix, result, diff --git a/include/infill/SubDivCube.h b/include/infill/SubDivCube.h index bfb10f487a..cea8cae2ac 100644 --- a/include/infill/SubDivCube.h +++ b/include/infill/SubDivCube.h @@ -4,16 +4,22 @@ #ifndef INFILL_SUBDIVCUBE_H #define INFILL_SUBDIVCUBE_H +#include "geometry/point2ll.h" +#include "geometry/point3_matrix.h" +#include "geometry/point3ll.h" +#include "geometry/point_matrix.h" #include "settings/types/LayerIndex.h" #include "settings/types/Ratio.h" -#include "utils/Point2LL.h" -#include "utils/Point3LL.h" namespace cura { -class Polygons; +class Polygon; class SliceMeshStorage; +class OpenPolyline; + +template +class LinesSet; class SubDivCube { @@ -37,7 +43,7 @@ class SubDivCube * \param z the specified layer height * \param result (output) The resulting lines */ - void generateSubdivisionLines(const coord_t z, Polygons& result); + void generateSubdivisionLines(const coord_t z, LinesSet& result); private: /*! @@ -46,7 +52,7 @@ class SubDivCube * \param result (output) The resulting lines * \param directional_line_groups Array of 3 times a polylines. Used to keep track of line segments that are all pointing the same direction for line segment combining */ - void generateSubdivisionLines(const coord_t z, Polygons (&directional_line_groups)[3]); + void generateSubdivisionLines(const coord_t z, LinesSet (&directional_line_groups)[3]); struct CubeProperties { @@ -92,7 +98,7 @@ class SubDivCube * Adds the defined line to the specified polygons. It assumes that the specified polygons are all parallel lines. Combines line segments with touching ends closer than * epsilon. \param[out] group the polygons to add the line to \param from the first endpoint of the line \param to the second endpoint of the line */ - void addLineAndCombine(Polygons& group, Point2LL from, Point2LL to); + void addLineAndCombine(LinesSet& group, Point2LL from, Point2LL to); size_t depth_; //!< the recursion depth of the cube (0 is most recursed) Point3LL center_; //!< center location of the cube in absolute coordinates diff --git a/include/infill/ZigzagConnectorProcessor.h b/include/infill/ZigzagConnectorProcessor.h index 513ad9d8f1..a495ee5a8b 100644 --- a/include/infill/ZigzagConnectorProcessor.h +++ b/include/infill/ZigzagConnectorProcessor.h @@ -4,11 +4,20 @@ #ifndef INFILL_ZIGZAG_CONNECTOR_PROCESSOR_H #define INFILL_ZIGZAG_CONNECTOR_PROCESSOR_H -#include "../utils/polygon.h" //TODO: We have implementation in this header file! +#include + +#include "geometry/point2ll.h" namespace cura { +class Polygon; +class Polygons; +class PointMatrix; +class OpenPolyline; +template +class LinesSet; + /*! * Processor class for processing the connections between lines which makes the infill a zigzag pattern. * @@ -108,7 +117,13 @@ class ZigzagConnectorProcessor * \param skip_some_zags Whether to skip some zags * \param zag_skip_count Skip 1 zag in every N zags */ - ZigzagConnectorProcessor(const PointMatrix& rotation_matrix, Polygons& result, bool use_endpieces, bool connected_endpieces, bool skip_some_zags, int zag_skip_count) + ZigzagConnectorProcessor( + const PointMatrix& rotation_matrix, + LinesSet& result, + bool use_endpieces, + bool connected_endpieces, + bool skip_some_zags, + int zag_skip_count) : rotation_matrix_(rotation_matrix) , result_(result) , use_endpieces_(use_endpieces) @@ -156,7 +171,7 @@ class ZigzagConnectorProcessor * * \param polyline The polyline to add */ - void addPolyline(PolygonRef polyline); + void addPolyline(const Polygon& polyline); /*! * Checks whether the current connector should be added or not. @@ -188,7 +203,7 @@ class ZigzagConnectorProcessor protected: const PointMatrix& rotation_matrix_; //!< The rotation matrix used to enforce the infill angle - Polygons& result_; //!< The result of the computation + LinesSet& result_; //!< The result of the computation const bool use_endpieces_; //!< Whether to include end pieces or not const bool connected_endpieces_; //!< Whether the end pieces should be connected with the rest part of the infill @@ -212,29 +227,6 @@ class ZigzagConnectorProcessor std::vector current_connector_; }; -// -// Inline functions -// - -inline void ZigzagConnectorProcessor::reset() -{ - is_first_connector_ = true; - first_connector_end_scanline_index_ = 0; - last_connector_index_ = 0; - first_connector_.clear(); - current_connector_.clear(); -} - -inline void ZigzagConnectorProcessor::addPolyline(PolygonRef polyline) -{ - result_.emplace_back(polyline); - for (Point2LL& p : result_.back()) - { - p = rotation_matrix_.unapply(p); - } -} - - } // namespace cura diff --git a/include/pathPlanning/Comb.h b/include/pathPlanning/Comb.h index 289a5a1f5d..98276751c1 100644 --- a/include/pathPlanning/Comb.h +++ b/include/pathPlanning/Comb.h @@ -7,9 +7,11 @@ #include // To find the maximum for coord_t. #include // shared_ptr -#include "../settings/types/LayerIndex.h" // To store the layer on which we comb. -#include "../utils/polygon.h" -#include "../utils/polygonUtils.h" +#include "geometry/parts_view.h" +#include "geometry/polygon.h" +#include "geometry/single_shape.h" +#include "settings/types/LayerIndex.h" // To store the layer on which we comb. +#include "utils/polygonUtils.h" namespace cura { @@ -36,7 +38,7 @@ class SliceDataStorage; * perpendicular to its boundary. * * As an optimization, the combing paths inside are calculated on specifically - * those PolygonsParts within which to comb, while the boundary_outside isn't + * those SingleShapes within which to comb, while the boundary_outside isn't * split into outside parts, because generally there is only one outside part; * encapsulated holes occur less often. */ @@ -56,8 +58,8 @@ class Comb bool dest_is_inside_; //!< Whether the startPoint or endPoint is inside the inside boundary Point2LL in_or_mid_; //!< The point on the inside boundary, or in between the inside and outside boundary if the start/end point isn't inside the inside boudary Point2LL out_; //!< The point on the outside boundary - PolygonsPart dest_part_; //!< The assembled inside-boundary PolygonsPart in which the dest_point lies. (will only be initialized when Crossing::dest_is_inside holds) - std::optional dest_crossing_poly_; //!< The polygon of the part in which dest_point lies, which will be crossed (often will be the outside polygon) + SingleShape dest_part_; //!< The assembled inside-boundary SingleShape in which the dest_point lies. (will only be initialized when Crossing::dest_is_inside holds) + std::optional dest_crossing_poly_; //!< The polygon of the part in which dest_point lies, which will be crossed (often will be the outside polygon) const Polygons& boundary_inside_; //!< The inside boundary as in \ref Comb::boundary_inside const LocToLineGrid& inside_loc_to_line_; //!< The loc to line grid \ref Comb::inside_loc_to_line @@ -116,8 +118,8 @@ class Comb * \param comber[in] The combing calculator which has references to the offsets and boundaries to use in combing. * \return A pair of which the first is the crossing point on the inside boundary and the second the crossing point on the outside boundary */ - std::shared_ptr> - findBestCrossing(const ExtruderTrain& train, const Polygons& outside, ConstPolygonRef from, const Point2LL estimated_start, const Point2LL estimated_end, Comb& comber); + std::shared_ptr> + findBestCrossing(const ExtruderTrain& train, const Polygons& outside, const Polygon& from, const Point2LL estimated_start, const Point2LL estimated_end, Comb& comber); }; diff --git a/include/pathPlanning/CombPath.h b/include/pathPlanning/CombPath.h index 6559e8c7ee..2d73555141 100644 --- a/include/pathPlanning/CombPath.h +++ b/include/pathPlanning/CombPath.h @@ -4,7 +4,7 @@ #ifndef PATH_PLANNING_COMB_PATH_H #define PATH_PLANNING_COMB_PATH_H -#include "../utils/Point2LL.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/pathPlanning/GCodePath.h b/include/pathPlanning/GCodePath.h index 8ac4286082..28a3d2302b 100644 --- a/include/pathPlanning/GCodePath.h +++ b/include/pathPlanning/GCodePath.h @@ -12,7 +12,7 @@ #include "TimeMaterialEstimates.h" #include "settings/types/Ratio.h" #include "sliceDataStorage.h" -#include "utils/Point2LL.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/pathPlanning/LinePolygonsCrossings.h b/include/pathPlanning/LinePolygonsCrossings.h index 5fb641dd9b..68f4cfd97d 100644 --- a/include/pathPlanning/LinePolygonsCrossings.h +++ b/include/pathPlanning/LinePolygonsCrossings.h @@ -4,9 +4,10 @@ #ifndef PATH_PLANNING_LINE_POLYGONS_CROSSINGS_H #define PATH_PLANNING_LINE_POLYGONS_CROSSINGS_H -#include "../utils/polygon.h" -#include "../utils/polygonUtils.h" #include "CombPath.h" +#include "geometry/point_matrix.h" +#include "geometry/polygon.h" +#include "utils/polygonUtils.h" namespace cura { diff --git a/include/plugins/converters.h b/include/plugins/converters.h index 01870b2056..5e736b38bc 100644 --- a/include/plugins/converters.h +++ b/include/plugins/converters.h @@ -4,6 +4,14 @@ #ifndef PLUGINS_CONVERTERS_H #define PLUGINS_CONVERTERS_H +#include +#include +#include + +#include +#include +#include + #include "Cura.pb.h" #include "WallToolPaths.h" #include "cura/plugins/slots/broadcast/v0/broadcast.grpc.pb.h" @@ -24,15 +32,7 @@ #include "plugins/types.h" #include "settings/Settings.h" #include "settings/types/LayerIndex.h" -#include "utils/polygon.h" - -#include -#include -#include - -#include -#include -#include +#include "geometry/polygon.h" namespace cura::plugins @@ -106,7 +106,8 @@ struct infill_generate_request : public details::converter>, Polygons, Polygons>> + : public details:: + converter>, Polygons, LinesSet>> { native_value_type operator()(const value_type& message) const; }; diff --git a/include/plugins/slots.h b/include/plugins/slots.h index 3ca98c2e54..8ff484a914 100644 --- a/include/plugins/slots.h +++ b/include/plugins/slots.h @@ -21,9 +21,9 @@ #include "plugins/slotproxy.h" #include "plugins/types.h" #include "plugins/validator.h" -#include "utils/Point2LL.h" +#include "geometry/point2ll.h" #include "utils/Simplify.h" // TODO: Remove once the simplify slot has been removed -#include "utils/polygon.h" +#include "geometry/polygon.h" #include "utils/types/char_range_literal.h" namespace cura @@ -51,7 +51,7 @@ struct simplify_default struct infill_generate_default { - std::tuple, Polygons, Polygons> operator()([[maybe_unused]] auto&&... args) + std::tuple, Polygons, LinesSet> operator()([[maybe_unused]] auto&&... args) { // this code is only reachable when no slot is registered while the infill type is requested to be // generated by a plugin; this should not be possible to set up in the first place. Return an empty diff --git a/include/plugins/types.h b/include/plugins/types.h index eb443d0b27..df2132614e 100644 --- a/include/plugins/types.h +++ b/include/plugins/types.h @@ -11,8 +11,8 @@ #include #include "cura/plugins/v0/slot_id.pb.h" -#include "utils/Point2LL.h" -#include "utils/polygon.h" +#include "geometry/point2ll.h" +#include "geometry/polygon.h" namespace fmt { diff --git a/include/settings/ZSeamConfig.h b/include/settings/ZSeamConfig.h index db1fb49ef9..19348bd4b5 100644 --- a/include/settings/ZSeamConfig.h +++ b/include/settings/ZSeamConfig.h @@ -4,7 +4,7 @@ #ifndef ZSEAMCONFIG_H #define ZSEAMCONFIG_H -#include "../utils/Point2LL.h" //To store the preferred seam position. +#include "geometry/point2ll.h" //To store the preferred seam position. #include "EnumSettings.h" //For EZSeamType and EZSeamCornerPrefType. namespace cura diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index e18a3783d3..34ec3782ee 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -13,14 +13,16 @@ #include "SupportInfillPart.h" #include "TopSurface.h" #include "WipeScriptConfig.h" +#include "geometry/open_polyline.h" +#include "geometry/point2ll.h" +#include "geometry/polygon.h" +#include "geometry/single_shape.h" #include "settings/Settings.h" //For MAX_EXTRUDERS. #include "settings/types/Angle.h" //Infill angles. #include "settings/types/LayerIndex.h" #include "utils/AABB.h" #include "utils/AABB3D.h" #include "utils/NoCopy.h" -#include "utils/Point2LL.h" -#include "utils/polygon.h" // libArachne #include "utils/ExtrusionLine.h" @@ -40,8 +42,8 @@ class LightningGenerator; class SkinPart { public: - PolygonsPart outline; //!< The skinOutline is the area which needs to be 100% filled to generate a proper top&bottom filling. It's filled by the "skin" module. Includes both - //!< roofing and non-roofing. + SingleShape outline; //!< The skinOutline is the area which needs to be 100% filled to generate a proper top&bottom filling. It's filled by the "skin" module. Includes both + //!< roofing and non-roofing. Polygons skin_fill; //!< The part of the skin which is not roofing. Polygons roofing_fill; //!< The inner infill which has air directly above Polygons top_most_surface_fill; //!< The inner infill of the uppermost top layer which has air directly above. @@ -59,9 +61,9 @@ class SliceLayerPart AABB boundaryBox; //!< The boundaryBox is an axis-aligned boundary box which is used to quickly check for possible //!< collision between different parts on different layers. It's an optimization used during //!< skin calculations. - PolygonsPart outline; //!< The outline is the first member that is filled, and it's filled with polygons that match - //!< a cross-section of the 3D model. The first polygon is the outer boundary polygon and the - //!< rest are holes. + SingleShape outline; //!< The outline is the first member that is filled, and it's filled with polygons that match + //!< a cross-section of the 3D model. The first polygon is the outer boundary polygon and the + //!< rest are holes. Polygons print_outline; //!< An approximation to the outline of what's actually printed, based on the outer wall. //!< Too small parts will be omitted compared to the outline. Polygons spiral_wall; //!< The centerline of the wall used by spiralize mode. Only computed if spiralize mode is enabled. @@ -166,7 +168,7 @@ class SliceLayer coord_t printZ; //!< The height at which this layer needs to be printed. Can differ from sliceZ due to the raft. coord_t thickness; //!< The thickness of this layer. Can be different when using variable layer heights. std::vector parts; //!< An array of LayerParts which contain the actual data. The parts are printed one at a time to minimize travel outside of the 3D model. - Polygons openPolyLines; //!< A list of lines which were never hooked up into a 2D polygon. (Currently unused in normal operation) + LinesSet openPolyLines; //!< A list of lines which were never hooked up into a 2D polygon. (Currently unused in normal operation) /*! * \brief The parts of the model that are exposed at the very top of the @@ -336,7 +338,7 @@ class SliceMeshStorage */ struct SkirtBrimLine { - Polygons open_polylines; + LinesSet open_polylines; Polygons closed_polygons; }; @@ -354,7 +356,7 @@ class SliceDataStorage : public NoCopy SupportStorage support; std::vector skirt_brim[MAX_EXTRUDERS]; //!< Skirt/brim polygons per extruder, ordered from inner to outer polygons. - Polygons support_brim; //!< brim lines for support, going from the edge of the support inward. \note Not ordered by inset. + LinesSet support_brim; //!< brim lines for support, going from the edge of the support inward. \note Not ordered by inset. // Storage for the outline of the raft-parts. Will be filled with lines when the GCode is generated. Polygons raftBaseOutline; diff --git a/include/slicer.h b/include/slicer.h index 37cd45f122..4f9bd0fcda 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -9,7 +9,8 @@ #include #include "settings/EnumSettings.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" +#include "geometry/polygons.h" /* The Slicer creates layers of polygons from an optimized 3D model. @@ -61,7 +62,7 @@ class SlicerLayer int z = -1; Polygons polygons; - Polygons openPolylines; + LinesSet openPolylines; /*! * \brief Connect the segments into polygons for this layer of this \p mesh. @@ -76,7 +77,7 @@ class SlicerLayer * * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop */ - void makeBasicPolygonLoops(Polygons& open_polylines); + void makeBasicPolygonLoops(std::vector& open_polylines); /*! * Connect the segments into a loop, starting from the segment with index \p start_segment_idx @@ -84,7 +85,7 @@ class SlicerLayer * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop * \param[in] start_segment_idx The index into SlicerLayer::segments for the first segment from which to start the polygon loop */ - void makeBasicPolygonLoop(Polygons& open_polylines, const size_t start_segment_idx); + void makeBasicPolygonLoop(std::vector& open_polylines, const size_t start_segment_idx); /*! * Get the next segment connected to the end of \p segment. @@ -104,7 +105,7 @@ class SlicerLayer * * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop */ - void connectOpenPolylines(Polygons& open_polylines); + void connectOpenPolylines(std::vector& open_polylines); /*! * Link up all the missing ends, closing up the smallest gaps first. This is an inefficient implementation which can run in O(n*n*n) time. @@ -113,7 +114,7 @@ class SlicerLayer * * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop yet */ - void stitch(Polygons& open_polylines); + void stitch(std::vector& open_polylines); std::optional findPolygonGapCloser(Point2LL ip0, Point2LL ip1); @@ -126,7 +127,7 @@ class SlicerLayer * * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop yet */ - void stitch_extensive(Polygons& open_polylines); + void stitch_extensive(std::vector& open_polylines); private: /*! @@ -417,7 +418,7 @@ class SlicerLayer * the order of a polyline. * \return The stitches that are allowed in order from best to worst. */ - std::priority_queue findPossibleStitches(const Polygons& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) const; + std::priority_queue findPossibleStitches(const std::vector& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) const; /*! Plans the best way to perform a stitch. * @@ -435,7 +436,7 @@ class SlicerLayer * \param[in,out] terminus_1 the Terminus on polyline_1 to join at. * \param[out] reverse Whether the polylines need to be reversed. */ - void planPolylineStitch(const Polygons& open_polylines, Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const; + void planPolylineStitch(const std::vector& open_polylines, Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const; /*! Joins polyline_1 onto polyline_0. * @@ -453,7 +454,7 @@ class SlicerLayer * polyline_0 and reverse[1] indicates whether to reverse * polyline_1 */ - void joinPolylines(PolygonRef& polyline_0, PolygonRef& polyline_1, const bool reverse[2]) const; + static void joinPolylines(OpenPolyline& polyline_0, OpenPolyline& polyline_1, const bool reverse[2]); /*! * Connecting polylines that are not closed yet. @@ -473,7 +474,7 @@ class SlicerLayer * \param[in] allow_reverse If true, then this function is allowed * to reverse edge directions to merge polylines. */ - void connectOpenPolylinesImpl(Polygons& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse); + void connectOpenPolylinesImpl(std::vector& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse); }; class Slicer diff --git a/include/support.h b/include/support.h index 81b1218929..739c2f2661 100644 --- a/include/support.h +++ b/include/support.h @@ -8,7 +8,7 @@ #include #include "settings/types/LayerIndex.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" namespace cura { diff --git a/include/utils/AABB.h b/include/utils/AABB.h index b69d8c2c57..57e3e8c2b6 100644 --- a/include/utils/AABB.h +++ b/include/utils/AABB.h @@ -4,12 +4,11 @@ #ifndef UTILS_AABB_H #define UTILS_AABB_H -#include "Point2LL.h" +#include "geometry/point2ll.h" namespace cura { -class ConstPolygonRef; class Polygon; class Polygons; @@ -22,10 +21,10 @@ class AABB AABB(); //!< initializes with invalid min and max AABB(const Point2LL& min, const Point2LL& max); //!< initializes with given min and max AABB(const Polygons& polys); //!< Computes the boundary box for the given polygons - AABB(ConstPolygonRef poly); //!< Computes the boundary box for the given polygons + AABB(const Polygon& poly); //!< Computes the boundary box for the given polygons void calculate(const Polygons& polys); //!< Calculates the aabb for the given polygons (throws away old min and max data of this aabb) - void calculate(ConstPolygonRef poly); //!< Calculates the aabb for the given polygon (throws away old min and max data of this aabb) + void calculate(const Polygon& poly); //!< Calculates the aabb for the given polygon (throws away old min and max data of this aabb) /*! * Whether the bounding box contains the specified point. @@ -79,7 +78,9 @@ class AABB * * \param point The point to include in the bounding box. */ - void include(Point2LL point); + void include(const Point2LL& point); + + void include(const Polygon& polygon); /*! * \brief Includes the specified bounding box in the bounding box. @@ -90,7 +91,7 @@ class AABB * * \param other The bounding box to include in this one. */ - void include(const AABB other); + void include(const AABB& other); /*! * Expand the borders of the bounding box in each direction with the given amount diff --git a/include/utils/AABB3D.h b/include/utils/AABB3D.h index 48142d24ce..a505c0cf52 100644 --- a/include/utils/AABB3D.h +++ b/include/utils/AABB3D.h @@ -4,7 +4,7 @@ #ifndef UTILS_AABB3D_H #define UTILS_AABB3D_H -#include "Point2LL.h" +#include "geometry/point2ll.h" #include "utils/AABB.h" namespace cura diff --git a/include/utils/ExtrusionJunction.h b/include/utils/ExtrusionJunction.h index 66cb46c9cc..d1621fa75f 100644 --- a/include/utils/ExtrusionJunction.h +++ b/include/utils/ExtrusionJunction.h @@ -5,7 +5,7 @@ #ifndef UTILS_EXTRUSION_JUNCTION_H #define UTILS_EXTRUSION_JUNCTION_H -#include "Point2LL.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/utils/ExtrusionLine.h b/include/utils/ExtrusionLine.h index 4b3eb2c84b..f54b527073 100644 --- a/include/utils/ExtrusionLine.h +++ b/include/utils/ExtrusionLine.h @@ -10,7 +10,8 @@ #include #include "ExtrusionJunction.h" -#include "polygon.h" +#include "geometry/polygon.h" +#include "geometry/polygons.h" namespace cura { @@ -208,11 +209,7 @@ struct ExtrusionLine /*! * Sum the total length of this path. */ - coord_t getLength() const; - coord_t polylineLength() const - { - return getLength(); - } + coord_t length() const; /*! * Put all junction locations into a polygon object. @@ -224,7 +221,7 @@ struct ExtrusionLine Polygon ret; for (const ExtrusionJunction& j : junctions_) - ret.add(j.p_); + ret.push_back(j.p_); return ret; } @@ -264,8 +261,8 @@ struct ExtrusionLine add_line_direction(junctions_ | ranges::views::reverse); Polygons paths; - paths.emplace_back(poly.poly); - ClipperLib::SimplifyPolygons(paths.paths, ClipperLib::pftNonZero); + paths.emplace_back(poly); + ClipperLib::SimplifyPolygons(paths.getCallable(), ClipperLib::pftNonZero); return paths; } diff --git a/include/utils/ExtrusionLineStitcher.h b/include/utils/ExtrusionLineStitcher.h new file mode 100644 index 0000000000..ca7b72f22f --- /dev/null +++ b/include/utils/ExtrusionLineStitcher.h @@ -0,0 +1,16 @@ +// Copyright (c) 2022 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#ifndef UTILS_EXTRUSION_LINE_STITCHER_H +#define UTILS_EXTRUSION_LINE_STITCHER_H + +#include "PolylineStitcher.h" +#include "utils/ExtrusionLine.h" + +namespace cura +{ + +using ExtrusionLineStitcher = PolylineStitcher; + +} // namespace cura +#endif // UTILS_EXTRUSION_LINE_STITCHER_H diff --git a/include/utils/ExtrusionSegment.h b/include/utils/ExtrusionSegment.h index 99430f8789..2f888ada6c 100644 --- a/include/utils/ExtrusionSegment.h +++ b/include/utils/ExtrusionSegment.h @@ -8,8 +8,8 @@ #include #include "ExtrusionJunction.h" -#include "Point2LL.h" -#include "polygon.h" +#include "geometry/point2ll.h" +#include "geometry/polygon.h" #include "polygonUtils.h" namespace cura diff --git a/include/utils/HalfEdge.h b/include/utils/HalfEdge.h index ae8736f589..d1e91cfa81 100644 --- a/include/utils/HalfEdge.h +++ b/include/utils/HalfEdge.h @@ -7,7 +7,7 @@ #include #include -#include "../utils/Point2LL.h" +#include "geometry/point2ll.h" #include "Coord_t.h" namespace cura diff --git a/include/utils/HalfEdgeNode.h b/include/utils/HalfEdgeNode.h index 163b45d07b..117e3c285d 100644 --- a/include/utils/HalfEdgeNode.h +++ b/include/utils/HalfEdgeNode.h @@ -6,7 +6,7 @@ #include -#include "Point2LL.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/utils/ImplicitSharedDataContainer.h b/include/utils/ImplicitSharedDataContainer.h new file mode 100644 index 0000000000..ab706d7f0e --- /dev/null +++ b/include/utils/ImplicitSharedDataContainer.h @@ -0,0 +1,188 @@ +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef UTILS_IMPLICITSHAREDDATACONTAINER_H +#define UTILS_IMPLICITSHAREDDATACONTAINER_H + +namespace cura +{ + +template +class ImplicitSharedDataContainer +{ +public: + virtual ImplicitSharedDataContainer& operator=(const ImplicitSharedDataContainer& other) noexcept + { + data_ = other.data_; + return *this; + } + + virtual ImplicitSharedDataContainer& operator=(ImplicitSharedDataContainer&& other) noexcept + { + data_ = std::move(other.data_); + return *this; + } + +protected: + ImplicitSharedDataContainer() noexcept + : data_(std::make_shared()) + { + } + + ImplicitSharedDataContainer(const ImplicitSharedDataContainer& other) noexcept = default; + + ImplicitSharedDataContainer(ImplicitSharedDataContainer&& movable) noexcept = default; + + virtual ~ImplicitSharedDataContainer() = default; + + inline const DataType& getData() const noexcept + { + return *data_; + } + + DataType& getData() noexcept + { + if (! data_.unique()) + { + // Data is shared, make it unique so that we can modify it + data_ = std::make_shared(*data_); + } + + return *data_; + } + +private: + std::shared_ptr data_; +}; + +template +class ImplicitArraydDataContainer : public ImplicitSharedDataContainer +{ +public: + inline size_t size() const noexcept + { + return getData().size(); + } + + inline bool empty() const noexcept + { + return getData().empty(); + } + + DataType::const_reference operator[](size_t index) const + { + return getData()[index]; + } + + void reserve(size_t min_size) noexcept + { + getData().reserve(min_size); + } + + /*template + ClipperLib::Path::iterator insert(ClipperLib::Path::const_iterator pos, iterator first, iterator last) + { + return path_->insert(pos, first, last); + }*/ + + void add(const DataType::const_reference value) noexcept + { + getData().push_back(value); + } + + template + void emplace_back(Args&&... args) noexcept + { + getData().emplace_back(args...); + } + + void remove(size_t index) + { + DataType& data = getData(); + assert(index < data.size() && index <= static_cast(std::numeric_limits::max())); + data.erase(data.begin() + static_cast(index)); + } + + /*! + * Removes an element from the list and moves the last elements to its place. This is usually + * faster to process because it does only requires to resize the list. + * + * \warning The counterpart it that it changes the order of the elements ! + */ + void removeFast(size_t index) + { + DataType& data = getData(); + assert(index < data.size()); + if (index < data.size() - 1) + { + data[index] = std::move(data.back()); + } + data.resize(data.size() - 1); + } + + void insert(size_t index, DataType::const_reference value) + { + DataType& data = getData(); + assert(index < data.size() && index <= static_cast(std::numeric_limits::max())); + data.insert(std::next(), data.begin() + static_cast(index), value); + } + + void clear() noexcept + { + getData().clear(); + } + + void pop_back() + { + getData().pop_back(); + } + + void erase(DataType::iterator start, DataType::iterator end) + { + getData().erase(start, end); + } + + DataType::iterator begin() noexcept + { + return getData().begin(); + } + + DataType::const_iterator begin() const noexcept + { + return getData().begin(); + } + + DataType::iterator end() noexcept + { + return getData().end(); + } + + DataType::const_iterator end() const noexcept + { + return getData().end(); + } + + DataType::reference front() noexcept + { + return getData().front(); + } + + DataType::const_reference front() const noexcept + { + return getData().front(); + } + + DataType::reference back() noexcept + { + return getData().back(); + } + + DataType::const_reference back() const noexcept + { + return getData().back(); + } +}; + +} // namespace cura + +#endif // UTILS_IMPLICITSHAREDDATACONTAINER_H diff --git a/include/utils/ListPolyIt.h b/include/utils/ListPolyIt.h index 0847305bdf..11161beb1c 100644 --- a/include/utils/ListPolyIt.h +++ b/include/utils/ListPolyIt.h @@ -7,13 +7,18 @@ #include #include -#include "Point2LL.h" -#include "polygon.h" +#include "geometry/point2ll.h" namespace cura { +class Polygon; +class Polygons; + +using ListPolygon = std::list; //!< A polygon represented by a linked list instead of a vector +using ListPolygons = std::vector; //!< Polygons represented by a vector of linked lists instead of a vector of vectors + /*! * A wrapper class for a ListPolygon::iterator and a reference to the containing ListPolygon */ @@ -118,7 +123,7 @@ class ListPolyIt * \param polys The polygons to convert * \param result The converted polygons */ - static void convertPolygonToList(ConstPolygonRef poly, ListPolygon& result); + static void convertPolygonToList(const Polygon& poly, ListPolygon& result); /*! * Convert ListPolygons to Polygons @@ -134,7 +139,7 @@ class ListPolyIt * \param list_polygons The polygons to convert * \param polygons The converted polygons */ - static void convertListPolygonToPolygon(const ListPolygon& list_polygon, PolygonRef polygon); + static void convertListPolygonToPolygon(const ListPolygon& list_polygon, Polygon& polygon); /*! * Insert a point into a ListPolygon if it's not a duplicate of the point before or the point after. diff --git a/include/utils/MinimumSpanningTree.h b/include/utils/MinimumSpanningTree.h index 599ab2273b..4b88607f94 100644 --- a/include/utils/MinimumSpanningTree.h +++ b/include/utils/MinimumSpanningTree.h @@ -8,7 +8,7 @@ #include #include -#include "Point2LL.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/utils/OpenPolylineStitcher.h b/include/utils/OpenPolylineStitcher.h new file mode 100644 index 0000000000..a4576ba735 --- /dev/null +++ b/include/utils/OpenPolylineStitcher.h @@ -0,0 +1,18 @@ +// Copyright (c) 2024 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#ifndef UTILS_OPEN_POLYLINE_STITCHER_H +#define UTILS_OPEN_POLYLINE_STITCHER_H + +#include "PolylineStitcher.h" +#include "geometry/open_polyline.h" +#include "geometry/polygon.h" +#include "geometry/polygons.h" + +namespace cura +{ + +using OpenPolylineStitcher = PolylineStitcher, Polygons, OpenPolyline, Point2LL>; + +} // namespace cura +#endif // UTILS_OPEN_POLYLINE_STITCHER_H diff --git a/include/utils/Point3D.h b/include/utils/Point3D.h index 8405d03c4d..0fb3b540a0 100644 --- a/include/utils/Point3D.h +++ b/include/utils/Point3D.h @@ -7,7 +7,7 @@ #include #include -#include "Point2LL.h" +#include "geometry/point2ll.h" namespace cura diff --git a/include/utils/Point3F.h b/include/utils/Point3F.h index 44262ad2b0..4fe49067d4 100644 --- a/include/utils/Point3F.h +++ b/include/utils/Point3F.h @@ -7,7 +7,7 @@ #include #include -#include "Point2LL.h" +#include "geometry/point2ll.h" #include "Point3D.h" diff --git a/include/utils/PolygonConnector.h b/include/utils/PolygonConnector.h index 3dc7b75dec..c9fa24d2f6 100644 --- a/include/utils/PolygonConnector.h +++ b/include/utils/PolygonConnector.h @@ -9,10 +9,11 @@ #endif #include -#include "Point2LL.h" +#include "geometry/point2ll.h" +#include "geometry/polygon.h" #include "linearAlg2D.h" -#include "polygon.h" #include "polygonUtils.h" +#include "settings/types/Ratio.h" namespace cura { diff --git a/include/utils/PolygonsPointIndex.h b/include/utils/PolygonsPointIndex.h index c4ce020105..cf38f1980e 100644 --- a/include/utils/PolygonsPointIndex.h +++ b/include/utils/PolygonsPointIndex.h @@ -6,8 +6,9 @@ #include -#include "Point2LL.h" -#include "polygon.h" +#include "geometry/point2ll.h" +#include "geometry/polygon.h" +#include "geometry/polygons.h" namespace cura @@ -79,7 +80,7 @@ class PathsPointIndex /*! * Get the polygon to which this PolygonsPointIndex refers */ - ConstPolygonRef getPolygon() const; + const Polygon& getPolygon() const; /*! * Test whether two iterators refer to the same polygon in the same polygon list. @@ -153,14 +154,7 @@ using PolygonsPointIndex = PathsPointIndex; */ struct PolygonsPointIndexSegmentLocator { - std::pair operator()(const PolygonsPointIndex& val) const - { - ConstPolygonRef poly = (*val.polygons_)[val.poly_idx_]; - Point2LL start = poly[val.point_idx_]; - size_t next_point_idx = (val.point_idx_ + 1ul) % poly.size(); - Point2LL end = poly[next_point_idx]; - return std::pair(start, end); - } + std::pair operator()(const PolygonsPointIndex& val) const; }; diff --git a/include/utils/PolylineStitcher.h b/include/utils/PolylineStitcher.h index 7d608f1ee7..6c9b51dcff 100644 --- a/include/utils/PolylineStitcher.h +++ b/include/utils/PolylineStitcher.h @@ -5,20 +5,19 @@ #define UTILS_POLYLINE_STITCHER_H #include -#include -#include "PolygonsPointIndex.h" #include "SparsePointGrid.h" -#include "SymmetricPair.h" -#include "polygon.h" namespace cura { +template +class PathsPointIndex; + /*! * Class for stitching polylines into longer polylines or into polygons */ -template +template class PolylineStitcher { public: @@ -52,191 +51,12 @@ class PolylineStitcher * \param snap_distance Points closer than this distance are considered to * be the same point. */ - static void stitch(const Paths& lines, Paths& result_lines, Paths& result_polygons, coord_t max_stitch_distance = MM2INT(0.1), coord_t snap_distance = 10) - { - if (lines.empty()) - { - return; - } - - SparsePointGrid, PathsPointIndexLocator> grid(max_stitch_distance, lines.size() * 2); - - // populate grid - for (size_t line_idx = 0; line_idx < lines.size(); line_idx++) - { - const auto line = lines[line_idx]; - grid.insert(PathsPointIndex(&lines, line_idx, 0)); - grid.insert(PathsPointIndex(&lines, line_idx, line.size() - 1)); - } - - std::vector processed(lines.size(), false); - - for (size_t line_idx = 0; line_idx < lines.size(); line_idx++) - { - if (processed[line_idx]) - { - continue; - } - processed[line_idx] = true; - const auto line = lines[line_idx]; - bool should_close = isOdd(line); - - Path chain = line; - bool closest_is_closing_polygon = false; - for (bool go_in_reverse_direction : { false, true }) // first go in the unreversed direction, to try to prevent the chain.reverse() operation. - { // NOTE: Implementation only works for this order; we currently only re-reverse the chain when it's closed. - if (go_in_reverse_direction) - { // try extending chain in the other direction - chain.reverse(); - } - coord_t chain_length = chain.polylineLength(); - - while (true) - { - Point2LL from = make_point(chain.back()); - - PathsPointIndex closest; - coord_t closest_distance = std::numeric_limits::max(); - grid.processNearby( - from, - max_stitch_distance, - std::function&)>( - [from, - &chain, - &closest, - &closest_is_closing_polygon, - &closest_distance, - &processed, - &chain_length, - go_in_reverse_direction, - max_stitch_distance, - snap_distance, - should_close](const PathsPointIndex& nearby) -> bool - { - bool is_closing_segment = false; - coord_t dist = vSize(nearby.p() - from); - if (dist > max_stitch_distance) - { - return true; // keep looking - } - if (vSize2(nearby.p() - make_point(chain.front())) < snap_distance * snap_distance) - { - if (chain_length + dist < 3 * max_stitch_distance // prevent closing of small poly, cause it might be able to continue making a larger polyline - || chain.size() <= 2) // don't make 2 vert polygons - { - return true; // look for a better next line - } - is_closing_segment = true; - if (! should_close) - { - dist += 10; // prefer continuing polyline over closing a polygon; avoids closed zigzags from being printed separately - // continue to see if closing segment is also the closest - // there might be a segment smaller than [max_stitch_distance] which closes the polygon better - } - else - { - dist -= 10; // Prefer closing the polygon if it's 100% even lines. Used to create closed contours. - // Continue to see if closing segment is also the closest. - } - } - else if (processed[nearby.poly_idx_]) - { // it was already moved to output - return true; // keep looking for a connection - } - bool nearby_would_be_reversed = nearby.point_idx_ != 0; - nearby_would_be_reversed - = nearby_would_be_reversed != go_in_reverse_direction; // flip nearby_would_be_reversed when searching in the reverse direction - if (! canReverse(nearby) && nearby_would_be_reversed) - { // connecting the segment would reverse the polygon direction - return true; // keep looking for a connection - } - if (! canConnect(chain, (*nearby.polygons_)[nearby.poly_idx_])) - { - return true; // keep looking for a connection - } - if (dist < closest_distance) - { - closest_distance = dist; - closest = nearby; - closest_is_closing_polygon = is_closing_segment; - } - if (dist < snap_distance) - { // we have found a good enough next line - return false; // stop looking for alternatives - } - return true; // keep processing elements - })); - - if (! closest.initialized() // we couldn't find any next line - || closest_is_closing_polygon // we closed the polygon - ) - { - break; - } - - - coord_t segment_dist = vSize(make_point(chain.back()) - closest.p()); - assert(segment_dist <= max_stitch_distance + 10); - const size_t old_size = chain.size(); - if (closest.point_idx_ == 0) - { - auto start_pos = (*closest.polygons_)[closest.poly_idx_].begin(); - if (segment_dist < snap_distance) - { - ++start_pos; - } - chain.insert(chain.end(), start_pos, (*closest.polygons_)[closest.poly_idx_].end()); - } - else - { - auto start_pos = (*closest.polygons_)[closest.poly_idx_].rbegin(); - if (segment_dist < snap_distance) - { - ++start_pos; - } - chain.insert(chain.end(), start_pos, (*closest.polygons_)[closest.poly_idx_].rend()); - } - for (size_t i = old_size; i < chain.size(); ++i) // Update chain length. - { - chain_length += vSize(chain[i] - chain[i - 1]); - } - should_close = should_close & ! isOdd((*closest.polygons_)[closest.poly_idx_]); // If we connect an even to an odd line, we should no longer try to close it. - assert(! processed[closest.poly_idx_]); - processed[closest.poly_idx_] = true; - } - - if (closest_is_closing_polygon) - { - if (go_in_reverse_direction) - { // re-reverse chain to retain original direction - // NOTE: not sure if this code could ever be reached, since if a polygon can be closed that should be already possible in the forward direction - chain.reverse(); - } - - break; // don't consider reverse direction - } - } - if (closest_is_closing_polygon) - { - result_polygons.emplace_back(chain); - } - else - { - PathsPointIndex ppi_here(&lines, line_idx, 0); - if (! canReverse(ppi_here)) - { // Since closest_is_closing_polygon is false we went through the second iterations of the for-loop, where go_in_reverse_direction is true - // the polyline isn't allowed to be reversed, so we re-reverse it. - chain.reverse(); - } - result_lines.emplace_back(chain); - } - } - } + static void stitch(const InputPaths& lines, InputPaths& result_lines, OutputPaths& result_polygons, coord_t max_stitch_distance = MM2INT(0.1), coord_t snap_distance = 10); /*! * Whether a polyline is allowed to be reversed. (Not true for wall polylines which are not odd) */ - static bool canReverse(const PathsPointIndex& polyline); + static bool canReverse(const PathsPointIndex& polyline); /*! * Whether two paths are allowed to be connected. diff --git a/include/utils/SVG.h b/include/utils/SVG.h index 058bacc414..d362a74af5 100644 --- a/include/utils/SVG.h +++ b/include/utils/SVG.h @@ -12,7 +12,7 @@ #include "AABB.h" #include "ExtrusionLine.h" //To accept variable-width paths. #include "NoCopy.h" -#include "Point2LL.h" +#include "geometry/point2ll.h" namespace cura { @@ -101,11 +101,11 @@ class SVG : NoCopy void writeAreas(const Polygons& polygons, const ColorObject color = Color::GRAY, const ColorObject outline_color = Color::BLACK, const double stroke_width = 1.0) const; - void writeAreas(ConstPolygonRef polygon, const ColorObject color = Color::GRAY, const ColorObject outline_color = Color::BLACK, const double stroke_width = 1.0) const; + void writeAreas(const Polygon& polygon, const ColorObject color = Color::GRAY, const ColorObject outline_color = Color::BLACK, const double stroke_width = 1.0) const; void writePoint(const Point2LL& p, const bool write_coords = false, const double size = 5.0, const ColorObject color = Color::BLACK) const; - void writePoints(ConstPolygonRef poly, const bool write_coords = false, const double size = 5.0, const ColorObject color = Color::BLACK) const; + void writePoints(const Polygon& poly, const bool write_coords = false, const double size = 5.0, const ColorObject color = Color::BLACK) const; void writePoints(const Polygons& polygons, const bool write_coords = false, const double size = 5.0, const ColorObject color = Color::BLACK) const; @@ -146,11 +146,11 @@ class SVG : NoCopy void writePolygons(const Polygons& polys, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; - void writePolygon(ConstPolygonRef poly, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; + void writePolygon(const Polygon& poly, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; void writePolylines(const Polygons& polys, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; - void writePolyline(ConstPolygonRef poly, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; + void writePolyline(const Polygon& poly, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; /*! * Draw variable-width paths into the image. diff --git a/include/utils/Simplify.h b/include/utils/Simplify.h index 3ca5b0009d..129c9057e3 100644 --- a/include/utils/Simplify.h +++ b/include/utils/Simplify.h @@ -6,8 +6,8 @@ #include "../settings/Settings.h" //To load the parameters from a Settings object. #include "ExtrusionLine.h" +#include "geometry/polygon.h" #include "linearAlg2D.h" //To calculate line deviations and intersecting lines. -#include "polygon.h" namespace cura { @@ -105,7 +105,8 @@ class Simplify * \param polylines The polylines to simplify. * \return The simplified polylines. */ - Polygons polyline(const Polygons& polylines) const; + template + LinesSet polyline(const LinesSet& polylines) const; /*! * Simplify a polyline. @@ -114,7 +115,8 @@ class Simplify * \param polyline The polyline to simplify. * \return The simplified polyline. */ - Polygon polyline(const Polygon& polyline) const; + template + Polyline polyline(const Polyline& polyline) const; /*! * Simplify a variable-line-width polyline. @@ -416,7 +418,8 @@ class Simplify * \param polygon The polygon to add to. * \param vertex The vertex to add. */ - void appendVertex(Polygon& polygon, const Point2LL& vertex) const; + template + void appendVertex(Polyline& polygon, const Point2LL& vertex) const; /*! * Append a vertex to this extrusion line. diff --git a/include/utils/SparseGrid.h b/include/utils/SparseGrid.h index 11b0708942..0b6e306e22 100644 --- a/include/utils/SparseGrid.h +++ b/include/utils/SparseGrid.h @@ -10,8 +10,8 @@ #include #include -#include "Point2LL.h" #include "SquareGrid.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/utils/SparseLineGrid.h b/include/utils/SparseLineGrid.h index 5b22818797..7fdaf86ce3 100644 --- a/include/utils/SparseLineGrid.h +++ b/include/utils/SparseLineGrid.h @@ -10,7 +10,7 @@ #include #include -#include "Point2LL.h" +#include "geometry/point2ll.h" #include "SVG.h" // debug #include "SparseGrid.h" diff --git a/include/utils/SparsePointGrid.h b/include/utils/SparsePointGrid.h index 4565a5dc4a..44fd27cfa6 100644 --- a/include/utils/SparsePointGrid.h +++ b/include/utils/SparsePointGrid.h @@ -9,8 +9,8 @@ #include #include -#include "Point2LL.h" #include "SparseGrid.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/utils/SparsePointGridInclusive.h b/include/utils/SparsePointGridInclusive.h index 962c0d602e..e5f2c65aa6 100644 --- a/include/utils/SparsePointGridInclusive.h +++ b/include/utils/SparsePointGridInclusive.h @@ -9,7 +9,7 @@ #include #include -#include "Point2LL.h" +#include "geometry/point2ll.h" #include "SparsePointGrid.h" namespace cura diff --git a/include/utils/SquareGrid.h b/include/utils/SquareGrid.h index ebbab19ca2..cf10414339 100644 --- a/include/utils/SquareGrid.h +++ b/include/utils/SquareGrid.h @@ -9,7 +9,7 @@ #include #include -#include "Point2LL.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/utils/ToolpathVisualizer.h b/include/utils/ToolpathVisualizer.h index d3ad54ac7a..d71cf0c091 100644 --- a/include/utils/ToolpathVisualizer.h +++ b/include/utils/ToolpathVisualizer.h @@ -4,7 +4,7 @@ #include "ExtrusionSegment.h" #include "SVG.h" -#include "polygon.h" +#include "geometry/polygon.h" namespace cura { diff --git a/include/utils/VoxelUtils.h b/include/utils/VoxelUtils.h index f6cd123677..d1b47e8883 100644 --- a/include/utils/VoxelUtils.h +++ b/include/utils/VoxelUtils.h @@ -7,8 +7,8 @@ #include #include -#include "utils/Point2LL.h" -#include "utils/polygon.h" +#include "geometry/point2ll.h" +#include "geometry/polygon.h" namespace cura { diff --git a/include/utils/linearAlg2D.h b/include/utils/linearAlg2D.h index 5c7867e4d6..796c040c46 100644 --- a/include/utils/linearAlg2D.h +++ b/include/utils/linearAlg2D.h @@ -4,10 +4,13 @@ #ifndef UTILS_LINEAR_ALG_2D_H #define UTILS_LINEAR_ALG_2D_H -#include "Point2LL.h" +#include "geometry/point2ll.h" namespace cura { + +class Point3Matrix; + class LinearAlg2D { public: @@ -64,37 +67,7 @@ class LinearAlg2D return -1; } - static bool lineLineIntersection(const Point2LL& a, const Point2LL& b, const Point2LL& c, const Point2LL& d, Point2LL& output) - { - // Adapted from Apex: https://github.com/Ghostkeeper/Apex/blob/eb75f0d96e36c7193d1670112826842d176d5214/include/apex/line_segment.hpp#L91 - // Adjusted to work with lines instead of line segments. - const Point2LL l1_delta = b - a; - const Point2LL l2_delta = d - c; - const coord_t divisor = cross(l1_delta, l2_delta); // Pre-compute divisor needed for the intersection check. - if (divisor == 0) - { - // The lines are parallel if the cross product of their directions is zero. - return false; - } - - // Create a parametric representation of each line. - // We'll equate the parametric equations to each other to find the intersection then. - // Parametric equation is L = P + Vt (where P and V are a starting point and directional vector). - // We'll map the starting point of one line onto the parameter system of the other line. - // Then using the divisor we can see whether and where they cross. - const Point2LL starts_delta = a - c; - const coord_t l1_parametric = cross(l2_delta, starts_delta); - Point2LL result = a + Point2LL(round_divide_signed(l1_parametric * l1_delta.X, divisor), round_divide_signed(l1_parametric * l1_delta.Y, divisor)); - - if (std::abs(result.X) > std::numeric_limits::max() || std::abs(result.Y) > std::numeric_limits::max()) - { - // Intersection is so far away that it could lead to integer overflows. - // Even though the lines aren't 100% parallel, it's better to pretend they are. They are practically parallel. - return false; - } - output = result; - return true; - } + static bool lineLineIntersection(const Point2LL& a, const Point2LL& b, const Point2LL& c, const Point2LL& d, Point2LL& output); /*! * Find whether a point projected on a line segment would be projected to @@ -403,12 +376,7 @@ class LinearAlg2D /*! * Get the rotation matrix for rotating around a specific point in place. */ - static Point3Matrix rotateAround(const Point2LL& middle, double rotation) - { - PointMatrix rotation_matrix(rotation); - Point3Matrix rotation_matrix_homogeneous(rotation_matrix); - return Point3Matrix::translate(middle).compose(rotation_matrix_homogeneous).compose(Point3Matrix::translate(-middle)); - } + static Point3Matrix rotateAround(const Point2LL& middle, double rotation); /*! * Test whether a point is inside a corner. diff --git a/include/utils/orderOptimizer.h b/include/utils/orderOptimizer.h index cf3abaa2ba..558c9bbfe2 100644 --- a/include/utils/orderOptimizer.h +++ b/include/utils/orderOptimizer.h @@ -9,7 +9,7 @@ #include // pair #include -#include "Point2LL.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/utils/polygon.h b/include/utils/polygon.h deleted file mode 100644 index 01bed2a687..0000000000 --- a/include/utils/polygon.h +++ /dev/null @@ -1,803 +0,0 @@ -// Copyright (c) 2023 UltiMaker -// CuraEngine is released under the terms of the AGPLv3 or higher - -#ifndef UTILS_POLYGON_H -#define UTILS_POLYGON_H - -#include -#include -#include -#include -#include -#include -#include - -#include "../settings/types/Angle.h" -#include "../settings/types/Ratio.h" -#include "Point2LL.h" -#include "utils/ListPolyIt.h" -#include "utils/ShapeType.h" -#include "utils/linearAlg2D.h" - -#define CHECK_POLY_ACCESS -#ifdef CHECK_POLY_ACCESS -#define POLY_ASSERT(e) assert(e) -#else -#define POLY_ASSERT(e) \ - do \ - { \ - } while (0) -#endif - -namespace cura -{ - -using point_t = ClipperLib::IntPoint; -using path_t = ClipperLib::Path; -using paths_t = ClipperLib::Paths; - -template -bool shorterThan(const T& shape, const coord_t check_length) -{ - const auto* p0 = &shape.back(); - int64_t length = 0; - for (const auto& p1 : shape) - { - length += vSize(*p0 - p1); - if (length >= check_length) - { - return false; - } - p0 = &p1; - } - return true; -} - -class PartsView; -class Polygons; -class OpenPolyline; -class ListPolyIt; - -const static int clipper_init = (0); -#define NO_INDEX (std::numeric_limits::max()) - -class PointsSet : public std::vector -{ -public: - PointsSet() = default; - - PointsSet(const std::initializer_list& initializer) - : std::vector(initializer) - { - } - - PointsSet(const std::vector& points) - : std::vector(points) - { - } - - PointsSet(std::vector&& points) - : std::vector(std::move(points)) - { - } - - /*PointsSet& operator=(const PointsSet& other) - { - std::vector::operator=(other); - return *this; - }*/ - - Point2LL min() const; - - Point2LL max() const; - - Point2LL closestPointTo(Point2LL p) const; - - /*! - * Translate the whole polygon in some direction. - * - * \param translation The direction in which to move the polygon - */ - void translate(Point2LL translation) - { - for (Point2LL& p : *this) - { - p += translation; - } - } - - /*! - * Apply a matrix to each vertex in this set - */ - void applyMatrix(const PointMatrix& matrix); - void applyMatrix(const Point3Matrix& matrix); -}; - -// Transitory structure used to iterate over segments within a polygon/polyline -template -struct Segment -{ - using PointType = typename std::conditional::type; - - PointType& start; - PointType& end; -}; - -// Custom iterator to loop over the segments of an existing polygon/polyline -template -struct SegmentIterator -{ - using iterator_category = std::random_access_iterator_tag; - using value_type = Segment; - using difference_type = std::ptrdiff_t; - using pointer = Segment*; - using reference = Segment&; - using source_iterator_type = typename std::conditional::const_iterator, typename std::vector::iterator>::type; - -private: - source_iterator_type current_pos_; - source_iterator_type begin_; - source_iterator_type before_end_; - -public: - SegmentIterator(source_iterator_type pos, source_iterator_type begin, source_iterator_type end) - : current_pos_(pos) - , begin_(begin) - , before_end_(end != begin ? std::prev(end) : end) - { - } - - Segment operator*() const - { - if (current_pos_ == before_end_) - { - return Segment{ *current_pos_, *begin_ }; - } - else - { - return Segment{ *current_pos_, *std::next(current_pos_) }; - } - } - - SegmentIterator& operator++() - { - current_pos_++; - return *this; - } - - bool operator==(const SegmentIterator& other) const - { - return current_pos_ == other.current_pos_; - } - - bool operator!=(const SegmentIterator& other) const - { - return ! (*this == other); - } - - friend difference_type operator-(const SegmentIterator& iterator1, const SegmentIterator& iterator2) - { - return iterator1.current_pos_ - iterator2.current_pos_; - } -}; - -template -class Polyline : public PointsSet -{ - friend class Polygons; - -public: - static constexpr ShapeType shape_type_ = ShapeTypeVal; - -public: - using segments_iterator = SegmentIterator; - using const_segments_iterator = SegmentIterator; - - Polyline() = default; - - Polyline(const std::initializer_list& initializer) - : PointsSet(initializer) - { - } - - Polyline(const std::vector& points) - : PointsSet(points) - { - } - - Polyline(std::vector&& points) - : PointsSet(points) - { - } - - /*Polyline& operator=(const Polyline& other) - { - std::vector::operator=(other); - return *this; - }*/ - - const_segments_iterator beginSegments() const; - - const_segments_iterator endSegments() const; - - segments_iterator beginSegments(); - - segments_iterator endSegments(); - - /*! - * Split these poly line objects into several line segment objects consisting of only two verts - * and store them in the \p result - */ - void splitIntoSegments(std::vector& result) const; - std::vector splitIntoSegments() const; - - /*! - * On Y-axis positive upward displays, Orientation will return true if the polygon's orientation is counter-clockwise. - * - * from http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/Orientation.htm - */ - bool orientation() const - { - return ClipperLib::Orientation(*this); - } - - coord_t length() const; - - bool shorterThan(const coord_t check_length) const; - - void reverse() - { - ClipperLib::ReversePath(*this); - } - - void removeColinearEdges(const AngleRadians max_deviation_angle); - - /*! - * Removes consecutive line segments with same orientation and changes this polygon. - * - * 1. Removes verts which are connected to line segments which are too small. - * 2. Removes verts which detour from a direct line from the previous and next vert by a too small amount. - * 3. Moves a vert when a small line segment is connected to a much longer one. in order to maintain the outline of the object. - * 4. Don't remove a vert when the impact on the outline of the object is too great. - * - * Note that the simplify is a best effort algorithm. It does not guarantee that no lines below the provided smallest_line_segment_squared are left. - * - * The following example (Two very long line segments (" & , respectively) that are connected by a very small line segment (i) is unsimplifable by this - * function, even though the actual area change of removing line segment i is very small. The reason for this is that in the case of long lines, even a small - * deviation from it's original direction is very noticeable in the final result, especially if the polygons above make a slightly different choice. - * - * """"""""""""""""""""""""""""""""i,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, - - * - * \param smallest_line_segment_squared maximal squared length of removed line segments - * \param allowed_error_distance_squared The square of the distance of the middle point to the line segment of the consecutive and previous point for which the middle point is - removed - */ - void simplify(const coord_t smallest_line_segment_squared = MM2INT(0.01) * MM2INT(0.01), const coord_t allowed_error_distance_squared = 25); - - /*! - * See simplify(.) - */ -#warning This can probably be merge with simplify ? - void simplifyPolyline(const coord_t smallest_line_segment_squared = 100, const coord_t allowed_error_distance_squared = 25); - -private: - /*! - * Private implementation for both simplify and simplifyPolygons. - * - * Made private to avoid accidental use of the wrong function. - */ - void _simplify(const coord_t smallest_line_segment_squared = 100, const coord_t allowed_error_distance_squared = 25, bool processing_polylines = false); -}; - -template -class _ClosedPolyline : public Polyline -{ - friend class Polygons; - -public: - _ClosedPolyline() = default; - - _ClosedPolyline(const std::initializer_list& initializer) - : Polyline(initializer) - { - } - - _ClosedPolyline(const std::vector& points) - : Polyline(points) - { - } - - _ClosedPolyline& operator=(const _ClosedPolyline& other) - { - Polyline::operator=(other); - return *this; - } - - /*! - * Check if we are inside the polygon. We do this by tracing from the point towards the positive X direction, - * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. - * Care needs to be taken, if p.Y exactly matches a vertex to the right of p, then we need to count 1 intersect if the - * outline passes vertically past; and 0 (or 2) intersections if that point on the outline is a 'top' or 'bottom' vertex. - * The easiest way to do this is to break out two cases for increasing and decreasing Y ( from p0 to p1 ). - * A segment is tested if pa.Y <= p.Y < pb.Y, where pa and pb are the points (from p0,p1) with smallest & largest Y. - * When both have the same Y, no intersections are counted but there is a special test to see if the point falls - * exactly on the line. - * - * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. - * - * \deprecated This function is no longer used, since the Clipper function is used by the function PolygonRef::inside(.) - * - * \param p The point for which to check if it is inside this polygon - * \param border_result What to return when the point is exactly on the border - * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) - */ - // bool _inside(Point2LL p, bool border_result = false) const; - - /*! - * Clipper function. - * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. - * - * http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/PointInPolygon.htm - */ - bool inside(Point2LL p, bool border_result = false) const - { - int res = ClipperLib::PointInPolygon(p, *this); - if (res == -1) - { - return border_result; - } - return res == 1; - } - - bool inside(const auto& polygon) const - { - for (const auto& point : *this) - { - if (! ClipperLib::PointInPolygon(point, polygon)) - { - return false; - } - } - return true; - } -}; - -using ClosedPolyline = _ClosedPolyline; - -class Polygon : public _ClosedPolyline -{ - friend class Polygons; - -public: - Polygon() = default; - - Polygon(const Polygon& other) = default; - - Polygon(Polygon&& other) = default; - - Polygon(const std::initializer_list& initializer) - : _ClosedPolyline(initializer) - { - } - - Polygon(const std::vector& points) - : _ClosedPolyline(points) - { - } - - Polygon& operator=(const Polygon& other) - { - _ClosedPolyline::operator=(other); - return *this; - } - - /*! - * Compute the morphological intersection between this polygon and another. - * - * Note that the result may consist of multiple polygons, if you have bad - * luck. - * - * \param other The polygon with which to intersect this polygon. - */ - Polygons intersection(const Polygon& other) const; - - double area() const - { - return ClipperLib::Area(*this); - } - - Point2LL centerOfMass() const; - - Polygons offset(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; - - /*! - * Smooth out small perpendicular segments and store the result in \p result. - * Smoothing is performed by removing the inner most vertex of a line segment smaller than \p remove_length - * which has an angle with the next and previous line segment smaller than roughly 150* - * - * Note that in its current implementation this function doesn't remove line segments with an angle smaller than 30* - * Such would be the case for an N shape. - * - * \param remove_length The length of the largest segment removed - * \param result (output) The result polygon, assumed to be empty - */ - void smooth(int remove_length, Polygon& result) const; - - /*! - * Smooth out sharp inner corners, by taking a shortcut which bypasses the corner - * - * \param angle The maximum angle of inner corners to be smoothed out - * \param shortcut_length The desired length of the shortcut line segment introduced (shorter shortcuts may be unavoidable) - * \param result The resulting polygon - */ - void smooth_outward(const AngleDegrees angle, int shortcut_length, Polygon& result) const; - - /*! - * Smooth out the polygon and store the result in \p result. - * Smoothing is performed by removing vertices for which both connected line segments are smaller than \p remove_length - * - * \param remove_length The length of the largest segment removed - * \param result (output) The result polygon, assumed to be empty - */ - void smooth2(int remove_length, Polygon& result) const; - - /*! - * Smooth out a simple corner consisting of two linesegments. - * - * Auxiliary function for \ref smooth_outward - * - * \param p0 The point before the corner - * \param p1 The corner - * \param p2 The point after the corner - * \param p0_it Iterator to the point before the corner - * \param p1_it Iterator to the corner - * \param p2_it Iterator to the point after the corner - * \param v10 Vector from \p p1 to \p p0 - * \param v12 Vector from \p p1 to \p p2 - * \param v02 Vector from \p p0 to \p p2 - * \param shortcut_length The desired length ofthe shortcutting line - * \param cos_angle The cosine on the angle in L 012 - */ - static void smooth_corner_simple( - const Point2LL p0, - const Point2LL p1, - const Point2LL p2, - const ListPolyIt p0_it, - const ListPolyIt p1_it, - const ListPolyIt p2_it, - const Point2LL v10, - const Point2LL v12, - const Point2LL v02, - const int64_t shortcut_length, - double cos_angle); - - /*! - * Smooth out a complex corner where the shortcut bypasses more than two line segments - * - * Auxiliary function for \ref smooth_outward - * - * \warning This function might try to remove the whole polygon - * Error code -1 means the whole polygon should be removed (which means it is a hole polygon) - * - * \param p1 The corner point - * \param[in,out] p0_it Iterator to the last point checked before \p p1 to consider cutting off - * \param[in,out] p2_it Iterator to the last point checked after \p p1 to consider cutting off - * \param shortcut_length The desired length ofthe shortcutting line - * \return Whether this whole polygon whould be removed by the smoothing - */ - static bool smooth_corner_complex(const Point2LL p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length); - - /*! - * Try to take a step away from the corner point in order to take a bigger shortcut. - * - * Try to take the shortcut from a place as far away from the corner as the place we are taking the shortcut to. - * - * Auxiliary function for \ref smooth_outward - * - * \param[in] p1 The corner point - * \param[in] shortcut_length2 The square of the desired length ofthe shortcutting line - * \param[in,out] p0_it Iterator to the previously checked point somewhere beyond \p p1. Updated for the next iteration. - * \param[in,out] p2_it Iterator to the previously checked point somewhere before \p p1. Updated for the next iteration. - * \param[in,out] forward_is_blocked Whether trying another step forward is blocked by the smoothing outward condition. Updated for the next iteration. - * \param[in,out] backward_is_blocked Whether trying another step backward is blocked by the smoothing outward condition. Updated for the next iteration. - * \param[in,out] forward_is_too_far Whether trying another step forward is blocked by the shortcut length condition. Updated for the next iteration. - * \param[in,out] backward_is_too_far Whether trying another step backward is blocked by the shortcut length condition. Updated for the next iteration. - */ - static void smooth_outward_step( - const Point2LL p1, - const int64_t shortcut_length2, - ListPolyIt& p0_it, - ListPolyIt& p2_it, - bool& forward_is_blocked, - bool& backward_is_blocked, - bool& forward_is_too_far, - bool& backward_is_too_far); -}; - -class OpenPolyline : public Polyline -{ -public: - OpenPolyline() = default; - - OpenPolyline(const OpenPolyline& other) = default; - - OpenPolyline(OpenPolyline&& other) = default; - - OpenPolyline(const std::initializer_list& initializer) - : Polyline(initializer) - { - } - - OpenPolyline(const std::vector& points) - : Polyline(points) - { - } - - OpenPolyline(std::vector&& points) - : Polyline(points) - { - } - - OpenPolyline& operator=(const OpenPolyline& other) - { - Polyline::operator=(other); - return *this; - } - - OpenPolyline& operator=(OpenPolyline&& other) - { - Polyline::operator=(other); - return *this; - } -}; - -#if 0 -/*! - * Outer polygons should be counter-clockwise, - * inner hole polygons should be clockwise. - * (When negative X is to the left and negative Y is downward.) - */ -class ConstPolygonRef -{ - -}; - -class PolygonsPart; - -class Polygons -{ - - Polygons& operator=(const Polygons& other) - { - paths = other.paths; - return *this; - } - Polygons& operator=(Polygons&& other) - { - if (this != &other) - { - paths = std::move(other.paths); - } - return *this; - } -}; -#endif - -// ########################################################### -// Definitions of templated methods -// ########################################################### -#if 0 -seems to be unused -template -bool SurfaceContainer::_inside(Point2LL p, bool border_result) const -{ - if (size() < 1) - { - return false; - } - - int crossings = 0; - Point2LL p0 = back(); - for (unsigned int n = 0; n < size(); n++) - { - Point2LL p1 = (*this)[n]; - // no tests unless the segment p0-p1 is at least partly at, or to right of, p.X - short comp = LinearAlg2D::pointLiesOnTheRightOfLine(p, p0, p1); - if (comp == 1) - { - crossings++; - } - else if (comp == 0) - { - return border_result; - } - p0 = p1; - } - return (crossings % 2) == 1; -} -#endif - -template -void Polyline::removeColinearEdges(const AngleRadians max_deviation_angle) -{ - // TODO: Can be made more efficient (for example, use pointer-types for process-/skip-indices, so we can swap them without copy). - - size_t num_removed_in_iteration = 0; - do - { - num_removed_in_iteration = 0; - - std::vector process_indices(size(), true); - - bool go = true; - while (go) - { - go = false; - - const path_t& rpath = *this; - const size_t pathlen = rpath.size(); - if (pathlen <= 3) - { - return; - } - - std::vector skip_indices(size(), false); - - Polyline new_path; - for (size_t point_idx = 0; point_idx < pathlen; ++point_idx) - { - // Don't iterate directly over process-indices, but do it this way, because there are points _in_ process-indices that should nonetheless be skipped: - if (! process_indices[point_idx]) - { - new_path.push_back(rpath[point_idx]); - continue; - } - - // Should skip the last point for this iteration if the old first was removed (which can be seen from the fact that the new first was skipped): - if (point_idx == (pathlen - 1) && skip_indices[0]) - { - skip_indices[new_path.size()] = true; - go = true; - new_path.push_back(rpath[point_idx]); - break; - } - - const Point2LL& prev = rpath[(point_idx - 1 + pathlen) % pathlen]; - const Point2LL& pt = rpath[point_idx]; - const Point2LL& next = rpath[(point_idx + 1) % pathlen]; - - double angle = LinearAlg2D::getAngleLeft(prev, pt, next); // [0 : 2 * pi] - if (angle >= std::numbers::pi) - { - angle -= std::numbers::pi; - } // map [pi : 2 * pi] to [0 : pi] - - // Check if the angle is within limits for the point to 'make sense', given the maximum deviation. - // If the angle indicates near-parallel segments ignore the point 'pt' - if (angle > max_deviation_angle && angle < std::numbers::pi - max_deviation_angle) - { - new_path.push_back(pt); - } - else if (point_idx != (pathlen - 1)) - { - // Skip the next point, since the current one was removed: - skip_indices[new_path.size()] = true; - go = true; - new_path.push_back(next); - ++point_idx; - } - } - (*this) = new_path; - num_removed_in_iteration += pathlen - size(); - - process_indices.clear(); - process_indices.insert(process_indices.end(), skip_indices.begin(), skip_indices.end()); - } - } while (num_removed_in_iteration > 0); -} - -template -Polyline::const_segments_iterator Polyline::beginSegments() const -{ - return const_segments_iterator(begin(), begin(), end()); -} - -template -Polyline::const_segments_iterator Polyline::endSegments() const -{ - if constexpr (shape_type_ == ShapeType::Closed || shape_type_ == ShapeType::Filled) - { - return const_segments_iterator(end(), begin(), end()); - } - else - { - return const_segments_iterator(size() > 1 ? std::prev(end()) : end(), begin(), end()); - } -} - -template -Polyline::segments_iterator Polyline::beginSegments() -{ - return segments_iterator(begin(), begin(), end()); -} - -template -Polyline::segments_iterator Polyline::endSegments() -{ - if constexpr (shape_type_ == ShapeType::Closed || shape_type_ == ShapeType::Filled) - { - return segments_iterator(end(), begin(), end()); - } - else - { - return segments_iterator(size() > 1 ? std::prev(end()) : end(), begin(), end()); - } -} - -template -coord_t Polyline::length() const -{ - return std::accumulate( - beginSegments(), - endSegments(), - 0, - [](coord_t total, const const_segments_iterator::value_type& segment) - { - return total + vSize(segment.end - segment.start); - }); -} - -template -bool Polyline::shorterThan(const coord_t check_length) const -{ - coord_t length = 0; - auto iterator_segment = std::find_if( - beginSegments(), - endSegments(), - [&length, &check_length](const const_segments_iterator::value_type& segment) - { - length += vSize(segment.end - segment.start); - if (length >= check_length) - { - return true; - } - }); - return iterator_segment == endSegments(); -} - -template -void Polyline::splitIntoSegments(std::vector& result) const -{ - for (auto it = beginSegments(); it != endSegments(); ++it) - { - result.emplace_back(std::initializer_list{ (*it).start, (*it).end }); - } -} - -template -std::vector Polyline::splitIntoSegments() const -{ - std::vector result; - splitIntoSegments(result); - return result; -} - -} // namespace cura - -namespace std -{ -#if 0 -template<> -struct hash -{ - size_t operator()(const cura::PolygonPointer& poly) const - { - const cura::ConstPolygonRef ref = *static_cast(poly); - return std::hash()(&*ref); - } -}; -#endif -} // namespace std - -#endif // UTILS_POLYGON_H diff --git a/include/utils/polygonUtils.h b/include/utils/polygonUtils.h index ecda641626..156c130046 100644 --- a/include/utils/polygonUtils.h +++ b/include/utils/polygonUtils.h @@ -12,7 +12,7 @@ #include "PolygonsPointIndex.h" #include "SparseLineGrid.h" #include "SparsePointGridInclusive.h" -#include "polygon.h" +#include "geometry/polygon.h" namespace cura { @@ -20,14 +20,14 @@ namespace cura /*! * Result of finding the closest point to a given within a set of polygons, with extra information on where the point is. */ -struct ClosestPolygonPoint +struct ClosestPoint { Point2LL location_; //!< Result location - ConstPolygonPointer poly_; //!< Polygon in which the result was found (or nullptr if no result was found) - size_t poly_idx_; //!< The index of the polygon in some Polygons where ClosestPolygonPoint::poly can be found + const PointsSet* poly_{ nullptr }; //!< Line in which the result was found (or nullptr if no result was found) + size_t poly_idx_; //!< The index of the polygon in some Polygons where ClosestPoint::poly can be found size_t point_idx_; //!< Index to the first point in the polygon of the line segment on which the result was found - ClosestPolygonPoint(Point2LL p, size_t pos, ConstPolygonRef poly) + ClosestPoint(Point2LL p, size_t pos, const PointsSet* poly) : location_(p) , poly_(poly) , poly_idx_(NO_INDEX) @@ -35,7 +35,7 @@ struct ClosestPolygonPoint { } - ClosestPolygonPoint(Point2LL p, size_t pos, ConstPolygonRef poly, size_t poly_idx) + ClosestPoint(Point2LL p, size_t pos, const PointsSet* poly, size_t poly_idx) : location_(p) , poly_(poly) , poly_idx_(poly_idx) @@ -43,14 +43,14 @@ struct ClosestPolygonPoint { } - ClosestPolygonPoint(ConstPolygonRef poly) + ClosestPoint(const PointsSet* poly) : poly_(poly) , poly_idx_(NO_INDEX) , point_idx_(NO_INDEX) { } - ClosestPolygonPoint() + ClosestPoint() : poly_idx_(NO_INDEX) , point_idx_(NO_INDEX) { @@ -66,7 +66,7 @@ struct ClosestPolygonPoint return point_idx_ != NO_INDEX; } - bool operator==(const ClosestPolygonPoint& rhs) const + bool operator==(const ClosestPoint& rhs) const { // no need to compare on poy_idx // it's sometimes unused while poly is always initialized @@ -79,9 +79,9 @@ struct ClosestPolygonPoint namespace std { template<> -struct hash +struct hash { - size_t operator()(const cura::ClosestPolygonPoint& cpp) const + size_t operator()(const cura::ClosestPoint& cpp) const { return std::hash()(cpp.p()); } @@ -147,7 +147,7 @@ class PolygonUtils * \param n_dots number of dots to spread out * \param result Where to store the generated points */ - static void spreadDots(PolygonsPointIndex start, PolygonsPointIndex end, unsigned int n_dots, std::vector& result); + static void spreadDots(PolygonsPointIndex start, PolygonsPointIndex end, unsigned int n_dots, std::vector& result); /*! * Generate a grid of dots inside of the area of the \p polygons. @@ -175,7 +175,7 @@ class PolygonUtils * \param poly The polygon. * \param point_idx The index of the point in the polygon. */ - static Point2LL getVertexInwardNormal(ConstPolygonRef poly, unsigned int point_idx); + static Point2LL getVertexInwardNormal(const Polygon& poly, unsigned int point_idx); /*! * Get a point from the \p poly with a given \p offset. @@ -185,7 +185,7 @@ class PolygonUtils * \param offset The distance the point has to be moved outward from the polygon. * \return A point at the given distance inward from the point on the boundary polygon. */ - static Point2LL getBoundaryPointWithOffset(ConstPolygonRef poly, unsigned int point_idx, int64_t offset); + static Point2LL getBoundaryPointWithOffset(const Polygon& poly, unsigned int point_idx, int64_t offset); /*! * Move a point away from the boundary by looking at the boundary normal of the nearest vert. @@ -193,7 +193,7 @@ class PolygonUtils * \param point_on_boundary The object holding the point on the boundary along with the information of which line segment the point is on. * \param offset The distance the point has to be moved inward from the polygon. */ - static Point2LL moveInsideDiagonally(ClosestPolygonPoint point_on_boundary, int64_t inset); + static Point2LL moveInsideDiagonally(ClosestPoint point_on_boundary, int64_t inset); /*! * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within the root of \p max_dist2 distance. @@ -225,7 +225,7 @@ class PolygonUtils * the polygon. * \return Always returns 0. */ - static unsigned int moveInside(const ConstPolygonRef polygon, Point2LL& from, int distance = 0, int64_t max_dist2 = std::numeric_limits::max()); + static unsigned int moveInside(const Polygon& polygon, Point2LL& from, int distance = 0, int64_t max_dist2 = std::numeric_limits::max()); /*! * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within the root of \p max_dist2 distance. @@ -235,7 +235,7 @@ class PolygonUtils * * \warning If \p loc_to_line_grid is used, it's best to have all and only \p polygons in there. * If \p from is not closest to \p polygons this function may - * return a ClosestPolygonPoint on a polygon in \p loc_to_line_grid which is not in \p polygons. + * return a ClosestPoint on a polygon in \p loc_to_line_grid which is not in \p polygons. * * \param polygons The polygons onto which to move the point * \param from[in,out] The point to move. @@ -246,7 +246,7 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPolygonPoint moveInside2( + static ClosestPoint moveInside2( const Polygons& polygons, Point2LL& from, const int distance = 0, @@ -274,9 +274,9 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPolygonPoint moveInside2( + static ClosestPoint moveInside2( const Polygons& loc_to_line_polygons, - ConstPolygonRef polygon, + const Polygon& polygon, Point2LL& from, const int distance = 0, const int64_t max_dist2 = std::numeric_limits::max(), @@ -308,7 +308,7 @@ class PolygonUtils * \param distance The distance by which to move the point. * \return A point at a \p distance from the point in \p cpp orthogonal to the boundary there. */ - static Point2LL moveInside(const ClosestPolygonPoint& cpp, const int distance); + static Point2LL moveInside(const ClosestPoint& cpp, const int distance); /*! * The opposite of moveInside. @@ -320,7 +320,7 @@ class PolygonUtils * \param distance The distance by which to move the point. * \return A point at a \p distance from the point in \p cpp orthogonal to the boundary there. */ - static Point2LL moveOutside(const ClosestPolygonPoint& cpp, const int distance); + static Point2LL moveOutside(const ClosestPoint& cpp, const int distance); /*! * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within \p distance. @@ -345,7 +345,7 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPolygonPoint ensureInsideOrOutside( + static ClosestPoint ensureInsideOrOutside( const Polygons& polygons, Point2LL& from, int preferred_dist_inside, @@ -377,10 +377,10 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPolygonPoint ensureInsideOrOutside( + static ClosestPoint ensureInsideOrOutside( const Polygons& polygons, Point2LL& from, - const ClosestPolygonPoint& closest_polygon_point, + const ClosestPoint& closest_polygon_point, int preferred_dist_inside, const Polygons* loc_to_line_polygons = nullptr, const LocToLineGrid* loc_to_line_grid = nullptr, @@ -390,7 +390,7 @@ class PolygonUtils * * \warning Assumes \p poly1_result and \p poly2_result have their pos and poly fields initialized! */ - static void walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_result, ClosestPolygonPoint& poly2_result); + static void walkToNearestSmallestConnection(ClosestPoint& poly1_result, ClosestPoint& poly2_result); /*! * Find the nearest closest point on a polygon from a given index. @@ -400,7 +400,7 @@ class PolygonUtils * \param start_idx The index of the point in the polygon from which to start looking. * \return The nearest point from \p start_idx going along the \p polygon (in both directions) with a locally minimal distance to \p from. */ - static ClosestPolygonPoint findNearestClosest(Point2LL from, ConstPolygonRef polygon, int start_idx); + static ClosestPoint findNearestClosest(Point2LL from, const Polygon& polygon, int start_idx); /*! * Find the nearest closest point on a polygon from a given index walking in one direction along the polygon. @@ -411,7 +411,7 @@ class PolygonUtils * \param direction The direction to walk: 1 for walking along the \p polygon, -1 for walking in opposite direction * \return The nearest point from \p start_idx going along the \p polygon with a locally minimal distance to \p from. */ - static ClosestPolygonPoint findNearestClosest(const Point2LL from, ConstPolygonRef polygon, int start_idx, int direction); + static ClosestPoint findNearestClosest(const Point2LL from, const Polygon& polygon, int start_idx, int direction); /*! * Find the point closest to \p from in all polygons in \p polygons. @@ -420,7 +420,7 @@ class PolygonUtils * * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. */ - static ClosestPolygonPoint findClosest(Point2LL from, const Polygons& polygons, const std::function& penalty_function = no_penalty_function); + static ClosestPoint findClosest(Point2LL from, const Polygons& polygons, const std::function& penalty_function = no_penalty_function); /*! * Find the point closest to \p from in the polygon \p polygon. @@ -429,7 +429,7 @@ class PolygonUtils * * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. */ - static ClosestPolygonPoint findClosest(Point2LL from, ConstPolygonRef polygon, const std::function& penalty_function = no_penalty_function); + static ClosestPoint findClosest(Point2LL from, const Polygon& polygon, const std::function& penalty_function = no_penalty_function); /*! * Find the nearest vertex to \p from in \p polys @@ -445,7 +445,7 @@ class PolygonUtils * \param poly The polygon in which to search * \return The index to the nearest vertex on the polygon */ - static unsigned int findNearestVert(const Point2LL from, ConstPolygonRef poly); + static unsigned int findNearestVert(const Point2LL from, const Polygon& poly); /*! * Create a SparsePointGridInclusive mapping from locations to line segments occurring in the \p polygons @@ -470,7 +470,7 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The nearest point on the polygon if the polygon was within a distance equal to the cell_size of the SparsePointGridInclusive */ - static std::optional + static std::optional findClose(Point2LL from, const Polygons& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function = no_penalty_function); /*! @@ -486,8 +486,8 @@ class PolygonUtils * \return A collection of near crossing from the \p from polygon to the \p destination polygon. Each element in the sollection is a pair with as first a cpp in the \p from * polygon and as second a cpp in the \p destination polygon. */ - static std::vector> findClose( - ConstPolygonRef from, + static std::vector> findClose( + const Polygon& from, const Polygons& destination, const LocToLineGrid& destination_loc_to_line, const std::function& penalty_function = no_penalty_function); @@ -517,12 +517,12 @@ class PolygonUtils * \param start_idx the index of the prev poly point on the poly. * \param poly_start_idx The index of the point in the polygon which is to be handled as the start of the polygon. No point further than this point will be the result. */ - static bool getNextPointWithDistance(Point2LL from, int64_t dist, ConstPolygonRef poly, int start_idx, int poly_start_idx, GivenDistPoint& result); + static bool getNextPointWithDistance(Point2LL from, int64_t dist, const Polygon& poly, int start_idx, int poly_start_idx, GivenDistPoint& result); /*! * Walk a given \p distance along the polygon from a given point \p from on the polygon */ - static ClosestPolygonPoint walk(const ClosestPolygonPoint& from, coord_t distance); + static ClosestPoint walk(const ClosestPoint& from, coord_t distance); /*! * Get the point on a polygon which intersects a line parallel to a line going through the starting point and through another point. @@ -536,7 +536,7 @@ class PolygonUtils * \param forward Whether to look forward from \p start in the direction of the polygon, or go in the other direction. * \return The earliest point on the polygon in the given direction which crosses a line parallel to the given one at the distance \p dist - if any */ - static std::optional getNextParallelIntersection(const ClosestPolygonPoint& start, const Point2LL& line_to, const coord_t dist, const bool forward); + static std::optional getNextParallelIntersection(const ClosestPoint& start, const Point2LL& line_to, const coord_t dist, const bool forward); /*! * Checks whether a given line segment collides with a given polygon(s). @@ -559,7 +559,7 @@ class PolygonUtils * polygon(s) */ static bool - polygonCollidesWithLineSegment(ConstPolygonRef poly, const Point2LL& transformed_startPoint, const Point2LL& transformed_endPoint, PointMatrix transformation_matrix); + polygonCollidesWithLineSegment(const Polygon& poly, const Point2LL& transformed_startPoint, const Point2LL& transformed_endPoint, PointMatrix transformation_matrix); /*! * Checks whether a given line segment collides with a given polygon(s). @@ -575,7 +575,7 @@ class PolygonUtils * \return whether the line segment collides with the boundary of the * polygon(s) */ - static bool polygonCollidesWithLineSegment(ConstPolygonRef poly, const Point2LL& startPoint, const Point2LL& endPoint); + static bool polygonCollidesWithLineSegment(const Polygon& poly, const Point2LL& startPoint, const Point2LL& endPoint); /*! * Checks whether a given line segment collides with a given polygon(s). @@ -623,7 +623,7 @@ class PolygonUtils * \param poly_b Another polygon group * \return true if \p poly_a and \p poly_b intersect, false otherwise */ - static bool polygonsIntersect(const ConstPolygonRef& poly_a, const ConstPolygonRef& poly_b); + static bool polygonsIntersect(const Polygon& poly_a, const Polygon& poly_b); /*! * Checks whether two polygons are adjacent (closer than \p max_gap) @@ -633,7 +633,7 @@ class PolygonUtils * \param[in] max_gap Polygons must be closer together than this distance to be considered adjacent. * \return true if a vertex in \p inner_poly is sufficiently close to a line in \p outer_poly, false otherwise */ - static bool polygonOutlinesAdjacent(const ConstPolygonRef inner_poly, const ConstPolygonRef outer_poly, const coord_t max_gap); + static bool polygonOutlinesAdjacent(const Polygon& inner_poly, const Polygon& outer_poly, const coord_t max_gap); /*! * Searches \p possible_adjacent_polys for polygons that are closer to \p poly than \p max_gap. The indices of adjacent polygons are stored in \p adjacent_poly_indices. @@ -643,11 +643,8 @@ class PolygonUtils * \param[in] possible_adjacent_polys The vector of polygons we are testing. * \param[in] max_gap Polygons must be closer together than this distance to be considered adjacent. */ - static void findAdjacentPolygons( - std::vector& adjacent_poly_indices, - const ConstPolygonRef& poly, - const std::vector& possible_adjacent_polys, - const coord_t max_gap); + static void + findAdjacentPolygons(std::vector& adjacent_poly_indices, const Polygon& poly, const std::vector& possible_adjacent_polys, const coord_t max_gap); /*! * Calculate the Hamming Distance between two polygons relative to their own @@ -680,9 +677,9 @@ class PolygonUtils */ static Polygons connect(const Polygons& input); - static void fixSelfIntersections(const coord_t epsilon, Polygons& thiss); + static void fixSelfIntersections(const coord_t epsilon, Polygons& polygon); - static Polygons unionManySmall(const Polygons& p); + static Polygons unionManySmall(const Polygons& polygon); /*! @@ -718,13 +715,13 @@ class PolygonUtils * Helper function for PolygonUtils::moveInside2: moves a point \p from which was moved onto \p closest_polygon_point towards inside/outside when it's not already * inside/outside by enough distance. * - * \param closest_polygon_point The ClosestPolygonPoint we have to move inside + * \param closest_polygon_point The ClosestPoint we have to move inside * \param distance The distance by which to move the point. * \param from[in,out] The point to move. * \param max_dist2 The squared maximal allowed distance from the point to the nearest polygon. * \return The point on the polygon closest to \p from */ - static ClosestPolygonPoint _moveInside2(const ClosestPolygonPoint& closest_polygon_point, const int distance, Point2LL& from, const int64_t max_dist2); + static ClosestPoint _moveInside2(const ClosestPoint& closest_polygon_point, const int distance, Point2LL& from, const int64_t max_dist2); }; diff --git a/src/ConicalOverhang.cpp b/src/ConicalOverhang.cpp index 9918d8a782..1fb47ba079 100644 --- a/src/ConicalOverhang.cpp +++ b/src/ConicalOverhang.cpp @@ -4,6 +4,7 @@ #include "ConicalOverhang.h" +#include "geometry/single_shape.h" #include "mesh.h" #include "settings/types/Angle.h" //To process the overhang angle. #include "settings/types/LayerIndex.h" @@ -39,7 +40,7 @@ void ConicalOverhang::apply(Slicer* slicer, const Mesh& mesh) else { // Get the current layer and split it into parts - std::vector layerParts = layer.polygons.splitIntoParts(); + std::vector layerParts = layer.polygons.splitIntoParts(); // Get a copy of the layer above to prune away before we shrink it Polygons above = layer_above.polygons; @@ -52,7 +53,7 @@ void ConicalOverhang::apply(Slicer* slicer, const Mesh& mesh) for (unsigned int hole_nr = 1; hole_nr < layerParts[part].size(); ++hole_nr) { Polygons holePoly; - holePoly.add(layerParts[part][hole_nr]); + holePoly.push_back(layerParts[part][hole_nr]); if (maxHoleArea > 0.0 && INT2MM2(std::abs(holePoly.area())) < maxHoleArea) { Polygons holeWithAbove = holePoly.intersection(above); diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 6008826fbf..87c35cc46c 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -27,6 +27,8 @@ #include "WallToolPaths.h" #include "bridge.h" #include "communication/Communication.h" //To send layer view data. +#include "geometry/open_polyline.h" +#include "geometry/point_matrix.h" #include "infill.h" #include "progress/Progress.h" #include "raft.h" @@ -213,10 +215,10 @@ unsigned int FffGcodeWriter::findSpiralizedLayerSeamVertexIndex(const SliceDataS // note that the code below doesn't assume that last_layer_nr is one less than layer_nr but the print is going // to come out pretty weird if that isn't true as it implies that there are empty layers - ConstPolygonRef last_wall = (*storage.spiralize_wall_outlines[last_layer_nr])[0]; + const Polygon& last_wall = (*storage.spiralize_wall_outlines[last_layer_nr])[0]; // Even though this is just one (contiguous) part, the spiralize wall may still be multiple parts if the part is somewhere thinner than 1 line width. // This case is so rare that we don't bother with finding the best polygon to start with. Just start with the first polygon (`spiral_wall[0]`). - ConstPolygonRef wall = layer.parts[0].spiral_wall[0]; + const Polygon& wall = layer.parts[0].spiral_wall[0]; const size_t n_points = wall.size(); const Point2LL last_wall_seam_vertex = last_wall[storage.spiralize_seam_vertex_indices[last_layer_nr]]; @@ -605,7 +607,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Application::getInstance().communication_->sendLayerComplete(layer_nr, z, layer_height); - Polygons raft_lines; + LinesSet raft_lines; AngleDegrees fill_angle = (num_surface_layers + num_interface_layers) % 2 ? 45 : 135; // 90 degrees rotated from the interface layer. constexpr bool zig_zaggify_infill = false; constexpr bool connect_polygons = true; // causes less jerks, so better adhesion @@ -792,7 +794,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_outline_path = storage.raftInterfaceOutline.offset(-small_offset); raft_outline_path = Simplify(interface_settings).polygon(raft_outline_path); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage_.raft_interface_config.getLineWidth(); - Polygons raft_lines; + LinesSet raft_lines; AngleDegrees fill_angle = (num_surface_layers + num_interface_layers - raft_interface_layer) % 2 ? 45 : 135; // 90 degrees rotated from the first top layer. constexpr bool zig_zaggify_infill = true; constexpr bool connect_polygons = true; // why not? @@ -963,7 +965,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_outline_path = storage.raftSurfaceOutline.offset(-small_offset); raft_outline_path = Simplify(interface_settings).polygon(raft_outline_path); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage_.raft_surface_config.getLineWidth(); - Polygons raft_lines; + LinesSet raft_lines; AngleDegrees fill_angle = (num_surface_layers - raft_surface_layer) % 2 ? 45 : 135; // Alternate between -45 and +45 degrees, ending up 90 degrees rotated from the default skin angle. constexpr bool zig_zaggify_infill = true; @@ -1324,7 +1326,7 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan struct BrimLineReference { const size_t inset_idx; - ConstPolygonPointer poly; + const OpenPolyline* poly; }; size_t total_line_count = 0; @@ -1333,7 +1335,7 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan total_line_count += line.closed_polygons.size(); total_line_count += line.open_polylines.size(); } - Polygons all_brim_lines; + LinesSet all_brim_lines; all_brim_lines.reserve(total_line_count); @@ -1345,34 +1347,35 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan for (size_t inset_idx = 0; inset_idx < storage.skirt_brim[extruder_nr].size(); inset_idx++) { - const auto& offset = storage.skirt_brim[extruder_nr][inset_idx]; - const auto closed_polygons_open_polylines = { offset.closed_polygons, offset.open_polylines }; - const auto closed_open = { true, false }; - for (const auto [polygon, closed] : ranges::views::zip(closed_polygons_open_polylines, closed_open)) + const SkirtBrimLine& offset = storage.skirt_brim[extruder_nr][inset_idx]; + auto push_lines = [&all_brim_lines, &grid, &inset_idx](const LinesSet& lines) { - for (ConstPolygonRef line : polygon) + for (const LineType& line : lines) { if (line.size() <= 1) { continue; } all_brim_lines.emplace_back(line); - if (closed) + if constexpr (LineType::type_ != PolylineType::Open) { // add closing segment - all_brim_lines.back().add(line.front()); + all_brim_lines.back().push_back(line.front()); } - ConstPolygonPointer pp(all_brim_lines.back()); - for (Point2LL p : line) + const OpenPolyline* pp = &all_brim_lines.back(); + for (const Point2LL& p : line) { grid.insert(p, BrimLineReference{ inset_idx, pp }); } } - } + }; + + push_lines(offset.closed_polygons); + push_lines(offset.open_polylines); } const auto smart_brim_ordering = train.settings_.get("brim_smart_ordering") && train.settings_.get("adhesion_type") == EPlatformAdhesion::BRIM; - std::unordered_multimap order_requirements; + std::unordered_multimap order_requirements; for (const std::pair>& p : grid) { const BrimLineReference& here = p.second.val; @@ -1429,8 +1432,8 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan if (! all_brim_lines.empty()) { // For layer_nr != 0 add only the innermost brim line (which is only the case if skirt_height > 1) - Polygons inner_brim_line; - inner_brim_line.add(all_brim_lines[0]); + LinesSet inner_brim_line; + inner_brim_line.push_back(all_brim_lines[0]); gcode_layer.addLinesByOptimizer( layer_nr == 0 ? all_brim_lines : inner_brim_line, @@ -1453,8 +1456,9 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan if ((layer_nr == 0) && (extruder_nr == mesh_group_settings.get("support_extruder_nr_layer_0").extruder_nr_)) { total_line_count += storage.support_brim.size(); - Polygons support_brim_lines = storage.support_brim; - support_brim_lines.toPolylines(); + LinesSet support_brim_lines = storage.support_brim; +#warning Check for bugs !! + // support_brim_lines.toPolylines(); gcode_layer.addLinesByOptimizer( support_brim_lines, gcode_layer.configs_storage_.skirt_brim_config_per_extruder[extruder_nr], @@ -1821,7 +1825,7 @@ bool FffGcodeWriter::processMultiLayerInfill( const bool connect_polygons = mesh.settings.get("connect_infill_polygons"); const size_t infill_multiplier = mesh.settings.get("infill_multiplier"); Polygons infill_polygons; - Polygons infill_lines; + LinesSet infill_lines; std::vector infill_paths = part.infill_wall_toolpaths; for (size_t density_idx = part.infill_area_per_combine_per_density.size() - 1; (int)density_idx >= 0; density_idx--) { // combine different density infill areas (for gradual infill) @@ -1942,7 +1946,7 @@ bool FffGcodeWriter::processSingleLayerInfill( // Combine the 1 layer thick infill with the top/bottom skin and print that as one thing. Polygons infill_polygons; std::vector> wall_tool_paths; // All wall toolpaths binned by inset_idx (inner) and by density_idx (outer) - Polygons infill_lines; + LinesSet infill_lines; const auto pattern = mesh.settings.get("infill_pattern"); const bool zig_zaggify_infill = mesh.settings.get("zig_zaggify_infill") || pattern == EFillMethod::ZIG_ZAG; @@ -1995,7 +1999,7 @@ bool FffGcodeWriter::processSingleLayerInfill( continue; } - Polygons infill_lines_here; + LinesSet infill_lines_here; Polygons infill_polygons_here; // the highest density infill combines with the next to create a grid with density_factor 1 @@ -2103,7 +2107,7 @@ bool FffGcodeWriter::processSingleLayerInfill( } } - const coord_t circumference = in_outline.polygonLength(); + const coord_t circumference = in_outline.length(); // Originally an area of 0.4*0.4*2 (2 line width squares) was found to be a good threshold for removal. // However we found that this doesn't scale well with polygons with larger circumference (https://github.com/Ultimaker/Cura/issues/3992). // Given that the original test worked for approximately 2x2cm models, this scaling by circumference should make it work for any size. @@ -2193,7 +2197,7 @@ bool FffGcodeWriter::processSingleLayerInfill( } else if (! infill_polygons.empty()) { - PolygonRef start_poly = infill_polygons[rand() % infill_polygons.size()]; + const Polygon& start_poly = infill_polygons[rand() % infill_polygons.size()]; near_start_location = start_poly[rand() % start_poly.size()]; } else // So walls_generated must be true. @@ -2399,7 +2403,7 @@ void FffGcodeWriter::processSpiralizedWall( // wall doesn't have usable outline return; } - const ClipperLib::Path* last_wall_outline = &*part.spiral_wall[0]; // default to current wall outline + const Polygon* last_wall_outline = &(part.spiral_wall[0]); // default to current wall outline int last_seam_vertex_idx = -1; // last layer seam vertex index int layer_nr = gcode_layer.getLayerNr(); if (layer_nr > 0) @@ -2407,7 +2411,7 @@ void FffGcodeWriter::processSpiralizedWall( if (storage.spiralize_wall_outlines[layer_nr - 1] != nullptr) { // use the wall outline from the previous layer - last_wall_outline = &*(*storage.spiralize_wall_outlines[layer_nr - 1])[0]; + last_wall_outline = &(storage.spiralize_wall_outlines[layer_nr - 1]->front()); // and the seam vertex index pre-computed for that layer last_seam_vertex_idx = storage.spiralize_seam_vertex_indices[layer_nr - 1]; } @@ -2416,10 +2420,9 @@ void FffGcodeWriter::processSpiralizedWall( const bool is_top_layer = ((size_t)layer_nr == (storage.spiralize_wall_outlines.size() - 1) || storage.spiralize_wall_outlines[layer_nr + 1] == nullptr); const int seam_vertex_idx = storage.spiralize_seam_vertex_indices[layer_nr]; // use pre-computed seam vertex index for current layer // output a wall slice that is interpolated between the last and current walls - for (const ConstPolygonRef& wall_outline : part.spiral_wall) + for (const Polygon& wall_outline : part.spiral_wall) { - gcode_layer - .spiralizeWallSlice(mesh_config.inset0_config, wall_outline, ConstPolygonRef(*last_wall_outline), seam_vertex_idx, last_seam_vertex_idx, is_top_layer, is_bottom_layer); + gcode_layer.spiralizeWallSlice(mesh_config.inset0_config, wall_outline, *last_wall_outline, seam_vertex_idx, last_seam_vertex_idx, is_top_layer, is_bottom_layer); } } @@ -2463,7 +2466,7 @@ bool FffGcodeWriter::processInsets( added_something = true; gcode_layer.setIsInside(true); // going to print stuff inside print object // start this first wall at the same vertex the spiral starts - const ConstPolygonRef spiral_inset = part.spiral_wall[0]; + const Polygon& spiral_inset = part.spiral_wall[0]; const size_t spiral_start_vertex = storage.spiralize_seam_vertex_indices[initial_bottom_layers]; if (spiral_start_vertex < spiral_inset.size()) { @@ -2988,7 +2991,7 @@ void FffGcodeWriter::processSkinPrintFeature( double fan_speed) const { Polygons skin_polygons; - Polygons skin_lines; + LinesSet skin_lines; std::vector skin_paths; constexpr int infill_multiplier = 1; @@ -3363,7 +3366,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer Polygons support_polygons; std::vector wall_toolpaths_here; - Polygons support_lines; + LinesSet support_lines; const size_t max_density_idx = part.infill_area_per_combine_per_density_.size() - 1; for (size_t density_idx = max_density_idx; (density_idx + 1) > 0; --density_idx) { @@ -3622,7 +3625,7 @@ bool FffGcodeWriter::addSupportRoofsToGCode( pocket_size); Polygons roof_polygons; std::vector roof_paths; - Polygons roof_lines; + LinesSet roof_lines; roof_computation.generate(roof_paths, roof_polygons, roof_lines, roof_extruder.settings_, gcode_layer.getLayerNr(), SectionType::SUPPORT); if ((gcode_layer.getLayerNr() == 0 && wall.empty()) || (gcode_layer.getLayerNr() > 0 && roof_paths.empty() && roof_polygons.empty() && roof_lines.empty())) { @@ -3739,7 +3742,7 @@ bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, L pocket_size); Polygons bottom_polygons; std::vector bottom_paths; - Polygons bottom_lines; + LinesSet bottom_lines; bottom_computation.generate(bottom_paths, bottom_polygons, bottom_lines, bottom_extruder.settings_, gcode_layer.getLayerNr(), SectionType::SUPPORT); if (bottom_paths.empty() && bottom_polygons.empty() && bottom_lines.empty()) { diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 384093794c..47b676c5e8 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -49,6 +49,7 @@ #include "utils/ThreadPool.h" #include "utils/gettime.h" #include "utils/math.h" +#include "geometry/open_polyline.h" #include "utils/Simplify.h" // clang-format on @@ -568,17 +569,17 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz // they have to be polylines, because they might break up further when doing the cutting for (SliceLayerPart& part : layer.parts) { - for (PolygonRef poly : part.outline) + for (const Polygon& poly : part.outline) { - layer.openPolyLines.add(poly); - layer.openPolyLines.back().add(layer.openPolyLines.back()[0]); // add the segment which closes the polygon + layer.openPolyLines.push_back(OpenPolyline(poly)); + layer.openPolyLines.back().push_back(layer.openPolyLines.back()[0]); // add the segment which closes the polygon } } layer.parts.clear(); } - std::vector new_parts; - Polygons new_polylines; + std::vector new_parts; + LinesSet new_polylines; for (const size_t other_mesh_idx : mesh_order) { // limit the infill mesh's outline to within the infill of all meshes with lower order @@ -607,14 +608,14 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz Polygons new_outline = part.outline.intersection(other_part.getOwnInfillArea()); if (new_outline.size() == 1) { // we don't have to call splitIntoParts, because a single polygon can only be a single part - PolygonsPart outline_part_here; - outline_part_here.add(new_outline[0]); + SingleShape outline_part_here; + outline_part_here.push_back(new_outline[0]); new_parts.push_back(outline_part_here); } else if (new_outline.size() > 1) { // we don't know whether it's a multitude of parts because of newly introduced holes, or because the polygon has been split up - std::vector new_parts_here = new_outline.splitIntoParts(); - for (PolygonsPart& new_part_here : new_parts_here) + std::vector new_parts_here = new_outline.splitIntoParts(); + for (SingleShape& new_part_here : new_parts_here) { new_parts.push_back(new_part_here); } @@ -628,19 +629,19 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz if (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { const Polygons& own_infill_area = other_part.getOwnInfillArea(); - Polygons cut_lines = own_infill_area.intersectionPolyLines(layer.openPolyLines); + std::vector cut_lines = own_infill_area.intersectionPolyLines(layer.openPolyLines); new_polylines.add(cut_lines); // NOTE: closed polygons will be represented as polylines, which will be closed automatically in the PathOrderOptimizer if (! own_infill_area.empty()) { - other_part.infill_area_own = own_infill_area.difference(layer.openPolyLines.offsetPolyLine(surface_line_width / 2)); + other_part.infill_area_own = own_infill_area.difference(layer.openPolyLines.offset(surface_line_width / 2)); } } } } layer.parts.clear(); - for (PolygonsPart& part : new_parts) + for (SingleShape& part : new_parts) { layer.parts.emplace_back(); layer.parts.back().outline = part; diff --git a/src/GCodePathConfig.cpp b/src/GCodePathConfig.cpp index 6cdfbd5d66..a1a2179f6f 100644 --- a/src/GCodePathConfig.cpp +++ b/src/GCodePathConfig.cpp @@ -3,7 +3,7 @@ #include "GCodePathConfig.h" -#include "utils/Point2LL.h" // INT2MM +#include "geometry/point2ll.h" // INT2MM namespace cura { diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 82d4199d01..529ade9671 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -170,7 +170,7 @@ InsetOrderOptimizer::value_type InsetOrderOptimizer::getRegionOrder(const std::v | ranges::views::transform( [](const ExtrusionLine* line) { - const auto poly = line->toPolygon(); + const Polygon poly = line->toPolygon(); AABB aabb; aabb.include(poly); return std::make_pair(line, aabb.area()); @@ -206,7 +206,7 @@ InsetOrderOptimizer::value_type InsetOrderOptimizer::getRegionOrder(const std::v Polygons hole_polygons; if (extrusion_line->is_closed_) { - hole_polygons.add(extrusion_line->toPolygon()); + hole_polygons.push_back(extrusion_line->toPolygon()); } if (hole_polygons.empty()) diff --git a/src/InterlockingGenerator.cpp b/src/InterlockingGenerator.cpp index ea1849d96f..dcd8ff1628 100644 --- a/src/InterlockingGenerator.cpp +++ b/src/InterlockingGenerator.cpp @@ -12,6 +12,7 @@ #include "Application.h" #include "Slice.h" +#include "geometry/point_matrix.h" #include "settings/types/LayerIndex.h" #include "slicer.h" #include "utils/VoxelUtils.h" @@ -111,7 +112,7 @@ void InterlockingGenerator::handleThinAreas(const std::unordered_set const Point3LL bottom_corner = vu_.toLowerCorner(cell); for (coord_t layer_nr = bottom_corner.z_; layer_nr < bottom_corner.z_ + cell_size_.z_ && layer_nr < static_cast(near_interlock_per_layer.size()); ++layer_nr) { - near_interlock_per_layer[static_cast(layer_nr)].add(vu_.toPolygon(cell)); + near_interlock_per_layer[static_cast(layer_nr)].push_back(vu_.toPolygon(cell)); } } for (auto& near_interlock : near_interlock_per_layer) @@ -255,7 +256,7 @@ std::vector> InterlockingGenerator::generateMicrostructure Point2LL offset(mesh_idx ? middle : 0, 0); Point2LL area_size(width[mesh_idx], cell_size_.y_); - PolygonRef poly = cell_area_per_mesh_per_layer[0][mesh_idx].newPoly(); + Polygon& poly = cell_area_per_mesh_per_layer[0][mesh_idx].newLine(); poly.emplace_back(offset); poly.emplace_back(offset + Point2LL(area_size.X, 0)); poly.emplace_back(offset + area_size); @@ -264,7 +265,7 @@ std::vector> InterlockingGenerator::generateMicrostructure cell_area_per_mesh_per_layer[1] = cell_area_per_mesh_per_layer[0]; for (Polygons& polys : cell_area_per_mesh_per_layer[1]) { - for (PolygonRef poly : polys) + for (Polygon& poly : polys) { for (Point2LL& p : poly) { diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index b1a553646a..31fddba043 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -547,7 +547,7 @@ void LayerPlan::addExtrusionMove( } void LayerPlan::addPolygon( - ConstPolygonRef polygon, + const Polygon& polygon, int start_idx, const bool backwards, const GCodePathConfig& config, @@ -616,16 +616,16 @@ void LayerPlan::addPolygonsByOptimizer( { return; } - PathOrderOptimizer orderOptimizer(start_near_location ? start_near_location.value() : getLastPlannedPositionOrStartingPosition(), z_seam_config); + PathOrderOptimizer orderOptimizer(start_near_location ? start_near_location.value() : getLastPlannedPositionOrStartingPosition(), z_seam_config); for (size_t poly_idx = 0; poly_idx < polygons.size(); poly_idx++) { - orderOptimizer.addPolygon(polygons[poly_idx]); + orderOptimizer.addPolygon(&polygons[poly_idx]); } orderOptimizer.optimize(); if (! reverse_order) { - for (const PathOrdering& path : orderOptimizer.paths_) + for (const PathOrdering& path : orderOptimizer.paths_) { addPolygon(*path.vertices_, path.start_vertex_, path.backwards_, config, wall_0_wipe_dist, spiralize, flow_ratio, always_retract); } @@ -634,8 +634,8 @@ void LayerPlan::addPolygonsByOptimizer( { for (int index = orderOptimizer.paths_.size() - 1; index >= 0; --index) { - const PathOrdering& path = orderOptimizer.paths_[index]; - addPolygon(**path.vertices_, path.start_vertex_, path.backwards_, config, wall_0_wipe_dist, spiralize, flow_ratio, always_retract); + const PathOrdering& path = orderOptimizer.paths_[index]; + addPolygon(*path.vertices_, path.start_vertex_, path.backwards_, config, wall_0_wipe_dist, spiralize, flow_ratio, always_retract); } } } @@ -782,7 +782,7 @@ void LayerPlan::addWallLine( // the default_config. Since the original line segment was straight we can simply print // to the first and last point of the intersected line segments alternating between // roofing and default_config's. - Polygons line_polys; + LinesSet line_polys; line_polys.addLine(p0, p1); constexpr bool restitch = false; // only a single line doesn't need stitching auto roofing_line_segments = roofing_mask_.intersectionPolyLines(line_polys, restitch); @@ -855,7 +855,7 @@ void LayerPlan::addWallLine( // determine which segments of the line are bridges - Polygons line_polys; + LinesSet line_polys; line_polys.addLine(p0, p1); constexpr bool restitch = false; // only a single line doesn't need stitching line_polys = bridge_wall_mask_.intersectionPolyLines(line_polys, restitch); @@ -865,9 +865,9 @@ void LayerPlan::addWallLine( while (line_polys.size() > 0) { // find the bridge line segment that's nearest to the current point - int nearest = 0; + size_t nearest = 0; double smallest_dist2 = vSize2f(cur_point - line_polys[0][0]); - for (unsigned i = 1; i < line_polys.size(); ++i) + for (size_t i = 1; i < line_polys.size(); ++i) { double dist2 = vSize2f(cur_point - line_polys[i][0]); if (dist2 < smallest_dist2) @@ -876,7 +876,7 @@ void LayerPlan::addWallLine( smallest_dist2 = dist2; } } - ConstPolygonRef bridge = line_polys[nearest]; + const Polygon& bridge = line_polys[nearest]; // set b0 to the nearest vertex and b1 the furthest Point2LL b0 = bridge[0]; @@ -916,7 +916,7 @@ void LayerPlan::addWallLine( } // finished with this segment - line_polys.remove(nearest); + line_polys.removeAt(nearest); } // if we haven't yet reached p1, fill the gap with default_config line @@ -937,7 +937,7 @@ void LayerPlan::addWallLine( } void LayerPlan::addWall( - ConstPolygonRef wall, + const Polygon& wall, int start_idx, const Settings& settings, const GCodePathConfig& default_config, @@ -1027,7 +1027,7 @@ void LayerPlan::addWall( // determine which segments of the line are bridges - Polygons line_polys; + LinesSet line_polys; line_polys.addLine(p0.p_, p1.p_); constexpr bool restitch = false; // only a single line doesn't need stitching line_polys = bridge_wall_mask_.intersectionPolyLines(line_polys, restitch); @@ -1035,7 +1035,7 @@ void LayerPlan::addWall( while (line_polys.size() > 0) { // find the bridge line segment that's nearest to p0 - int nearest = 0; + size_t nearest = 0; double smallest_dist2 = vSize2f(p0.p_ - line_polys[0][0]); for (unsigned i = 1; i < line_polys.size(); ++i) { @@ -1046,7 +1046,7 @@ void LayerPlan::addWall( smallest_dist2 = dist2; } } - ConstPolygonRef bridge = line_polys[nearest]; + const Polygon& bridge = line_polys[nearest]; // set b0 to the nearest vertex and b1 the furthest Point2LL b0 = bridge[0]; @@ -1072,7 +1072,7 @@ void LayerPlan::addWall( distance_to_bridge_start += bridge_line_len; // finished with this segment - line_polys.remove(nearest); + line_polys.removeAt(nearest); } } else if (! bridge_wall_mask_.inside(p0.p_, true)) @@ -1253,21 +1253,21 @@ void LayerPlan::addWalls( bool always_retract) { // TODO: Deprecated in favor of ExtrusionJunction version below. - PathOrderOptimizer orderOptimizer(getLastPlannedPositionOrStartingPosition(), z_seam_config); - for (size_t poly_idx = 0; poly_idx < walls.size(); poly_idx++) + PathOrderOptimizer orderOptimizer(getLastPlannedPositionOrStartingPosition(), z_seam_config); + for (const Polygon& polygon : walls) { - orderOptimizer.addPolygon(walls[poly_idx]); + orderOptimizer.addPolygon(&polygon); } orderOptimizer.optimize(); - for (const PathOrdering& path : orderOptimizer.paths_) + for (const PathOrdering& path : orderOptimizer.paths_) { - addWall(**path.vertices_, path.start_vertex_, settings, default_config, roofing_config, bridge_config, wall_0_wipe_dist, flow_ratio, always_retract); + addWall(*path.vertices_, path.start_vertex_, settings, default_config, roofing_config, bridge_config, wall_0_wipe_dist, flow_ratio, always_retract); } } void LayerPlan::addLinesByOptimizer( - const Polygons& polygons, + const std::vector& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const bool enable_travel_optimization, @@ -1276,7 +1276,7 @@ void LayerPlan::addLinesByOptimizer( const std::optional near_start_location, const double fan_speed, const bool reverse_print_direction, - const std::unordered_multimap& order_requirements) + const std::unordered_multimap& order_requirements) { Polygons boundary; if (enable_travel_optimization && ! comb_boundary_minimum_.empty()) @@ -1301,16 +1301,16 @@ void LayerPlan::addLinesByOptimizer( boundary = Simplify(MM2INT(0.1), MM2INT(0.1), 0).polygon(boundary); } constexpr bool detect_loops = true; - PathOrderOptimizer order_optimizer( + PathOrderOptimizer order_optimizer( near_start_location.value_or(getLastPlannedPositionOrStartingPosition()), ZSeamConfig(), detect_loops, &boundary, reverse_print_direction, order_requirements); - for (size_t line_idx = 0; line_idx < polygons.size(); line_idx++) + for (const OpenPolyline& polyline : lines) { - order_optimizer.addPolyline(polygons[line_idx]); + order_optimizer.addPolyline(&polyline); } order_optimizer.optimize(); @@ -1319,7 +1319,7 @@ void LayerPlan::addLinesByOptimizer( void LayerPlan::addLinesInGivenOrder( - const std::vector>& paths, + const std::vector>& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const coord_t wipe_dist, @@ -1328,10 +1328,10 @@ void LayerPlan::addLinesInGivenOrder( { coord_t half_line_width = config.getLineWidth() / 2; coord_t line_width_2 = half_line_width * half_line_width; - for (size_t order_idx = 0; order_idx < paths.size(); order_idx++) + for (size_t order_idx = 0; order_idx < lines.size(); order_idx++) { - const PathOrdering& path = paths[order_idx]; - ConstPolygonRef polyline = *path.vertices_; + const PathOrdering& path = lines[order_idx]; + const OpenPolyline& polyline = *path.vertices_; const size_t start_idx = path.start_vertex_; assert(start_idx == 0 || start_idx == polyline.size() - 1 || path.is_closed_); const Point2LL start = polyline[start_idx]; @@ -1391,16 +1391,16 @@ void LayerPlan::addLinesInGivenOrder( int line_width = config.getLineWidth(); // Don't wipe if current extrusion is too small - if (polyline.polylineLength() <= line_width * 2) + if (polyline.length() <= line_width * 2) { wipe = false; } // Don't wipe if next starting point is very near - if (wipe && (order_idx < paths.size() - 1)) + if (wipe && (order_idx < lines.size() - 1)) { - const PathOrdering& next_path = paths[order_idx + 1]; - ConstPolygonRef next_polygon = *next_path.vertices_; + const PathOrdering& next_path = lines[order_idx + 1]; + const Polygon& next_polygon = *next_path.vertices_; const size_t next_start = next_path.start_vertex_; const Point2LL& next_p0 = next_polygon[next_start]; if (vSize2(next_p0 - p1) <= line_width * line_width * 4) @@ -1423,7 +1423,7 @@ void LayerPlan::addLinesInGivenOrder( void LayerPlan::addLinesMonotonic( const Polygons& area, - const Polygons& polygons, + const std::vector& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const AngleRadians monotonic_direction, @@ -1438,34 +1438,34 @@ void LayerPlan::addLinesMonotonic( const Point2LL last_position = getLastPlannedPositionOrStartingPosition(); // First lay all adjacent lines next to each other, to have a sensible input to the monotonic part of the algorithm. - PathOrderOptimizer line_order(last_position); - for (const ConstPolygonRef polyline : polygons) + PathOrderOptimizer line_order(last_position); + for (const OpenPolyline& line : lines) { - line_order.addPolyline(polyline); + line_order.addPolyline(&line); } line_order.optimize(); - const auto is_inside_exclusion = [&exclude_areas, &exclude_dist2](ConstPolygonRef path) + const auto is_inside_exclusion = [&exclude_areas, &exclude_dist2](const Polygon& path) { return vSize2(path[1] - path[0]) < exclude_dist2 && exclude_areas.inside((path[0] + path[1]) / 2); }; // Order monotonically, except for line-segments which stay in the excluded areas (read: close to the walls) consecutively. - PathOrderMonotonic order(monotonic_direction, max_adjacent_distance, last_position); - Polygons left_over; + PathOrderMonotonic order(monotonic_direction, max_adjacent_distance, last_position); + std::vector left_over; bool last_would_have_been_excluded = false; for (size_t line_idx = 0; line_idx < line_order.paths_.size(); ++line_idx) { - const ConstPolygonRef polyline = *line_order.paths_[line_idx].vertices_; + const OpenPolyline& polyline = *line_order.paths_[line_idx].vertices_; const bool inside_exclusion = is_inside_exclusion(polyline); const bool next_would_have_been_included = inside_exclusion && (line_idx < line_order.paths_.size() - 1 && is_inside_exclusion(*line_order.paths_[line_idx + 1].vertices_)); if (inside_exclusion && last_would_have_been_excluded && next_would_have_been_included) { - left_over.add(polyline); + left_over.push_back(polyline); } else { - order.addPolyline(polyline); + order.addPolyline(&polyline); } last_would_have_been_excluded = inside_exclusion; } @@ -1480,8 +1480,8 @@ void LayerPlan::addLinesMonotonic( void LayerPlan::spiralizeWallSlice( const GCodePathConfig& config, - ConstPolygonRef wall, - ConstPolygonRef last_wall, + const Polygon& wall, + const Polygon& last_wall, const int seam_vertex_idx, const int last_seam_vertex_idx, const bool is_top_layer, @@ -1512,7 +1512,7 @@ void LayerPlan::spiralizeWallSlice( const int n_points = wall.size(); Polygons last_wall_polygons; - last_wall_polygons.add(last_wall); + last_wall_polygons.push_back(last_wall); const int max_dist2 = config.getLineWidth() * config.getLineWidth() * 4; // (2 * lineWidth)^2; double total_length = 0.0; // determine the length of the complete wall @@ -1583,7 +1583,7 @@ void LayerPlan::spiralizeWallSlice( if (smooth_contours && ! is_bottom_layer && wall_point_idx < n_points) { // now find the point on the last wall that is closest to p - ClosestPolygonPoint cpp = PolygonUtils::findClosest(p, last_wall_polygons); + ClosestPoint cpp = PolygonUtils::findClosest(p, last_wall_polygons); // if we found a point and it's not further away than max_dist2, use it if (cpp.isValid() && vSize2(cpp.location_ - p) <= max_dist2) diff --git a/src/Mold.cpp b/src/Mold.cpp index c5149467af..c9ac159a39 100644 --- a/src/Mold.cpp +++ b/src/Mold.cpp @@ -7,10 +7,11 @@ #include "ExtruderTrain.h" #include "Scene.h" #include "Slice.h" +#include "geometry/open_polyline.h" +#include "geometry/point2ll.h" #include "settings/types/Ratio.h" #include "sliceDataStorage.h" #include "slicer.h" -#include "utils/Point2LL.h" namespace cura { @@ -76,7 +77,7 @@ void Mold::process(std::vector& slicer_list) SlicerLayer& layer = slicer.layers[layer_nr]; - Polygons model_outlines = layer.polygons.unionPolygons(layer.openPolylines.offsetPolyLine(open_polyline_width / 2)); + Polygons model_outlines = layer.polygons.unionPolygons(layer.openPolylines.offset(open_polyline_width / 2)); layer.openPolylines.clear(); all_original_mold_outlines.add(model_outlines); diff --git a/src/PathOrderPath.cpp b/src/PathOrderPath.cpp index cfca513fa9..4c1a2b888e 100644 --- a/src/PathOrderPath.cpp +++ b/src/PathOrderPath.cpp @@ -9,42 +9,54 @@ namespace cura { template<> -ConstPolygonRef PathOrdering::getVertexData() +const Polygon& PathOrdering::getVertexData() { return *vertices_; } template<> -ConstPolygonRef PathOrdering::getVertexData() +const Polygon& PathOrdering::getVertexData() { return *vertices_; } template<> -ConstPolygonRef PathOrdering::getVertexData() +const Polygon& PathOrdering::getVertexData() +{ + return *reinterpret_cast(vertices_); +} + +template<> +const Polygon& PathOrdering::getVertexData() +{ + return *reinterpret_cast(vertices_); +} + +template<> +const Polygon& PathOrdering::getVertexData() { return vertices_->outline.outerPolygon(); } template<> -ConstPolygonRef PathOrdering::getVertexData() +const Polygon& PathOrdering::getVertexData() { return vertices_->outline.outerPolygon(); } template<> -ConstPolygonRef PathOrdering::getVertexData() +const Polygon& PathOrdering::getVertexData() { return vertices_->outline_.outerPolygon(); } template<> -ConstPolygonRef PathOrdering::getVertexData() +const Polygon& PathOrdering::getVertexData() { if (! cached_vertices_) { cached_vertices_ = vertices_->toPolygon(); } - return ConstPolygonRef(*cached_vertices_); + return *cached_vertices_; } } // namespace cura diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index b56c94913c..cb8b110a4c 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -94,7 +94,7 @@ void PrimeTower::generateGroundpoly() const coord_t x = mesh_group_settings.get("prime_tower_position_x"); const coord_t y = mesh_group_settings.get("prime_tower_position_y"); const coord_t tower_radius = tower_size / 2; - outer_poly_.add(PolygonUtils::makeCircle(Point2LL(x - tower_radius, y + tower_radius), tower_radius, TAU / CIRCLE_RESOLUTION)); + outer_poly_.push_back(PolygonUtils::makeCircle(Point2LL(x - tower_radius, y + tower_radius), tower_radius, TAU / CIRCLE_RESOLUTION)); middle_ = Point2LL(x - tower_size / 2, y + tower_size / 2); post_wipe_point_ = Point2LL(x - tower_size / 2, y + tower_size / 2); @@ -142,7 +142,7 @@ void PrimeTower::generatePaths_denseInfill() // Create a new polygon with an offset from the outer polygon. Polygons polygons = outer_poly_.offset(-cumulative_inset - wall_nr * line_width - line_width / 2); prime_moves.add(polygons); - current_volume += polygons.polygonLength() * line_width * layer_height * flow; + current_volume += polygons.length() * line_width * layer_height * flow; if (polygons.empty()) // Don't continue. We won't ever reach the required volume because it doesn't fit. { break; @@ -298,7 +298,7 @@ void PrimeTower::gotoStartLocation(LayerPlan& gcode_layer, const int extruder_nr int current_start_location_idx = ((((extruder_nr + 1) * gcode_layer.getLayerNr()) % number_of_prime_tower_start_locations_) + number_of_prime_tower_start_locations_) % number_of_prime_tower_start_locations_; - const ClosestPolygonPoint wipe_location = prime_tower_start_locations_[current_start_location_idx]; + const ClosestPoint wipe_location = prime_tower_start_locations_[current_start_location_idx]; const ExtruderTrain& train = Application::getInstance().current_slice_->scene.extruders[extruder_nr]; const coord_t inward_dist = train.settings_.get("machine_nozzle_size") * 3 / 2; diff --git a/src/SkeletalTrapezoidation.cpp b/src/SkeletalTrapezoidation.cpp index d31aa52ce9..26bf3135ae 100644 --- a/src/SkeletalTrapezoidation.cpp +++ b/src/SkeletalTrapezoidation.cpp @@ -402,7 +402,7 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) std::vector segments; for (size_t poly_idx = 0; poly_idx < polys.size(); poly_idx++) { - ConstPolygonRef poly = polys[poly_idx]; + const Polygon& poly = polys[poly_idx]; for (size_t point_idx = 0; point_idx < poly.size(); point_idx++) { segments.emplace_back(&polys, poly_idx, point_idx); diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index a2b67503ec..6bc084817f 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -12,8 +12,8 @@ #include "settings/types/Ratio.h" #include "sliceDataStorage.h" #include "support.h" -#include "utils/PolylineStitcher.h" -#include "utils/Simplify.h" //Simplifying the brim/skirt at every inset. +#include "utils/OpenPolylineStitcher.h" +#include "utils/Simplify.h" namespace cura { @@ -231,8 +231,8 @@ Polygons SkirtBrim::getInternalHoleExclusionArea(const Polygons& outline, const const coord_t hole_brim_distance = settings.get("brim_inside_margin"); Polygons ret; - std::vector parts = outline.splitIntoParts(); - for (const PolygonsPart& part : parts) + std::vector parts = outline.splitIntoParts(); + for (const SingleShape& part : parts) { for (size_t hole_idx = 1; hole_idx < part.size(); hole_idx++) { @@ -258,7 +258,7 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, { // prevent unioning of external polys enclosed by other parts, e.g. a small part inside a hollow cylinder. for (Polygons& polys : reference_outline->sortByNesting()) { // offset external polygons of islands contained within another part in each batch - for (PolygonRef poly : polys) + for (Polygon& poly : polys) { if (poly.area() < 0) { @@ -267,7 +267,7 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, } brim.add(polys.offset(offset.offset_value_, ClipperLib::jtRound)); newly_covered.add(polys.offset(offset.offset_value_ + line_widths_[offset.extruder_nr_] / 2, ClipperLib::jtRound)); - for (PolygonRef poly : polys) + for (Polygon& poly : polys) { poly.reverse(); } @@ -286,10 +286,10 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, auto offset_dist = line_widths_[offset.extruder_nr_]; Polygons local_brim; - auto closed_polygons_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].closed_polygons.offsetPolyLine(offset_dist, ClipperLib::jtRound, true); + auto closed_polygons_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].closed_polygons.offset(offset_dist, ClipperLib::jtRound); local_brim.add(closed_polygons_brim); - auto open_polylines_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].open_polylines.offsetPolyLine(offset_dist, ClipperLib::jtRound); + auto open_polylines_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].open_polylines.offset(offset_dist, ClipperLib::jtRound); local_brim.add(open_polylines_brim); local_brim.unionPolygons(); @@ -301,20 +301,19 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, { // limit brim lines to allowed areas, stitch them and store them in the result brim = Simplify(Application::getInstance().current_slice_->scene.extruders[offset.extruder_nr_].settings_).polygon(brim); - brim.toPolylines(); - Polygons brim_lines = allowed_areas_per_extruder[offset.extruder_nr_].intersectionPolyLines(brim, false); - length_added = brim_lines.polyLineLength(); + LinesSet brim_lines = allowed_areas_per_extruder[offset.extruder_nr_].intersectionPolyLines(brim.toType(), false); + length_added = brim_lines.length(); const coord_t max_stitch_distance = line_widths_[offset.extruder_nr_]; - PolylineStitcher::stitch(brim_lines, result.open_polylines, result.closed_polygons, max_stitch_distance); + OpenPolylineStitcher::stitch(brim_lines, result.open_polylines, result.closed_polygons, max_stitch_distance); // clean up too small lines for (size_t line_idx = 0; line_idx < result.open_polylines.size();) { - PolygonRef line = result.open_polylines[line_idx]; + const OpenPolyline& line = result.open_polylines[line_idx]; if (line.shorterThan(min_brim_line_length)) { - result.open_polylines.remove(line_idx); + result.open_polylines.removeAt(line_idx); } else { @@ -599,8 +598,8 @@ void SkirtBrim::generateSupportBrim() for (const SkirtBrimLine& brim_line : storage_.skirt_brim[support_infill_extruder.extruder_nr_]) { - skirt_brim_length += brim_line.closed_polygons.polygonLength(); - skirt_brim_length += brim_line.open_polylines.polyLineLength(); + skirt_brim_length += brim_line.closed_polygons.length(); + skirt_brim_length += brim_line.open_polylines.length(); } SupportLayer& support_layer = storage_.support.supportLayers[0]; @@ -626,13 +625,13 @@ void SkirtBrim::generateSupportBrim() const double area = brim_line[n].area(); if (area < 0 && area > -brim_line_width * brim_line_width * brim_area_minimum_hole_size_multiplier) { - brim_line.remove(n--); + brim_line.removeAt(n--); } } - storage_.support_brim.add(brim_line); + storage_.support_brim.add(brim_line.toType()); // In case of adhesion::NONE length of support brim is only the length of the brims formed for the support - const coord_t length = (adhesion_type_ == EPlatformAdhesion::NONE) ? skirt_brim_length : skirt_brim_length + storage_.support_brim.polygonLength(); + const coord_t length = (adhesion_type_ == EPlatformAdhesion::NONE) ? skirt_brim_length : skirt_brim_length + storage_.support_brim.length(); if (skirt_brim_number + 1 >= line_count && length > 0 && length < minimal_length) // Make brim or skirt have more lines when total length is too small. { line_count++; diff --git a/src/SupportInfillPart.cpp b/src/SupportInfillPart.cpp index fb504f5fb5..fc8e788a81 100644 --- a/src/SupportInfillPart.cpp +++ b/src/SupportInfillPart.cpp @@ -8,7 +8,7 @@ using namespace cura; -SupportInfillPart::SupportInfillPart(const PolygonsPart& outline, coord_t support_line_width, bool use_fractional_config, int inset_count_to_generate, coord_t custom_line_distance) +SupportInfillPart::SupportInfillPart(const SingleShape& outline, coord_t support_line_width, bool use_fractional_config, int inset_count_to_generate, coord_t custom_line_distance) : outline_(outline) , outline_boundary_box_(outline) , support_line_width_(support_line_width) diff --git a/src/TopSurface.cpp b/src/TopSurface.cpp index a717ccb3bb..c1b2c3fa57 100644 --- a/src/TopSurface.cpp +++ b/src/TopSurface.cpp @@ -108,7 +108,7 @@ bool TopSurface::ironing(const SliceDataStorage& storage, const SliceMeshStorage skip_line_stitching); std::vector ironing_paths; Polygons ironing_polygons; - Polygons ironing_lines; + LinesSet ironing_lines; infill_generator.generate(ironing_paths, ironing_polygons, ironing_lines, mesh.settings, layer.getLayerNr(), SectionType::IRONING); if (ironing_polygons.empty() && ironing_lines.empty() && ironing_paths.empty()) diff --git a/src/TreeModelVolumes.cpp b/src/TreeModelVolumes.cpp index 7318061091..6d058ffd8c 100644 --- a/src/TreeModelVolumes.cpp +++ b/src/TreeModelVolumes.cpp @@ -584,7 +584,7 @@ Polygons TreeModelVolumes::extractOutlineFromMesh(const SliceMeshStorage& mesh, layer.getOutlines(total, external_polys_only); if (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { - total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(FUDGE_LENGTH * 2)); + total = total.unionPolygons(layer.openPolyLines.offset(FUDGE_LENGTH * 2)); } const coord_t maximum_resolution = mesh.settings.get("meshfix_maximum_resolution"); const coord_t maximum_deviation = mesh.settings.get("meshfix_maximum_deviation"); diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 8985432a6a..15e012223f 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -1145,7 +1145,7 @@ void TreeSupport::increaseAreas( { // If the area becomes for whatever reason something that clipper sees as a line, offset would stop working, so ensure that even if if wrongly would be a line, // it still actually has an area that can be increased - Polygons lines_offset = TreeSupportUtils::toPolylines(*parent->area_).offsetPolyLine(EPSILON); + Polygons lines_offset = TreeSupportUtils::toPolylines(*parent->area_).offset(EPSILON); Polygons base_error_area = parent->area_->unionPolygons(lines_offset); result = increaseSingleArea(settings, layer_idx, parent, base_error_area, to_bp_data, to_model_data, inc_wo_collision, settings.increase_speed_, mergelayer); @@ -1646,7 +1646,7 @@ void TreeSupport::generateBranchAreas( for (Point2LL vertex : base_circle) { vertex = Point2LL(vertex.X * config.branch_radius / TreeSupportBaseCircle::base_radius, vertex.Y * config.branch_radius / TreeSupportBaseCircle::base_radius); - branch_circle.add(vertex); + branch_circle.push_back(vertex); } } @@ -1714,7 +1714,7 @@ void TreeSupport::generateBranchAreas( for (Point2LL vertex : branch_circle) { vertex = Point2LL(matrix[0] * vertex.X + matrix[1] * vertex.Y, matrix[2] * vertex.X + matrix[3] * vertex.Y); - circle.add(center_position + vertex); + circle.push_back(center_position + vertex); } poly.add(circle.offset(0)); } @@ -1749,7 +1749,7 @@ void TreeSupport::generateBranchAreas( if (nozzle_path.splitIntoParts(false).size() > 1) { Polygons polygons_with_correct_center; - for (PolygonsPart part : nozzle_path.splitIntoParts(false)) + for (SingleShape part : nozzle_path.splitIntoParts(false)) { if (part.inside(elem->result_on_layer_, true)) { @@ -2166,7 +2166,7 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor config.support_roof_line_distance, storage.support.cross_fill_provider, true) - .offsetPolyLine(config.support_roof_line_width / 2); + .offset(config.support_roof_line_width / 2); support_layer_storage[layer_idx] = support_layer_storage[layer_idx].difference(interface_lines); } break; @@ -2182,7 +2182,7 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor config.support_line_distance, storage.support.cross_fill_provider, true) - .offsetPolyLine(config.support_line_width / 2)); + .offset(config.support_line_width / 2)); storage.support.supportLayers[layer_idx].support_roof = storage.support.supportLayers[layer_idx].support_roof.difference(tree_lines); // Do not draw roof where the tree is. I prefer it this way as otherwise the roof may cut of a branch from its support below. } @@ -2227,7 +2227,7 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor support_layer_storage.size(), [&](const LayerIndex layer_idx) { - constexpr bool convert_every_part = true; // Convert every part into a PolygonsPart for the support. + constexpr bool convert_every_part = true; // Convert every part into a SingleShape for the support. storage.support.supportLayers[layer_idx] .fillInfillParts(layer_idx, support_layer_storage, config.support_line_width, config.support_wall_count, config.maximum_move_distance, convert_every_part); diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index a908d06d71..32eaee596d 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -104,7 +104,7 @@ TreeSupportTipGenerator::TreeSupportTipGenerator(const SliceMeshStorage& mesh, T } -std::vector TreeSupportTipGenerator::convertLinesToInternal(Polygons polylines, LayerIndex layer_idx) +std::vector TreeSupportTipGenerator::convertLinesToInternal(const LinesSet& polylines, LayerIndex layer_idx) { // NOTE: The volumes below (on which '.inside(p, true)' is called each time below) are the same each time. The values being calculated here are strictly local as well. // So they could in theory be pre-calculated here (outside of the loop). However, when I refatored it to be that way, it seemed to cause deadlocks each time for some @@ -114,7 +114,7 @@ std::vector TreeSupportTipGenerator::c std::vector result; // Also checks if the position is valid, if it is NOT, it deletes that point - for (const auto& line : polylines) + for (const OpenPolyline& line : polylines) { LineInformation res_line; for (const Point2LL& p : line) @@ -158,17 +158,17 @@ std::vector TreeSupportTipGenerator::c return result; } -Polygons TreeSupportTipGenerator::convertInternalToLines(std::vector lines) +LinesSet TreeSupportTipGenerator::convertInternalToLines(std::vector lines) { - Polygons result; + LinesSet result; for (const LineInformation& line : lines) { - Polygon path; + OpenPolyline path; for (const auto& point_data : line) { - path.add(point_data.first); + path.push_back(point_data.first); } - result.add(path); + result.push_back(path); } return result; } @@ -250,23 +250,24 @@ std::pair, std::vector>>>(keep, set_free); } -Polygons TreeSupportTipGenerator::ensureMaximumDistancePolyline(const Polygons& input, coord_t distance, size_t min_points, bool enforce_distance) const +LinesSet TreeSupportTipGenerator::ensureMaximumDistancePolyline(const LinesSet& input, coord_t distance, size_t min_points, bool enforce_distance) const { - Polygons result; - for (auto part : input) + LinesSet result; + for (OpenPolyline part : input) { if (part.size() == 0) { continue; } - const coord_t length = Polygon(part).offset(0).polyLineLength(); - Polygon line; + + const coord_t length = part.length(); + OpenPolyline line; coord_t current_distance = std::max(distance, coord_t(FUDGE_LENGTH * 2)); if (length < 2 * distance && min_points <= 1) { - ClosestPolygonPoint middle_point(part[0], 0, part); + ClosestPoint middle_point(part[0], 0, &part); middle_point = PolygonUtils::walk(middle_point, coord_t(length / 2)); - line.add(middle_point.location_); + line.push_back(middle_point.location_); } else { @@ -300,7 +301,7 @@ Polygons TreeSupportTipGenerator::ensureMaximumDistancePolyline(const Polygons& { line.clear(); Point2LL current_point = part[0]; - line.add(part[0]); + line.push_back(part[0]); bool should_add_endpoint = min_points > 1 || vSize2(part[0] - part[optimal_end_index]) > (current_distance * current_distance); bool added_endpoint = ! should_add_endpoint; // If no endpoint should be added all endpoints are already added. @@ -318,7 +319,7 @@ Polygons TreeSupportTipGenerator::ensureMaximumDistancePolyline(const Polygons& current_index = optimal_end_index; current_point = part[optimal_end_index]; added_endpoint = true; - line.add(part[optimal_end_index]); + line.push_back(part[optimal_end_index]); continue; } @@ -336,7 +337,7 @@ Polygons TreeSupportTipGenerator::ensureMaximumDistancePolyline(const Polygons& if (! enforce_distance || min_distance_to_existing_point_sqd >= (current_distance * current_distance)) { // viable point was found. Add to possible result. - line.add(next_point.location); + line.push_back(next_point.location); current_point = next_point.location; current_index = next_point.pos; next_distance = current_distance; @@ -366,13 +367,13 @@ Polygons TreeSupportTipGenerator::ensureMaximumDistancePolyline(const Polygons& if (! added_endpoint) { - line.add(part[optimal_end_index]); + line.push_back(part[optimal_end_index]); } current_distance *= 0.9; } } - result.add(line); + result.push_back(line); } return result; } @@ -637,9 +638,9 @@ void TreeSupportTipGenerator::addPointAsInfluenceArea( } Polygon circle; Polygon base_circle = TreeSupportBaseCircle::getBaseCircle(); - for (Point2LL corner : base_circle) + for (const Point2LL& corner : base_circle) { - circle.add(p.first + corner); + circle.push_back(p.first + corner); } Polygons area = circle.offset(0); { @@ -694,9 +695,9 @@ void TreeSupportTipGenerator::addLinesAsInfluenceAreas( std::function)> evaluateRoofWillGenerate = [&](std::pair p) { Polygon roof_circle; - for (Point2LL corner : TreeSupportBaseCircle::getBaseCircle()) + for (const Point2LL& corner : TreeSupportBaseCircle::getBaseCircle()) { - roof_circle.add(p.first + corner * std::max(config_.min_radius / TreeSupportBaseCircle::base_radius, coord_t(1))); + roof_circle.push_back(p.first + corner * std::max(config_.min_radius / TreeSupportBaseCircle::base_radius, coord_t(1))); } Polygons area = roof_circle.offset(0); return ! TreeSupportUtils::generateSupportInfillLines(area, config_, true, insert_layer_idx - dtt_roof_tip, support_roof_line_distance_, cross_fill_provider_, true) @@ -733,11 +734,11 @@ void TreeSupportTipGenerator::addLinesAsInfluenceAreas( for (std::pair p : line) { Polygon roof_circle; - for (Point2LL corner : TreeSupportBaseCircle::getBaseCircle()) + for (const Point2LL& corner : TreeSupportBaseCircle::getBaseCircle()) { - roof_circle.add(p.first + corner * std::max(config_.min_radius / TreeSupportBaseCircle::base_radius, coord_t(1))); + roof_circle.push_back(p.first + corner * std::max(config_.min_radius / TreeSupportBaseCircle::base_radius, coord_t(1))); } - added_roofs.add(roof_circle); + added_roofs.push_back(roof_circle); } } added_roofs = added_roofs.unionPolygons(); @@ -879,7 +880,7 @@ void TreeSupportTipGenerator::generateTips( = relevant_forbidden.offset(EPSILON) .unionPolygons(); // Prevent rounding errors down the line, points placed directly on the line of the forbidden area may not be added otherwise. - std::function generateLines = [&](const Polygons& area, bool roof, LayerIndex generate_layer_idx) + std::function(const Polygons&, bool, LayerIndex)> generateLines = [&](const Polygons& area, bool roof, LayerIndex generate_layer_idx) { coord_t upper_line_distance = support_supporting_branch_distance_; coord_t line_distance = std::max(roof ? support_roof_line_distance_ : support_tree_branch_distance_, upper_line_distance); @@ -978,7 +979,7 @@ void TreeSupportTipGenerator::generateTips( } std::vector overhang_lines; - Polygons polylines = ensureMaximumDistancePolyline(generateLines(remaining_overhang_part, false, layer_idx), config_.min_radius, 1, false); + LinesSet polylines = ensureMaximumDistancePolyline(generateLines(remaining_overhang_part, false, layer_idx), config_.min_radius, 1, false); // ^^^ Support_line_width to form a line here as otherwise most will be unsupported. // Technically this violates branch distance, but not only is this the only reasonable choice, // but it ensures consistent behavior as some infill patterns generate each line segment as its own polyline part causing a similar line forming behavior. @@ -1054,14 +1055,14 @@ void TreeSupportTipGenerator::generateTips( { const bool roof_allowed_for_this_part = overhang_pair.second; Polygons overhang_outset = overhang_pair.first; - const size_t min_support_points = std::max(coord_t(1), std::min(coord_t(EPSILON), overhang_outset.polygonLength() / connect_length_)); + const size_t min_support_points = std::max(coord_t(1), std::min(coord_t(EPSILON), overhang_outset.length() / connect_length_)); std::vector overhang_lines; bool only_lines = true; // The tip positions are determined here. // todo can cause inconsistent support density if a line exactly aligns with the model - Polygons polylines = ensureMaximumDistancePolyline( + LinesSet polylines = ensureMaximumDistancePolyline( generateLines(overhang_outset, roof_allowed_for_this_part, layer_idx + roof_allowed_for_this_part), ! roof_allowed_for_this_part ? config_.min_radius * 2 : use_fake_roof_ ? support_supporting_branch_distance_ @@ -1173,7 +1174,7 @@ void TreeSupportTipGenerator::generateTips( support_roof_line_distance_, cross_fill_provider_, false) - .offsetPolyLine(config_.support_line_width / 2)); + .offset(config_.support_line_width / 2)); } else { diff --git a/src/WallToolPaths.cpp b/src/WallToolPaths.cpp index 75a98b843a..163685eff2 100644 --- a/src/WallToolPaths.cpp +++ b/src/WallToolPaths.cpp @@ -13,7 +13,7 @@ #include "ExtruderTrain.h" #include "SkeletalTrapezoidation.h" -#include "utils/PolylineStitcher.h" +#include "utils/ExtrusionLineStitcher.h" #include "utils/Simplify.h" #include "utils/SparsePointGrid.h" //To stitch the inner contour. #include "utils/actions/smooth.h" @@ -95,18 +95,18 @@ const std::vector& WallToolPaths::generate() { // No need to smooth support walls auto smoother = actions::smooth(settings_); - for (auto& polygon : prepared_outline) + for (Polygon& polygon : prepared_outline) { - polygon = smoother(polygon); + polygon = smoother(polygon.asRawVector()); } } PolygonUtils::fixSelfIntersections(epsilon_offset, prepared_outline); - prepared_outline.removeDegenerateVerts(); + prepared_outline.removeDegenerateVertsForEveryone(); prepared_outline.removeColinearEdges(AngleRadians(0.005)); // Removing collinear edges may introduce self intersections, so we need to fix them again PolygonUtils::fixSelfIntersections(epsilon_offset, prepared_outline); - prepared_outline.removeDegenerateVerts(); + prepared_outline.removeDegenerateVertsForEveryone(); prepared_outline = prepared_outline.unionPolygons(); prepared_outline = Simplify(settings_).polygon(prepared_outline); @@ -251,7 +251,7 @@ void WallToolPaths::stitchToolPaths(std::vector& toolpaths, VariableWidthLines stitched_polylines; VariableWidthLines closed_polygons; - PolylineStitcher::stitch(wall_lines, stitched_polylines, closed_polygons, stitch_distance); + ExtrusionLineStitcher::stitch(wall_lines, stitched_polylines, closed_polygons, stitch_distance); wall_lines = stitched_polylines; // replace input toolpaths with stitched polylines for (ExtrusionLine& wall_polygon : closed_polygons) diff --git a/src/WallsComputation.cpp b/src/WallsComputation.cpp index ea8f959746..c6cde890b3 100644 --- a/src/WallsComputation.cpp +++ b/src/WallsComputation.cpp @@ -84,7 +84,7 @@ void WallsComputation::generateWalls(SliceLayerPart* part, SectionType section_t part->wall_toolpaths = wall_tool_paths.getToolPaths(); part->inner_area = wall_tool_paths.getInnerContour(); } - part->outline = PolygonsPart{ Simplify(settings_).polygon(part->outline) }; + part->outline = SingleShape{ Simplify(settings_).polygon(part->outline) }; part->print_outline = part->outline; } @@ -127,7 +127,7 @@ void WallsComputation::generateSpiralInsets(SliceLayerPart* part, coord_t line_w // Optimize the wall. This prevents buffer underruns in the printer firmware, and reduces processing time in CuraEngine. const ExtruderTrain& train_wall = settings_.get("wall_0_extruder_nr"); part->spiral_wall = Simplify(train_wall.settings_).polygon(part->spiral_wall); - part->spiral_wall.removeDegenerateVerts(); + part->spiral_wall.removeDegenerateVertsForEveryone(); if (recompute_outline_based_on_outer_wall) { part->print_outline = part->spiral_wall.offset(line_width_0 / 2, ClipperLib::jtSquare); diff --git a/src/bridge.cpp b/src/bridge.cpp index 554d81d5b1..7d4842e673 100644 --- a/src/bridge.cpp +++ b/src/bridge.cpp @@ -3,10 +3,11 @@ #include "bridge.h" +#include "geometry/open_polyline.h" +#include "geometry/polygon.h" #include "settings/types/Ratio.h" #include "sliceDataStorage.h" #include "utils/AABB.h" -#include "utils/polygon.h" namespace cura { @@ -112,7 +113,7 @@ double bridgeAngle( if (support_threshold > 0 && (supported_regions.area() / (skin_outline.area() + 1)) < support_threshold) { Polygons bb_poly; - bb_poly.add(boundary_box.toPolygon()); + bb_poly.push_back(boundary_box.toPolygon()); // airBelow is the region below the skin that is not supported, it extends well past the boundary of the skin. // It needs to be shrunk slightly so that the vertices of the skin polygon that would otherwise fall exactly on @@ -121,23 +122,23 @@ double bridgeAngle( const coord_t bb_max_dim = std::max(boundary_box.max_.X - boundary_box.min_.X, boundary_box.max_.Y - boundary_box.min_.Y); const Polygons air_below(bb_poly.offset(bb_max_dim).difference(prev_layer_outline).offset(-10)); - Polygons skin_perimeter_lines; - for (ConstPolygonRef poly : skin_outline) + std::vector skin_perimeter_lines; + for (const Polygon& poly : skin_outline) { - if (poly.empty()) - continue; - skin_perimeter_lines.add(poly); - skin_perimeter_lines.back().emplace_back(poly.front()); + if (! poly.empty()) + { + skin_perimeter_lines.emplace_back(poly); + } } - Polygons skin_perimeter_lines_over_air(air_below.intersectionPolyLines(skin_perimeter_lines)); + LinesSet skin_perimeter_lines_over_air(air_below.intersectionPolyLines(skin_perimeter_lines)); if (skin_perimeter_lines_over_air.size()) { // one or more edges of the skin region are unsupported, determine the longest coord_t max_dist2 = 0; double line_angle = -1; - for (PolygonRef air_line : skin_perimeter_lines_over_air) + for (const Polygon& air_line : skin_perimeter_lines_over_air) { Point2LL p0 = air_line[0]; for (unsigned i = 1; i < air_line.size(); ++i) diff --git a/src/communication/ArcusCommunication.cpp b/src/communication/ArcusCommunication.cpp index 80f27db79d..1583b58a97 100644 --- a/src/communication/ArcusCommunication.cpp +++ b/src/communication/ArcusCommunication.cpp @@ -37,7 +37,7 @@ #include "settings/types/LayerIndex.h" //To point to layers. #include "settings/types/Velocity.h" //To send to layer view how fast stuff is printing. #include "utils/channel.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" namespace cura { @@ -236,7 +236,7 @@ class ArcusCommunication::PathCompiler * \param thickness The layer thickness of the polygon. * \param velocity How fast the polygon is printed. */ - void sendPolygon(const PrintFeatureType& print_feature_type, const ConstPolygonRef& polygon, const coord_t& width, const coord_t& thickness, const Velocity& velocity) + void sendPolygon(const PrintFeatureType& print_feature_type, const Polygon& polygon, const coord_t& width, const coord_t& thickness, const Velocity& velocity) { if (polygon.size() < 2) // Don't send single points or empty polygons. { @@ -444,12 +444,7 @@ void ArcusCommunication::sendOptimizedLayerData() data.slice_data.clear(); } -void ArcusCommunication::sendPolygon( - const PrintFeatureType& type, - const ConstPolygonRef& polygon, - const coord_t& line_width, - const coord_t& line_thickness, - const Velocity& velocity) +void ArcusCommunication::sendPolygon(const PrintFeatureType& type, const Polygon& polygon, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity) { path_compiler->sendPolygon(type, polygon, line_width, line_thickness, velocity); } diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index 95359abae4..2adb959cf1 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -52,7 +52,7 @@ void CommandLine::sendLineTo(const PrintFeatureType&, const Point2LL&, const coo void CommandLine::sendOptimizedLayerData() { } -void CommandLine::sendPolygon(const PrintFeatureType&, const ConstPolygonRef&, const coord_t&, const coord_t&, const Velocity&) +void CommandLine::sendPolygon(const PrintFeatureType&, const Polygon&, const coord_t&, const coord_t&, const Velocity&) { } void CommandLine::sendPolygons(const PrintFeatureType&, const Polygons&, const coord_t&, const coord_t&, const Velocity&) diff --git a/src/geometry/lines_set.cpp b/src/geometry/lines_set.cpp new file mode 100644 index 0000000000..82f5715d54 --- /dev/null +++ b/src/geometry/lines_set.cpp @@ -0,0 +1,239 @@ +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#include "geometry/lines_set.h" + +#include + +#include "geometry/open_polyline.h" +#include "geometry/polygon.h" +#include "geometry/polygons.h" +#include "geometry/polyline_type.h" + +namespace cura +{ + +template +size_t LinesSet::pointCount() const +{ + return std::accumulate( + this->begin(), + this->end(), + size_t(0), + [](size_t total, const Polygon& polygon) + { + return total + polygon.size(); + }); +} + +template +void LinesSet::addLine(const Point2LL& from, const Point2LL& to) +{ + this->emplace_back(std::initializer_list{ from, to }); +} + +template +void LinesSet::addIfNotEmpty(const LineType& line) +{ + if (! line.empty()) + { + this->push_back(line); + } +} + +template +void LinesSet::addIfNotEmpty(LineType&& line) +{ + if (! line.empty()) + { + this->emplace_back(std::move(line)); + } +} + +template +void LinesSet::removeAt(size_t index) +{ + if (this->size() == 1) + { + this->clear(); + } + else if (this->size() > 1) + { + assert(index < this->size()); + if (index < this->size() - 1) + { + (*this)[index] = std::move(this->back()); + } + this->resize(this->size() - 1); + } +} + +template +void LinesSet::splitIntoSegments(LinesSet& result) const +{ + for (const LineType& line : (*this)) + { + line.splitIntoSegments(result); + } +} + +template +LinesSet LinesSet::splitIntoSegments() const +{ + LinesSet result; + for (const LineType& line : (*this)) + { + line.splitIntoSegments(result); + } + return result; +} + +template +coord_t LinesSet::length() const +{ + return std::accumulate( + this->begin(), + this->end(), + 0, + [](coord_t total, const LineType& line) + { + return total += line.length(); + }); +} + +template +Polygons LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const +{ + return offset(outer_offset).difference(offset(-inner_offset)); +} + +template +Polygons LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const +{ + if (distance == 0) + { + return Polygons(getCallable()); + } + + Polygons temp; + const ClipperLib::Paths* actual_polygons = &getCallable(); + Polygons ret; + ClipperLib::EndType end_type; + if constexpr (LineType::type_ == PolylineType::Filled) + { + temp = Polygons(getCallable()).unionPolygons(); + actual_polygons = &temp.getCallable(); + end_type = ClipperLib::etClosedPolygon; + } + else if constexpr (LineType::type_ == PolylineType::Closed) + { + end_type = ClipperLib::etClosedLine; + } + else if (joinType == ClipperLib::jtMiter) + { + end_type = ClipperLib::etOpenSquare; + } + else + { + end_type = ClipperLib::etOpenRound; + } + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + clipper.AddPaths(*actual_polygons, joinType, end_type); + clipper.MiterLimit = miter_limit; + clipper.Execute(ret.getCallable(), distance); + return ret; +} + +template +void LinesSet::removeDegenerateVertsForEveryone() +{ + constexpr bool for_polyline = LineType::type_ == PolylineType::Open; + for (size_t poly_idx = 0; poly_idx < this->size(); poly_idx++) + { + LineType& poly = (*this)[poly_idx]; + Polygon result; + + auto isDegenerate = [](const Point2LL& last, const Point2LL& now, const Point2LL& next) + { + Point2LL last_line = now - last; + Point2LL next_line = next - now; + return dot(last_line, next_line) == -1 * vSize(last_line) * vSize(next_line); + }; + + // With polylines, skip the first and last vertex. + const size_t start_vertex = for_polyline ? 1 : 0; + const size_t end_vertex = for_polyline ? poly.size() - 1 : poly.size(); + for (size_t i = 0; i < start_vertex; ++i) + { + result.push_back(poly[i]); // Add everything before the start vertex. + } + + bool isChanged = false; + for (size_t idx = start_vertex; idx < end_vertex; idx++) + { + const Point2LL& last = (result.size() == 0) ? poly.back() : result.back(); + if (idx + 1 >= poly.size() && result.size() == 0) + { + break; + } + const Point2LL& next = (idx + 1 >= poly.size()) ? result[0] : poly[idx + 1]; + if (isDegenerate(last, poly[idx], next)) + { // lines are in the opposite direction + // don't add vert to the result + isChanged = true; + while (result.size() > 1 && isDegenerate(result[result.size() - 2], result.back(), next)) + { + result.pop_back(); + } + } + else + { + result.push_back(poly[idx]); + } + } + + for (size_t i = end_vertex; i < poly.size(); ++i) + { + result.push_back(poly[i]); // Add everything after the end vertex. + } + + if (isChanged) + { + if (for_polyline || result.size() > 2) + { + poly = result; + } + else + { + removeAt(poly_idx); + poly_idx--; // effectively the next iteration has the same poly_idx (referring to a new poly which is not yet processed) + } + } + } +} + +template size_t LinesSet::pointCount() const; +template void LinesSet::addLine(const Point2LL& from, const Point2LL& to); +template void LinesSet::removeAt(size_t index); +template void LinesSet::splitIntoSegments(LinesSet& result) const; +template LinesSet LinesSet::splitIntoSegments() const; +template coord_t LinesSet::length() const; +template Polygons LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template Polygons LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; +template void LinesSet::removeDegenerateVertsForEveryone(); +template void LinesSet::addIfNotEmpty(const OpenPolyline& line); +template void LinesSet::addIfNotEmpty(OpenPolyline&& line); + +template size_t LinesSet::pointCount() const; +template void LinesSet::addLine(const Point2LL& from, const Point2LL& to); +template void LinesSet::removeAt(size_t index); +template void LinesSet::splitIntoSegments(LinesSet& result) const; +template LinesSet LinesSet::splitIntoSegments() const; +template coord_t LinesSet::length() const; +template Polygons LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template Polygons LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; +template void LinesSet::removeDegenerateVertsForEveryone(); +template void LinesSet::addIfNotEmpty(const Polygon& line); +template void LinesSet::addIfNotEmpty(Polygon&& line); + +} // namespace cura diff --git a/src/geometry/parts_view.cpp b/src/geometry/parts_view.cpp new file mode 100644 index 0000000000..0422cd0d92 --- /dev/null +++ b/src/geometry/parts_view.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#include "geometry/parts_view.h" + +#include "geometry/single_shape.h" + +namespace cura +{ + +size_t PartsView::getPartContaining(size_t poly_idx, size_t* boundary_poly_idx) const +{ + const PartsView& partsView = *this; + for (size_t part_idx_now = 0; part_idx_now < partsView.size(); part_idx_now++) + { + const std::vector& partView = partsView[part_idx_now]; + if (partView.size() == 0) + { + continue; + } + std::vector::const_iterator result = std::find(partView.begin(), partView.end(), poly_idx); + if (result != partView.end()) + { + if (boundary_poly_idx) + { + *boundary_poly_idx = partView[0]; + } + return part_idx_now; + } + } + return NO_INDEX; +} + +SingleShape PartsView::assemblePart(size_t part_idx) const +{ + const PartsView& partsView = *this; + SingleShape ret; + if (part_idx != NO_INDEX) + { + for (size_t poly_idx_ff : partsView[part_idx]) + { + ret.push_back(polygons_[poly_idx_ff]); + } + } + return ret; +} + +SingleShape PartsView::assemblePartContaining(size_t poly_idx, size_t* boundary_poly_idx) const +{ + SingleShape ret; + size_t part_idx = getPartContaining(poly_idx, boundary_poly_idx); + if (part_idx != NO_INDEX) + { + return assemblePart(part_idx); + } + return ret; +} + +} // namespace cura diff --git a/src/geometry/points_set.cpp b/src/geometry/points_set.cpp new file mode 100644 index 0000000000..707e1c01bb --- /dev/null +++ b/src/geometry/points_set.cpp @@ -0,0 +1,90 @@ +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#include "geometry/points_set.h" + +#include "geometry/point2ll.h" +#include "geometry/point3_matrix.h" +#include "geometry/point_matrix.h" + +namespace cura +{ + +PointsSet::PointsSet(const std::initializer_list& initializer) + : std::vector(initializer) +{ +} + +PointsSet::PointsSet(const std::vector& points) + : std::vector(points) +{ +} + +PointsSet::PointsSet(std::vector&& points) + : std::vector(std::move(points)) +{ +} + +void PointsSet::applyMatrix(const PointMatrix& matrix) +{ + for (Point2LL& point : (*this)) + { + point = matrix.apply(point); + } +} + +void PointsSet::applyMatrix(const Point3Matrix& matrix) +{ + for (Point2LL& point : (*this)) + { + point = matrix.apply(point); + } +} + +Point2LL PointsSet::min() const +{ + Point2LL ret = Point2LL(POINT_MAX, POINT_MAX); + for (Point2LL p : *this) + { + ret.X = std::min(ret.X, p.X); + ret.Y = std::min(ret.Y, p.Y); + } + return ret; +} + +Point2LL PointsSet::max() const +{ + Point2LL ret = Point2LL(POINT_MIN, POINT_MIN); + for (Point2LL p : *this) + { + ret.X = std::max(ret.X, p.X); + ret.Y = std::max(ret.Y, p.Y); + } + return ret; +} + +Point2LL PointsSet::closestPointTo(const Point2LL& p) const +{ + Point2LL ret = p; + double bestDist = std::numeric_limits::max(); + for (size_t n = 0; n < size(); n++) + { + double dist = vSize2f(p - (*this)[n]); + if (dist < bestDist) + { + ret = (*this)[n]; + bestDist = dist; + } + } + return ret; +} + +void PointsSet::translate(const Point2LL& translation) +{ + for (Point2LL& p : *this) + { + p += translation; + } +} + +} // namespace cura diff --git a/src/utils/polygon.cpp b/src/geometry/polygon.cpp similarity index 92% rename from src/utils/polygon.cpp rename to src/geometry/polygon.cpp index 292b2bf1bb..517b3708ed 100644 --- a/src/utils/polygon.cpp +++ b/src/geometry/polygon.cpp @@ -1,28 +1,32 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "utils/polygon.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utils/PolylineStitcher.h" -#include "utils/polygons.h" +#include "geometry/polygon.h" + +// #include + +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +#include "utils/ListPolyIt.h" +#include "utils/linearAlg2D.h" + +// #include "utils/PolylineStitcher.h" +#include "geometry/point3_matrix.h" +#include "geometry/point_matrix.h" +#include "geometry/polygons.h" namespace cura { @@ -624,58 +628,4 @@ Polygons Polygon::offset(int distance, ClipperLib::JoinType join_type, double mi return ret; } -void PointsSet::applyMatrix(const PointMatrix& matrix) -{ - for (point_t& point : (*this)) - { - point = matrix.apply(point); - } -} - -void PointsSet::applyMatrix(const Point3Matrix& matrix) -{ - for (point_t& point : (*this)) - { - point = matrix.apply(point); - } -} - -Point2LL PointsSet::min() const -{ - Point2LL ret = Point2LL(POINT_MAX, POINT_MAX); - for (Point2LL p : *this) - { - ret.X = std::min(ret.X, p.X); - ret.Y = std::min(ret.Y, p.Y); - } - return ret; -} - -Point2LL PointsSet::max() const -{ - Point2LL ret = Point2LL(POINT_MIN, POINT_MIN); - for (Point2LL p : *this) - { - ret.X = std::max(ret.X, p.X); - ret.Y = std::max(ret.Y, p.Y); - } - return ret; -} - -Point2LL PointsSet::closestPointTo(Point2LL p) const -{ - Point2LL ret = p; - double bestDist = std::numeric_limits::max(); - for (size_t n = 0; n < size(); n++) - { - double dist = vSize2f(p - (*this)[n]); - if (dist < bestDist) - { - ret = (*this)[n]; - bestDist = dist; - } - } - return ret; -} - } // namespace cura diff --git a/src/utils/polygons.cpp b/src/geometry/polygons.cpp similarity index 72% rename from src/utils/polygons.cpp rename to src/geometry/polygons.cpp index 76887a48a9..82dcec5c27 100644 --- a/src/utils/polygons.cpp +++ b/src/geometry/polygons.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "utils/polygons.h" +#include "geometry/polygons.h" #include @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -18,24 +17,16 @@ #include #include #include -#include -#include +#include "geometry/parts_view.h" +#include "geometry/single_shape.h" +#include "settings/types/Ratio.h" #include "utils/OpenPolylineStitcher.h" +#include "utils/linearAlg2D.h" namespace cura { -Polygons Polygon::intersection(const Polygon& other) const -{ - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - clipper.AddPath(*this, ClipperLib::ptSubject, true); - clipper.AddPath(other, ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctIntersection, ret.getCallable()); - return ret; -} - Polygons Polygons::approxConvexHull(int extra_outset) const { constexpr int overshoot = MM2INT(100); // 10cm (hard-coded value). @@ -44,7 +35,7 @@ Polygons Polygons::approxConvexHull(int extra_outset) const // Perform the offset for each polygon one at a time. // This is necessary because the polygons may overlap, in which case the offset could end up in an infinite loop. // See http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperOffset/_Body.htm - for (const path_t& path : (*this)) + for (const ClipperLib::Path& path : (*this)) { Polygons offset_result; ClipperLib::ClipperOffset offsetter(1.2, 10.0); @@ -65,21 +56,21 @@ void Polygons::makeConvex() } // Andrew’s Monotone Chain Convex Hull Algorithm - std::vector points; - for (const path_t& poly : (*this)) + std::vector points; + for (const std::vector& poly : (*this)) { points.insert(points.end(), poly.begin(), poly.end()); } Polygon convexified; - auto make_sorted_poly_convex = [&convexified](std::vector& poly) + auto make_sorted_poly_convex = [&convexified](std::vector& poly) { convexified.push_back(poly[0]); for (const auto window : poly | ranges::views::sliding(2)) { - const point_t& current = window[0]; - const point_t& after = window[1]; + const Point2LL& current = window[0]; + const Point2LL& after = window[1]; if (LinearAlg2D::pointIsLeftOfLine(current, convexified.back(), after) < 0) { @@ -98,7 +89,7 @@ void Polygons::makeConvex() std::sort( points.begin(), points.end(), - [](point_t a, point_t b) + [](const Point2LL& a, const Point2LL& b) { return a.X == b.X ? a.Y < b.Y : a.X < b.X; }); @@ -148,67 +139,11 @@ Polygons& Polygons::operator=(Polygons&& polygons) return *this; } -size_t Polygons::pointCount() const -{ - return std::accumulate( - begin(), - end(), - size_t(0), - [](size_t total, const Polygon& polygon) - { - return total + polygon.size(); - }); -} - -void Polygons::remove(size_t index) -{ - if (size() == 1) - { - clear(); - } - else if (size() > 1) - { - POLY_ASSERT(index < size()); - if (index < size() - 1) - { - (*this)[index] = std::move(back()); - } - resize(size() - 1); - } -} - void Polygons::add(const Polygons& other) { std::copy(other.begin(), other.end(), std::back_inserter(*this)); } -void Polygons::addIfNotEmpty(const Polygon& polygon) -{ - if (! polygon.empty()) - { - push_back(polygon); - } -} - -void Polygons::addIfNotEmpty(Polygon&& polygon) -{ - if (! polygon.empty()) - { - emplace_back(std::move(polygon)); - } -} - -void Polygons::addLine(const point_t& from, const point_t& to) -{ - emplace_back(Polygon{ from, to }); -} - -Polygon& Polygons::newPoly() -{ - emplace_back(); - return back(); -} - bool Polygons::inside(Point2LL p, bool border_result) const { int poly_count_inside = 0; @@ -224,57 +159,6 @@ bool Polygons::inside(Point2LL p, bool border_result) const return (poly_count_inside % 2) == 1; } -bool PolygonsPart::inside(Point2LL p, bool border_result) const -{ - if (size() < 1) - { - return false; - } - - if (! (*this)[0].inside(p, border_result)) - { - return false; - } - - for (unsigned int n = 1; n < size(); n++) - { - if ((*this)[n].inside(p, border_result)) - { - return false; - } - } - return true; -} - -bool Polygons::insideOld(Point2LL p, bool border_result) const -{ - const Polygons& thiss = *this; - if (size() < 1) - { - return false; - } - - int crossings = 0; - for (const ClipperLib::Path& poly : thiss) - { - Point2LL p0 = poly.back(); - for (const Point2LL& p1 : poly) - { - short comp = LinearAlg2D::pointLiesOnTheRightOfLine(p, p0, p1); - if (comp == 1) - { - crossings++; - } - else if (comp == 0) - { - return border_result; - } - p0 = p1; - } - } - return (crossings % 2) == 1; -} - size_t Polygons::findInside(Point2LL p, bool border_result) const { if (size() < 1) @@ -340,7 +224,7 @@ size_t Polygons::findInside(Point2LL p, bool border_result) const return ret; } -std::vector Polygons::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const +LinesSet Polygons::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const { LinesSet split_polylines = polylines.splitIntoSegments(); @@ -354,7 +238,7 @@ std::vector Polygons::intersectionPolyLines(const LinesSet result_lines; + LinesSet result_lines; Polygons result_polygons; const coord_t snap_distance = 10_mu; OpenPolylineStitcher::stitch(ret, result_lines, result_polygons, max_stitch_distance, snap_distance); @@ -400,103 +284,28 @@ void Polygons::toPolylines() poly.emplace_back(poly.front()); } } - -void Polygons::splitPolylinesIntoSegments(Polygons& result) const -{ -for (ConstPolygonRef poly : *this) -{ - poly.splitPolylineIntoSegments(result); - } -} -Polygons Polygons::splitPolylinesIntoSegments() const -{ - Polygons ret; - splitPolylinesIntoSegments(ret); - return ret; -} - -void Polygons::splitPolygonsIntoSegments(Polygons& result) const -{ - for (ConstPolygonRef poly : *this) - { - poly.splitPolygonIntoSegments(result); - } -} -Polygons Polygons::splitPolygonsIntoSegments() const -{ - Polygons ret; - splitPolygonsIntoSegments(ret); - return ret; -} - -coord_t Polygons::polyLineLength() const -{ - coord_t length = 0; - for (ConstPolygonRef poly : *this) - { - length += poly.polylineLength(); - } - return length; -} */ -template -Polygons LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const -{ - if (distance == 0) - { - return Polygons(getCallable()); - } - - Polygons temp; - const paths_t* actual_polygons = &getCallable(); - Polygons ret; - ClipperLib::EndType end_type; - if constexpr (LineType::shape_type_ == ShapeType::Filled) - { - temp = Polygons(getCallable()).unionPolygons(); - actual_polygons = &temp.getCallable(); - end_type = ClipperLib::etClosedPolygon; - } - else if constexpr (LineType::shape_type_ == ShapeType::Closed) - { - end_type = ClipperLib::etClosedLine; - } - else if (joinType == ClipperLib::jtMiter) - { - end_type = ClipperLib::etOpenSquare; - } - else - { - end_type = ClipperLib::etOpenRound; - } - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - clipper.AddPaths(*actual_polygons, joinType, end_type); - clipper.MiterLimit = miter_limit; - clipper.Execute(ret.getCallable(), distance); - return ret; -} -/* -Polygons Polygons::offset(const std::vector& offset_dists) const +Polygons Polygons::offsetMulti(const std::vector& offset_dists) const { // we need as many offset-dists as points assert(pointCount() == offset_dists.size()); Polygons ret; size_t i = 0; - for (const path_t& poly_line : (*this) - | ranges::views::filter( - [](const path_t& path) - { - return ! path.empty(); - })) + for (const ClipperLib::Path& poly_line : (*this) + | ranges::views::filter( + [](const ClipperLib::Path& path) + { + return ! path.empty(); + })) { Polygon ret_poly_line; auto prev_p = poly_line.back(); auto prev_dist = offset_dists[i + poly_line.size() - 1]; - for (const point_t& p : poly_line) + for (const Point2LL& p : poly_line) { auto offset_dist = offset_dists[i]; @@ -524,7 +333,7 @@ Polygons Polygons::offset(const std::vector& offset_dists) const return ret; } -*/ + Polygons Polygons::getOutsidePolygons() const { Polygons ret; @@ -698,75 +507,7 @@ void Polygons::removeSmallAreaCircumference(const double min_area_size, const co *this = new_polygon; } -template -void LinesSet::removeDegenerateVertsForEveryone() -{ - constexpr bool for_polyline = LineType::shape_type_ == ShapeType::Open; - for (size_t poly_idx = 0; poly_idx < this->size(); poly_idx++) - { - Polygon& poly = (*this)[poly_idx]; - Polygon result; - - auto isDegenerate = [](const Point2LL& last, const Point2LL& now, const Point2LL& next) - { - Point2LL last_line = now - last; - Point2LL next_line = next - now; - return dot(last_line, next_line) == -1 * vSize(last_line) * vSize(next_line); - }; - - // With polylines, skip the first and last vertex. - const size_t start_vertex = for_polyline ? 1 : 0; - const size_t end_vertex = for_polyline ? poly.size() - 1 : poly.size(); - for (size_t i = 0; i < start_vertex; ++i) - { - result.push_back(poly[i]); // Add everything before the start vertex. - } - - bool isChanged = false; - for (size_t idx = start_vertex; idx < end_vertex; idx++) - { - const Point2LL& last = (result.size() == 0) ? poly.back() : result.back(); - if (idx + 1 >= poly.size() && result.size() == 0) - { - break; - } - const Point2LL& next = (idx + 1 >= poly.size()) ? result[0] : poly[idx + 1]; - if (isDegenerate(last, poly[idx], next)) - { // lines are in the opposite direction - // don't add vert to the result - isChanged = true; - while (result.size() > 1 && isDegenerate(result[result.size() - 2], result.back(), next)) - { - result.pop_back(); - } - } - else - { - result.push_back(poly[idx]); - } - } - - for (size_t i = end_vertex; i < poly.size(); ++i) - { - result.push_back(poly[i]); // Add everything after the end vertex. - } - - if (isChanged) - { - if (for_polyline || result.size() > 2) - { - poly = result; - } - else - { - remove(poly_idx); - poly_idx--; // effectively the next iteration has the same poly_idx (referring to a new poly which is not yet processed) - } - } - } -} - -Polygons Polygons::remove(const Polygons& to_be_removed, int same_distance) const +Polygons Polygons::removePolygon(const Polygons& to_be_removed, int same_distance) const { Polygons result; for (size_t poly_keep_idx = 0; poly_keep_idx < size(); poly_keep_idx++) @@ -847,7 +588,7 @@ Polygons Polygons::toPolygons(ClipperLib::PolyTree& poly_tree) Polygon outer; for (const auto& point : poly.outer()) { - outer.push_back(point_t(point.x(), point.y())); + outer.push_back(Point2LL(point.x(), point.y())); } ret.push_back(outer); @@ -856,7 +597,7 @@ Polygons Polygons::toPolygons(ClipperLib::PolyTree& poly_tree) Polygon inner; for (const auto& point : hole) { - inner.push_back(point_t(point.x(), point.y())); + inner.push_back(Point2LL(point.x(), point.y())); } ret.push_back(inner); } @@ -899,7 +640,7 @@ Polygons Polygons::smooth_outward(const AngleDegrees max_angle, int shortcut_len ret.push_back(poly); continue; } - poly.smooth_outward(max_angle, shortcut_length, ret.newPoly()); + poly.smooth_outward(max_angle, shortcut_length, ret.newLine()); if (ret.back().size() < 3) { ret.resize(ret.size() - 1); @@ -922,7 +663,7 @@ Polygons Polygons::smooth(int remove_length) const ret.push_back(poly); continue; } - poly.smooth(remove_length, ret.newPoly()); + poly.smooth(remove_length, ret.newLine()); Polygon& back = ret.back(); if (back.size() < 3) { @@ -952,7 +693,7 @@ Polygons Polygons::smooth2(int remove_length, int min_area) const } else { - poly.smooth2(remove_length, ret.newPoly()); + poly.smooth2(remove_length, ret.newLine()); } } return ret; @@ -966,7 +707,7 @@ void Polygons::removeColinearEdges(const AngleRadians max_deviation_angle) thiss[p].removeColinearEdges(max_deviation_angle); if (thiss[p].size() < 3) { - remove(p); + removeAt(p); p--; } } @@ -988,7 +729,7 @@ void Polygons::scale(const Ratio& ratio) } } -void Polygons::translate(const point_t& delta) +void Polygons::translate(const Point2LL& delta) { if (delta.X != 0 || delta.Y != 0) { @@ -1019,9 +760,9 @@ double Polygons::area() const return area; } -std::vector Polygons::splitIntoParts(bool unionAll) const +std::vector Polygons::splitIntoParts(bool unionAll) const { - std::vector ret; + std::vector ret; ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree resultPolyTree; clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); @@ -1034,12 +775,12 @@ std::vector Polygons::splitIntoParts(bool unionAll) const return ret; } -void Polygons::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const +void Polygons::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const { for (int n = 0; n < node->ChildCount(); n++) { ClipperLib::PolyNode* child = node->Childs[n]; - PolygonsPart part; + SingleShape part; part.emplace_back(child->Contour); for (int i = 0; i < child->ChildCount(); i++) { @@ -1076,59 +817,6 @@ void Polygons::sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, con } } -Polygons Polygons::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const -{ - return this->offset(outer_offset).difference(this->offset(-inner_offset)); -} - -size_t PartsView::getPartContaining(size_t poly_idx, size_t* boundary_poly_idx) const -{ - const PartsView& partsView = *this; - for (size_t part_idx_now = 0; part_idx_now < partsView.size(); part_idx_now++) - { - const std::vector& partView = partsView[part_idx_now]; - if (partView.size() == 0) - { - continue; - } - std::vector::const_iterator result = std::find(partView.begin(), partView.end(), poly_idx); - if (result != partView.end()) - { - if (boundary_poly_idx) - { - *boundary_poly_idx = partView[0]; - } - return part_idx_now; - } - } - return NO_INDEX; -} - -PolygonsPart PartsView::assemblePart(size_t part_idx) const -{ - const PartsView& partsView = *this; - PolygonsPart ret; - if (part_idx != NO_INDEX) - { - for (size_t poly_idx_ff : partsView[part_idx]) - { - ret.push_back(polygons_[poly_idx_ff]); - } - } - return ret; -} - -PolygonsPart PartsView::assemblePartContaining(size_t poly_idx, size_t* boundary_poly_idx) const -{ - PolygonsPart ret; - size_t part_idx = getPartContaining(poly_idx, boundary_poly_idx); - if (part_idx != NO_INDEX) - { - return assemblePart(part_idx); - } - return ret; -} - PartsView Polygons::splitIntoPartsView(bool unionAll) { Polygons reordered; @@ -1171,7 +859,7 @@ void Polygons::ensureManifold() std::unordered_set poly_locations; for (const Polygon& poly : (*this)) { - for (const point_t& p : poly) + for (const Point2LL& p : poly) { if (poly_locations.find(p) != poly_locations.end()) { @@ -1181,9 +869,9 @@ void Polygons::ensureManifold() } } Polygons removal_dots; - for (Point2LL p : duplicate_locations) + for (const Point2LL& p : duplicate_locations) { - Polygon& dot = removal_dots.newPoly(); + Polygon& dot = removal_dots.newLine(); dot.push_back(p + Point2LL(0, 5)); dot.push_back(p + Point2LL(5, 0)); dot.push_back(p + Point2LL(0, -5)); @@ -1195,25 +883,13 @@ void Polygons::ensureManifold() } } -coord_t Polygons::length() const -{ - return std::accumulate( - begin(), - end(), - 0, - [](coord_t total, const Polygon& polygon) - { - return total += polygon.length(); - }); -} - -point_t Polygons::min() const +Point2LL Polygons::min() const { - point_t ret = point_t(POINT_MAX, POINT_MAX); + Point2LL ret = Point2LL(POINT_MAX, POINT_MAX); for (const Polygon& polygon : *this) { - for (const point_t& p : polygon) + for (const Point2LL& p : polygon) { ret.X = std::min(ret.X, p.X); ret.Y = std::min(ret.Y, p.Y); @@ -1223,13 +899,13 @@ point_t Polygons::min() const return ret; } -point_t Polygons::max() const +Point2LL Polygons::max() const { - point_t ret = point_t(POINT_MIN, POINT_MIN); + Point2LL ret = Point2LL(POINT_MIN, POINT_MIN); for (const Polygon& polygon : *this) { - for (const point_t& p : polygon) + for (const Point2LL& p : polygon) { ret.X = std::max(ret.X, p.X); ret.Y = std::max(ret.Y, p.Y); diff --git a/src/geometry/polyline.cpp b/src/geometry/polyline.cpp new file mode 100644 index 0000000000..9062c182c9 --- /dev/null +++ b/src/geometry/polyline.cpp @@ -0,0 +1,211 @@ +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#include "geometry/polyline.h" + +#include + +#include "geometry/lines_set.h" +#include "geometry/open_polyline.h" +#include "settings/types/Angle.h" +#include "utils/linearAlg2D.h" + +namespace cura +{ + +template +void Polyline::removeColinearEdges(const AngleRadians max_deviation_angle) +{ + // TODO: Can be made more efficient (for example, use pointer-types for process-/skip-indices, so we can swap them without copy). + + size_t num_removed_in_iteration = 0; + do + { + num_removed_in_iteration = 0; + + std::vector process_indices(size(), true); + + bool go = true; + while (go) + { + go = false; + + const ClipperLib::Path& rpath = *this; + const size_t pathlen = rpath.size(); + if (pathlen <= 3) + { + return; + } + + std::vector skip_indices(size(), false); + + Polyline new_path; + for (size_t point_idx = 0; point_idx < pathlen; ++point_idx) + { + // Don't iterate directly over process-indices, but do it this way, because there are points _in_ process-indices that should nonetheless be skipped: + if (! process_indices[point_idx]) + { + new_path.push_back(rpath[point_idx]); + continue; + } + + // Should skip the last point for this iteration if the old first was removed (which can be seen from the fact that the new first was skipped): + if (point_idx == (pathlen - 1) && skip_indices[0]) + { + skip_indices[new_path.size()] = true; + go = true; + new_path.push_back(rpath[point_idx]); + break; + } + + const Point2LL& prev = rpath[(point_idx - 1 + pathlen) % pathlen]; + const Point2LL& pt = rpath[point_idx]; + const Point2LL& next = rpath[(point_idx + 1) % pathlen]; + + double angle = LinearAlg2D::getAngleLeft(prev, pt, next); // [0 : 2 * pi] + if (angle >= std::numbers::pi) + { + angle -= std::numbers::pi; + } // map [pi : 2 * pi] to [0 : pi] + + // Check if the angle is within limits for the point to 'make sense', given the maximum deviation. + // If the angle indicates near-parallel segments ignore the point 'pt' + if (angle > max_deviation_angle && angle < std::numbers::pi - max_deviation_angle) + { + new_path.push_back(pt); + } + else if (point_idx != (pathlen - 1)) + { + // Skip the next point, since the current one was removed: + skip_indices[new_path.size()] = true; + go = true; + new_path.push_back(next); + ++point_idx; + } + } + (*this) = new_path; + num_removed_in_iteration += pathlen - size(); + + process_indices.clear(); + process_indices.insert(process_indices.end(), skip_indices.begin(), skip_indices.end()); + } + } while (num_removed_in_iteration > 0); +} + +template +Polyline::const_segments_iterator Polyline::beginSegments() const +{ + return const_segments_iterator(begin(), begin(), end()); +} + +template +Polyline::const_segments_iterator Polyline::endSegments() const +{ + if constexpr (type_ == PolylineType::Closed || type_ == PolylineType::Filled) + { + return const_segments_iterator(end(), begin(), end()); + } + else + { + return const_segments_iterator(size() > 1 ? std::prev(end()) : end(), begin(), end()); + } +} + +template +Polyline::segments_iterator Polyline::beginSegments() +{ + return segments_iterator(begin(), begin(), end()); +} + +template +Polyline::segments_iterator Polyline::endSegments() +{ + if constexpr (type_ == PolylineType::Closed || type_ == PolylineType::Filled) + { + return segments_iterator(end(), begin(), end()); + } + else + { + return segments_iterator(size() > 1 ? std::prev(end()) : end(), begin(), end()); + } +} + +template +coord_t Polyline::length() const +{ + return std::accumulate( + beginSegments(), + endSegments(), + 0, + [](coord_t total, const const_segments_iterator::value_type& segment) + { + return total + vSize(segment.end - segment.start); + }); +} + +template +bool Polyline::shorterThan(const coord_t check_length) const +{ + coord_t length = 0; + auto iterator_segment = std::find_if( + beginSegments(), + endSegments(), + [&length, &check_length](const const_segments_iterator::value_type& segment) + { + length += vSize(segment.end - segment.start); + if (length >= check_length) + { + return true; + } + }); + return iterator_segment == endSegments(); +} + +template +void Polyline::splitIntoSegments(LinesSet& result) const +{ + for (auto it = beginSegments(); it != endSegments(); ++it) + { + result.emplace_back(std::initializer_list{ (*it).start, (*it).end }); + } +} + +template +LinesSet Polyline::splitIntoSegments() const +{ + LinesSet result; + splitIntoSegments(result); + return result; +} + +template void Polyline::removeColinearEdges(const AngleRadians max_deviation_angle); +template Polyline::const_segments_iterator Polyline::beginSegments() const; +template Polyline::const_segments_iterator Polyline::endSegments() const; +template Polyline::segments_iterator Polyline::beginSegments(); +template Polyline::segments_iterator Polyline::endSegments(); +template coord_t Polyline::length() const; +template bool Polyline::shorterThan(const coord_t check_length) const; +template void Polyline::splitIntoSegments(LinesSet& result) const; +template LinesSet Polyline::splitIntoSegments() const; + +template void Polyline::removeColinearEdges(const AngleRadians max_deviation_angle); +template Polyline::const_segments_iterator Polyline::beginSegments() const; +template Polyline::const_segments_iterator Polyline::endSegments() const; +template Polyline::segments_iterator Polyline::beginSegments(); +template Polyline::segments_iterator Polyline::endSegments(); +template coord_t Polyline::length() const; +template bool Polyline::shorterThan(const coord_t check_length) const; +template void Polyline::splitIntoSegments(LinesSet& result) const; +template LinesSet Polyline::splitIntoSegments() const; + +template void Polyline::removeColinearEdges(const AngleRadians max_deviation_angle); +template Polyline::const_segments_iterator Polyline::beginSegments() const; +template Polyline::const_segments_iterator Polyline::endSegments() const; +template Polyline::segments_iterator Polyline::beginSegments(); +template Polyline::segments_iterator Polyline::endSegments(); +template coord_t Polyline::length() const; +template bool Polyline::shorterThan(const coord_t check_length) const; +template void Polyline::splitIntoSegments(LinesSet& result) const; +template LinesSet Polyline::splitIntoSegments() const; + +} // namespace cura diff --git a/src/geometry/single_shape.cpp b/src/geometry/single_shape.cpp new file mode 100644 index 0000000000..09f28285dd --- /dev/null +++ b/src/geometry/single_shape.cpp @@ -0,0 +1,41 @@ +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#include "geometry/single_shape.h" + +namespace cura +{ + +bool SingleShape::inside(const Point2LL& p, bool border_result) const +{ + if (size() < 1) + { + return false; + } + + if (! (*this)[0].inside(p, border_result)) + { + return false; + } + + for (unsigned int n = 1; n < size(); n++) + { + if ((*this)[n].inside(p, border_result)) + { + return false; + } + } + return true; +} + +Polygon& SingleShape::outerPolygon() +{ + return front(); +} + +const Polygon& SingleShape::outerPolygon() const +{ + return front(); +} + +} // namespace cura diff --git a/src/infill.cpp b/src/infill.cpp index e746846c02..b6ba03fecb 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -11,6 +11,7 @@ #include #include "WallToolPaths.h" +#include "geometry/point_matrix.h" #include "infill/GyroidInfill.h" #include "infill/ImageBasedDensityProvider.h" #include "infill/LightningGenerator.h" @@ -21,8 +22,8 @@ #include "infill/UniformDensityProvider.h" #include "plugins/slots.h" #include "sliceDataStorage.h" +#include "utils/OpenPolylineStitcher.h" #include "utils/PolygonConnector.h" -#include "utils/PolylineStitcher.h" #include "utils/Simplify.h" #include "utils/UnionFind.h" #include "utils/linearAlg2D.h" @@ -83,7 +84,7 @@ Polygons Infill::generateWallToolPaths( void Infill::generate( std::vector& toolpaths, Polygons& result_polygons, - Polygons& result_lines, + LinesSet& result_lines, const Settings& settings, int layer_idx, SectionType section_type, @@ -179,7 +180,7 @@ void Infill::generate( zig_zaggify_ = false; } Polygons generated_result_polygons; - Polygons generated_result_lines; + LinesSet generated_result_lines; _generate(toolpaths, generated_result_polygons, generated_result_lines, settings, cross_fill_provider, lightning_trees, mesh); @@ -193,7 +194,7 @@ void Infill::generate( //_generate may clear() the generated_result_lines, but this is an output variable that may contain data before we start. // So make sure we provide it with a Polygons that is safe to clear and only add stuff to result_lines. Polygons generated_result_polygons; - Polygons generated_result_lines; + LinesSet generated_result_lines; _generate(toolpaths, generated_result_polygons, generated_result_lines, settings, cross_fill_provider, lightning_trees, mesh); @@ -219,7 +220,7 @@ void Infill::generate( auto it = std::remove_if( result_polygons.begin(), result_polygons.end(), - [snap_distance](PolygonRef poly) + [snap_distance](const Polygon& poly) { return poly.shorterThan(snap_distance); }); @@ -251,7 +252,7 @@ void Infill::generate( void Infill::_generate( std::vector& toolpaths, Polygons& result_polygons, - Polygons& result_lines, + LinesSet& result_lines, const Settings& settings, const std::shared_ptr& cross_fill_provider, const std::shared_ptr& lightning_trees, @@ -346,14 +347,14 @@ void Infill::_generate( && (zig_zaggify_ || pattern_ == EFillMethod::CROSS || pattern_ == EFillMethod::CROSS_3D || pattern_ == EFillMethod::CUBICSUBDIV || pattern_ == EFillMethod::GYROID || pattern_ == EFillMethod::ZIG_ZAG)) { // don't stich for non-zig-zagged line infill types - Polygons stitched_lines; - PolylineStitcher::stitch(result_lines, stitched_lines, result_polygons, infill_line_width_); - result_lines = stitched_lines; + LinesSet stitched_lines; + OpenPolylineStitcher::stitch(result_lines, stitched_lines, result_polygons, infill_line_width_); + result_lines = std::move(stitched_lines); } result_lines = simplifier.polyline(result_lines); } -void Infill::multiplyInfill(Polygons& result_polygons, Polygons& result_lines) +void Infill::multiplyInfill(Polygons& result_polygons, LinesSet& result_lines) { if (pattern_ == EFillMethod::CONCENTRIC) { @@ -367,7 +368,7 @@ void Infill::multiplyInfill(Polygons& result_polygons, Polygons& result_lines) Polygons result; Polygons first_offset; { - const Polygons first_offset_lines = result_lines.offsetPolyLine(offset); // make lines on both sides of the input lines + const Polygons first_offset_lines = result_lines.offset(offset); // make lines on both sides of the input lines const Polygons first_offset_polygons_inward = result_polygons.offset(-offset); // make lines on the inside of the input polygons const Polygons first_offset_polygons_outward = result_polygons.offset(offset); // make lines on the other side of the input polygons const Polygons first_offset_polygons = first_offset_polygons_outward.difference(first_offset_polygons_inward); @@ -385,7 +386,7 @@ void Infill::multiplyInfill(Polygons& result_polygons, Polygons& result_lines) if (infill_multiplier_ > 3) { Polygons reference_polygons = first_offset; - const size_t multiplier = static_cast(infill_multiplier_ / 2); + const size_t multiplier = infill_multiplier_ / 2; const int extra_offset = mirror_offset_ ? -infill_line_width_ : infill_line_width_; for (size_t infill_line = 1; infill_line < multiplier; ++infill_line) @@ -409,28 +410,20 @@ void Infill::multiplyInfill(Polygons& result_polygons, Polygons& result_lines) result_polygons.add(result); if (! zig_zaggify_) { - for (PolygonRef poly : result_polygons) - { // make polygons into polylines - if (poly.empty()) - { - continue; - } - poly.add(poly[0]); - } - Polygons polylines = inner_contour_.intersectionPolyLines(result_polygons); + LinesSet polylines = inner_contour_.intersectionPolyLines(*reinterpret_cast*>(&result_polygons)); result_polygons.clear(); - PolylineStitcher::stitch(polylines, result_lines, result_polygons, infill_line_width_); + OpenPolylineStitcher::stitch(polylines, result_lines, result_polygons, infill_line_width_); } } -void Infill::generateGyroidInfill(Polygons& result_lines, Polygons& result_polygons) +void Infill::generateGyroidInfill(LinesSet& result_lines, Polygons& result_polygons) { - Polygons line_segments; + LinesSet line_segments; GyroidInfill::generateTotalGyroidInfill(line_segments, zig_zaggify_, line_distance_, inner_contour_, z_); - PolylineStitcher::stitch(line_segments, result_lines, result_polygons, infill_line_width_); + OpenPolylineStitcher::stitch(line_segments, result_lines, result_polygons, infill_line_width_); } -void Infill::generateLightningInfill(const std::shared_ptr& trees, Polygons& result_lines) +void Infill::generateLightningInfill(const std::shared_ptr& trees, LinesSet& result_lines) { // Don't need to support areas smaller than line width, as they are always within radius: if (std::abs(inner_contour_.area()) < infill_line_width_ || ! trees) @@ -468,13 +461,13 @@ void Infill::generateConcentricInfill(std::vector& toolpaths } } -void Infill::generateGridInfill(Polygons& result) +void Infill::generateGridInfill(LinesSet& result) { generateLineInfill(result, line_distance_, fill_angle_, 0); generateLineInfill(result, line_distance_, fill_angle_ + 90, 0); } -void Infill::generateCubicInfill(Polygons& result) +void Infill::generateCubicInfill(LinesSet& result) { const coord_t shift = one_over_sqrt_2 * z_; generateLineInfill(result, line_distance_, fill_angle_, shift); @@ -482,19 +475,19 @@ void Infill::generateCubicInfill(Polygons& result) generateLineInfill(result, line_distance_, fill_angle_ + 240, shift); } -void Infill::generateTetrahedralInfill(Polygons& result) +void Infill::generateTetrahedralInfill(LinesSet& result) { generateHalfTetrahedralInfill(0.0, 0, result); generateHalfTetrahedralInfill(0.0, 90, result); } -void Infill::generateQuarterCubicInfill(Polygons& result) +void Infill::generateQuarterCubicInfill(LinesSet& result) { generateHalfTetrahedralInfill(0.0, 0, result); generateHalfTetrahedralInfill(0.5, 90, result); } -void Infill::generateHalfTetrahedralInfill(double pattern_z_shift, int angle_shift, Polygons& result) +void Infill::generateHalfTetrahedralInfill(double pattern_z_shift, int angle_shift, LinesSet& result) { const coord_t period = line_distance_ * 2; coord_t shift = coord_t(one_over_sqrt_2 * (z_ + pattern_z_shift * period * 2)) % period; @@ -505,29 +498,29 @@ void Infill::generateHalfTetrahedralInfill(double pattern_z_shift, int angle_shi generateLineInfill(result, period, fill_angle_ + angle_shift, -shift); } -void Infill::generateTriangleInfill(Polygons& result) +void Infill::generateTriangleInfill(LinesSet& result) { generateLineInfill(result, line_distance_, fill_angle_, 0); generateLineInfill(result, line_distance_, fill_angle_ + 60, 0); generateLineInfill(result, line_distance_, fill_angle_ + 120, 0); } -void Infill::generateTrihexagonInfill(Polygons& result) +void Infill::generateTrihexagonInfill(LinesSet& result) { generateLineInfill(result, line_distance_, fill_angle_, 0); generateLineInfill(result, line_distance_, fill_angle_ + 60, 0); generateLineInfill(result, line_distance_, fill_angle_ + 120, line_distance_ / 2); } -void Infill::generateCubicSubDivInfill(Polygons& result, const SliceMeshStorage& mesh) +void Infill::generateCubicSubDivInfill(LinesSet& result, const SliceMeshStorage& mesh) { - Polygons uncropped; + LinesSet uncropped; mesh.base_subdiv_cube->generateSubdivisionLines(z_, uncropped); constexpr bool restitch = false; // cubic subdivision lines are always single line segments - not polylines consisting of multiple segments. result = outer_contour_.offset(infill_overlap_).intersectionPolyLines(uncropped, restitch); } -void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provider, Polygons& result_polygons, Polygons& result_lines) +void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provider, Polygons& result_polygons, LinesSet& result_lines) { Polygon cross_pattern_polygon = cross_fill_provider.generate(pattern_, z_, infill_line_width_, pocket_size_); @@ -539,23 +532,23 @@ void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provid if (zig_zaggify_) { Polygons cross_pattern_polygons; - cross_pattern_polygons.add(cross_pattern_polygon); + cross_pattern_polygons.push_back(cross_pattern_polygon); result_polygons.add(inner_contour_.intersection(cross_pattern_polygons)); } else { // make the polyline closed in order to handle cross_pattern_polygon as a polyline, rather than a closed polygon - cross_pattern_polygon.add(cross_pattern_polygon[0]); + cross_pattern_polygon.push_back(cross_pattern_polygon[0]); - Polygons cross_pattern_polylines; - cross_pattern_polylines.add(cross_pattern_polygon); - Polygons poly_lines = inner_contour_.intersectionPolyLines(cross_pattern_polylines); - PolylineStitcher::stitch(poly_lines, result_lines, result_polygons, infill_line_width_); + LinesSet cross_pattern_polylines; + cross_pattern_polylines.push_back(cross_pattern_polygon); + LinesSet poly_lines = inner_contour_.intersectionPolyLines(cross_pattern_polylines); + OpenPolylineStitcher::stitch(poly_lines, result_lines, result_polygons, infill_line_width_); } } void Infill::addLineInfill( - Polygons& result, + LinesSet& result, const PointMatrix& rotation_matrix, const int scanline_min_idx, const int line_distance, @@ -596,7 +589,7 @@ coord_t Infill::getShiftOffsetFromInfillOriginAndRotation(const double& infill_r return 0; } -void Infill::generateLineInfill(Polygons& result, int line_distance, const double& infill_rotation, coord_t shift) +void Infill::generateLineInfill(LinesSet& result, int line_distance, const double& infill_rotation, coord_t shift) { shift += getShiftOffsetFromInfillOriginAndRotation(infill_rotation); PointMatrix rotation_matrix(infill_rotation); @@ -606,7 +599,7 @@ void Infill::generateLineInfill(Polygons& result, int line_distance, const doubl } -void Infill::generateZigZagInfill(Polygons& result, const coord_t line_distance, const double& infill_rotation) +void Infill::generateZigZagInfill(LinesSet& result, const coord_t line_distance, const double& infill_rotation) { const coord_t shift = getShiftOffsetFromInfillOriginAndRotation(infill_rotation); @@ -639,7 +632,7 @@ void Infill::generateZigZagInfill(Polygons& result, const coord_t line_distance, * while I also call a boundary segment leaving from an even scanline toward the right as belonging to an even scansegment. */ void Infill::generateLinearBasedInfill( - Polygons& result, + LinesSet& result, const int line_distance, const PointMatrix& rotation_matrix, ZigzagConnectorProcessor& zigzag_connector_processor, @@ -702,7 +695,7 @@ void Infill::generateLinearBasedInfill( for (size_t poly_idx = 0; poly_idx < outline.size(); poly_idx++) { - PolygonRef poly = outline[poly_idx]; + const Polygon& poly = outline[poly_idx]; if (connect_lines_) { crossings_on_line_[poly_idx].resize(poly.size()); // One for each line in this polygon. @@ -852,7 +845,7 @@ void Infill::resolveIntersection(const coord_t at_distance, const Point2LL& inte } } -void Infill::connectLines(Polygons& result_lines) +void Infill::connectLines(LinesSet& result_lines) { UnionFind connected_lines; // Keeps track of which lines are connected to which. for (const std::vector>& crossings_on_polygon : crossings_on_line_) @@ -872,7 +865,7 @@ void Infill::connectLines(Polygons& result_lines) const auto half_line_distance_squared = (line_distance_ * line_distance_) / 4; for (size_t polygon_index = 0; polygon_index < inner_contour_.size(); polygon_index++) { - ConstPolygonRef inner_contour_polygon = inner_contour_[polygon_index]; + const Polygon& inner_contour_polygon = inner_contour_[polygon_index]; if (inner_contour_polygon.empty()) { continue; @@ -1014,7 +1007,7 @@ void Infill::connectLines(Polygons& result_lines) } // Now go along the linked list of infill lines and output the infill lines to the actual result. - PolygonRef result_line = result_lines.newPoly(); + OpenPolyline& result_line = result_lines.newLine(); InfillLineSegment* old_line = current_infill_line; if (current_infill_line->previous_) { @@ -1056,21 +1049,21 @@ void Infill::InfillLineSegment::swapDirection() std::swap(next_, previous_); } -void Infill::InfillLineSegment::appendTo(PolygonRef& result_polyline, const bool include_start) +void Infill::InfillLineSegment::appendTo(OpenPolyline& result_polyline, const bool include_start) { if (include_start) { - result_polyline.add(altered_start_); + result_polyline.push_back(altered_start_); } if (start_bend_.has_value()) { - result_polyline.add(start_bend_.value()); + result_polyline.push_back(start_bend_.value()); } if (end_bend_.has_value()) { - result_polyline.add(end_bend_.value()); + result_polyline.push_back(end_bend_.value()); } - result_polyline.add(altered_end_); + result_polyline.push_back(altered_end_); } } // namespace cura diff --git a/src/infill/GyroidInfill.cpp b/src/infill/GyroidInfill.cpp index 6a95df7d54..e956fee723 100644 --- a/src/infill/GyroidInfill.cpp +++ b/src/infill/GyroidInfill.cpp @@ -3,9 +3,11 @@ #include "infill/GyroidInfill.h" +#include "geometry/open_polyline.h" +#include "geometry/polygon.h" +#include "geometry/polygons.h" #include "utils/AABB.h" #include "utils/linearAlg2D.h" -#include "utils/polygon.h" namespace cura { @@ -18,7 +20,7 @@ GyroidInfill::~GyroidInfill() { } -void GyroidInfill::generateTotalGyroidInfill(Polygons& result_lines, bool zig_zaggify, coord_t line_distance, const Polygons& in_outline, coord_t z) +void GyroidInfill::generateTotalGyroidInfill(LinesSet& result_lines, bool zig_zaggify, coord_t line_distance, const Polygons& in_outline, coord_t z) { // generate infill based on the gyroid equation: sin_x * cos_y + sin_y * cos_z + sin_z * cos_x = 0 // kudos to the author of the Slic3r implementation equation code, the equation code here is based on that @@ -39,7 +41,7 @@ void GyroidInfill::generateTotalGyroidInfill(Polygons& result_lines, bool zig_za const double sin_z = std::sin(z_rads); std::vector odd_line_coords; std::vector even_line_coords; - Polygons result; + LinesSet result; std::vector chains[2]; // [start_points[], end_points[]] std::vector connected_to[2]; // [chain_indices[], chain_indices[]] std::vector line_numbers; // which row/column line a chain is part of @@ -85,7 +87,7 @@ void GyroidInfill::generateTotalGyroidInfill(Polygons& result_lines, bool zig_za else if (last_inside != current_inside) { // line hits the boundary, add the part that's inside the boundary - Polygons line; + LinesSet line; line.addLine(last, current); constexpr bool restitch = false; // only a single line doesn't need stitching line = in_outline.intersectionPolyLines(line, restitch); @@ -177,7 +179,7 @@ void GyroidInfill::generateTotalGyroidInfill(Polygons& result_lines, bool zig_za else if (last_inside != current_inside) { // line hits the boundary, add the part that's inside the boundary - Polygons line; + LinesSet line; line.addLine(last, current); constexpr bool restitch = false; // only a single line doesn't need stitching line = in_outline.intersectionPolyLines(line, restitch); @@ -238,7 +240,7 @@ void GyroidInfill::generateTotalGyroidInfill(Polygons& result_lines, bool zig_za int chain_ends_remaining = chains[0].size() * 2; - for (ConstPolygonRef outline_poly : in_outline) + for (const Polygon& outline_poly : in_outline) { std::vector connector_points; // the points that make up a connector line @@ -340,7 +342,7 @@ void GyroidInfill::generateTotalGyroidInfill(Polygons& result_lines, bool zig_za if (chain_index != connector_start_chain_index && connected_to[(point_index + 1) % 2][chain_index] != connector_start_chain_index) { - result.add(connector_points); + result.push_back(connector_points); drawing = false; connector_points.clear(); // remember the connection @@ -389,9 +391,9 @@ void GyroidInfill::generateTotalGyroidInfill(Polygons& result_lines, bool zig_za { // output the connector line segments from the last chain to the first point in the outline connector_points.push_back(outline_poly[0]); - result.add(connector_points); + result.push_back(connector_points); // output the connector line segments from the first point in the outline to the first chain - result.add(path_to_first_chain); + result.push_back(path_to_first_chain); } if (chain_ends_remaining < 1) diff --git a/src/infill/LightningDistanceField.cpp b/src/infill/LightningDistanceField.cpp index 1afea87a24..18f67f4128 100644 --- a/src/infill/LightningDistanceField.cpp +++ b/src/infill/LightningDistanceField.cpp @@ -20,7 +20,7 @@ LightningDistanceField::LightningDistanceField(const coord_t& radius, const Poly std::vector regular_dots = PolygonUtils::spreadDotsArea(current_overhang, cell_size_); for (const auto& p : regular_dots) { - const ClosestPolygonPoint cpp = PolygonUtils::findClosest(p, current_outline); + const ClosestPoint cpp = PolygonUtils::findClosest(p, current_outline); const coord_t dist_to_boundary = vSize(p - cpp.p()); unsupported_points_.emplace_back(p, dist_to_boundary); } diff --git a/src/infill/LightningLayer.cpp b/src/infill/LightningLayer.cpp index 6cefaff8be..c48e4ab902 100644 --- a/src/infill/LightningLayer.cpp +++ b/src/infill/LightningLayer.cpp @@ -87,7 +87,7 @@ GroundingLocation LightningLayer::getBestGroundingLocation( const SparseLightningTreeNodeGrid& tree_node_locator, const LightningTreeNodeSPtr& exclude_tree) { - ClosestPolygonPoint cpp = PolygonUtils::findClosest(unsupported_location, current_outlines); + ClosestPoint cpp = PolygonUtils::findClosest(unsupported_location, current_outlines); Point2LL node_location = cpp.p(); const coord_t within_dist = vSize(node_location - unsupported_location); @@ -120,7 +120,7 @@ GroundingLocation LightningLayer::getBestGroundingLocation( } else { - return GroundingLocation{ sub_tree, std::optional() }; + return GroundingLocation{ sub_tree, std::optional() }; } } @@ -217,15 +217,15 @@ void LightningLayer::reconnectRoots( } // Returns 'added someting'. -Polygons LightningLayer::convertToLines(const Polygons& limit_to_outline, const coord_t line_width) const +LinesSet LightningLayer::convertToLines(const Polygons& limit_to_outline, const coord_t line_width) const { - Polygons result_lines; + LinesSet result_lines; if (tree_roots.empty()) { return result_lines; } - for (const auto& tree : tree_roots) + for (const LightningTreeNodeSPtr& tree : tree_roots) { tree->convertToPolylines(result_lines, line_width); } diff --git a/src/infill/LightningTreeNode.cpp b/src/infill/LightningTreeNode.cpp index 573cffb80a..09ad8a69b1 100644 --- a/src/infill/LightningTreeNode.cpp +++ b/src/infill/LightningTreeNode.cpp @@ -3,6 +3,7 @@ #include "infill/LightningTreeNode.h" +#include "geometry/open_polyline.h" #include "utils/linearAlg2D.h" using namespace cura; @@ -354,43 +355,43 @@ const std::optional& LightningTreeNode::getLastGroundingLocation() con return last_grounding_location_; } -void LightningTreeNode::convertToPolylines(Polygons& output, const coord_t line_width) const +void LightningTreeNode::convertToPolylines(LinesSet& output, const coord_t line_width) const { - Polygons result; - result.newPoly(); + LinesSet result; + result.emplace_back(); convertToPolylines(0, result); removeJunctionOverlap(result, line_width); output.add(result); } -void LightningTreeNode::convertToPolylines(size_t long_line_idx, Polygons& output) const +void LightningTreeNode::convertToPolylines(size_t long_line_idx, LinesSet& output) const { if (children_.empty()) { - output[long_line_idx].add(p_); + output[long_line_idx].push_back(p_); return; } size_t first_child_idx = rand() % children_.size(); children_[first_child_idx]->convertToPolylines(long_line_idx, output); - output[long_line_idx].add(p_); + output[long_line_idx].push_back(p_); for (size_t idx_offset = 1; idx_offset < children_.size(); idx_offset++) { size_t child_idx = (first_child_idx + idx_offset) % children_.size(); const LightningTreeNode& child = *children_[child_idx]; - output.newPoly(); + output.emplace_back(); size_t child_line_idx = output.size() - 1; child.convertToPolylines(child_line_idx, output); - output[child_line_idx].add(p_); + output[child_line_idx].push_back(p_); } } -void LightningTreeNode::removeJunctionOverlap(Polygons& result_lines, const coord_t line_width) const +void LightningTreeNode::removeJunctionOverlap(LinesSet& result_lines, const coord_t line_width) const { const coord_t reduction = line_width / 2; // TODO make configurable? for (auto poly_it = result_lines.begin(); poly_it != result_lines.end();) { - PolygonRef polyline = *poly_it; + OpenPolyline& polyline = *poly_it; if (polyline.size() <= 1) { polyline = std::move(result_lines.back()); diff --git a/src/infill/SierpinskiFill.cpp b/src/infill/SierpinskiFill.cpp index bdb4962228..c69e609631 100644 --- a/src/infill/SierpinskiFill.cpp +++ b/src/infill/SierpinskiFill.cpp @@ -14,7 +14,7 @@ #include "infill/UniformDensityProvider.h" #include "utils/AABB3D.h" #include "utils/SVG.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" namespace cura { @@ -718,10 +718,10 @@ Polygon SierpinskiFill::generateCross() const edge_middle -= triangle.a_; break; } - ret.add(edge_middle / 2); + ret.push_back(edge_middle / 2); } - double realized_length = INT2MM(ret.polygonLength()); + double realized_length = INT2MM(ret.length()); double requested_length = root_.requested_length_; double error = (realized_length - requested_length) / requested_length; spdlog::debug("realized_length: {}, requested_length: {} :: {}% error", realized_length, requested_length, 0.01 * static_cast(10000 * error)); @@ -759,13 +759,13 @@ Polygon SierpinskiFill::generateCross(coord_t z, coord_t min_dist_to_side, coord sides. The steeper overhang is then only in the corner, which is deemed acceptable since the corners are never too sharp. */ const coord_t period = vSize(triangle.straight_corner_ - triangle.a_); - ret.add(get_edge_crossing_location(period, triangle.getFromEdge())); + ret.push_back(get_edge_crossing_location(period, triangle.getFromEdge())); last_triangle = ▵ } assert(last_triangle); const coord_t period = vSize(last_triangle->straight_corner_ - last_triangle->a_); - ret.add(get_edge_crossing_location(period, last_triangle->getToEdge())); + ret.push_back(get_edge_crossing_location(period, last_triangle->getToEdge())); if (pocket_size > 10) { @@ -793,12 +793,12 @@ Polygon SierpinskiFill::generateCross(coord_t z, coord_t min_dist_to_side, coord { coord_t pocket_rounding = std::min(std::min(pocket_size_side, vSize(v0) / 3), vSize(v1) / 3); // a third so that if a line segment is shortened on both sides the middle remains - pocketed.add(p1 + normal(v0, pocket_rounding)); - pocketed.add(p1 + normal(v1, pocket_rounding)); + pocketed.push_back(p1 + normal(v0, pocket_rounding)); + pocketed.push_back(p1 + normal(v1, pocket_rounding)); } else { - pocketed.add(p1); + pocketed.push_back(p1); } p0 = p1; } diff --git a/src/infill/SierpinskiFillProvider.cpp b/src/infill/SierpinskiFillProvider.cpp index 0123c42b04..cfec010c15 100644 --- a/src/infill/SierpinskiFillProvider.cpp +++ b/src/infill/SierpinskiFillProvider.cpp @@ -9,7 +9,7 @@ #include "infill/UniformDensityProvider.h" #include "utils/AABB3D.h" #include "utils/math.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" namespace cura { diff --git a/src/infill/SubDivCube.cpp b/src/infill/SubDivCube.cpp index f30affc602..39a26ab686 100644 --- a/src/infill/SubDivCube.cpp +++ b/src/infill/SubDivCube.cpp @@ -8,7 +8,9 @@ #include "settings/types/Angle.h" //For the infill angle. #include "sliceDataStorage.h" #include "utils/math.h" +#include "geometry/polygon.h" #include "utils/polygonUtils.h" +#include "geometry/polygons.h" #define ONE_OVER_SQRT_2 0.7071067811865475244008443621048490392848359376884740 // 1 / sqrt(2) #define ONE_OVER_SQRT_3 0.577350269189625764509148780501957455647601751270126876018 // 1 / sqrt(3) @@ -83,19 +85,19 @@ void SubDivCube::precomputeOctree(SliceMeshStorage& mesh, const Point2LL& infill mesh.base_subdiv_cube = std::make_shared(mesh, center, curr_recursion_depth - 1); } -void SubDivCube::generateSubdivisionLines(const coord_t z, Polygons& result) +void SubDivCube::generateSubdivisionLines(const coord_t z, LinesSet& result) { if (cube_properties_per_recursion_step_.empty()) // Infill is set to 0%. { return; } - Polygons directional_line_groups[3]; + LinesSet directional_line_groups[3]; generateSubdivisionLines(z, directional_line_groups); for (int dir_idx = 0; dir_idx < 3; dir_idx++) { - Polygons& line_group = directional_line_groups[dir_idx]; + LinesSet& line_group = directional_line_groups[dir_idx]; for (unsigned int line_idx = 0; line_idx < line_group.size(); line_idx++) { result.addLine(line_group[line_idx][0], line_group[line_idx][1]); @@ -103,7 +105,7 @@ void SubDivCube::generateSubdivisionLines(const coord_t z, Polygons& result) } } -void SubDivCube::generateSubdivisionLines(const coord_t z, Polygons (&directional_line_groups)[3]) +void SubDivCube::generateSubdivisionLines(const coord_t z, LinesSet (&directional_line_groups)[3]) { CubeProperties cube_properties = cube_properties_per_recursion_step_[depth_]; @@ -236,7 +238,7 @@ coord_t SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, const LayerI Point2LL centerpoint = location; bool inside = collide.inside(centerpoint); - ClosestPolygonPoint border_point = PolygonUtils::moveInside2(collide, centerpoint); + ClosestPoint border_point = PolygonUtils::moveInside2(collide, centerpoint); Point2LL diff = border_point.location_ - location; *distance2 = vSize2(diff); if (inside) @@ -261,7 +263,7 @@ void SubDivCube::rotatePoint120(Point2LL& target) target.X = x; } -void SubDivCube::addLineAndCombine(Polygons& group, Point2LL from, Point2LL to) +void SubDivCube::addLineAndCombine(LinesSet& group, Point2LL from, Point2LL to) { int epsilon = 10; // the smallest distance of two points which are viewed as coincident (dist > 0 due to rounding errors) for (unsigned int idx = 0; idx < group.size(); idx++) @@ -269,14 +271,14 @@ void SubDivCube::addLineAndCombine(Polygons& group, Point2LL from, Point2LL to) if (std::abs(from.X - group[idx][1].X) < epsilon && std::abs(from.Y - group[idx][1].Y) < epsilon) { from = group[idx][0]; - group.remove(idx); + group.removeAt(idx); idx--; continue; } if (std::abs(to.X - group[idx][0].X) < epsilon && std::abs(to.Y - group[idx][0].Y) < epsilon) { to = group[idx][1]; - group.remove(idx); + group.removeAt(idx); idx--; continue; } diff --git a/src/infill/ZigzagConnectorProcessor.cpp b/src/infill/ZigzagConnectorProcessor.cpp index 7f75b608ff..d31527194a 100644 --- a/src/infill/ZigzagConnectorProcessor.cpp +++ b/src/infill/ZigzagConnectorProcessor.cpp @@ -5,6 +5,11 @@ #include +#include "geometry/open_polyline.h" +#include "geometry/point_matrix.h" +#include "geometry/polygon.h" +#include "geometry/polygons.h" + using namespace cura; @@ -20,7 +25,6 @@ void ZigzagConnectorProcessor::registerVertex(const Point2LL& vertex) } } - bool ZigzagConnectorProcessor::shouldAddCurrentConnector(int start_scanline_idx, int end_scanline_idx) const { int direction = end_scanline_idx - start_scanline_idx; @@ -150,3 +154,21 @@ void ZigzagConnectorProcessor::addZagConnector(std::vector& points, bo } addPolyline(polyline); } + +void cura::ZigzagConnectorProcessor::reset() +{ + is_first_connector_ = true; + first_connector_end_scanline_index_ = 0; + last_connector_index_ = 0; + first_connector_.clear(); + current_connector_.clear(); +} + +void cura::ZigzagConnectorProcessor::addPolyline(const Polygon& polyline) +{ + result_.emplace_back(polyline); + for (Point2LL& p : result_.back()) + { + p = rotation_matrix_.unapply(p); + } +} diff --git a/src/layerPart.cpp b/src/layerPart.cpp index b0fb7ece93..3d4eae5325 100644 --- a/src/layerPart.cpp +++ b/src/layerPart.cpp @@ -8,7 +8,7 @@ #include "settings/Settings.h" #include "sliceDataStorage.h" #include "slicer.h" -#include "utils/PolylineStitcher.h" +#include "utils/OpenPolylineStitcher.h" #include "utils/Simplify.h" //Simplifying the layers after creating them. #include "utils/ThreadPool.h" @@ -29,7 +29,7 @@ namespace cura void createLayerWithParts(const Settings& settings, SliceLayer& storageLayer, SlicerLayer* layer) { - PolylineStitcher::stitch(layer->openPolylines, storageLayer.openPolyLines, layer->polygons, settings.get("wall_line_width_0")); + OpenPolylineStitcher::stitch(layer->openPolylines, storageLayer.openPolyLines, layer->polygons, settings.get("wall_line_width_0")); storageLayer.openPolyLines = Simplify(settings).polyline(storageLayer.openPolyLines); @@ -43,16 +43,16 @@ void createLayerWithParts(const Settings& settings, SliceLayer& storageLayer, Sl } } - std::vector result; + std::vector result; const bool union_layers = settings.get("meshfix_union_all"); const ESurfaceMode surface_only = settings.get("magic_mesh_surface_mode"); if (surface_only == ESurfaceMode::SURFACE && ! union_layers) { // Don't do anything with overlapping areas; no union nor xor result.reserve(layer->polygons.size()); - for (const PolygonRef poly : layer->polygons) + for (const Polygon& poly : layer->polygons) { result.emplace_back(); - result.back().add(poly); + result.back().push_back(poly); } } else diff --git a/src/multiVolumes.cpp b/src/multiVolumes.cpp index 6852469919..7ff6317869 100644 --- a/src/multiVolumes.cpp +++ b/src/multiVolumes.cpp @@ -10,7 +10,7 @@ #include "settings/EnumSettings.h" #include "settings/types/LayerIndex.h" #include "slicer.h" -#include "utils/PolylineStitcher.h" +#include "utils/OpenPolylineStitcher.h" namespace cura { @@ -119,27 +119,28 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: for (LayerIndex layer_nr = 0; layer_nr < cutting_mesh_volume.layers.size(); layer_nr++) { Polygons& cutting_mesh_polygons = cutting_mesh_volume.layers[layer_nr].polygons; - Polygons& cutting_mesh_polylines = cutting_mesh_volume.layers[layer_nr].openPolylines; + LinesSet& cutting_mesh_polylines = cutting_mesh_volume.layers[layer_nr].openPolylines; Polygons cutting_mesh_area_recomputed; Polygons* cutting_mesh_area; coord_t surface_line_width = cutting_mesh.settings_.get("wall_line_width_0"); { // compute cutting_mesh_area if (cutting_mesh.settings_.get("magic_mesh_surface_mode") == ESurfaceMode::BOTH) { - cutting_mesh_area_recomputed = cutting_mesh_polygons.unionPolygons(cutting_mesh_polylines.offsetPolyLine(surface_line_width / 2)); + cutting_mesh_area_recomputed = cutting_mesh_polygons.unionPolygons(cutting_mesh_polylines.offset(surface_line_width / 2)); cutting_mesh_area = &cutting_mesh_area_recomputed; } else if (cutting_mesh.settings_.get("magic_mesh_surface_mode") == ESurfaceMode::SURFACE) { // break up polygons into polylines // they have to be polylines, because they might break up further when doing the cutting - for (PolygonRef poly : cutting_mesh_polygons) + for (Polygon& poly : cutting_mesh_polygons) { - poly.add(poly[0]); + poly.push_back(poly[0]); + cutting_mesh_polylines.push_back(poly); } - cutting_mesh_polylines.add(cutting_mesh_polygons); + cutting_mesh_polygons.clear(); - cutting_mesh_area_recomputed = cutting_mesh_polylines.offsetPolyLine(surface_line_width / 2); + cutting_mesh_area_recomputed = cutting_mesh_polylines.offset(surface_line_width / 2); cutting_mesh_area = &cutting_mesh_area_recomputed; } else @@ -149,7 +150,7 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: } Polygons new_outlines; - Polygons new_polylines; + LinesSet new_polylines; for (unsigned int carved_mesh_idx = 0; carved_mesh_idx < volumes.size(); carved_mesh_idx++) { const Mesh& carved_mesh = meshes[carved_mesh_idx]; @@ -174,7 +175,7 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: if (cutting_mesh.settings_.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { cutting_mesh_polylines.clear(); - PolylineStitcher::stitch(new_polylines, cutting_mesh_polylines, cutting_mesh_polygons, surface_line_width); + OpenPolylineStitcher::stitch(new_polylines, cutting_mesh_polylines, cutting_mesh_polygons, surface_line_width); } } } diff --git a/src/pathPlanning/Comb.cpp b/src/pathPlanning/Comb.cpp index e8fbcb5919..7fe25ec014 100644 --- a/src/pathPlanning/Comb.cpp +++ b/src/pathPlanning/Comb.cpp @@ -119,7 +119,7 @@ bool Comb::calc( // normal combing within part using optimal comb boundary if (start_inside && end_inside && start_part_idx == end_part_idx) { - PolygonsPart part = parts_view_inside_optimal_.assemblePart(start_part_idx); + SingleShape part = parts_view_inside_optimal_.assemblePart(start_part_idx); comb_paths.emplace_back(); const bool combing_succeeded = LinePolygonsCrossings::comb( part, @@ -155,7 +155,7 @@ bool Comb::calc( // normal combing within part using minimum comb boundary if (start_inside_min && end_inside_min && start_part_idx_min == end_part_idx_min) { - PolygonsPart part = parts_view_inside_minimum_.assemblePart(start_part_idx_min); + SingleShape part = parts_view_inside_minimum_.assemblePart(start_part_idx_min); comb_paths.emplace_back(); comb_result = LinePolygonsCrossings::comb( @@ -419,8 +419,8 @@ Comb::Crossing::Crossing( { if (dest_is_inside) { - dest_crossing_poly_.emplace(boundary_inside[dest_part_boundary_crossing_poly_idx]); // initialize with most obvious poly, cause mostly a combing move will move outside the - // part, rather than inside a hole in the part + dest_crossing_poly_ = &(boundary_inside[dest_part_boundary_crossing_poly_idx]); // initialize with most obvious poly, cause mostly a combing move will move outside the + // part, rather than inside a hole in the part } } @@ -428,7 +428,7 @@ bool Comb::moveInside(Polygons& boundary_inside, bool is_inside, LocToLineGrid* { if (is_inside) { - ClosestPolygonPoint cpp + ClosestPoint cpp = PolygonUtils::ensureInsideOrOutside(boundary_inside, dest_point, offset_extra_start_end_, max_moveInside_distance2_, &boundary_inside, inside_loc_to_line); if (! cpp.isValid()) { @@ -456,7 +456,7 @@ void Comb::Crossing::findCrossingInOrMid(const PartsView& partsView_inside, cons }); dest_part_ = partsView_inside.assemblePart(dest_part_idx_); - ClosestPolygonPoint boundary_crossing_point; + ClosestPoint boundary_crossing_point; { // set [result] to a point on the destination part closest to close_to (but also a bit close to _dest_point) std::unordered_set dest_part_poly_indices; for (unsigned int poly_idx : partsView_inside[dest_part_idx_]) @@ -476,7 +476,7 @@ void Comb::Crossing::findCrossingInOrMid(const PartsView& partsView_inside, cons if (dist2_score_here < dist2_score) { dist2_score = dist2_score_here; - boundary_crossing_point = ClosestPolygonPoint(closest_here, boundary_segment.point_idx_, boundary_segment.getPolygon(), boundary_segment.poly_idx_); + boundary_crossing_point = ClosestPoint(closest_here, boundary_segment.point_idx_, &boundary_segment.getPolygon(), boundary_segment.poly_idx_); } return true; }; @@ -489,7 +489,7 @@ void Comb::Crossing::findCrossingInOrMid(const PartsView& partsView_inside, cons result = dest_point_; } - ClosestPolygonPoint crossing_1_in_cp = PolygonUtils::ensureInsideOrOutside( + ClosestPoint crossing_1_in_cp = PolygonUtils::ensureInsideOrOutside( dest_part_, result, boundary_crossing_point, @@ -499,7 +499,7 @@ void Comb::Crossing::findCrossingInOrMid(const PartsView& partsView_inside, cons close_towards_start_penalty_function); if (crossing_1_in_cp.isValid()) { - dest_crossing_poly_ = crossing_1_in_cp.poly_; + dest_crossing_poly_ = reinterpret_cast(crossing_1_in_cp.poly_); in_or_mid_ = result; } else @@ -524,7 +524,7 @@ bool Comb::Crossing::findOutside(const ExtruderTrain& train, const Polygons& out { return vSize2((candidate - preferred_crossing_1_out) / 2); }); - std::optional crossing_1_out_cpp = PolygonUtils::findClose(in_or_mid_, outside, comber.getOutsideLocToLine(train), close_to_penalty_function); + std::optional crossing_1_out_cpp = PolygonUtils::findClose(in_or_mid_, outside, comber.getOutsideLocToLine(train), close_to_penalty_function); if (crossing_1_out_cpp) { out_ = PolygonUtils::moveOutside(*crossing_1_out_cpp, comber.offset_dist_to_get_from_on_the_polygon_to_outside_); @@ -539,7 +539,7 @@ bool Comb::Crossing::findOutside(const ExtruderTrain& train, const Polygons& out { // if move is too far over in_between // find crossing closer by assert(dest_crossing_poly_ && "destination crossing poly should have been instantiated!"); - std::shared_ptr> best = findBestCrossing(train, outside, **dest_crossing_poly_, dest_point_, close_to, comber); + std::shared_ptr> best = findBestCrossing(train, outside, **dest_crossing_poly_, dest_point_, close_to, comber); if (best) { in_or_mid_ = PolygonUtils::moveInside(best->first, comber.offset_dist_to_get_from_on_the_polygon_to_outside_); @@ -554,21 +554,21 @@ bool Comb::Crossing::findOutside(const ExtruderTrain& train, const Polygons& out } -std::shared_ptr> Comb::Crossing::findBestCrossing( +std::shared_ptr> Comb::Crossing::findBestCrossing( const ExtruderTrain& train, const Polygons& outside, - ConstPolygonRef from, + const Polygon& from, const Point2LL estimated_start, const Point2LL estimated_end, Comb& comber) { - ClosestPolygonPoint* best_in = nullptr; - ClosestPolygonPoint* best_out = nullptr; + ClosestPoint* best_in = nullptr; + ClosestPoint* best_out = nullptr; coord_t best_detour_score = std::numeric_limits::max(); coord_t best_crossing_dist2; - std::vector> crossing_out_candidates = PolygonUtils::findClose(from, outside, comber.getOutsideLocToLine(train)); + std::vector> crossing_out_candidates = PolygonUtils::findClose(from, outside, comber.getOutsideLocToLine(train)); bool seen_close_enough_connection = false; - for (std::pair& crossing_candidate : crossing_out_candidates) + for (std::pair& crossing_candidate : crossing_out_candidates) { const coord_t crossing_dist2 = vSize2(crossing_candidate.first.location_ - crossing_candidate.second.location_); if (crossing_dist2 > comber.max_crossing_dist2_ * 2) @@ -603,7 +603,7 @@ std::shared_ptr> Comb::Cross } if (best_detour_score == std::numeric_limits::max()) { // i.e. if best_in == nullptr or if best_out == nullptr - return std::shared_ptr>(); + return std::shared_ptr>(); } if (best_crossing_dist2 > comber.max_crossing_dist2_) { // find closer point on line segments, rather than moving between vertices of the polygons only @@ -611,10 +611,10 @@ std::shared_ptr> Comb::Cross best_crossing_dist2 = vSize2(best_in->location_ - best_out->location_); if (best_crossing_dist2 > comber.max_crossing_dist2_) { - return std::shared_ptr>(); + return std::shared_ptr>(); } } - return std::make_shared>(*best_in, *best_out); + return std::make_shared>(*best_in, *best_out); } } // namespace cura diff --git a/src/pathPlanning/LinePolygonsCrossings.cpp b/src/pathPlanning/LinePolygonsCrossings.cpp index 1391dffb7a..a2867386ea 100644 --- a/src/pathPlanning/LinePolygonsCrossings.cpp +++ b/src/pathPlanning/LinePolygonsCrossings.cpp @@ -22,7 +22,7 @@ bool LinePolygonsCrossings::calcScanlineCrossings(bool fail_on_unavoidable_obsta { for (unsigned int poly_idx = 0; poly_idx < boundary_.size(); poly_idx++) { - ConstPolygonRef poly = boundary_[poly_idx]; + const Polygon& poly = boundary_[poly_idx]; Point2LL p0 = transformation_matrix_.apply(poly[poly.size() - 1]); for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++) { @@ -74,7 +74,7 @@ bool LinePolygonsCrossings::lineSegmentCollidesWithBoundary() transformed_start_point_ = transformation_matrix_.apply(start_point_); transformed_end_point_ = transformation_matrix_.apply(end_point_); - for (ConstPolygonRef poly : boundary_) + for (const Polygon& poly : boundary_) { Point2LL p0 = transformation_matrix_.apply(poly.back()); for (Point2LL p1_ : poly) @@ -152,7 +152,7 @@ void LinePolygonsCrossings::generateBasicCombingPath(const Crossing& min, const { // minimise the path length by measuring the length of both paths around the polygon so we can determine the shorter path - ConstPolygonRef poly = boundary_[min.poly_idx_]; + const Polygon& poly = boundary_[min.poly_idx_]; combPath.push_back(transformation_matrix_.unapply(Point2LL(min.x_ - std::abs(dist_to_move_boundary_point_outside_), transformed_start_point_.Y))); // follow the path in the same direction as the winding order of the boundary polygon diff --git a/src/plugins/converters.cpp b/src/plugins/converters.cpp index 40988a2f7b..12b6a21c14 100644 --- a/src/plugins/converters.cpp +++ b/src/plugins/converters.cpp @@ -14,7 +14,7 @@ #include "pathPlanning/SpeedDerivatives.h" #include "settings/Settings.h" #include "settings/types/LayerIndex.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" namespace cura::plugins { @@ -101,7 +101,7 @@ simplify_request::value_type simplify_request::operator()( auto* msg_polygon = msg_polygons->add_polygons(); auto* msg_outline = msg_polygon->mutable_outline(); - for (const auto& point : ranges::front(polygons.paths)) + for (const auto& point : ranges::front(polygons)) { auto* msg_outline_path = msg_outline->add_path(); msg_outline_path->set_x(point.X); @@ -109,7 +109,7 @@ simplify_request::value_type simplify_request::operator()( } auto* msg_holes = msg_polygon->mutable_holes(); - for (const auto& polygon : polygons.paths | ranges::views::drop(1)) + for (const auto& polygon : polygons | ranges::views::drop(1)) { auto* msg_hole = msg_holes->Add(); for (const auto& point : polygon) @@ -135,18 +135,18 @@ simplify_response::native_value_type Polygon o{}; for (const auto& point : paths.outline().path()) { - o.add(Point2LL{ point.x(), point.y() }); + o.push_back(Point2LL{ point.x(), point.y() }); } - poly.add(o); + poly.push_back(o); for (const auto& hole : paths.holes()) { Polygon h{}; for (const auto& point : hole.path()) { - h.add(Point2LL{ point.x(), point.y() }); + h.push_back(Point2LL{ point.x(), point.y() }); } - poly.add(h); + poly.push_back(h); } } return poly; @@ -185,7 +185,7 @@ infill_generate_request::value_type auto* msg_polygon = msg_polygons->add_polygons(); auto* msg_outline = msg_polygon->mutable_outline(); - for (const auto& point : ranges::front(inner_contour.paths)) + for (const auto& point : ranges::front(inner_contour)) { auto* msg_outline_path = msg_outline->add_path(); msg_outline_path->set_x(point.X); @@ -193,7 +193,7 @@ infill_generate_request::value_type } auto* msg_holes = msg_polygon->mutable_holes(); - for (const auto& polygon : inner_contour.paths | ranges::views::drop(1)) + for (const auto& polygon : inner_contour | ranges::views::drop(1)) { auto* msg_hole = msg_holes->Add(); for (const auto& point : polygon) @@ -211,7 +211,7 @@ infill_generate_response::native_value_type infill_generate_response::operator() { VariableWidthLines toolpaths; Polygons result_polygons; - Polygons result_lines; + LinesSet result_lines; for (auto& tool_path : message.tool_paths().tool_paths()) { @@ -236,9 +236,9 @@ infill_generate_response::native_value_type infill_generate_response::operator() Polygon outline{}; for (auto& path_msg : polygon_msg.outline().path()) { - outline.add(Point2LL{ path_msg.x(), path_msg.y() }); + outline.push_back(Point2LL{ path_msg.x(), path_msg.y() }); } - polygon.add(outline); + polygon.push_back(outline); for (auto& hole_msg : polygon_msg.holes()) @@ -246,9 +246,9 @@ infill_generate_response::native_value_type infill_generate_response::operator() Polygon hole{}; for (auto& path_msg : hole_msg.path()) { - hole.add(Point2LL{ path_msg.x(), path_msg.y() }); + hole.push_back(Point2LL{ path_msg.x(), path_msg.y() }); } - polygon.add(hole); + polygon.push_back(hole); } result_polygons.add(polygon); diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index 9ec36c2446..31126794b4 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -27,7 +27,8 @@ #include "settings/types/Temperature.h" //For temperature settings. #include "settings/types/Velocity.h" //For velocity settings. #include "utils/Matrix4x3D.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" +#include "geometry/polygons.h" #include "utils/string.h" //For Escaped. #include "utils/types/string_switch.h" //For string switch. @@ -287,8 +288,7 @@ Polygons Settings::get(const std::string& key) const { std::string polygon_str = *polygon_match_iter++; - result.emplace_back(); - PolygonRef poly = result.back(); + Polygon& poly = result.newLine(); std::regex point2D_regex(R"(\[([^,\[]*),([^,\]]*)\])"); // matches to a list of exactly two things diff --git a/src/skin.cpp b/src/skin.cpp index 1f36864698..587f4cceac 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -154,7 +154,7 @@ void SkinInfillAreaComputation::generateSkinAndInfillAreas(SliceLayerPart& part) generateInfill(part); } - for (PolygonsPart& skin_area_part : skin.splitIntoParts()) + for (SingleShape& skin_area_part : skin.splitIntoParts()) { part.skin_parts.emplace_back(); part.skin_parts.back().outline = skin_area_part; diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index e87250191b..521ad63c61 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -81,7 +81,7 @@ void SliceLayer::getOutlines(Polygons& result, bool external_polys_only) const { if (external_polys_only) { - result.add(part.outline.outerPolygon()); + result.push_back(part.outline.outerPolygon()); } else { @@ -305,11 +305,11 @@ Polygons { if (external_polys_only) { - std::vector parts = raftOutline->splitIntoParts(); + std::vector parts = raftOutline->splitIntoParts(); Polygons result; - for (PolygonsPart& part : parts) + for (SingleShape& part : parts) { - result.add(part.outerPolygon()); + result.push_back(part.outerPolygon()); } return result; } @@ -341,7 +341,7 @@ Polygons layer.getOutlines(total, external_polys_only); if (mesh->settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { - total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(MM2INT(0.1))); + total = total.unionPolygons(layer.openPolyLines.offset(MM2INT(0.1))); } } } @@ -570,7 +570,7 @@ Polygons SliceDataStorage::getMachineBorder(int checking_extruder_nr) const Polygons border; border.emplace_back(); - PolygonRef outline = border.back(); + Polygon& outline = border.back(); switch (mesh_group_settings.get("machine_shape")) { case BuildPlateShape::ELLIPTIC: @@ -599,7 +599,7 @@ Polygons SliceDataStorage::getMachineBorder(int checking_extruder_nr) const // may be expressed in front-left-centered coordinantes, so in this case we need to translate them if (! mesh_group_settings.get("machine_center_is_zero")) { - for (PolygonRef poly : disallowed_areas) + for (Polygon& poly : disallowed_areas) { for (Point2LL& p : poly) { @@ -715,7 +715,7 @@ void SupportLayer::excludeAreasFromSupportInfillAreas(const Polygons& exclude_po continue; } - std::vector smaller_support_islands = result_polygons.splitIntoParts(); + std::vector smaller_support_islands = result_polygons.splitIntoParts(); if (smaller_support_islands.empty()) { // extra safety guard in case result_polygons consists of too small polygons which are automatically removed in splitIntoParts @@ -730,7 +730,7 @@ void SupportLayer::excludeAreasFromSupportInfillAreas(const Polygons& exclude_po for (size_t support_island_idx = 1; support_island_idx < smaller_support_islands.size(); ++support_island_idx) { - const PolygonsPart& smaller_island = smaller_support_islands[support_island_idx]; + const SingleShape& smaller_island = smaller_support_islands[support_island_idx]; support_infill_parts.emplace_back(smaller_island, support_infill_part.support_line_width_, support_infill_part.inset_count_to_generate_); } } @@ -765,7 +765,7 @@ void SupportLayer::fillInfillParts( bool use_fractional_config = true; for (auto& support_areas : all_support_areas_in_layer) { - for (const PolygonsPart& island_outline : support_areas.splitIntoParts(unionAll)) + for (const SingleShape& island_outline : support_areas.splitIntoParts(unionAll)) { support_infill_parts.emplace_back(island_outline, support_line_width, use_fractional_config, wall_line_count, custom_line_distance); } diff --git a/src/slicer.cpp b/src/slicer.cpp index d13908458f..751ea6ea3c 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -30,7 +30,7 @@ constexpr int largest_neglected_gap_first_phase = MM2INT(0.01); //!< distance be constexpr int largest_neglected_gap_second_phase = MM2INT(0.02); //!< distance between two line segments regarded as connected constexpr int max_stitch1 = MM2INT(10.0); //!< maximal distance stitched between open polylines to form polygons -void SlicerLayer::makeBasicPolygonLoops(Polygons& open_polylines) +void SlicerLayer::makeBasicPolygonLoops(std::vector& open_polylines) { for (size_t start_segment_idx = 0; start_segment_idx < segments.size(); start_segment_idx++) { @@ -43,25 +43,25 @@ void SlicerLayer::makeBasicPolygonLoops(Polygons& open_polylines) segments.clear(); } -void SlicerLayer::makeBasicPolygonLoop(Polygons& open_polylines, const size_t start_segment_idx) +void SlicerLayer::makeBasicPolygonLoop(std::vector& open_polylines, const size_t start_segment_idx) { - Polygon poly; - poly.add(segments[start_segment_idx].start); + OpenPolyline poly; + poly.push_back(segments[start_segment_idx].start); for (int segment_idx = start_segment_idx; segment_idx != -1;) { SlicerSegment& segment = segments[segment_idx]; - poly.add(segment.end); + poly.push_back(segment.end); segment.addedToPolygon = true; segment_idx = getNextSegmentIdx(segment, start_segment_idx); if (segment_idx == static_cast(start_segment_idx)) { // polyon is closed - polygons.add(poly); + polygons.push_back(poly); return; } } // polygon couldn't be closed - open_polylines.add(poly); + open_polylines.push_back(poly); } int SlicerLayer::tryFaceNextSegmentIdx(const SlicerSegment& segment, const int face_idx, const size_t start_segment_idx) const @@ -128,7 +128,7 @@ int SlicerLayer::getNextSegmentIdx(const SlicerSegment& segment, const size_t st return next_segment_idx; } -void SlicerLayer::connectOpenPolylines(Polygons& open_polylines) +void SlicerLayer::connectOpenPolylines(std::vector& open_polylines) { constexpr bool allow_reverse = false; // Search a bit fewer cells but at cost of covering more area. @@ -137,7 +137,7 @@ void SlicerLayer::connectOpenPolylines(Polygons& open_polylines) connectOpenPolylinesImpl(open_polylines, largest_neglected_gap_second_phase, cell_size, allow_reverse); } -void SlicerLayer::stitch(Polygons& open_polylines) +void SlicerLayer::stitch(std::vector& open_polylines) { bool allow_reverse = true; connectOpenPolylinesImpl(open_polylines, max_stitch1, max_stitch1, allow_reverse); @@ -189,7 +189,8 @@ bool SlicerLayer::PossibleStitch::operator<(const PossibleStitch& other) const return false; } -std::priority_queue SlicerLayer::findPossibleStitches(const Polygons& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) const +std::priority_queue + SlicerLayer::findPossibleStitches(const std::vector& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) const { std::priority_queue stitch_queue; @@ -224,7 +225,7 @@ std::priority_queue SlicerLayer::findPossibleStitch // insert the starts of the polylines). for (unsigned int polyline_0_idx = 0; polyline_0_idx < open_polylines.size(); polyline_0_idx++) { - ConstPolygonRef polyline_0 = open_polylines[polyline_0_idx]; + const OpenPolyline& polyline_0 = open_polylines[polyline_0_idx]; if (polyline_0.size() < 1) continue; @@ -240,7 +241,7 @@ std::priority_queue SlicerLayer::findPossibleStitch { for (unsigned int polyline_0_idx = 0; polyline_0_idx < open_polylines.size(); polyline_0_idx++) { - ConstPolygonRef polyline_0 = open_polylines[polyline_0_idx]; + const OpenPolyline& polyline_0 = open_polylines[polyline_0_idx]; if (polyline_0.size() < 1) continue; @@ -255,7 +256,7 @@ std::priority_queue SlicerLayer::findPossibleStitch // search for nearby end points for (unsigned int polyline_1_idx = 0; polyline_1_idx < open_polylines.size(); polyline_1_idx++) { - ConstPolygonRef polyline_1 = open_polylines[polyline_1_idx]; + const OpenPolyline& polyline_1 = open_polylines[polyline_1_idx]; if (polyline_1.size() < 1) continue; @@ -335,7 +336,7 @@ std::priority_queue SlicerLayer::findPossibleStitch return stitch_queue; } -void SlicerLayer::planPolylineStitch(const Polygons& open_polylines, Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const +void SlicerLayer::planPolylineStitch(const std::vector& open_polylines, Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const { size_t polyline_0_idx = terminus_0.getPolylineIdx(); size_t polyline_1_idx = terminus_1.getPolylineIdx(); @@ -384,7 +385,7 @@ void SlicerLayer::planPolylineStitch(const Polygons& open_polylines, Terminus& t } } -void SlicerLayer::joinPolylines(PolygonRef& polyline_0, PolygonRef& polyline_1, const bool reverse[2]) const +void SlicerLayer::joinPolylines(OpenPolyline& polyline_0, OpenPolyline& polyline_1, const bool reverse[2]) { if (reverse[0]) { @@ -399,13 +400,13 @@ void SlicerLayer::joinPolylines(PolygonRef& polyline_0, PolygonRef& polyline_1, { // reverse polyline_1 by adding in reverse order for (int poly_idx = polyline_1.size() - 1; poly_idx >= 0; poly_idx--) - polyline_0.add(polyline_1[poly_idx]); + polyline_0.push_back(polyline_1[poly_idx]); } else { // append polyline_1 onto polyline_0 for (Point2LL& p : polyline_1) - polyline_0.add(p); + polyline_0.push_back(p); } polyline_1.clear(); } @@ -451,7 +452,7 @@ void SlicerLayer::TerminusTrackingMap::updateMap( } } -void SlicerLayer::connectOpenPolylinesImpl(Polygons& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) +void SlicerLayer::connectOpenPolylinesImpl(std::vector& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) { // below code closes smallest gaps first @@ -491,9 +492,8 @@ void SlicerLayer::connectOpenPolylinesImpl(Polygons& open_polylines, coord_t max if (completed_poly) { // finished polygon - PolygonRef polyline_0 = open_polylines[best_polyline_0_idx]; - polygons.add(polyline_0); - polyline_0.clear(); + OpenPolyline& polyline_0 = open_polylines[best_polyline_0_idx]; + polygons.push_back(std::move(polyline_0)); // Will also clear the polyline Terminus cur_terms[2] = { { best_polyline_0_idx, false }, { best_polyline_0_idx, true } }; for (size_t idx = 0U; idx != 2U; ++idx) { @@ -511,8 +511,8 @@ void SlicerLayer::connectOpenPolylinesImpl(Polygons& open_polylines, coord_t max // need to reread since planPolylineStitch can swap terminus_0/1 best_polyline_0_idx = terminus_0.getPolylineIdx(); best_polyline_1_idx = terminus_1.getPolylineIdx(); - PolygonRef polyline_0 = open_polylines[best_polyline_0_idx]; - PolygonRef polyline_1 = open_polylines[best_polyline_1_idx]; + OpenPolyline& polyline_0 = open_polylines[best_polyline_0_idx]; + OpenPolyline& polyline_1 = open_polylines[best_polyline_1_idx]; // join polylines according to plan joinPolylines(polyline_0, polyline_1, reverse); @@ -534,7 +534,7 @@ void SlicerLayer::connectOpenPolylinesImpl(Polygons& open_polylines, coord_t max } } -void SlicerLayer::stitch_extensive(Polygons& open_polylines) +void SlicerLayer::stitch_extensive(std::vector& open_polylines) { // For extensive stitching find 2 open polygons that are touching 2 closed polygons. // Then find the shortest path over this polygon that can be used to connect the open polygons, @@ -549,7 +549,7 @@ void SlicerLayer::stitch_extensive(Polygons& open_polylines) for (unsigned int polyline_1_idx = 0; polyline_1_idx < open_polylines.size(); polyline_1_idx++) { - PolygonRef polyline_1 = open_polylines[polyline_1_idx]; + OpenPolyline& polyline_1 = open_polylines[polyline_1_idx]; if (polyline_1.size() < 1) continue; @@ -565,7 +565,7 @@ void SlicerLayer::stitch_extensive(Polygons& open_polylines) for (unsigned int polyline_2_idx = 0; polyline_2_idx < open_polylines.size(); polyline_2_idx++) { - PolygonRef polyline_2 = open_polylines[polyline_2_idx]; + OpenPolyline& polyline_2 = open_polylines[polyline_2_idx]; if (polyline_2.size() < 1 || polyline_1_idx == polyline_2_idx) continue; @@ -585,24 +585,24 @@ void SlicerLayer::stitch_extensive(Polygons& open_polylines) { if (best_result->pointIdxA == best_result->pointIdxB) { - polygons.add(open_polylines[best_polyline_1_idx]); + polygons.push_back(open_polylines[best_polyline_1_idx]); open_polylines[best_polyline_1_idx].clear(); } else if (best_result->AtoB) { - PolygonRef poly = polygons.newPoly(); + Polygon& poly = polygons.newLine(); for (unsigned int j = best_result->pointIdxA; j != best_result->pointIdxB; j = (j + 1) % polygons[best_result->polygonIdx].size()) - poly.add(polygons[best_result->polygonIdx][j]); + poly.push_back(polygons[best_result->polygonIdx][j]); for (unsigned int j = open_polylines[best_polyline_1_idx].size() - 1; int(j) >= 0; j--) - poly.add(open_polylines[best_polyline_1_idx][j]); + poly.push_back(open_polylines[best_polyline_1_idx][j]); open_polylines[best_polyline_1_idx].clear(); } else { unsigned int n = polygons.size(); - polygons.add(open_polylines[best_polyline_1_idx]); + polygons.push_back(open_polylines[best_polyline_1_idx]); for (unsigned int j = best_result->pointIdxB; j != best_result->pointIdxA; j = (j + 1) % polygons[best_result->polygonIdx].size()) - polygons[n].add(polygons[best_result->polygonIdx][j]); + polygons[n].push_back(polygons[best_result->polygonIdx][j]); open_polylines[best_polyline_1_idx].clear(); } } @@ -611,26 +611,26 @@ void SlicerLayer::stitch_extensive(Polygons& open_polylines) if (best_result->pointIdxA == best_result->pointIdxB) { for (unsigned int n = 0; n < open_polylines[best_polyline_1_idx].size(); n++) - open_polylines[best_polyline_2_idx].add(open_polylines[best_polyline_1_idx][n]); + open_polylines[best_polyline_2_idx].push_back(open_polylines[best_polyline_1_idx][n]); open_polylines[best_polyline_1_idx].clear(); } else if (best_result->AtoB) { Polygon poly; for (unsigned int n = best_result->pointIdxA; n != best_result->pointIdxB; n = (n + 1) % polygons[best_result->polygonIdx].size()) - poly.add(polygons[best_result->polygonIdx][n]); + poly.push_back(polygons[best_result->polygonIdx][n]); for (unsigned int n = poly.size() - 1; int(n) >= 0; n--) - open_polylines[best_polyline_2_idx].add(poly[n]); + open_polylines[best_polyline_2_idx].push_back(poly[n]); for (unsigned int n = 0; n < open_polylines[best_polyline_1_idx].size(); n++) - open_polylines[best_polyline_2_idx].add(open_polylines[best_polyline_1_idx][n]); + open_polylines[best_polyline_2_idx].push_back(open_polylines[best_polyline_1_idx][n]); open_polylines[best_polyline_1_idx].clear(); } else { for (unsigned int n = best_result->pointIdxB; n != best_result->pointIdxA; n = (n + 1) % polygons[best_result->polygonIdx].size()) - open_polylines[best_polyline_2_idx].add(polygons[best_result->polygonIdx][n]); + open_polylines[best_polyline_2_idx].push_back(polygons[best_result->polygonIdx][n]); for (unsigned int n = open_polylines[best_polyline_1_idx].size() - 1; int(n) >= 0; n--) - open_polylines[best_polyline_2_idx].add(open_polylines[best_polyline_1_idx][n]); + open_polylines[best_polyline_2_idx].push_back(open_polylines[best_polyline_1_idx][n]); open_polylines[best_polyline_1_idx].clear(); } } @@ -735,7 +735,7 @@ std::optional SlicerLayer::findPolygonPointClosestTo(Point2L void SlicerLayer::makePolygons(const Mesh* mesh) { - Polygons open_polylines; + std::vector open_polylines; makeBasicPolygonLoops(open_polylines); @@ -757,31 +757,30 @@ void SlicerLayer::makePolygons(const Mesh* mesh) if (mesh->settings_.get("meshfix_keep_open_polygons")) { - for (PolygonRef polyline : open_polylines) + for (const OpenPolyline& polyline : open_polylines) { - if (polyline.size() > 0) - polygons.add(polyline); + polygons.addIfNotEmpty(polyline); } } - for (PolygonRef polyline : open_polylines) + for (const OpenPolyline& polyline : open_polylines) { - if (polyline.size() > 0) + if (! polyline.empty()) { - openPolylines.add(polyline); + openPolylines.push_back(std::move(polyline)); } } // Remove all the tiny polygons, or polygons that are not closed. As they do not contribute to the actual print. const coord_t snap_distance = std::max(mesh->settings_.get("minimum_polygon_circumference"), static_cast(1)); - auto it = std::remove_if( + auto itPolygons = std::remove_if( polygons.begin(), polygons.end(), - [snap_distance](PolygonRef poly) + [snap_distance](const Polygon& poly) { return poly.shorterThan(snap_distance); }); - polygons.erase(it, polygons.end()); + polygons.erase(itPolygons, polygons.end()); // Finally optimize all the polygons. Every point removed saves time in the long run. // polygons = Simplify(mesh->settings).polygon(polygons); @@ -790,19 +789,19 @@ void SlicerLayer::makePolygons(const Mesh* mesh) mesh->settings_.get("meshfix_maximum_resolution"), mesh->settings_.get("meshfix_maximum_deviation"), static_cast(mesh->settings_.get("meshfix_maximum_extrusion_area_deviation"))); - polygons.removeDegenerateVerts(); // remove verts connected to overlapping line segments + polygons.removeDegenerateVertsForEveryone(); // remove verts connected to overlapping line segments // Clean up polylines for Surface Mode printing - it = std::remove_if( + auto itPolylines = std::remove_if( openPolylines.begin(), openPolylines.end(), - [snap_distance](PolygonRef poly) + [snap_distance](const OpenPolyline& line) { - return poly.shorterThan(snap_distance); + return line.shorterThan(snap_distance); }); - openPolylines.erase(it, openPolylines.end()); + openPolylines.erase(itPolylines, openPolylines.end()); - openPolylines.removeDegenerateVertsPolyline(); + openPolylines.removeDegenerateVertsForEveryone(); } Slicer::Slicer(Mesh* i_mesh, const coord_t thickness, const size_t slice_layer_count, bool use_variable_layer_heights, std::vector* adaptive_layers) @@ -1076,7 +1075,7 @@ void Slicer::makePolygons(Mesh& mesh, SlicingTolerance slicing_tolerance, std::v { Polygons holes; Polygons outline; - for (ConstPolygonRef poly : part) + for (const Polygon& poly : part) { const auto area = poly.area(); const auto abs_area = std::abs(area); @@ -1094,12 +1093,12 @@ void Slicer::makePolygons(Mesh& mesh, SlicingTolerance slicing_tolerance, std::v } else { - holes.add(poly); + holes.push_back(poly); } } else { - outline.add(poly); + outline.push_back(poly); } } diff --git a/src/support.cpp b/src/support.cpp index 3ef52db616..f617a32d25 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -494,12 +494,12 @@ Polygons AreaSupport::join(const SliceDataStorage& storage, const Polygons& supp const coord_t y = machine_middle.y_ + sin(angle) * depth / 2; border_circle.emplace_back(x, y); } - machine_volume_border.add(border_circle); + machine_volume_border.push_back(border_circle); break; } case BuildPlateShape::RECTANGULAR: default: - machine_volume_border.add(storage.machine_size.flatten().toPolygon()); + machine_volume_border.push_back(storage.machine_size.flatten().toPolygon()); break; } coord_t adhesion_size = 0; // Make sure there is enough room for the platform adhesion around support. @@ -820,7 +820,7 @@ Polygons AreaSupport::generateVaryingXYDisallowedArea(const SliceMeshStorage& st constexpr auto close_dist = 20; - auto layer_current = simplify.polygon(storage.layers[layer_idx].getOutlines().offset(-close_dist).offset(close_dist)); + Polygons layer_current = simplify.polygon(storage.layers[layer_idx].getOutlines().offset(-close_dist).offset(close_dist)); using point_pair_t = std::pair; using poly_point_key = std::tuple; @@ -951,7 +951,7 @@ Polygons AreaSupport::generateVaryingXYDisallowedArea(const SliceMeshStorage& st const auto smooth_dist = xy_distance / 2.0; Polygons varying_xy_disallowed_areas = layer_current // offset using the varying offset distances we calculated previously - .offset(varying_offsets) + .offsetMulti(varying_offsets) // close operation to smooth the x/y disallowed area boundary. With varying xy distances we see some jumps in the boundary. // As the x/y disallowed areas "cut in" to support the xy-disallowed area may propagate through the support area. If the // x/y disallowed area is not smoothed boost has trouble generating a voronoi diagram. @@ -1171,7 +1171,7 @@ void AreaSupport::generateSupportAreasForMesh( // make towers for small support if (use_towers) { - for (PolygonsPart poly : layer_this.splitIntoParts()) + for (SingleShape poly : layer_this.splitIntoParts()) { const auto polygon_part = poly.difference(xy_disallowed_per_layer[layer_idx]).offset(-half_min_feature_width).offset(half_min_feature_width); @@ -1624,7 +1624,7 @@ void AreaSupport::handleWallStruts(const Settings& settings, Polygons& supportLa const coord_t tower_diameter = settings.get("support_tower_diameter"); for (unsigned int p = 0; p < supportLayer_this.size(); p++) { - PolygonRef poly = supportLayer_this[p]; + const Polygon& poly = supportLayer_this[p]; if (poly.size() < 6) // might be a single wall { int best = -1; @@ -1652,11 +1652,11 @@ void AreaSupport::handleWallStruts(const Settings& settings, Polygons& supportLa { Point2LL mid = (poly[best] + poly[(best + 1) % poly.size()]) / 2; Polygons struts; - PolygonRef strut = struts.newPoly(); - strut.add(mid + Point2LL(tower_diameter / 2, tower_diameter / 2)); - strut.add(mid + Point2LL(-tower_diameter / 2, tower_diameter / 2)); - strut.add(mid + Point2LL(-tower_diameter / 2, -tower_diameter / 2)); - strut.add(mid + Point2LL(tower_diameter / 2, -tower_diameter / 2)); + Polygon& strut = struts.newLine(); + strut.push_back(mid + Point2LL(tower_diameter / 2, tower_diameter / 2)); + strut.push_back(mid + Point2LL(-tower_diameter / 2, tower_diameter / 2)); + strut.push_back(mid + Point2LL(-tower_diameter / 2, -tower_diameter / 2)); + strut.push_back(mid + Point2LL(tower_diameter / 2, -tower_diameter / 2)); supportLayer_this = supportLayer_this.unionPolygons(struts); } } diff --git a/src/utils/AABB.cpp b/src/utils/AABB.cpp index f3a93cbf1d..974881331a 100644 --- a/src/utils/AABB.cpp +++ b/src/utils/AABB.cpp @@ -6,7 +6,8 @@ #include #include "utils/linearAlg2D.h" -#include "utils/polygon.h" //To create the AABB of a polygon. +#include "geometry/polygon.h" +#include "geometry/polygons.h" namespace cura { @@ -31,7 +32,7 @@ AABB::AABB(const Polygons& polys) calculate(polys); } -AABB::AABB(ConstPolygonRef poly) +AABB::AABB(const Polygon& poly) : min_(POINT_MAX, POINT_MAX) , max_(POINT_MIN, POINT_MIN) { @@ -72,16 +73,16 @@ void AABB::calculate(const Polygons& polys) { min_ = Point2LL(POINT_MAX, POINT_MAX); max_ = Point2LL(POINT_MIN, POINT_MIN); - for (unsigned int i = 0; i < polys.size(); i++) + for (const Polygon& poly : polys) { - for (unsigned int j = 0; j < polys[i].size(); j++) + for (const Point2LL& point : poly) { - include(polys[i][j]); + include(point); } } } -void AABB::calculate(ConstPolygonRef poly) +void AABB::calculate(const Polygon& poly) { min_ = Point2LL(POINT_MAX, POINT_MAX); max_ = Point2LL(POINT_MIN, POINT_MIN); @@ -131,7 +132,7 @@ bool AABB::hit(const AABB& other) const return true; } -void AABB::include(Point2LL point) +void AABB::include(const Point2LL& point) { min_.X = std::min(min_.X, point.X); min_.Y = std::min(min_.Y, point.Y); @@ -139,7 +140,15 @@ void AABB::include(Point2LL point) max_.Y = std::max(max_.Y, point.Y); } -void AABB::include(const AABB other) +void AABB::include(const Polygon& polygon) +{ + for (const Point2LL& point : polygon) + { + include(point); + } +} + +void AABB::include(const AABB& other) { // Note that this is different from including the min and max points, since when 'min > max' it's used to denote an negative/empty box. min_.X = std::min(min_.X, other.min_.X); @@ -162,12 +171,7 @@ void AABB::expand(int dist) Polygon AABB::toPolygon() const { - Polygon ret; - ret.add(min_); - ret.add(Point2LL(max_.X, min_.Y)); - ret.add(max_); - ret.add(Point2LL(min_.X, max_.Y)); - return ret; + return Polygon({ min_, Point2LL(max_.X, min_.Y), max_, Point2LL(min_.X, max_.Y) }); } } // namespace cura diff --git a/src/utils/ExtrusionLine.cpp b/src/utils/ExtrusionLine.cpp index 5183aab67b..c0c274e8a6 100644 --- a/src/utils/ExtrusionLine.cpp +++ b/src/utils/ExtrusionLine.cpp @@ -12,7 +12,7 @@ namespace cura { -coord_t ExtrusionLine::getLength() const +coord_t ExtrusionLine::length() const { if (junctions_.empty()) { diff --git a/src/utils/ExtrusionSegment.cpp b/src/utils/ExtrusionSegment.cpp index 71a2d59bef..81caac1243 100644 --- a/src/utils/ExtrusionSegment.cpp +++ b/src/utils/ExtrusionSegment.cpp @@ -26,7 +26,7 @@ Polygons ExtrusionSegment::toPolygons(bool reduced) return ret; } - PolygonRef poly = ret.newPoly(); + Polygon& poly = ret.newLine(); const double delta_r = 0.5 * std::abs(from_.w_ - to_.w_); const double vec_length_fixed = std::max(delta_r, static_cast(vec_length)); float alpha = std::acos(delta_r / vec_length_fixed); // Angle between the slope along the edge of the polygon (due to varying line width) and the centerline. @@ -49,7 +49,7 @@ Polygons ExtrusionSegment::toPolygons(bool reduced) // Draw the endcap on the "from" vertex's end. { - poly.emplace_back(from_.p_ + Point2LL(from_.w_ / 2 * cos(alpha + dir), from_.w_ / 2 * sin(alpha + dir))); + poly.push_back(from_.p_ + Point2LL(from_.w_ / 2 * cos(alpha + dir), from_.w_ / 2 * sin(alpha + dir))); double start_a = 2 * std::numbers::pi; while (start_a > alpha + dir) @@ -74,7 +74,7 @@ Polygons ExtrusionSegment::toPolygons(bool reduced) // Draw the endcap on the "to" vertex's end. { - poly.emplace_back( + poly.push_back( to_.p_ + Point2LL( to_.w_ / 2 * cos(2 * std::numbers::pi - alpha + dir), @@ -125,7 +125,7 @@ Polygons ExtrusionSegment::toPolygons(bool reduced) } #ifdef DEBUG - for (Point2LL p : poly) + for (const Point2LL& p : poly) { assert(p.X < 0x3FFFFFFFFFFFFFFFLL); assert(p.Y < 0x3FFFFFFFFFFFFFFFLL); diff --git a/src/utils/ListPolyIt.cpp b/src/utils/ListPolyIt.cpp index c2c4a7cf0a..ddf39cddb5 100644 --- a/src/utils/ListPolyIt.cpp +++ b/src/utils/ListPolyIt.cpp @@ -8,6 +8,7 @@ #include "utils/AABB.h" // for debug output svg html #include "utils/SVG.h" +#include "geometry/polygon.h" namespace cura { @@ -15,14 +16,14 @@ namespace cura void ListPolyIt::convertPolygonsToLists(const Polygons& polys, ListPolygons& result) { - for (ConstPolygonRef poly : polys) + for (const Polygon& poly : polys) { result.emplace_back(); convertPolygonToList(poly, result.back()); } } -void ListPolyIt::convertPolygonToList(ConstPolygonRef poly, ListPolygon& result) +void ListPolyIt::convertPolygonToList(const Polygon& poly, ListPolygon& result) { #ifdef DEBUG Point2LL last = poly.back(); @@ -50,11 +51,11 @@ void ListPolyIt::convertListPolygonsToPolygons(const ListPolygons& list_polygons } } -void ListPolyIt::convertListPolygonToPolygon(const ListPolygon& list_polygon, PolygonRef polygon) +void ListPolyIt::convertListPolygonToPolygon(const ListPolygon& list_polygon, Polygon& polygon) { for (const Point2LL& p : list_polygon) { - polygon.add(p); + polygon.push_back(p); } } diff --git a/src/utils/Matrix4x3D.cpp b/src/utils/Matrix4x3D.cpp index 43b255379f..e779bb697f 100644 --- a/src/utils/Matrix4x3D.cpp +++ b/src/utils/Matrix4x3D.cpp @@ -4,7 +4,7 @@ #include "utils/Matrix4x3D.h" //The definitions we're implementing. #include "settings/types/Ratio.h" //Scale factor. -#include "utils/Point2LL.h" //Conversion directly into integer-based coordinates. +#include "geometry/point2ll.h" //Conversion directly into integer-based coordinates. #include "utils/Point3D.h" //This matrix gets applied to floating point coordinates. namespace cura diff --git a/src/utils/Point3LL.cpp b/src/utils/Point3LL.cpp index 2420552fb6..6a72feb929 100644 --- a/src/utils/Point3LL.cpp +++ b/src/utils/Point3LL.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2022 Ultimaker B.V. // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "utils/Point3LL.h" //The headers we're implementing. +#include "geometry/point3ll.h" //The headers we're implementing. namespace cura { diff --git a/src/utils/PolygonConnector.cpp b/src/utils/PolygonConnector.cpp index 936ad69850..2b95247630 100644 --- a/src/utils/PolygonConnector.cpp +++ b/src/utils/PolygonConnector.cpp @@ -16,7 +16,7 @@ PolygonConnector::PolygonConnector(const coord_t line_width) void PolygonConnector::add(const Polygons& input) { - for (ConstPolygonRef poly : input) + for (const Polygon& poly : input) { input_polygons_.push_back(poly); } @@ -36,9 +36,9 @@ void PolygonConnector::add(const std::vector& input) void PolygonConnector::connect(Polygons& output_polygons, std::vector& output_paths) { std::vector result_polygons = connectGroup(input_polygons_); - for (Polygon& polygon : result_polygons) + for (const Polygon& polygon : result_polygons) { - output_polygons.add(polygon); + output_polygons.push_back(polygon); } std::vector result_paths = connectGroup(input_paths_); @@ -67,12 +67,12 @@ coord_t PolygonConnector::getWidth(const ExtrusionJunction& junction) const void PolygonConnector::addVertex(Polygon& polygonal, const Point2LL& position, const coord_t) const { - polygonal.add(position); + polygonal.push_back(position); } void PolygonConnector::addVertex(Polygon& polygonal, const Point2LL& vertex) const { - polygonal.add(vertex); + polygonal.push_back(vertex); } void PolygonConnector::addVertex(ExtrusionLine& polygonal, const Point2LL& position, const coord_t width) const diff --git a/src/utils/PolygonsPointIndex.cpp b/src/utils/PolygonsPointIndex.cpp index d41092baba..6a26c2b37b 100644 --- a/src/utils/PolygonsPointIndex.cpp +++ b/src/utils/PolygonsPointIndex.cpp @@ -3,13 +3,24 @@ #include "utils/PolygonsPointIndex.h" +#include "geometry/polygons.h" + namespace cura { template<> -ConstPolygonRef PathsPointIndex::getPolygon() const +const Polygon& PathsPointIndex::getPolygon() const { return (*polygons_)[poly_idx_]; } +std::pair PolygonsPointIndexSegmentLocator::operator()(const PolygonsPointIndex& val) const +{ + const Polygon& poly = (*val.polygons_)[val.poly_idx_]; + Point2LL start = poly[val.point_idx_]; + size_t next_point_idx = (val.point_idx_ + 1ul) % poly.size(); + Point2LL end = poly[next_point_idx]; + return std::pair(start, end); +} + } // namespace cura diff --git a/src/utils/PolylineStitcher.cpp b/src/utils/PolylineStitcher.cpp index 61a3b11594..4fb09b1f9b 100644 --- a/src/utils/PolylineStitcher.cpp +++ b/src/utils/PolylineStitcher.cpp @@ -3,14 +3,15 @@ #include "utils/PolylineStitcher.h" -#include "utils/ExtrusionLine.h" -#include "utils/polygon.h" +#include "utils/ExtrusionLineStitcher.h" +#include "utils/OpenPolylineStitcher.h" +#include "utils/PolygonsPointIndex.h" namespace cura { template<> -bool PolylineStitcher::canReverse(const PathsPointIndex& ppi) +bool ExtrusionLineStitcher::canReverse(const PathsPointIndex& ppi) { if ((*ppi.polygons_)[ppi.poly_idx_].is_odd_) { @@ -22,32 +23,232 @@ bool PolylineStitcher::can } } +template +void PolylineStitcher::stitch( + const InputPaths& lines, + InputPaths& result_lines, + OutputPaths& result_polygons, + coord_t max_stitch_distance, + coord_t snap_distance) +{ + if (lines.empty()) + { + return; + } + + SparsePointGrid, PathsPointIndexLocator> grid(max_stitch_distance, lines.size() * 2); + + // populate grid + for (size_t line_idx = 0; line_idx < lines.size(); line_idx++) + { + const auto line = lines[line_idx]; + grid.insert(PathsPointIndex(&lines, line_idx, 0)); + grid.insert(PathsPointIndex(&lines, line_idx, line.size() - 1)); + } + + std::vector processed(lines.size(), false); + + for (size_t line_idx = 0; line_idx < lines.size(); line_idx++) + { + if (processed[line_idx]) + { + continue; + } + processed[line_idx] = true; + const auto line = lines[line_idx]; + bool should_close = isOdd(line); + + Path chain = line; + bool closest_is_closing_polygon = false; + for (bool go_in_reverse_direction : { false, true }) // first go in the unreversed direction, to try to prevent the chain.reverse() operation. + { // NOTE: Implementation only works for this order; we currently only re-reverse the chain when it's closed. + if (go_in_reverse_direction) + { // try extending chain in the other direction + chain.reverse(); + } + coord_t chain_length = chain.length(); + + while (true) + { + Point2LL from = make_point(chain.back()); + + PathsPointIndex closest; + coord_t closest_distance = std::numeric_limits::max(); + grid.processNearby( + from, + max_stitch_distance, + std::function&)>( + [from, + &chain, + &closest, + &closest_is_closing_polygon, + &closest_distance, + &processed, + &chain_length, + go_in_reverse_direction, + max_stitch_distance, + snap_distance, + should_close](const PathsPointIndex& nearby) -> bool + { + bool is_closing_segment = false; + coord_t dist = vSize(nearby.p() - from); + if (dist > max_stitch_distance) + { + return true; // keep looking + } + if (vSize2(nearby.p() - make_point(chain.front())) < snap_distance * snap_distance) + { + if (chain_length + dist < 3 * max_stitch_distance // prevent closing of small poly, cause it might be able to continue making a larger polyline + || chain.size() <= 2) // don't make 2 vert polygons + { + return true; // look for a better next line + } + is_closing_segment = true; + if (! should_close) + { + dist += 10; // prefer continuing polyline over closing a polygon; avoids closed zigzags from being printed separately + // continue to see if closing segment is also the closest + // there might be a segment smaller than [max_stitch_distance] which closes the polygon better + } + else + { + dist -= 10; // Prefer closing the polygon if it's 100% even lines. Used to create closed contours. + // Continue to see if closing segment is also the closest. + } + } + else if (processed[nearby.poly_idx_]) + { // it was already moved to output + return true; // keep looking for a connection + } + bool nearby_would_be_reversed = nearby.point_idx_ != 0; + nearby_would_be_reversed = nearby_would_be_reversed != go_in_reverse_direction; // flip nearby_would_be_reversed when searching in the reverse direction + if (! canReverse(nearby) && nearby_would_be_reversed) + { // connecting the segment would reverse the polygon direction + return true; // keep looking for a connection + } + if (! canConnect(chain, (*nearby.polygons_)[nearby.poly_idx_])) + { + return true; // keep looking for a connection + } + if (dist < closest_distance) + { + closest_distance = dist; + closest = nearby; + closest_is_closing_polygon = is_closing_segment; + } + if (dist < snap_distance) + { // we have found a good enough next line + return false; // stop looking for alternatives + } + return true; // keep processing elements + })); + + if (! closest.initialized() // we couldn't find any next line + || closest_is_closing_polygon // we closed the polygon + ) + { + break; + } + + + coord_t segment_dist = vSize(make_point(chain.back()) - closest.p()); + assert(segment_dist <= max_stitch_distance + 10); + const size_t old_size = chain.size(); + if (closest.point_idx_ == 0) + { + auto start_pos = (*closest.polygons_)[closest.poly_idx_].begin(); + if (segment_dist < snap_distance) + { + ++start_pos; + } + chain.insert(chain.end(), start_pos, (*closest.polygons_)[closest.poly_idx_].end()); + } + else + { + auto start_pos = (*closest.polygons_)[closest.poly_idx_].rbegin(); + if (segment_dist < snap_distance) + { + ++start_pos; + } + chain.insert(chain.end(), start_pos, (*closest.polygons_)[closest.poly_idx_].rend()); + } + for (size_t i = old_size; i < chain.size(); ++i) // Update chain length. + { + chain_length += vSize(chain[i] - chain[i - 1]); + } + should_close = should_close & ! isOdd((*closest.polygons_)[closest.poly_idx_]); // If we connect an even to an odd line, we should no longer try to close it. + assert(! processed[closest.poly_idx_]); + processed[closest.poly_idx_] = true; + } + + if (closest_is_closing_polygon) + { + if (go_in_reverse_direction) + { // re-reverse chain to retain original direction + // NOTE: not sure if this code could ever be reached, since if a polygon can be closed that should be already possible in the forward direction + chain.reverse(); + } + + break; // don't consider reverse direction + } + } + if (closest_is_closing_polygon) + { + result_polygons.emplace_back(chain); + } + else + { + PathsPointIndex ppi_here(&lines, line_idx, 0); + if (! canReverse(ppi_here)) + { // Since closest_is_closing_polygon is false we went through the second iterations of the for-loop, where go_in_reverse_direction is true + // the polyline isn't allowed to be reversed, so we re-reverse it. + chain.reverse(); + } + result_lines.emplace_back(chain); + } + } +} + +template void OpenPolylineStitcher::stitch( + const LinesSet& lines, + LinesSet& result_lines, + Polygons& result_polygons, + coord_t max_stitch_distance, + coord_t snap_distance); + +template void ExtrusionLineStitcher::stitch( + const VariableWidthLines& lines, + VariableWidthLines& result_lines, + VariableWidthLines& result_polygons, + coord_t max_stitch_distance, + coord_t snap_distance); + template<> -bool PolylineStitcher::canReverse(const PathsPointIndex&) +bool OpenPolylineStitcher::canReverse(const PathsPointIndex>&) { return true; } template<> -bool PolylineStitcher::canConnect(const ExtrusionLine& a, const ExtrusionLine& b) +bool ExtrusionLineStitcher::canConnect(const ExtrusionLine& a, const ExtrusionLine& b) { return a.is_odd_ == b.is_odd_; } template<> -bool PolylineStitcher::canConnect(const Polygon&, const Polygon&) +bool OpenPolylineStitcher::canConnect(const OpenPolyline&, const OpenPolyline&) { return true; } template<> -bool PolylineStitcher::isOdd(const ExtrusionLine& line) +bool ExtrusionLineStitcher::isOdd(const ExtrusionLine& line) { return line.is_odd_; } template<> -bool PolylineStitcher::isOdd(const Polygon&) +bool OpenPolylineStitcher::isOdd(const OpenPolyline&) { return false; } diff --git a/src/utils/SVG.cpp b/src/utils/SVG.cpp index a5ee2c14b8..a4fef6d1f7 100644 --- a/src/utils/SVG.cpp +++ b/src/utils/SVG.cpp @@ -7,9 +7,10 @@ #include +#include "geometry/polygon.h" +#include "geometry/single_shape.h" #include "utils/ExtrusionLine.h" #include "utils/Point3D.h" -#include "utils/polygon.h" namespace cura { @@ -157,10 +158,10 @@ void SVG::writeComment(const std::string& comment) const void SVG::writeAreas(const Polygons& polygons, const ColorObject color, const ColorObject outline_color, const double stroke_width) const { - std::vector parts = polygons.splitIntoParts(); + std::vector parts = polygons.splitIntoParts(); for (auto part_it = parts.rbegin(); part_it != parts.rend(); ++part_it) { - PolygonsPart& part = *part_it; + SingleShape& part = *part_it; for (size_t j = 0; j < part.size(); j++) { fprintf(out_, " #include //Priority queue to prioritise removing unimportant vertices. +#include "geometry/open_polyline.h" + namespace cura { @@ -45,9 +47,10 @@ ExtrusionLine Simplify::polygon(const ExtrusionLine& polygon) const return simplify(polygon, is_closed); } -Polygons Simplify::polyline(const Polygons& polylines) const +template +LinesSet Simplify::polyline(const LinesSet& polylines) const { - Polygons result; + LinesSet result; for (size_t i = 0; i < polylines.size(); ++i) { result.addIfNotEmpty(polyline(polylines[i])); @@ -55,10 +58,24 @@ Polygons Simplify::polyline(const Polygons& polylines) const return result; } -Polygon Simplify::polyline(const Polygon& polyline) const +template LinesSet Simplify::polyline(const LinesSet& polylines) const; + +template<> +Polyline Simplify::polyline(const Polyline& polyline) const { - constexpr bool is_closed = false; - return simplify(polyline, is_closed); + return simplify(polyline, false); +} + +template<> +Polyline Simplify::polyline(const Polyline& polyline) const +{ + return simplify(polyline, true); +} + +template<> +Polyline Simplify::polyline(const Polyline& polyline) const +{ + return simplify(polyline, true); } ExtrusionLine Simplify::polyline(const ExtrusionLine& polyline) const @@ -95,9 +112,10 @@ ExtrusionLine Simplify::createEmpty(const ExtrusionLine& original) const return result; } -void Simplify::appendVertex(Polygon& polygon, const Point2LL& vertex) const +template +void Simplify::appendVertex(Polyline& polygon, const Point2LL& vertex) const { - polygon.add(vertex); + polygon.push_back(vertex); } void Simplify::appendVertex(ExtrusionLine& extrusion_line, const ExtrusionJunction& vertex) const diff --git a/src/utils/ToolpathVisualizer.cpp b/src/utils/ToolpathVisualizer.cpp index 34526f8dca..c8d06c878d 100644 --- a/src/utils/ToolpathVisualizer.cpp +++ b/src/utils/ToolpathVisualizer.cpp @@ -31,7 +31,7 @@ void ToolpathVisualizer::toolpaths(const std::vector& all_segm SVG::ColorObject clr(c, c, c); polys = polys.execute(ClipperLib::pftNonZero); polys = PolygonUtils::connect(polys); - for (PolygonRef connected : polys) + for (const Polygon& connected : polys) svg_.writeAreas(connected, clr, SVG::Color::NONE); if (! rounded_visualization) break; diff --git a/src/utils/VoronoiUtils.cpp b/src/utils/VoronoiUtils.cpp index 564a48e99b..8833974be2 100644 --- a/src/utils/VoronoiUtils.cpp +++ b/src/utils/VoronoiUtils.cpp @@ -8,6 +8,7 @@ #include +#include "geometry/point_matrix.h" #include "utils/linearAlg2D.h" #include "utils/macros.h" diff --git a/src/utils/VoxelUtils.cpp b/src/utils/VoxelUtils.cpp index ddac6713d5..4b9f38db89 100644 --- a/src/utils/VoxelUtils.cpp +++ b/src/utils/VoxelUtils.cpp @@ -97,7 +97,7 @@ bool VoxelUtils::walkLine(Point3LL start, Point3LL end, const std::function& process_cell_func) const { - for (ConstPolygonRef poly : polys) + for (const Polygon& poly : polys) { Point2LL last = poly.back(); for (Point2LL p : poly) diff --git a/src/utils/LinearAlg2D.cpp b/src/utils/linearAlg2D.cpp similarity index 81% rename from src/utils/LinearAlg2D.cpp rename to src/utils/linearAlg2D.cpp index 2292323251..b75b333e0b 100644 --- a/src/utils/LinearAlg2D.cpp +++ b/src/utils/linearAlg2D.cpp @@ -7,7 +7,9 @@ #include #include // atan2 -#include "utils/Point2LL.h" // dot +#include "geometry/point3_matrix.h" +#include "geometry/point_matrix.h" +#include "utils/math.h" namespace cura { @@ -262,4 +264,43 @@ Point2LL LinearAlg2D::getBisectorVector(const Point2LL& intersect, const Point2L return (((a0 * vec_len) / std::max(1LL, vSize(a0))) + ((b0 * vec_len) / std::max(1LL, vSize(b0)))) / 2; } +Point3Matrix LinearAlg2D::rotateAround(const Point2LL& middle, double rotation) +{ + PointMatrix rotation_matrix(rotation); + Point3Matrix rotation_matrix_homogeneous(rotation_matrix); + return Point3Matrix::translate(middle).compose(rotation_matrix_homogeneous).compose(Point3Matrix::translate(-middle)); +} + +bool LinearAlg2D::lineLineIntersection(const Point2LL& a, const Point2LL& b, const Point2LL& c, const Point2LL& d, Point2LL& output) +{ + // Adapted from Apex: https://github.com/Ghostkeeper/Apex/blob/eb75f0d96e36c7193d1670112826842d176d5214/include/apex/line_segment.hpp#L91 + // Adjusted to work with lines instead of line segments. + const Point2LL l1_delta = b - a; + const Point2LL l2_delta = d - c; + const coord_t divisor = cross(l1_delta, l2_delta); // Pre-compute divisor needed for the intersection check. + if (divisor == 0) + { + // The lines are parallel if the cross product of their directions is zero. + return false; + } + + // Create a parametric representation of each line. + // We'll equate the parametric equations to each other to find the intersection then. + // Parametric equation is L = P + Vt (where P and V are a starting point and directional vector). + // We'll map the starting point of one line onto the parameter system of the other line. + // Then using the divisor we can see whether and where they cross. + const Point2LL starts_delta = a - c; + const coord_t l1_parametric = cross(l2_delta, starts_delta); + Point2LL result = a + Point2LL(round_divide_signed(l1_parametric * l1_delta.X, divisor), round_divide_signed(l1_parametric * l1_delta.Y, divisor)); + + if (std::abs(result.X) > std::numeric_limits::max() || std::abs(result.Y) > std::numeric_limits::max()) + { + // Intersection is so far away that it could lead to integer overflows. + // Even though the lines aren't 100% parallel, it's better to pretend they are. They are practically parallel. + return false; + } + output = result; + return true; +} + } // namespace cura diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index 4855f34046..e89f735f04 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -10,6 +10,9 @@ #include +#include "geometry/open_polyline.h" +#include "geometry/point_matrix.h" +#include "geometry/single_shape.h" #include "infill.h" #include "utils/SparsePointGridInclusive.h" #include "utils/linearAlg2D.h" @@ -34,7 +37,7 @@ int64_t PolygonUtils::segmentLength(PolygonsPointIndex start, PolygonsPointIndex assert(start.poly_idx_ == end.poly_idx_); int64_t segment_length = 0; Point2LL prev_vert = start.p(); - ConstPolygonRef poly = (*start.polygons_)[start.poly_idx_]; + const Polygon& poly = start.getPolygon(); for (unsigned int point_idx = 1; point_idx <= poly.size(); point_idx++) { unsigned int vert_idx = (start.point_idx_ + point_idx) % poly.size(); @@ -51,16 +54,16 @@ int64_t PolygonUtils::segmentLength(PolygonsPointIndex start, PolygonsPointIndex return segment_length; } -void PolygonUtils::spreadDots(PolygonsPointIndex start, PolygonsPointIndex end, unsigned int n_dots, std::vector& result) +void PolygonUtils::spreadDots(PolygonsPointIndex start, PolygonsPointIndex end, unsigned int n_dots, std::vector& result) { assert(start.poly_idx_ == end.poly_idx_); int64_t segment_length = segmentLength(start, end); - ConstPolygonRef poly = (*start.polygons_)[start.poly_idx_]; + const Polygon& poly = start.getPolygon(); unsigned int n_dots_in_between = n_dots; if (start == end) { - result.emplace_back(start.p(), start.point_idx_, poly); + result.emplace_back(start.p(), start.point_idx_, &poly); n_dots_in_between--; // generate one less below, because we already pushed a point to the result } @@ -78,7 +81,7 @@ void PolygonUtils::spreadDots(PolygonsPointIndex start, PolygonsPointIndex end, for (; dist_past_vert_to_insert_point < p0p1_length && n_points_generated < n_dots_in_between; dist_past_vert_to_insert_point += wipe_point_dist) { - result.emplace_back(p0 + normal(p0p1, dist_past_vert_to_insert_point), vert.point_idx_, poly); + result.emplace_back(p0 + normal(p0p1, dist_past_vert_to_insert_point), vert.point_idx_, &poly); n_points_generated++; } dist_past_vert_to_insert_point -= p0p1_length; @@ -103,10 +106,10 @@ std::vector PolygonUtils::spreadDotsArea(const Polygons& polygons, Poi Settings dummy_settings; Infill infill_gen(EFillMethod::LINES, false, false, polygons, 0, grid_size.X, 0, 1, 0, 0, 0, 0, 0); Polygons result_polygons; - Polygons result_lines; + LinesSet result_lines; infill_gen.generate(dummy_toolpaths, result_polygons, result_lines, dummy_settings, 0, SectionType::DOTS); // FIXME: @jellespijker make sure the propper layer nr is used std::vector result; - for (PolygonRef line : result_lines) + for (const OpenPolyline& line : result_lines) { assert(line.size() == 2); Point2LL a = line[0]; @@ -179,7 +182,7 @@ bool PolygonUtils::lineSegmentPolygonsIntersection( return closest_dist2 < within_max_dist2; } -Point2LL PolygonUtils::getVertexInwardNormal(ConstPolygonRef poly, unsigned int point_idx) +Point2LL PolygonUtils::getVertexInwardNormal(const Polygon& poly, unsigned int point_idx) { Point2LL p1 = poly[point_idx]; @@ -217,18 +220,19 @@ Point2LL PolygonUtils::getVertexInwardNormal(ConstPolygonRef poly, unsigned int return n; } -Point2LL PolygonUtils::getBoundaryPointWithOffset(ConstPolygonRef poly, unsigned int point_idx, int64_t offset) +Point2LL PolygonUtils::getBoundaryPointWithOffset(const Polygon& poly, unsigned int point_idx, int64_t offset) { return poly[point_idx] + normal(getVertexInwardNormal(poly, point_idx), -offset); } -Point2LL PolygonUtils::moveInsideDiagonally(ClosestPolygonPoint point_on_boundary, int64_t inset) +Point2LL PolygonUtils::moveInsideDiagonally(ClosestPoint point_on_boundary, int64_t inset) { if (! point_on_boundary.isValid()) { return no_point; } - ConstPolygonRef poly = **point_on_boundary.poly_; +#warning Check that it does not actually copy the pointsset to the polygon object + const Polygon& poly = *point_on_boundary.poly_; Point2LL p0 = poly[point_on_boundary.point_idx_]; Point2LL p1 = poly[(point_on_boundary.point_idx_ + 1) % poly.size()]; if (vSize2(p0 - point_on_boundary.location_) < vSize2(p1 - point_on_boundary.location_)) @@ -246,7 +250,7 @@ unsigned int PolygonUtils::moveOutside(const Polygons& polygons, Point2LL& from, return moveInside(polygons, from, -distance, maxDist2); } -ClosestPolygonPoint PolygonUtils::moveInside2( +ClosestPoint PolygonUtils::moveInside2( const Polygons& polygons, Point2LL& from, const int distance, @@ -255,7 +259,7 @@ ClosestPolygonPoint PolygonUtils::moveInside2( const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) { - std::optional closest_polygon_point; + std::optional closest_polygon_point; if (loc_to_line_grid) { closest_polygon_point = findClose(from, *loc_to_line_polygons, *loc_to_line_grid, penalty_function); @@ -267,16 +271,16 @@ ClosestPolygonPoint PolygonUtils::moveInside2( return _moveInside2(*closest_polygon_point, distance, from, max_dist2); } -ClosestPolygonPoint PolygonUtils::moveInside2( +ClosestPoint PolygonUtils::moveInside2( const Polygons& loc_to_line_polygons, - ConstPolygonRef polygon, + const Polygon& polygon, Point2LL& from, const int distance, const int64_t max_dist2, const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) { - std::optional closest_polygon_point; + std::optional closest_polygon_point; if (loc_to_line_grid) { closest_polygon_point = findClose(from, loc_to_line_polygons, *loc_to_line_grid, penalty_function); @@ -288,11 +292,11 @@ ClosestPolygonPoint PolygonUtils::moveInside2( return _moveInside2(*closest_polygon_point, distance, from, max_dist2); } -ClosestPolygonPoint PolygonUtils::_moveInside2(const ClosestPolygonPoint& closest_polygon_point, const int distance, Point2LL& from, const int64_t max_dist2) +ClosestPoint PolygonUtils::_moveInside2(const ClosestPoint& closest_polygon_point, const int distance, Point2LL& from, const int64_t max_dist2) { if (! closest_polygon_point.isValid()) { - return ClosestPolygonPoint(); // stub with invalid indices to signify we haven't found any + return ClosestPoint(); // stub with invalid indices to signify we haven't found any } const Point2LL v_boundary_from = from - closest_polygon_point.location_; Point2LL result = moveInside(closest_polygon_point, distance); @@ -314,7 +318,7 @@ ClosestPolygonPoint PolygonUtils::_moveInside2(const ClosestPolygonPoint& closes { if (vSize2(v_boundary_from) > max_dist2) { - return ClosestPolygonPoint(*closest_polygon_point.poly_); // stub with invalid indices to signify we haven't found any + return ClosestPoint(closest_polygon_point.poly_); // stub with invalid indices to signify we haven't found any } else { @@ -335,7 +339,7 @@ size_t PolygonUtils::moveInside(const Polygons& polygons, Point2LL& from, int di bool is_already_on_correct_side_of_boundary = false; // whether [from] is already on the right side of the boundary for (size_t poly_idx = 0; poly_idx < polygons.size(); poly_idx++) { - ConstPolygonRef poly = polygons[poly_idx]; + const Polygon& poly = polygons[poly_idx]; if (poly.size() < 2) continue; Point2LL p0 = poly[poly.size() - 2]; @@ -447,7 +451,7 @@ size_t PolygonUtils::moveInside(const Polygons& polygons, Point2LL& from, int di } // Version that works on single PolygonRef. -unsigned int PolygonUtils::moveInside(const ConstPolygonRef polygon, Point2LL& from, int distance, int64_t maxDist2) +unsigned int PolygonUtils::moveInside(const Polygon& polygon, Point2LL& from, int distance, int64_t maxDist2) { // TODO: This is copied from the moveInside of Polygons. /* @@ -565,12 +569,12 @@ unsigned int PolygonUtils::moveInside(const ConstPolygonRef polygon, Point2LL& f return 0; } -Point2LL PolygonUtils::moveOutside(const ClosestPolygonPoint& cpp, const int distance) +Point2LL PolygonUtils::moveOutside(const ClosestPoint& cpp, const int distance) { return moveInside(cpp, -distance); } -Point2LL PolygonUtils::moveInside(const ClosestPolygonPoint& cpp, const int distance) +Point2LL PolygonUtils::moveInside(const ClosestPoint& cpp, const int distance) { if (! cpp.isValid()) { @@ -580,7 +584,7 @@ Point2LL PolygonUtils::moveInside(const ClosestPolygonPoint& cpp, const int dist { // the point which is assumed to be on the boundary doesn't have to be moved return cpp.location_; } - ConstPolygonRef poly = *cpp.poly_; + const Polygon& poly = *cpp.poly_; unsigned int point_idx = cpp.point_idx_; const Point2LL& on_boundary = cpp.location_; @@ -616,7 +620,7 @@ Point2LL PolygonUtils::moveInside(const ClosestPolygonPoint& cpp, const int dist } } -ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside( +ClosestPoint PolygonUtils::ensureInsideOrOutside( const Polygons& polygons, Point2LL& from, int preferred_dist_inside, @@ -625,14 +629,14 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside( const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) { - const ClosestPolygonPoint closest_polygon_point = moveInside2(polygons, from, preferred_dist_inside, max_dist2, loc_to_line_polygons, loc_to_line_grid, penalty_function); + const ClosestPoint closest_polygon_point = moveInside2(polygons, from, preferred_dist_inside, max_dist2, loc_to_line_polygons, loc_to_line_grid, penalty_function); return ensureInsideOrOutside(polygons, from, closest_polygon_point, preferred_dist_inside, loc_to_line_polygons, loc_to_line_grid, penalty_function); } -ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside( +ClosestPoint PolygonUtils::ensureInsideOrOutside( const Polygons& polygons, Point2LL& from, - const ClosestPolygonPoint& closest_polygon_point, + const ClosestPoint& closest_polygon_point, int preferred_dist_inside, const Polygons* loc_to_line_polygons, const LocToLineGrid* loc_to_line_grid, @@ -640,9 +644,9 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside( { if (! closest_polygon_point.isValid()) { - return ClosestPolygonPoint(); // we couldn't move inside + return ClosestPoint(); // we couldn't move inside } - ConstPolygonRef closest_poly = *closest_polygon_point.poly_; + const Polygon& closest_poly = *closest_polygon_point.poly_; bool is_outside_boundary = closest_poly.orientation(); { @@ -674,9 +678,9 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside( = closest_poly.offset(offset / 2); // perform less inset, because chances are (thin parts of) the polygon will disappear, given that moveInside did an overshoot if (insetted.size() == 0) { - return ClosestPolygonPoint(); // we couldn't move inside + return ClosestPoint(); // we couldn't move inside } - ClosestPolygonPoint inside = findClosest(from, insetted, penalty_function); + ClosestPoint inside = findClosest(from, insetted, penalty_function); if (inside.isValid()) { bool is_inside = polygons.inside(inside.location_); @@ -685,7 +689,7 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside( // Insetting from the reference polygon ended up outside another polygon. // Perform an offset on all polygons instead. Polygons all_insetted = polygons.offset(-preferred_dist_inside); - ClosestPolygonPoint overall_inside = findClosest(from, all_insetted, penalty_function); + ClosestPoint overall_inside = findClosest(from, all_insetted, penalty_function); bool overall_is_inside = polygons.inside(overall_inside.location_); if (overall_is_inside != (preferred_dist_inside > 0)) { @@ -733,24 +737,24 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside( has_run = true; } #endif - return ClosestPolygonPoint(); + return ClosestPoint(); } inside = overall_inside; } from = inside.location_; } // otherwise we just return the closest polygon point without modifying the from location - return closest_polygon_point; // don't return a ClosestPolygonPoint with a reference to the above local polygons variable + return closest_polygon_point; // don't return a ClosestPoint with a reference to the above local polygons variable } } -void PolygonUtils::walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_result, ClosestPolygonPoint& poly2_result) +void PolygonUtils::walkToNearestSmallestConnection(ClosestPoint& poly1_result, ClosestPoint& poly2_result) { if (! poly1_result.isValid() || ! poly2_result.isValid()) { return; } - ConstPolygonRef poly1 = *poly1_result.poly_; - ConstPolygonRef poly2 = *poly2_result.poly_; + const Polygon& poly1 = *poly1_result.poly_; + const Polygon& poly2 = *poly2_result.poly_; size_t poly1_idx = poly1_result.poly_idx_; size_t poly2_idx = poly2_result.poly_idx_; if (poly1_result.point_idx_ == NO_INDEX || poly2_result.point_idx_ == NO_INDEX) @@ -781,10 +785,10 @@ void PolygonUtils::walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_re // o o >> should find connection here coord_t best_distance2 = vSize2(poly1_result.p() - poly2_result.p()); auto check_neighboring_vert - = [&best_distance2](ConstPolygonRef from_poly, ConstPolygonRef to_poly, ClosestPolygonPoint& from_poly_result, ClosestPolygonPoint& to_poly_result, bool vertex_after) + = [&best_distance2](const Polygon& from_poly, const Polygon& to_poly, ClosestPoint& from_poly_result, ClosestPoint& to_poly_result, bool vertex_after) { const Point2LL after_poly2_result = to_poly[(to_poly_result.point_idx_ + vertex_after) % to_poly.size()]; - const ClosestPolygonPoint poly1_after_poly2_result = findNearestClosest(after_poly2_result, from_poly, from_poly_result.point_idx_); + const ClosestPoint poly1_after_poly2_result = findNearestClosest(after_poly2_result, from_poly, from_poly_result.point_idx_); const coord_t poly1_after_poly2_result_dist2 = vSize2(poly1_after_poly2_result.p() - after_poly2_result); if (poly1_after_poly2_result_dist2 < best_distance2) { @@ -802,14 +806,14 @@ void PolygonUtils::walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_re poly2_result.poly_idx_ = poly2_idx; } -ClosestPolygonPoint PolygonUtils::findNearestClosest(Point2LL from, ConstPolygonRef polygon, int start_idx) +ClosestPoint PolygonUtils::findNearestClosest(Point2LL from, const Polygon& polygon, int start_idx) { - ClosestPolygonPoint forth = findNearestClosest(from, polygon, start_idx, 1); + ClosestPoint forth = findNearestClosest(from, polygon, start_idx, 1); if (! forth.isValid()) { return forth; // stop computation } - ClosestPolygonPoint back = findNearestClosest(from, polygon, start_idx, -1); + ClosestPoint back = findNearestClosest(from, polygon, start_idx, -1); assert(back.isValid()); if (vSize2(forth.location_ - from) < vSize2(back.location_ - from)) { @@ -821,11 +825,11 @@ ClosestPolygonPoint PolygonUtils::findNearestClosest(Point2LL from, ConstPolygon } } -ClosestPolygonPoint PolygonUtils::findNearestClosest(Point2LL from, ConstPolygonRef polygon, int start_idx, int direction) +ClosestPoint PolygonUtils::findNearestClosest(Point2LL from, const Polygon& polygon, int start_idx, int direction) { if (polygon.size() == 0) { - return ClosestPolygonPoint(polygon); + return ClosestPoint(&polygon); } Point2LL aPoint = polygon[0]; Point2LL best = aPoint; @@ -851,28 +855,28 @@ ClosestPolygonPoint PolygonUtils::findNearestClosest(Point2LL from, ConstPolygon } else { - return ClosestPolygonPoint(best, bestPos, polygon); + return ClosestPoint(best, bestPos, &polygon); } } - return ClosestPolygonPoint(best, bestPos, polygon); + return ClosestPoint(best, bestPos, &polygon); } -ClosestPolygonPoint PolygonUtils::findClosest(Point2LL from, const Polygons& polygons, const std::function& penalty_function) +ClosestPoint PolygonUtils::findClosest(Point2LL from, const Polygons& polygons, const std::function& penalty_function) { - ClosestPolygonPoint none; + ClosestPoint none; if (polygons.size() == 0) { return none; } - ConstPolygonPointer any_polygon = polygons[0]; + const Polygon* any_polygon = &(polygons[0]); unsigned int any_poly_idx; for (any_poly_idx = 0; any_poly_idx < polygons.size(); any_poly_idx++) { // find first point in all polygons if (polygons[any_poly_idx].size() > 0) { - any_polygon = polygons[any_poly_idx]; + any_polygon = &(polygons[any_poly_idx]); break; } } @@ -880,16 +884,16 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point2LL from, const Polygons& pol { return none; } - ClosestPolygonPoint best((*any_polygon)[0], 0, *any_polygon, any_poly_idx); + ClosestPoint best((*any_polygon)[0], 0, any_polygon, any_poly_idx); int64_t closestDist2_score = vSize2(from - best.location_) + penalty_function(best.location_); for (unsigned int ply = 0; ply < polygons.size(); ply++) { - ConstPolygonRef poly = polygons[ply]; + const Polygon& poly = polygons[ply]; if (poly.size() == 0) continue; - ClosestPolygonPoint closest_here = findClosest(from, poly, penalty_function); + ClosestPoint closest_here = findClosest(from, poly, penalty_function); if (! closest_here.isValid()) { continue; @@ -906,11 +910,11 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point2LL from, const Polygons& pol return best; } -ClosestPolygonPoint PolygonUtils::findClosest(Point2LL from, ConstPolygonRef polygon, const std::function& penalty_function) +ClosestPoint PolygonUtils::findClosest(Point2LL from, const Polygon& polygon, const std::function& penalty_function) { if (polygon.size() == 0) { - return ClosestPolygonPoint(polygon); + return ClosestPoint(&polygon); } Point2LL aPoint = polygon[0]; Point2LL best = aPoint; @@ -937,7 +941,7 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point2LL from, ConstPolygonRef pol } } - return ClosestPolygonPoint(best, bestPos, polygon); + return ClosestPoint(best, bestPos, &polygon); } PolygonsPointIndex PolygonUtils::findNearestVert(const Point2LL from, const Polygons& polys) @@ -946,7 +950,7 @@ PolygonsPointIndex PolygonUtils::findNearestVert(const Point2LL from, const Poly PolygonsPointIndex closest_vert; for (unsigned int poly_idx = 0; poly_idx < polys.size(); poly_idx++) { - ConstPolygonRef poly = polys[poly_idx]; + const Polygon& poly = polys[poly_idx]; for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++) { int64_t dist2 = vSize2(poly[point_idx] - from); @@ -960,7 +964,7 @@ PolygonsPointIndex PolygonUtils::findNearestVert(const Point2LL from, const Poly return closest_vert; } -unsigned int PolygonUtils::findNearestVert(const Point2LL from, ConstPolygonRef poly) +unsigned int PolygonUtils::findNearestVert(const Point2LL from, const Polygon& poly) { int64_t best_dist2 = std::numeric_limits::max(); unsigned int closest_vert_idx = -1; @@ -988,7 +992,7 @@ std::unique_ptr PolygonUtils::createLocToLineGrid(const Polygons& for (unsigned int poly_idx = 0; poly_idx < polygons.size(); poly_idx++) { - ConstPolygonRef poly = polygons[poly_idx]; + const Polygon& poly = polygons[poly_idx]; for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++) { ret->insert(PolygonsPointIndex(&polygons, poly_idx, point_idx)); @@ -1004,8 +1008,7 @@ std::unique_ptr PolygonUtils::createLocToLineGrid(const Polygons& * * We could skip the duplication by keeping a vector of vectors of bools. */ -std::optional - PolygonUtils::findClose(Point2LL from, const Polygons& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function) +std::optional PolygonUtils::findClose(Point2LL from, const Polygons& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function) { std::vector near_lines = loc_to_line.getNearby(from, loc_to_line.getCellSize()); @@ -1015,7 +1018,7 @@ std::optional PolygonsPointIndex best_point_poly_idx(nullptr, NO_INDEX, NO_INDEX); for (PolygonsPointIndex& point_poly_index : near_lines) { - ConstPolygonRef poly = polygons[point_poly_index.poly_idx_]; + const Polygon& poly = polygons[point_poly_index.poly_idx_]; const Point2LL& p1 = poly[point_poly_index.point_idx_]; const Point2LL& p2 = poly[(point_poly_index.point_idx_ + 1) % poly.size()]; @@ -1030,28 +1033,28 @@ std::optional } if (best_point_poly_idx.poly_idx_ == NO_INDEX) { - return std::optional(); + return std::optional(); } else { - return std::optional(std::in_place, best, best_point_poly_idx.point_idx_, polygons[best_point_poly_idx.poly_idx_], best_point_poly_idx.poly_idx_); + return std::optional(std::in_place, best, best_point_poly_idx.point_idx_, &(polygons[best_point_poly_idx.poly_idx_]), best_point_poly_idx.poly_idx_); } } -std::vector> - PolygonUtils::findClose(ConstPolygonRef from, const Polygons& destination, const LocToLineGrid& destination_loc_to_line, const std::function& penalty_function) +std::vector> + PolygonUtils::findClose(const Polygon& from, const Polygons& destination, const LocToLineGrid& destination_loc_to_line, const std::function& penalty_function) { - std::vector> ret; + std::vector> ret; int p0_idx = from.size() - 1; Point2LL p0(from[p0_idx]); int grid_size = destination_loc_to_line.getCellSize(); for (unsigned int p1_idx = 0; p1_idx < from.size(); p1_idx++) { const Point2LL& p1 = from[p1_idx]; - std::optional best_here = findClose(p1, destination, destination_loc_to_line, penalty_function); + std::optional best_here = findClose(p1, destination, destination_loc_to_line, penalty_function); if (best_here) { - ret.push_back(std::make_pair(ClosestPolygonPoint(p1, p1_idx, from), *best_here)); + ret.push_back(std::make_pair(ClosestPoint(p1, p1_idx, &from), *best_here)); } Point2LL p0p1 = p1 - p0; int dist_to_p1 = vSize(p0p1); @@ -1063,7 +1066,7 @@ std::vector> best_here = findClose(x, destination, destination_loc_to_line, penalty_function); if (best_here) { - ret.push_back(std::make_pair(ClosestPolygonPoint(x, p0_idx, from), *best_here)); + ret.push_back(std::make_pair(ClosestPoint(x, p0_idx, &from), *best_here)); } } p0 = p1; @@ -1072,7 +1075,7 @@ std::vector> return ret; } -bool PolygonUtils::getNextPointWithDistance(Point2LL from, int64_t dist, ConstPolygonRef poly, int start_idx, int poly_start_idx, GivenDistPoint& result) +bool PolygonUtils::getNextPointWithDistance(Point2LL from, int64_t dist, const Polygon& poly, int start_idx, int poly_start_idx, GivenDistPoint& result) { Point2LL prev_poly_point = poly[(start_idx + poly_start_idx) % poly.size()]; @@ -1146,9 +1149,9 @@ bool PolygonUtils::getNextPointWithDistance(Point2LL from, int64_t dist, ConstPo return false; } -ClosestPolygonPoint PolygonUtils::walk(const ClosestPolygonPoint& from, coord_t distance) +ClosestPoint PolygonUtils::walk(const ClosestPoint& from, coord_t distance) { - ConstPolygonRef poly = *from.poly_; + const Polygon& poly = *from.poly_; Point2LL last_vertex = from.p(); Point2LL next_vertex; size_t last_point_idx = from.point_idx_; @@ -1166,10 +1169,10 @@ ClosestPolygonPoint PolygonUtils::walk(const ClosestPolygonPoint& from, coord_t last_point_idx = point_idx; } Point2LL result = next_vertex + normal(last_vertex - next_vertex, -distance); - return ClosestPolygonPoint(result, last_point_idx, poly, from.poly_idx_); + return ClosestPoint(result, last_point_idx, &poly, from.poly_idx_); } -std::optional PolygonUtils::getNextParallelIntersection(const ClosestPolygonPoint& start, const Point2LL& line_to, const coord_t dist, const bool forward) +std::optional PolygonUtils::getNextParallelIntersection(const ClosestPoint& start, const Point2LL& line_to, const coord_t dist, const bool forward) { // <--o--t-----y----< poly 1 // : : @@ -1183,7 +1186,7 @@ std::optional PolygonUtils::getNextParallelIntersection(con // r=result // t=line_to - ConstPolygonRef poly = *start.poly_; + const Polygon& poly = *start.poly_; const Point2LL s = start.p(); const Point2LL t = line_to; @@ -1217,14 +1220,14 @@ std::optional PolygonUtils::getNextParallelIntersection(con vert_before_idx = (next_point_idx > 0) ? vert_before_idx - 1 : poly.size() - 1; } assert(vert_before_idx < poly.size()); - return ClosestPolygonPoint(intersection, vert_before_idx, poly); + return ClosestPoint(intersection, vert_before_idx, &poly); } prev_vert = next_vert; prev_projected = projected; } - return std::optional(); + return std::optional(); } @@ -1267,7 +1270,7 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const Point2LL from, const Poi } bool PolygonUtils::polygonCollidesWithLineSegment( - ConstPolygonRef poly, + const Polygon& poly, const Point2LL& transformed_startPoint, const Point2LL& transformed_endPoint, PointMatrix transformation_matrix) @@ -1285,7 +1288,7 @@ bool PolygonUtils::polygonCollidesWithLineSegment( return false; } -bool PolygonUtils::polygonCollidesWithLineSegment(ConstPolygonRef poly, const Point2LL& startPoint, const Point2LL& endPoint) +bool PolygonUtils::polygonCollidesWithLineSegment(const Polygon& poly, const Point2LL& startPoint, const Point2LL& endPoint) { Point2LL diff = endPoint - startPoint; @@ -1302,7 +1305,7 @@ bool PolygonUtils::polygonCollidesWithLineSegment( const Point2LL& transformed_endPoint, PointMatrix transformation_matrix) { - for (ConstPolygonRef poly : polys) + for (const Polygon& poly : polys) { if (poly.size() == 0) { @@ -1333,7 +1336,7 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, const P return polygonCollidesWithLineSegment(polys, transformed_startPoint, transformed_endPoint, transformation_matrix); } -bool PolygonUtils::polygonsIntersect(const ConstPolygonRef& poly_a, const ConstPolygonRef& poly_b) +bool PolygonUtils::polygonsIntersect(const Polygon& poly_a, const Polygon& poly_b) { // only do the full intersection when the polys' BBs overlap AABB bba(poly_a); @@ -1341,7 +1344,7 @@ bool PolygonUtils::polygonsIntersect(const ConstPolygonRef& poly_a, const ConstP return bba.hit(bbb) && poly_a.intersection(poly_b).size() > 0; } -bool PolygonUtils::polygonOutlinesAdjacent(const ConstPolygonRef inner_poly, const ConstPolygonRef outer_poly, const coord_t max_gap) +bool PolygonUtils::polygonOutlinesAdjacent(const Polygon& inner_poly, const Polygon& outer_poly, const coord_t max_gap) { // Heuristic check if their AABBs are near first. AABB inner_aabb(inner_poly); @@ -1373,8 +1376,8 @@ bool PolygonUtils::polygonOutlinesAdjacent(const ConstPolygonRef inner_poly, con void PolygonUtils::findAdjacentPolygons( std::vector& adjacent_poly_indices, - const ConstPolygonRef& poly, - const std::vector& possible_adjacent_polys, + const Polygon& poly, + const std::vector& possible_adjacent_polys, const coord_t max_gap) { // given a polygon, and a vector of polygons, return a vector containing the indices of the polygons that are adjacent to the given polygon @@ -1397,7 +1400,7 @@ double PolygonUtils::relativeHammingDistance(const Polygons& poly_a, const Polyg constexpr bool borders_allowed = true; if (total_area == 0.0) { - for (const ConstPolygonRef& polygon_a : poly_a) + for (const Polygon& polygon_a : poly_a) { for (Point2LL point : polygon_a) { @@ -1407,7 +1410,7 @@ double PolygonUtils::relativeHammingDistance(const Polygons& poly_a, const Polyg } } } - for (const ConstPolygonRef& polygon_b : poly_b) + for (const Polygon& polygon_b : poly_b) { for (Point2LL point : polygon_b) { @@ -1439,15 +1442,15 @@ Polygon PolygonUtils::makeCircle(const Point2LL mid, const coord_t radius, const Polygons PolygonUtils::connect(const Polygons& input) { Polygons ret; - std::vector parts = input.splitIntoParts(true); - for (PolygonsPart& part : parts) + std::vector parts = input.splitIntoParts(true); + for (SingleShape& part : parts) { - PolygonRef outline = part.outerPolygon(); + Polygon& outline = part.outerPolygon(); for (size_t hole_idx = 1; hole_idx < part.size(); hole_idx++) { - PolygonRef hole = part[hole_idx]; + Polygon& hole = part[hole_idx]; Point2LL hole_point = hole[0]; - hole.add(hole_point); + hole.push_back(hole_point); // find where the scanline passes the Y size_t best_segment_to_idx = 0; coord_t best_dist = std::numeric_limits::max(); @@ -1470,21 +1473,21 @@ Polygons PolygonUtils::connect(const Polygons& input) } prev = here; } - (*outline).insert(outline.begin() + best_segment_to_idx, 2, best_intersection_point); - (*outline).insert(outline.begin() + best_segment_to_idx + 1, hole.begin(), hole.end()); + outline.insert(outline.begin() + best_segment_to_idx, 2, best_intersection_point); + outline.insert(outline.begin() + best_segment_to_idx + 1, hole.begin(), hole.end()); } - ret.add(outline); + ret.push_back(outline); } return ret; } /* Note: Also tries to solve for near-self intersections, when epsilon >= 1 */ -void PolygonUtils::fixSelfIntersections(const coord_t epsilon, Polygons& thiss) +void PolygonUtils::fixSelfIntersections(const coord_t epsilon, Polygons& polygon) { if (epsilon < 1) { - ClipperLib::SimplifyPolygons(thiss.paths); + ClipperLib::SimplifyPolygons(polygon.getCallable()); return; } @@ -1493,32 +1496,32 @@ void PolygonUtils::fixSelfIntersections(const coord_t epsilon, Polygons& thiss) // Points too close to line segments should be moved a little away from those line segments, but less than epsilon, // so at least half-epsilon distance between points can still be guaranteed. constexpr coord_t grid_size = 2000; - auto query_grid = PolygonUtils::createLocToLineGrid(thiss, grid_size); + auto query_grid = PolygonUtils::createLocToLineGrid(polygon, grid_size); const coord_t move_dist = half_epsilon - 2; const coord_t half_epsilon_sqrd = half_epsilon * half_epsilon; - const size_t n = thiss.size(); + const size_t n = polygon.size(); for (size_t poly_idx = 0; poly_idx < n; poly_idx++) { - const size_t pathlen = thiss[poly_idx].size(); + const size_t pathlen = polygon[poly_idx].size(); for (size_t point_idx = 0; point_idx < pathlen; ++point_idx) { - Point2LL& pt = thiss[poly_idx][point_idx]; + Point2LL& pt = polygon[poly_idx][point_idx]; for (const auto& line : query_grid->getNearby(pt, epsilon * 2)) { - const size_t line_next_idx = (line.point_idx_ + 1) % thiss[line.poly_idx_].size(); + const size_t line_next_idx = (line.point_idx_ + 1) % polygon[line.poly_idx_].size(); if (poly_idx == line.poly_idx_ && (point_idx == line.point_idx_ || point_idx == line_next_idx)) { continue; } - const Point2LL& a = thiss[line.poly_idx_][line.point_idx_]; - const Point2LL& b = thiss[line.poly_idx_][line_next_idx]; + const Point2LL& a = polygon[line.poly_idx_][line.point_idx_]; + const Point2LL& b = polygon[line.poly_idx_][line_next_idx]; if (half_epsilon_sqrd >= vSize2(pt - LinearAlg2D::getClosestOnLineSegment(pt, a, b))) { - const Point2LL& other = thiss[poly_idx][(point_idx + 1) % pathlen]; + const Point2LL& other = polygon[poly_idx][(point_idx + 1) % pathlen]; const Point2LL vec = LinearAlg2D::pointIsLeftOfLine(other, a, b) > 0 ? b - a : a - b; const coord_t len = vSize(vec); pt.X += (-vec.Y * move_dist) / len; @@ -1528,22 +1531,22 @@ void PolygonUtils::fixSelfIntersections(const coord_t epsilon, Polygons& thiss) } } - ClipperLib::SimplifyPolygons(thiss.paths); + ClipperLib::SimplifyPolygons(polygon.getCallable()); } -Polygons PolygonUtils::unionManySmall(const Polygons& p) +Polygons PolygonUtils::unionManySmall(const Polygons& polygon) { - if (p.paths.size() < 8) + if (polygon.size() < 8) { - return p.unionPolygons(); + return polygon.unionPolygons(); } Polygons a, b; - a.paths.reserve(p.paths.size() / 2); - b.paths.reserve(a.paths.size() + 1); - for (const auto& [i, path] : p.paths | ranges::views::enumerate) + a.reserve(polygon.size() / 2); + b.reserve(a.size() + 1); + for (const auto& [i, path] : polygon | ranges::views::enumerate) { - (i % 2 == 0 ? b : a).paths.push_back(path); + (i % 2 == 0 ? b : a).push_back(path); } return unionManySmall(a).unionPolygons(unionManySmall(b)); } @@ -1589,7 +1592,7 @@ Polygons PolygonUtils::clipPolygonWithAABB(const Polygons& src, const AABB& aabb // the edge possibly cuts corner of the bounding box. (sides_prev & sides_this & sides_next) == 0) { - poly.add(path[i]); + poly.push_back(path[i]); sides_prev = sides_this; } else @@ -1607,12 +1610,12 @@ Polygons PolygonUtils::clipPolygonWithAABB(const Polygons& src, const AABB& aabb if (sides_this == 0 || // The last point is inside. Take it. (sides_prev & sides_this & sides_next) == 0) // Either this point is outside and previous or next is inside, or the edge possibly cuts corner of the bounding box. - poly.add(path.back()); + poly.push_back(path.back()); } if (! poly.empty()) { - out.add(poly); + out.push_back(poly); } } return out; diff --git a/stress_benchmark/stress_benchmark.cpp b/stress_benchmark/stress_benchmark.cpp index c2dc5614bf..ee2d80b584 100644 --- a/stress_benchmark/stress_benchmark.cpp +++ b/stress_benchmark/stress_benchmark.cpp @@ -25,7 +25,7 @@ #include "rapidjson/writer.h" #include "settings/Settings.h" #include "sliceDataStorage.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" constexpr std::string_view USAGE = R"(Stress Benchmark. diff --git a/tests/ClipperTest.cpp b/tests/ClipperTest.cpp index 14e54ac6ed..e88990e7d4 100644 --- a/tests/ClipperTest.cpp +++ b/tests/ClipperTest.cpp @@ -9,7 +9,7 @@ // #define TEST_INFILL_SVG_OUTPUT #ifdef TEST_INFILL_SVG_OUTPUT #include "utils/SVG.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" #include #endif // TEST_INFILL_SVG_OUTPUT diff --git a/tests/InfillTest.cpp b/tests/InfillTest.cpp index 8d95705934..aa95cab94c 100644 --- a/tests/InfillTest.cpp +++ b/tests/InfillTest.cpp @@ -2,20 +2,24 @@ // CuraEngine is released under the terms of the AGPLv3 or higher #include "infill.h" -#include "ReadTestPolygons.h" -#include "slicer.h" -#include "utils/Coord_t.h" -#include + #include #include -#include +#include #include +#include + +#include "ReadTestPolygons.h" +#include "slicer.h" +#include "utils/Coord_t.h" + // #define TEST_INFILL_SVG_OUTPUT #ifdef TEST_INFILL_SVG_OUTPUT -#include "utils/SVG.h" #include + +#include "utils/SVG.h" #endif // TEST_INFILL_SVG_OUTPUT // NOLINTBEGIN(*-magic-numbers) @@ -77,7 +81,11 @@ class InfillTestParameters std::string name; - InfillTestParameters() : valid(false), fail_reason("Read of file with test polygons failed (see generateInfillTests), can't continue tests."), params(InfillParameters(EFillMethod::NONE, false, false, 0)), name("UNNAMED") + InfillTestParameters() + : valid(false) + , fail_reason("Read of file with test polygons failed (see generateInfillTests), can't continue tests.") + , params(InfillParameters(EFillMethod::NONE, false, false, 0)) + , name("UNNAMED") { } @@ -89,7 +97,13 @@ class InfillTestParameters , result_lines(std::move(result_lines)) , result_polygons(std::move(result_polygons)) { - name = fmt::format("InfillTestParameters_P{:d}_Z{:d}_C{:d}_L{:d}__{:d}", static_cast(params.pattern), params.zig_zagify, params.connect_polygons, params.line_distance, test_polygon_id); + name = fmt::format( + "InfillTestParameters_P{:d}_Z{:d}_C{:d}_L{:d}__{:d}", + static_cast(params.pattern), + params.zig_zagify, + params.connect_polygons, + params.line_distance, + test_polygon_id); } friend std::ostream& operator<<(std::ostream& os, const InfillTestParameters& params) @@ -108,11 +122,12 @@ constexpr coord_t Z = 100; // Future improvement: Also take an uneven layer, so constexpr coord_t SHIFT = 0; constexpr coord_t MAX_RESOLUTION = 10; constexpr coord_t MAX_DEVIATION = 5; -const std::vector POLYGON_FILENAMES = { - std::filesystem::path(__FILE__).parent_path().append("resources/polygon_concave.txt").string(), std::filesystem::path(__FILE__).parent_path().append("resources/polygon_concave_hole.txt").string(), - std::filesystem::path(__FILE__).parent_path().append("resources/polygon_square.txt").string(), std::filesystem::path(__FILE__).parent_path().append("resources/polygon_square_hole.txt").string(), - std::filesystem::path(__FILE__).parent_path().append("resources/polygon_triangle.txt").string(), std::filesystem::path(__FILE__).parent_path().append("resources/polygon_two_squares.txt").string() -}; +const std::vector POLYGON_FILENAMES = { std::filesystem::path(__FILE__).parent_path().append("resources/polygon_concave.txt").string(), + std::filesystem::path(__FILE__).parent_path().append("resources/polygon_concave_hole.txt").string(), + std::filesystem::path(__FILE__).parent_path().append("resources/polygon_square.txt").string(), + std::filesystem::path(__FILE__).parent_path().append("resources/polygon_square_hole.txt").string(), + std::filesystem::path(__FILE__).parent_path().append("resources/polygon_triangle.txt").string(), + std::filesystem::path(__FILE__).parent_path().append("resources/polygon_two_squares.txt").string() }; #ifdef TEST_INFILL_SVG_OUTPUT void writeTestcaseSVG(const InfillTestParameters& params) @@ -144,19 +159,20 @@ InfillTestParameters generateInfillToTest(const InfillParameters& params, const const bool connect_polygons = params.connect_polygons; const coord_t line_distance = params.line_distance; - Infill infill(pattern, - zig_zagify, - connect_polygons, - outline_polygons, - INFILL_LINE_WIDTH, - line_distance, - INFILL_OVERLAP, - INFILL_MULTIPLIER, - FILL_ANGLE, - Z, - SHIFT, - MAX_RESOLUTION, - MAX_DEVIATION); // There are some optional parameters, but these will do for now (future improvement?). + Infill infill( + pattern, + zig_zagify, + connect_polygons, + outline_polygons, + INFILL_LINE_WIDTH, + line_distance, + INFILL_OVERLAP, + INFILL_MULTIPLIER, + FILL_ANGLE, + Z, + SHIFT, + MAX_RESOLUTION, + MAX_DEVIATION); // There are some optional parameters, but these will do for now (future improvement?). Settings infill_settings; std::vector result_paths; @@ -187,7 +203,8 @@ std::vector generateInfillTests() * - Gyroid, since it doesn't handle the 100% infill and related cases well * - Concentric and ZigZag, since they now use a method that starts from an extra infill wall, which fail these tests (TODO!) */ - std::vector skip_methods = { EFillMethod::CONCENTRIC, EFillMethod::ZIG_ZAG, EFillMethod::CROSS, EFillMethod::CROSS_3D, EFillMethod::CUBICSUBDIV, EFillMethod::GYROID, EFillMethod::LIGHTNING }; + std::vector skip_methods + = { EFillMethod::CONCENTRIC, EFillMethod::ZIG_ZAG, EFillMethod::CROSS, EFillMethod::CROSS_3D, EFillMethod::CUBICSUBDIV, EFillMethod::GYROID, EFillMethod::LIGHTNING }; std::vector methods; for (int i_method = 0; i_method < static_cast(EFillMethod::NONE); ++i_method) @@ -227,7 +244,14 @@ class InfillTest : public testing::TestWithParam { }; -INSTANTIATE_TEST_SUITE_P(InfillTestcases, InfillTest, testing::ValuesIn(generateInfillTests()), [](const testing::TestParamInfo& info) { return info.param.name; }); +INSTANTIATE_TEST_SUITE_P( + InfillTestcases, + InfillTest, + testing::ValuesIn(generateInfillTests()), + [](const testing::TestParamInfo& info) + { + return info.param.name; + }); TEST_P(InfillTest, TestInfillSanity) { @@ -251,7 +275,8 @@ TEST_P(InfillTest, TestInfillSanity) const long double min_expected_infill_area = (min_available_area * static_cast(INFILL_LINE_WIDTH)) / params.params.line_distance; const long double max_expected_infill_area = (max_available_area * INFILL_LINE_WIDTH) / params.params.line_distance + worst_case_zig_zag_added_area; - const long double out_infill_area = ((params.result_polygons.polygonLength() + params.result_lines.polyLineLength()) * static_cast(INFILL_LINE_WIDTH)) / getPatternMultiplier(params.params.pattern); + const long double out_infill_area = ((params.result_polygons.polygonLength() + params.result_lines.polyLineLength()) * static_cast(INFILL_LINE_WIDTH)) + / getPatternMultiplier(params.params.pattern); ASSERT_GT((coord_t)max_available_area, (coord_t)out_infill_area) << "Infill area should allways be less than the total area available."; ASSERT_GT((coord_t)out_infill_area, (coord_t)min_expected_infill_area) << "Infill area should be greater than the minimum area expected to be covered."; @@ -260,14 +285,16 @@ TEST_P(InfillTest, TestInfillSanity) const coord_t maximum_error = 10_mu; // potential rounding error const Polygons padded_shape_outline = params.outline_polygons.offset(INFILL_LINE_WIDTH / 2); constexpr bool restitch = false; // No need to restitch polylines - that would introduce stitching errors. - ASSERT_LE(std::abs(padded_shape_outline.intersectionPolyLines(params.result_lines, restitch).polyLineLength() - params.result_lines.polyLineLength()), maximum_error) << "Infill (lines) should not be outside target polygon."; + ASSERT_LE(std::abs(padded_shape_outline.intersectionPolyLines(params.result_lines, restitch).polyLineLength() - params.result_lines.polyLineLength()), maximum_error) + << "Infill (lines) should not be outside target polygon."; Polygons result_polygon_lines = params.result_polygons; - for (PolygonRef poly : result_polygon_lines) + for (Polygon& poly : result_polygon_lines) { poly.add(poly.front()); } - ASSERT_LE(std::abs(padded_shape_outline.intersectionPolyLines(result_polygon_lines, restitch).polyLineLength() - result_polygon_lines.polyLineLength()), maximum_error) << "Infill (lines) should not be outside target polygon."; + ASSERT_LE(std::abs(padded_shape_outline.intersectionPolyLines(result_polygon_lines, restitch).polyLineLength() - result_polygon_lines.polyLineLength()), maximum_error) + << "Infill (lines) should not be outside target polygon."; } } // namespace cura -// NOLINTEND(*-magic-numbers) \ No newline at end of file +// NOLINTEND(*-magic-numbers) diff --git a/tests/PathOrderMonotonicTest.cpp b/tests/PathOrderMonotonicTest.cpp index aaf9505c95..6d4a10a760 100644 --- a/tests/PathOrderMonotonicTest.cpp +++ b/tests/PathOrderMonotonicTest.cpp @@ -7,7 +7,7 @@ #include "slicer.h" #include "utils/Coord_t.h" #include "utils/math.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" #include #include #include diff --git a/tests/ReadTestPolygons.h b/tests/ReadTestPolygons.h index cf7f7b2884..6dc8524fa9 100644 --- a/tests/ReadTestPolygons.h +++ b/tests/ReadTestPolygons.h @@ -4,7 +4,7 @@ #ifndef READ_TEST_POLYGONS_H #define READ_TEST_POLYGONS_H -#include "utils/polygon.h" +#include "geometry/polygon.h" #include #include diff --git a/tests/WallsComputationTest.cpp b/tests/WallsComputationTest.cpp index a45cb5464a..fd89907b7e 100644 --- a/tests/WallsComputationTest.cpp +++ b/tests/WallsComputationTest.cpp @@ -6,7 +6,7 @@ #include "settings/Settings.h" //Settings to generate walls with. #include "sliceDataStorage.h" //Sl #include "slicer.h" -#include "utils/polygon.h" //To create example polygons. +#include "geometry/polygon.h" //To create example polygons. #include #include #include @@ -15,7 +15,7 @@ #ifdef WALLS_COMPUTATION_TEST_SVG_OUTPUT #include "utils/SVG.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" #include #endif // WALLS_COMPUTATION_TEST_SVG_OUTPUT diff --git a/tests/arcus/ArcusCommunicationTest.cpp b/tests/arcus/ArcusCommunicationTest.cpp index 7c1036166e..2599a0b941 100644 --- a/tests/arcus/ArcusCommunicationTest.cpp +++ b/tests/arcus/ArcusCommunicationTest.cpp @@ -6,7 +6,7 @@ #include "communication/ArcusCommunicationPrivate.h" //To access the private fields of this communication class. #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" -#include "utils/polygon.h" //Create test shapes to send over the socket. +#include "geometry/polygon.h" //Create test shapes to send over the socket. #include #include #include diff --git a/tests/arcus/MockCommunication.h b/tests/arcus/MockCommunication.h index f2401025fd..405ebc2878 100644 --- a/tests/arcus/MockCommunication.h +++ b/tests/arcus/MockCommunication.h @@ -9,7 +9,7 @@ #include "communication/Communication.h" //The interface we're implementing. #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" -#include "utils/polygon.h" //In the signature of Communication. +#include "geometry/polygon.h" //In the signature of Communication. namespace cura { @@ -25,9 +25,7 @@ class MockCommunication : public Communication MOCK_CONST_METHOD1(sendProgress, void(double progress)); MOCK_METHOD3(sendLayerComplete, void(const LayerIndex::value_type& layer_nr, const coord_t& z, const coord_t& thickness)); MOCK_METHOD5(sendPolygons, void(const PrintFeatureType& type, const Polygons& polygons, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity)); - MOCK_METHOD5( - sendPolygon, - void(const PrintFeatureType& type, const ConstPolygonRef& polygon, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity)); + MOCK_METHOD5(sendPolygon, void(const PrintFeatureType& type, const Polygon& polygon, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity)); MOCK_METHOD5(sendLineTo, void(const PrintFeatureType& type, const Point2LL& to, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity)); MOCK_METHOD1(sendCurrentPosition, void(const Point2LL& position)); MOCK_METHOD1(setExtruderForSend, void(const ExtruderTrain& extruder)); diff --git a/tests/integration/SlicePhaseTest.cpp b/tests/integration/SlicePhaseTest.cpp index de814b5099..13ca9b8b2e 100644 --- a/tests/integration/SlicePhaseTest.cpp +++ b/tests/integration/SlicePhaseTest.cpp @@ -10,7 +10,7 @@ #include "slicer.h" // Starts the slicing phase that we want to test. #include "utils/Coord_t.h" #include "utils/Matrix4x3D.h" // To load STL files. -#include "utils/polygon.h" // Creating polygons to compare to sliced layers. +#include "geometry/polygon.h" // Creating polygons to compare to sliced layers. #include "utils/polygonUtils.h" // Comparing similarity of polygons. namespace cura diff --git a/tests/utils/AABB3DTest.cpp b/tests/utils/AABB3DTest.cpp index 711e20849c..7cf43eee56 100644 --- a/tests/utils/AABB3DTest.cpp +++ b/tests/utils/AABB3DTest.cpp @@ -4,7 +4,7 @@ #include "utils/AABB3D.h" #include "utils/AABB.h" #include "utils/Coord_t.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" #include #include diff --git a/tests/utils/AABBTest.cpp b/tests/utils/AABBTest.cpp index bb39a91b4f..48c620b3aa 100644 --- a/tests/utils/AABBTest.cpp +++ b/tests/utils/AABBTest.cpp @@ -2,7 +2,7 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "utils/AABB.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" #include #include diff --git a/tests/utils/IntPointTest.cpp b/tests/utils/IntPointTest.cpp index 1332e1b8db..cd6d2f2a73 100644 --- a/tests/utils/IntPointTest.cpp +++ b/tests/utils/IntPointTest.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2022 Ultimaker B.V. // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "utils/Point2LL.h" +#include "geometry/point2ll.h" #include // NOLINTBEGIN(*-magic-numbers) diff --git a/tests/utils/PolygonConnectorTest.cpp b/tests/utils/PolygonConnectorTest.cpp index b423d74d31..61dc3de67d 100644 --- a/tests/utils/PolygonConnectorTest.cpp +++ b/tests/utils/PolygonConnectorTest.cpp @@ -3,7 +3,7 @@ #include "utils/PolygonConnector.h" // The class under test. #include "utils/Coord_t.h" -#include "utils/polygon.h" // To create polygons to test with. +#include "geometry/polygon.h" // To create polygons to test with. #include #include diff --git a/tests/utils/PolygonTest.cpp b/tests/utils/PolygonTest.cpp index bdf84466e1..8908cdef02 100644 --- a/tests/utils/PolygonTest.cpp +++ b/tests/utils/PolygonTest.cpp @@ -1,11 +1,13 @@ // Copyright (c) 2022 Ultimaker B.V. // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "utils/polygon.h" // The class under test. +#include "geometry/polygon.h" // The class under test. + +#include + #include "utils/Coord_t.h" #include "utils/SVG.h" // helper functions #include "utils/polygonUtils.h" // helper functions -#include // NOLINTBEGIN(*-magic-numbers) namespace cura @@ -79,7 +81,18 @@ class PolygonTest : public testing::Test } void twoPolygonsAreEqual(Polygons& polygon1, Polygons& polygon2) const { - auto poly_cmp = [](const ClipperLib::Path& a, const ClipperLib::Path& b) { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), [](const Point2LL& p1, const Point2LL& p2) { return p1 < p2; }); }; + auto poly_cmp = [](const ClipperLib::Path& a, const ClipperLib::Path& b) + { + return std::lexicographical_compare( + a.begin(), + a.end(), + b.begin(), + b.end(), + [](const Point2LL& p1, const Point2LL& p2) + { + return p1 < p2; + }); + }; std::sort(polygon1.begin(), polygon1.end(), poly_cmp); std::sort(polygon2.begin(), polygon2.end(), poly_cmp); @@ -102,7 +115,7 @@ TEST_F(PolygonTest, polygonOffsetTest) const coord_t expanded_length = expanded.polygonLength(); Polygons square_hole; - PolygonRef square_inverted = square_hole.newPoly(); + Polygon& square_inverted = square_hole.newLine(); for (int i = test_square.size() - 1; i >= 0; i--) { square_inverted.add(test_square[i]); @@ -144,7 +157,7 @@ TEST_F(PolygonTest, isOutsideTest) TEST_F(PolygonTest, isInsideTest) { Polygons test_polys; - PolygonRef poly = test_polys.newPoly(); + PolygonRef poly = test_polys.newLine(); poly.add(Point2LL(82124, 98235)); poly.add(Point2LL(83179, 98691)); poly.add(Point2LL(83434, 98950)); @@ -183,23 +196,23 @@ TEST_F(PolygonTest, DISABLED_isInsideLineTest) // Disabled because this fails du TEST_F(PolygonTest, splitIntoPartsWithHoleTest) { - const std::vector parts = clockwise_donut.splitIntoParts(); + const std::vector parts = clockwise_donut.splitIntoParts(); - EXPECT_EQ(parts.size(), 1) << "Difference between two polygons should be one PolygonsPart!"; + EXPECT_EQ(parts.size(), 1) << "Difference between two polygons should be one SingleShape!"; } TEST_F(PolygonTest, differenceContainsOriginalPointTest) { - const PolygonsPart part = clockwise_donut.splitIntoParts()[0]; - const ConstPolygonRef outer = part.outerPolygon(); + const SingleShape part = clockwise_donut.splitIntoParts()[0]; + const Polygon& outer = part.outerPolygon(); EXPECT_NE(std::find(outer.begin(), outer.end(), clockwise_large[0]), outer.end()) << "Outer vertex must be in polygons difference."; - const ConstPolygonRef inner = part[1]; + const Polygon& inner = part[1]; EXPECT_NE(std::find(inner.begin(), inner.end(), clockwise_small[0]), inner.end()) << "Inner vertex must be in polygons difference."; } TEST_F(PolygonTest, differenceClockwiseTest) { - const PolygonsPart part = clockwise_donut.splitIntoParts()[0]; + const SingleShape part = clockwise_donut.splitIntoParts()[0]; const ConstPolygonRef outer = part.outerPolygon(); // Apply the shoelace formula to determine surface area. If it's negative, the polygon is counterclockwise. @@ -243,7 +256,7 @@ TEST_F(PolygonTest, getEmptyHolesTest) TEST_F(PolygonTest, convexTestCube) { Polygons d_polygons; - PolygonRef d = d_polygons.newPoly(); + PolygonRef d = d_polygons.newLine(); d.add(Point2LL(0, 0)); d.add(Point2LL(10, 0)); d.add(Point2LL(10, 10)); @@ -264,7 +277,7 @@ TEST_F(PolygonTest, convexTestCube) TEST_F(PolygonTest, convexHullStar) { Polygons d_polygons; - PolygonRef d = d_polygons.newPoly(); + PolygonRef d = d_polygons.newLine(); const int num_points = 10; const int outer_radius = 20; @@ -300,7 +313,7 @@ TEST_F(PolygonTest, convexHullStar) TEST_F(PolygonTest, convexHullMultipleMinX) { Polygons d_polygons; - PolygonRef d = d_polygons.newPoly(); + PolygonRef d = d_polygons.newLine(); d.add(Point2LL(0, 0)); d.add(Point2LL(0, -10)); d.add(Point2LL(10, 0)); @@ -326,7 +339,7 @@ TEST_F(PolygonTest, convexHullMultipleMinX) TEST_F(PolygonTest, convexTestCubeColinear) { Polygons d_polygons; - PolygonRef d = d_polygons.newPoly(); + PolygonRef d = d_polygons.newLine(); d.add(Point2LL(0, 0)); d.add(Point2LL(5, 0)); d.add(Point2LL(10, 0)); @@ -351,7 +364,7 @@ TEST_F(PolygonTest, convexTestCubeColinear) TEST_F(PolygonTest, convexHullRemoveDuplicatePoints) { Polygons d_polygons; - PolygonRef d = d_polygons.newPoly(); + PolygonRef d = d_polygons.newLine(); d.add(Point2LL(0, 0)); d.add(Point2LL(0, 0)); d.add(Point2LL(10, 0)); diff --git a/tests/utils/PolygonUtilsTest.cpp b/tests/utils/PolygonUtilsTest.cpp index f859a48c08..7dbf07569f 100644 --- a/tests/utils/PolygonUtilsTest.cpp +++ b/tests/utils/PolygonUtilsTest.cpp @@ -6,8 +6,8 @@ #include #include "utils/Coord_t.h" -#include "utils/Point2LL.h" // Creating and testing with points. -#include "utils/polygon.h" // Creating polygons to test with. +#include "geometry/point2ll.h" // Creating and testing with points. +#include "geometry/polygon.h" // Creating polygons to test with. // NOLINTBEGIN(*-magic-numbers) namespace cura @@ -56,7 +56,7 @@ class MoveInsideTest : public testing::TestWithParam TEST_P(MoveInsideTest, MoveInside) { const MoveInsideParameters parameters = GetParam(); - const ClosestPolygonPoint cpp = PolygonUtils::findClosest(parameters.close_to, test_square); + const ClosestPoint cpp = PolygonUtils::findClosest(parameters.close_to, test_square); Point2LL result = PolygonUtils::moveInside(cpp, parameters.distance); // FIXME: Clean-up message with ftm when CURA-8258 is implemented or when we use C++20 @@ -99,7 +99,7 @@ TEST_F(MoveInsideTest, cornerEdgeTest) const Point2LL supposed1(80, 80); // Allow two possible values here, since the behaviour for this edge case is not specified. const Point2LL supposed2(72, 100); constexpr coord_t distance = 28; - const ClosestPolygonPoint cpp = PolygonUtils::findClosest(close_to, test_square); + const ClosestPoint cpp = PolygonUtils::findClosest(close_to, test_square); const Point2LL result = PolygonUtils::moveInside(cpp, distance); constexpr coord_t maximum_error = 10; @@ -120,7 +120,7 @@ TEST_F(MoveInsideTest, middleTest) const Point2LL supposed3(20, 50); const Point2LL supposed4(50, 20); constexpr coord_t distance = 20; - const ClosestPolygonPoint cpp = PolygonUtils::findClosest(close_to, test_square); + const ClosestPoint cpp = PolygonUtils::findClosest(close_to, test_square); const Point2LL result = PolygonUtils::moveInside(cpp, distance); constexpr coord_t maximum_error = 10; @@ -142,7 +142,7 @@ TEST_F(MoveInsideTest, middleTestPenalty) const Point2LL supposed(80, 50); const Point2LL preferred_dir(120, 60); constexpr coord_t distance = 20; - const ClosestPolygonPoint cpp = PolygonUtils::findClosest( + const ClosestPoint cpp = PolygonUtils::findClosest( close_to, test_square, [preferred_dir](Point2LL candidate) @@ -180,7 +180,7 @@ TEST_F(MoveInsideTest, pointyCorner) Point2LL result(from); Polygons inside; inside.add(pointy_square); - ClosestPolygonPoint cpp = PolygonUtils::ensureInsideOrOutside(inside, result, 10); + ClosestPoint cpp = PolygonUtils::ensureInsideOrOutside(inside, result, 10); ASSERT_NE(cpp.point_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_NE(cpp.poly_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; @@ -195,7 +195,7 @@ TEST_F(MoveInsideTest, pointyCornerFail) Polygons inside; inside.add(pointy_square); - ClosestPolygonPoint cpp = PolygonUtils::moveInside2(inside, result, 10); + ClosestPoint cpp = PolygonUtils::moveInside2(inside, result, 10); ASSERT_NE(cpp.point_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_NE(cpp.poly_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_FALSE(inside.inside(result)) << from << " could be moved inside, while it was designed to fail."; @@ -209,7 +209,7 @@ TEST_F(MoveInsideTest, outsidePointyCorner) Polygons inside; inside.add(pointy_square); - const ClosestPolygonPoint cpp = PolygonUtils::ensureInsideOrOutside(inside, result, -10); + const ClosestPoint cpp = PolygonUtils::ensureInsideOrOutside(inside, result, -10); ASSERT_NE(cpp.point_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_NE(cpp.poly_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_TRUE(! inside.inside(result)) << from << " couldn't be moved outside."; @@ -224,7 +224,7 @@ TEST_F(MoveInsideTest, outsidePointyCornerFail) Polygons inside; inside.add(pointy_square); - const ClosestPolygonPoint cpp = PolygonUtils::moveInside2(inside, result, -10); + const ClosestPoint cpp = PolygonUtils::moveInside2(inside, result, -10); ASSERT_NE(cpp.point_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_NE(cpp.poly_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_FALSE(! inside.inside(result)) << from << " could be moved outside to " << result << ", while it was designed to fail."; @@ -269,7 +269,7 @@ TEST_P(FindCloseTest, FindClose) polygons.add(test_square); auto loc_to_line = PolygonUtils::createLocToLineGrid(polygons, parameters.cell_size); - std::optional cpp; + std::optional cpp; if (parameters.penalty_function) { cpp = PolygonUtils::findClose(parameters.close_to, polygons, *loc_to_line, *parameters.penalty_function); @@ -341,12 +341,12 @@ class PolygonUtilsTest : public testing::Test TEST_F(PolygonUtilsTest, spreadDotsSegment) { - std::vector supposed; + std::vector supposed; supposed.emplace_back(Point2LL(50, 0), 0, test_squares[0], 0); supposed.emplace_back(Point2LL(100, 0), 1, test_squares[0], 0); supposed.emplace_back(Point2LL(100, 50), 1, test_squares[0], 0); - std::vector result; + std::vector result; PolygonUtils::spreadDots(PolygonsPointIndex(&test_squares, 0, 0), PolygonsPointIndex(&test_squares, 0, 2), 3, result); ASSERT_EQ(result.size(), supposed.size()); @@ -358,7 +358,7 @@ TEST_F(PolygonUtilsTest, spreadDotsSegment) TEST_F(PolygonUtilsTest, spreadDotsFull) { - std::vector supposed; + std::vector supposed; supposed.emplace_back(Point2LL(0, 0), 0, test_squares[0], 0); supposed.emplace_back(Point2LL(50, 0), 0, test_squares[0], 0); supposed.emplace_back(Point2LL(100, 0), 1, test_squares[0], 0); @@ -368,7 +368,7 @@ TEST_F(PolygonUtilsTest, spreadDotsFull) supposed.emplace_back(Point2LL(0, 100), 3, test_squares[0], 0); supposed.emplace_back(Point2LL(0, 50), 3, test_squares[0], 0); - std::vector result; + std::vector result; PolygonUtils::spreadDots(PolygonsPointIndex(&test_squares, 0, 0), PolygonsPointIndex(&test_squares, 0, 0), 8, result); ASSERT_EQ(result.size(), supposed.size()); @@ -416,8 +416,8 @@ class GetNextParallelIntersectionTest : public testing::TestWithParam computed = PolygonUtils::getNextParallelIntersection(start, parameters.line_to, parameters.dist, parameters.forward); + const ClosestPoint start = PolygonUtils::findClosest(parameters.start_point, test_squares); + std::optional computed = PolygonUtils::getNextParallelIntersection(start, parameters.line_to, parameters.dist, parameters.forward); ASSERT_EQ(bool(parameters.predicted), bool(computed)) << "An answer was predicted but not computed, or computed but not predicted."; if (parameters.predicted) diff --git a/tests/utils/SmoothTest.cpp b/tests/utils/SmoothTest.cpp index 1864e4b706..0354728feb 100644 --- a/tests/utils/SmoothTest.cpp +++ b/tests/utils/SmoothTest.cpp @@ -7,9 +7,9 @@ #include -#include "utils/Point2LL.h" +#include "geometry/point2ll.h" #include "utils/actions/smooth.h" -#include "utils/polygon.h" +#include "geometry/polygon.h" namespace cura { diff --git a/tests/utils/StringTest.cpp b/tests/utils/StringTest.cpp index 829c4c3da7..e9e7b7673e 100644 --- a/tests/utils/StringTest.cpp +++ b/tests/utils/StringTest.cpp @@ -2,7 +2,7 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "utils/string.h" // The file under test. -#include "utils/Point2LL.h" +#include "geometry/point2ll.h" #include // NOLINTBEGIN(*-magic-numbers) From ce2e39593f3f0567e2d01de681f5346a94aee12a Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Fri, 16 Feb 2024 10:35:53 +0000 Subject: [PATCH 003/135] Applied clang-format. --- include/ExtruderPlan.h | 2 +- include/LayerPlan.h | 2 +- include/PrimeTower.h | 2 +- include/SkeletalTrapezoidation.h | 2 +- include/TreeModelVolumes.h | 2 +- include/TreeSupport.h | 2 +- include/TreeSupportElement.h | 2 +- include/TreeSupportTipGenerator.h | 2 +- include/TreeSupportUtils.h | 2 +- include/WallToolPaths.h | 2 +- include/communication/Communication.h | 2 +- include/gcodeExport.h | 2 +- include/geometry/single_shape.h | 2 +- include/infill.h | 2 +- include/infill/LightningTreeNode.h | 2 +- include/pathPlanning/GCodePath.h | 2 +- include/plugins/converters.h | 2 +- include/plugins/slots.h | 4 ++-- include/settings/ZSeamConfig.h | 2 +- include/slicer.h | 2 +- include/support.h | 2 +- include/utils/HalfEdge.h | 2 +- include/utils/Point3F.h | 2 +- include/utils/SparseLineGrid.h | 2 +- include/utils/SparsePointGridInclusive.h | 2 +- src/communication/ArcusCommunication.cpp | 2 +- src/infill/SierpinskiFill.cpp | 2 +- src/infill/SierpinskiFillProvider.cpp | 2 +- src/infill/SubDivCube.cpp | 4 ++-- src/plugins/converters.cpp | 2 +- src/settings/Settings.cpp | 4 ++-- src/utils/AABB.cpp | 2 +- src/utils/ListPolyIt.cpp | 2 +- src/utils/Matrix4x3D.cpp | 2 +- 34 files changed, 37 insertions(+), 37 deletions(-) diff --git a/include/ExtruderPlan.h b/include/ExtruderPlan.h index 89cbf5cf03..785fc43944 100644 --- a/include/ExtruderPlan.h +++ b/include/ExtruderPlan.h @@ -7,12 +7,12 @@ #include "FanSpeedLayerTime.h" #include "RetractionConfig.h" #include "gcodeExport.h" +#include "geometry/point2ll.h" #include "pathPlanning/GCodePath.h" #include "pathPlanning/NozzleTempInsert.h" #include "pathPlanning/TimeMaterialEstimates.h" #include "settings/types/LayerIndex.h" #include "settings/types/Ratio.h" -#include "geometry/point2ll.h" #ifdef BUILD_TESTS #include //Friend tests, so that they can inspect the privates. diff --git a/include/LayerPlan.h b/include/LayerPlan.h index 21006d9d1f..49cf0713e6 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -10,6 +10,7 @@ #include "PathOrderOptimizer.h" #include "SpaceFillType.h" #include "gcodeExport.h" +#include "geometry/polygon.h" #include "pathPlanning/GCodePath.h" #include "pathPlanning/NozzleTempInsert.h" #include "pathPlanning/TimeMaterialEstimates.h" @@ -17,7 +18,6 @@ #include "settings/PathConfigStorage.h" #include "settings/types/LayerIndex.h" #include "utils/ExtrusionJunction.h" -#include "geometry/polygon.h" #ifdef BUILD_TESTS #include //Friend tests, so that they can inspect the privates. diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 62c92c5f86..7cb1b95b29 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -6,8 +6,8 @@ #include -#include "settings/types/LayerIndex.h" #include "geometry/polygon.h" // Polygons +#include "settings/types/LayerIndex.h" #include "utils/polygonUtils.h" diff --git a/include/SkeletalTrapezoidation.h b/include/SkeletalTrapezoidation.h index 9ed382c5db..3c3cb581e5 100644 --- a/include/SkeletalTrapezoidation.h +++ b/include/SkeletalTrapezoidation.h @@ -14,12 +14,12 @@ #include "SkeletalTrapezoidationEdge.h" #include "SkeletalTrapezoidationGraph.h" #include "SkeletalTrapezoidationJoint.h" +#include "geometry/polygon.h" #include "settings/types/Ratio.h" #include "utils/ExtrusionJunction.h" #include "utils/ExtrusionLine.h" #include "utils/HalfEdgeGraph.h" #include "utils/PolygonsSegmentIndex.h" -#include "geometry/polygon.h" #include "utils/section_type.h" namespace cura diff --git a/include/TreeModelVolumes.h b/include/TreeModelVolumes.h index 3a8a44b69e..84b8e3cca3 100644 --- a/include/TreeModelVolumes.h +++ b/include/TreeModelVolumes.h @@ -10,11 +10,11 @@ #include #include "TreeSupportSettings.h" +#include "geometry/polygon.h" //For polygon parameters. #include "settings/EnumSettings.h" //To store whether X/Y or Z distance gets priority. #include "settings/types/LayerIndex.h" //Part of the RadiusLayerPair. #include "sliceDataStorage.h" #include "utils/Simplify.h" -#include "geometry/polygon.h" //For polygon parameters. namespace cura { diff --git a/include/TreeSupport.h b/include/TreeSupport.h index 26f2e32757..24f7c7009f 100644 --- a/include/TreeSupport.h +++ b/include/TreeSupport.h @@ -10,11 +10,11 @@ #include "TreeSupportEnums.h" #include "TreeSupportSettings.h" #include "boost/functional/hash.hpp" // For combining hashes +#include "geometry/polygon.h" #include "polyclipping/clipper.hpp" #include "settings/EnumSettings.h" #include "sliceDataStorage.h" #include "utils/Coord_t.h" -#include "geometry/polygon.h" namespace cura { diff --git a/include/TreeSupportElement.h b/include/TreeSupportElement.h index d5c11181f0..259f6017b9 100644 --- a/include/TreeSupportElement.h +++ b/include/TreeSupportElement.h @@ -10,9 +10,9 @@ #include "TreeModelVolumes.h" #include "TreeSupportBaseCircle.h" #include "TreeSupportEnums.h" +#include "geometry/polygons.h" #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" -#include "geometry/polygons.h" namespace cura { diff --git a/include/TreeSupportTipGenerator.h b/include/TreeSupportTipGenerator.h index a20e7a8618..297bb8d927 100644 --- a/include/TreeSupportTipGenerator.h +++ b/include/TreeSupportTipGenerator.h @@ -11,11 +11,11 @@ #include "TreeSupportEnums.h" #include "TreeSupportSettings.h" #include "boost/functional/hash.hpp" // For combining hashes +#include "geometry/polygon.h" #include "polyclipping/clipper.hpp" #include "settings/EnumSettings.h" #include "sliceDataStorage.h" #include "utils/Coord_t.h" -#include "geometry/polygon.h" namespace cura { diff --git a/include/TreeSupportUtils.h b/include/TreeSupportUtils.h index 5b393fe330..d4fd828369 100644 --- a/include/TreeSupportUtils.h +++ b/include/TreeSupportUtils.h @@ -12,12 +12,12 @@ #include "TreeSupportEnums.h" #include "TreeSupportSettings.h" #include "boost/functional/hash.hpp" // For combining hashes +#include "geometry/polygon.h" #include "infill.h" #include "polyclipping/clipper.hpp" #include "settings/EnumSettings.h" #include "sliceDataStorage.h" #include "utils/Coord_t.h" -#include "geometry/polygon.h" namespace cura { diff --git a/include/WallToolPaths.h b/include/WallToolPaths.h index 08ee7b091c..595c160ef4 100644 --- a/include/WallToolPaths.h +++ b/include/WallToolPaths.h @@ -7,9 +7,9 @@ #include #include "BeadingStrategy/BeadingStrategyFactory.h" +#include "geometry/polygon.h" #include "settings/Settings.h" #include "utils/ExtrusionLine.h" -#include "geometry/polygon.h" #include "utils/section_type.h" namespace cura diff --git a/include/communication/Communication.h b/include/communication/Communication.h index dab6af1530..ba871adffc 100644 --- a/include/communication/Communication.h +++ b/include/communication/Communication.h @@ -4,9 +4,9 @@ #ifndef COMMUNICATION_H #define COMMUNICATION_H +#include "geometry/point2ll.h" #include "settings/types/LayerIndex.h" #include "settings/types/Velocity.h" -#include "geometry/point2ll.h" namespace cura { diff --git a/include/gcodeExport.h b/include/gcodeExport.h index 804b992609..5079859ed5 100644 --- a/include/gcodeExport.h +++ b/include/gcodeExport.h @@ -11,6 +11,7 @@ #include // for stream.str() #include +#include "geometry/point2ll.h" #include "settings/EnumSettings.h" #include "settings/Settings.h" //For MAX_EXTRUDERS. #include "settings/types/LayerIndex.h" @@ -20,7 +21,6 @@ #include "timeEstimate.h" #include "utils/AABB3D.h" //To track the used build volume for the Griffin header. #include "utils/NoCopy.h" -#include "geometry/point2ll.h" namespace cura { diff --git a/include/geometry/single_shape.h b/include/geometry/single_shape.h index e4e232dddd..733927ba2b 100644 --- a/include/geometry/single_shape.h +++ b/include/geometry/single_shape.h @@ -4,8 +4,8 @@ #ifndef GEOMETRY_SINGLE_SHAPE_H #define GEOMETRY_SINGLE_SHAPE_H -#include "point2ll.h" #include "geometry/polygons.h" +#include "point2ll.h" namespace cura { diff --git a/include/infill.h b/include/infill.h index 0f6495d472..2c592ac8bc 100644 --- a/include/infill.h +++ b/include/infill.h @@ -8,6 +8,7 @@ #include +#include "geometry/point2ll.h" #include "infill/LightningGenerator.h" #include "infill/ZigzagConnectorProcessor.h" #include "settings/EnumSettings.h" //For infill types. @@ -15,7 +16,6 @@ #include "settings/types/Angle.h" #include "utils/AABB.h" #include "utils/ExtrusionLine.h" -#include "geometry/point2ll.h" #include "utils/section_type.h" namespace cura diff --git a/include/infill/LightningTreeNode.h b/include/infill/LightningTreeNode.h index dc5cb89f83..124855b4ee 100644 --- a/include/infill/LightningTreeNode.h +++ b/include/infill/LightningTreeNode.h @@ -9,8 +9,8 @@ #include #include -#include "geometry/polygon.h" #include "../utils/polygonUtils.h" +#include "geometry/polygon.h" #include "geometry/polygons.h" namespace cura diff --git a/include/pathPlanning/GCodePath.h b/include/pathPlanning/GCodePath.h index 28a3d2302b..f91c917007 100644 --- a/include/pathPlanning/GCodePath.h +++ b/include/pathPlanning/GCodePath.h @@ -10,9 +10,9 @@ #include "GCodePathConfig.h" #include "SpaceFillType.h" #include "TimeMaterialEstimates.h" +#include "geometry/point2ll.h" #include "settings/types/Ratio.h" #include "sliceDataStorage.h" -#include "geometry/point2ll.h" namespace cura { diff --git a/include/plugins/converters.h b/include/plugins/converters.h index 5e736b38bc..5a9d210d36 100644 --- a/include/plugins/converters.h +++ b/include/plugins/converters.h @@ -26,13 +26,13 @@ #include "cura/plugins/slots/postprocess/v0/modify.pb.h" #include "cura/plugins/slots/simplify/v0/modify.grpc.pb.h" #include "cura/plugins/slots/simplify/v0/modify.pb.h" +#include "geometry/polygon.h" #include "pathPlanning/GCodePath.h" #include "pathPlanning/SpeedDerivatives.h" #include "plugins/metadata.h" #include "plugins/types.h" #include "settings/Settings.h" #include "settings/types/LayerIndex.h" -#include "geometry/polygon.h" namespace cura::plugins diff --git a/include/plugins/slots.h b/include/plugins/slots.h index 8ff484a914..01dd18f4e8 100644 --- a/include/plugins/slots.h +++ b/include/plugins/slots.h @@ -16,14 +16,14 @@ #include "cura/plugins/slots/postprocess/v0/modify.grpc.pb.h" #include "cura/plugins/slots/simplify/v0/modify.grpc.pb.h" #include "cura/plugins/v0/slot_id.pb.h" +#include "geometry/point2ll.h" +#include "geometry/polygon.h" #include "infill.h" #include "plugins/converters.h" #include "plugins/slotproxy.h" #include "plugins/types.h" #include "plugins/validator.h" -#include "geometry/point2ll.h" #include "utils/Simplify.h" // TODO: Remove once the simplify slot has been removed -#include "geometry/polygon.h" #include "utils/types/char_range_literal.h" namespace cura diff --git a/include/settings/ZSeamConfig.h b/include/settings/ZSeamConfig.h index 19348bd4b5..8aea9866d6 100644 --- a/include/settings/ZSeamConfig.h +++ b/include/settings/ZSeamConfig.h @@ -4,8 +4,8 @@ #ifndef ZSEAMCONFIG_H #define ZSEAMCONFIG_H -#include "geometry/point2ll.h" //To store the preferred seam position. #include "EnumSettings.h" //For EZSeamType and EZSeamCornerPrefType. +#include "geometry/point2ll.h" //To store the preferred seam position. namespace cura { diff --git a/include/slicer.h b/include/slicer.h index 4f9bd0fcda..dd3b98c516 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -8,9 +8,9 @@ #include #include -#include "settings/EnumSettings.h" #include "geometry/polygon.h" #include "geometry/polygons.h" +#include "settings/EnumSettings.h" /* The Slicer creates layers of polygons from an optimized 3D model. diff --git a/include/support.h b/include/support.h index 739c2f2661..4f74df5a45 100644 --- a/include/support.h +++ b/include/support.h @@ -7,8 +7,8 @@ #include #include -#include "settings/types/LayerIndex.h" #include "geometry/polygon.h" +#include "settings/types/LayerIndex.h" namespace cura { diff --git a/include/utils/HalfEdge.h b/include/utils/HalfEdge.h index d1e91cfa81..8a79343daf 100644 --- a/include/utils/HalfEdge.h +++ b/include/utils/HalfEdge.h @@ -7,8 +7,8 @@ #include #include -#include "geometry/point2ll.h" #include "Coord_t.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/utils/Point3F.h b/include/utils/Point3F.h index 4fe49067d4..68aa4ab737 100644 --- a/include/utils/Point3F.h +++ b/include/utils/Point3F.h @@ -7,8 +7,8 @@ #include #include -#include "geometry/point2ll.h" #include "Point3D.h" +#include "geometry/point2ll.h" namespace cura diff --git a/include/utils/SparseLineGrid.h b/include/utils/SparseLineGrid.h index 7fdaf86ce3..61c01089c4 100644 --- a/include/utils/SparseLineGrid.h +++ b/include/utils/SparseLineGrid.h @@ -10,9 +10,9 @@ #include #include -#include "geometry/point2ll.h" #include "SVG.h" // debug #include "SparseGrid.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/include/utils/SparsePointGridInclusive.h b/include/utils/SparsePointGridInclusive.h index e5f2c65aa6..55bd35d5aa 100644 --- a/include/utils/SparsePointGridInclusive.h +++ b/include/utils/SparsePointGridInclusive.h @@ -9,8 +9,8 @@ #include #include -#include "geometry/point2ll.h" #include "SparsePointGrid.h" +#include "geometry/point2ll.h" namespace cura { diff --git a/src/communication/ArcusCommunication.cpp b/src/communication/ArcusCommunication.cpp index 1583b58a97..de009d204a 100644 --- a/src/communication/ArcusCommunication.cpp +++ b/src/communication/ArcusCommunication.cpp @@ -33,11 +33,11 @@ #include "communication/ArcusCommunicationPrivate.h" //Our PIMPL. #include "communication/Listener.h" //To listen to the Arcus socket. #include "communication/SliceDataStruct.h" //To store sliced layer data. +#include "geometry/polygon.h" #include "plugins/slots.h" #include "settings/types/LayerIndex.h" //To point to layers. #include "settings/types/Velocity.h" //To send to layer view how fast stuff is printing. #include "utils/channel.h" -#include "geometry/polygon.h" namespace cura { diff --git a/src/infill/SierpinskiFill.cpp b/src/infill/SierpinskiFill.cpp index c69e609631..54b9ad729c 100644 --- a/src/infill/SierpinskiFill.cpp +++ b/src/infill/SierpinskiFill.cpp @@ -10,11 +10,11 @@ #include +#include "geometry/polygon.h" #include "infill/ImageBasedDensityProvider.h" #include "infill/UniformDensityProvider.h" #include "utils/AABB3D.h" #include "utils/SVG.h" -#include "geometry/polygon.h" namespace cura { diff --git a/src/infill/SierpinskiFillProvider.cpp b/src/infill/SierpinskiFillProvider.cpp index cfec010c15..643770162c 100644 --- a/src/infill/SierpinskiFillProvider.cpp +++ b/src/infill/SierpinskiFillProvider.cpp @@ -5,11 +5,11 @@ #include +#include "geometry/polygon.h" #include "infill/ImageBasedDensityProvider.h" #include "infill/UniformDensityProvider.h" #include "utils/AABB3D.h" #include "utils/math.h" -#include "geometry/polygon.h" namespace cura { diff --git a/src/infill/SubDivCube.cpp b/src/infill/SubDivCube.cpp index 39a26ab686..83c43b2d8e 100644 --- a/src/infill/SubDivCube.cpp +++ b/src/infill/SubDivCube.cpp @@ -5,12 +5,12 @@ #include +#include "geometry/polygon.h" +#include "geometry/polygons.h" #include "settings/types/Angle.h" //For the infill angle. #include "sliceDataStorage.h" #include "utils/math.h" -#include "geometry/polygon.h" #include "utils/polygonUtils.h" -#include "geometry/polygons.h" #define ONE_OVER_SQRT_2 0.7071067811865475244008443621048490392848359376884740 // 1 / sqrt(2) #define ONE_OVER_SQRT_3 0.577350269189625764509148780501957455647601751270126876018 // 1 / sqrt(3) diff --git a/src/plugins/converters.cpp b/src/plugins/converters.cpp index 12b6a21c14..e249dd7ef0 100644 --- a/src/plugins/converters.cpp +++ b/src/plugins/converters.cpp @@ -10,11 +10,11 @@ #include "GCodePathConfig.h" #include "WallToolPaths.h" +#include "geometry/polygon.h" #include "pathPlanning/GCodePath.h" #include "pathPlanning/SpeedDerivatives.h" #include "settings/Settings.h" #include "settings/types/LayerIndex.h" -#include "geometry/polygon.h" namespace cura::plugins { diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index 31126794b4..1432e0af35 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -18,6 +18,8 @@ #include "BeadingStrategy/BeadingStrategyFactory.h" #include "ExtruderTrain.h" #include "Slice.h" +#include "geometry/polygon.h" +#include "geometry/polygons.h" #include "settings/EnumSettings.h" #include "settings/FlowTempGraph.h" #include "settings/types/Angle.h" @@ -27,8 +29,6 @@ #include "settings/types/Temperature.h" //For temperature settings. #include "settings/types/Velocity.h" //For velocity settings. #include "utils/Matrix4x3D.h" -#include "geometry/polygon.h" -#include "geometry/polygons.h" #include "utils/string.h" //For Escaped. #include "utils/types/string_switch.h" //For string switch. diff --git a/src/utils/AABB.cpp b/src/utils/AABB.cpp index 974881331a..dcd7f786e2 100644 --- a/src/utils/AABB.cpp +++ b/src/utils/AABB.cpp @@ -5,9 +5,9 @@ #include -#include "utils/linearAlg2D.h" #include "geometry/polygon.h" #include "geometry/polygons.h" +#include "utils/linearAlg2D.h" namespace cura { diff --git a/src/utils/ListPolyIt.cpp b/src/utils/ListPolyIt.cpp index ddf39cddb5..f2644744b8 100644 --- a/src/utils/ListPolyIt.cpp +++ b/src/utils/ListPolyIt.cpp @@ -6,9 +6,9 @@ #include // isfinite #include // ostream +#include "geometry/polygon.h" #include "utils/AABB.h" // for debug output svg html #include "utils/SVG.h" -#include "geometry/polygon.h" namespace cura { diff --git a/src/utils/Matrix4x3D.cpp b/src/utils/Matrix4x3D.cpp index e779bb697f..d23abba21f 100644 --- a/src/utils/Matrix4x3D.cpp +++ b/src/utils/Matrix4x3D.cpp @@ -3,8 +3,8 @@ #include "utils/Matrix4x3D.h" //The definitions we're implementing. -#include "settings/types/Ratio.h" //Scale factor. #include "geometry/point2ll.h" //Conversion directly into integer-based coordinates. +#include "settings/types/Ratio.h" //Scale factor. #include "utils/Point3D.h" //This matrix gets applied to floating point coordinates. namespace cura From afbabac327a0694298ed7a3f44646abdfe8d3eb3 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 16 Feb 2024 13:35:10 +0100 Subject: [PATCH 004/135] Fix crash on shorterThan method CURA-9830 --- src/geometry/polyline.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/geometry/polyline.cpp b/src/geometry/polyline.cpp index 9062c182c9..40fdb074c2 100644 --- a/src/geometry/polyline.cpp +++ b/src/geometry/polyline.cpp @@ -153,10 +153,7 @@ bool Polyline::shorterThan(const coord_t check_length) const [&length, &check_length](const const_segments_iterator::value_type& segment) { length += vSize(segment.end - segment.start); - if (length >= check_length) - { - return true; - } + return length >= check_length; }); return iterator_segment == endSegments(); } From fdf694baed3bfcc0e8e645d9dddef2fe4f94b524 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 16 Feb 2024 13:35:36 +0100 Subject: [PATCH 005/135] Fix unit tests + add test for new lines methods CURA-9830 --- include/geometry/polygons.h | 8 +- include/geometry/polyline.h | 12 ++ src/geometry/polygons.cpp | 13 ++- tests/ReadTestPolygons.cpp | 7 +- tests/utils/PolygonTest.cpp | 214 ++++++++++++++++++++---------------- 5 files changed, 149 insertions(+), 105 deletions(-) diff --git a/include/geometry/polygons.h b/include/geometry/polygons.h index 6e85f8a3b5..e9440b3a25 100644 --- a/include/geometry/polygons.h +++ b/include/geometry/polygons.h @@ -37,13 +37,9 @@ class Polygons : public LinesSet { } - Polygons& operator=(const Polygons& other) - { - LinesSet::operator=(other); - return *this; - } + Polygons& operator=(const Polygons& other); - Polygons& operator=(Polygons&& polygons); + Polygons& operator=(Polygons&& other); void add(const Polygons& other); diff --git a/include/geometry/polyline.h b/include/geometry/polyline.h index 7cbc4ec51b..bb2e9ea8ab 100644 --- a/include/geometry/polyline.h +++ b/include/geometry/polyline.h @@ -45,6 +45,18 @@ class Polyline : public PointsSet { } + template + OtherType& toType() + { + return *reinterpret_cast(this); + } + + template + const OtherType& toType() const + { + return *reinterpret_cast(this); + } + /*Polyline& operator=(const Polyline& other) { std::vector::operator=(other); diff --git a/src/geometry/polygons.cpp b/src/geometry/polygons.cpp index 82dcec5c27..31c4ceb875 100644 --- a/src/geometry/polygons.cpp +++ b/src/geometry/polygons.cpp @@ -130,12 +130,15 @@ Polygons Polygons::intersection(const Polygons& other) const return ret; } -Polygons& Polygons::operator=(Polygons&& polygons) +Polygons& Polygons::operator=(const Polygons& other) { - if (this != &polygons) - { - (*this) = std::move(polygons); - } + LinesSet::operator=(other); + return *this; +} + +Polygons& Polygons::operator=(Polygons&& other) +{ + LinesSet::operator=(other); return *this; } diff --git a/tests/ReadTestPolygons.cpp b/tests/ReadTestPolygons.cpp index baa3d71147..6e0f196952 100644 --- a/tests/ReadTestPolygons.cpp +++ b/tests/ReadTestPolygons.cpp @@ -2,9 +2,12 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "ReadTestPolygons.h" -#include "utils/Coord_t.h" + #include +#include "geometry/polygons.h" +#include "utils/Coord_t.h" + // NOTE: See the documentation in the header-file for an explanation of this simple file format. namespace cura @@ -68,7 +71,7 @@ bool readTestPolygons(const std::string& filename, std::vector& polygo case '#': // end of file if (! next_path.empty()) { - next_shape.add(Polygon(next_path)); // copy and add + next_shape.push_back(Polygon(next_path)); // copy and add next_path.clear(); } if (command != 'x' && ! next_shape.empty()) diff --git a/tests/utils/PolygonTest.cpp b/tests/utils/PolygonTest.cpp index 8908cdef02..a63919fa3e 100644 --- a/tests/utils/PolygonTest.cpp +++ b/tests/utils/PolygonTest.cpp @@ -5,6 +5,9 @@ #include +#include "geometry/closed_polyline.h" +#include "geometry/open_polyline.h" +#include "geometry/single_shape.h" #include "utils/Coord_t.h" #include "utils/SVG.h" // helper functions #include "utils/polygonUtils.h" // helper functions @@ -67,8 +70,8 @@ class PolygonTest : public testing::Test Polygons outer; Polygons inner; - outer.add(clockwise_large); - inner.add(clockwise_small); + outer.push_back(clockwise_large); + inner.push_back(clockwise_small); clockwise_donut = outer.difference(inner); line.emplace_back(0, 0); @@ -110,18 +113,18 @@ class PolygonTest : public testing::Test TEST_F(PolygonTest, polygonOffsetTest) { Polygons test_squares; - test_squares.add(test_square); + test_squares.push_back(test_square); const Polygons expanded = test_squares.offset(25); - const coord_t expanded_length = expanded.polygonLength(); + const coord_t expanded_length = expanded.length(); Polygons square_hole; Polygon& square_inverted = square_hole.newLine(); for (int i = test_square.size() - 1; i >= 0; i--) { - square_inverted.add(test_square[i]); + square_inverted.push_back(test_square[i]); } const Polygons contracted = square_hole.offset(25); - const coord_t contracted_length = contracted.polygonLength(); + const coord_t contracted_length = contracted.length(); ASSERT_NEAR(expanded_length, contracted_length, 5) << "Offset on outside poly is different from offset on inverted poly!"; } @@ -129,10 +132,10 @@ TEST_F(PolygonTest, polygonOffsetTest) TEST_F(PolygonTest, polygonOffsetBugTest) { Polygons polys; - polys.add(clipper_bug); + polys.push_back(clipper_bug); const Polygons offsetted = polys.offset(-20); - for (const ConstPolygonRef poly : offsetted) + for (const Polygon& poly : offsetted) { for (const Point2LL& p : poly) { @@ -144,7 +147,7 @@ TEST_F(PolygonTest, polygonOffsetBugTest) TEST_F(PolygonTest, isOutsideTest) { Polygons test_triangle; - test_triangle.add(triangle); + test_triangle.push_back(triangle); EXPECT_FALSE(test_triangle.inside(Point2LL(0, 100))) << "Left point should be outside the triangle."; EXPECT_FALSE(test_triangle.inside(Point2LL(100, 100))) << "Middle left point should be outside the triangle."; @@ -157,19 +160,19 @@ TEST_F(PolygonTest, isOutsideTest) TEST_F(PolygonTest, isInsideTest) { Polygons test_polys; - PolygonRef poly = test_polys.newLine(); - poly.add(Point2LL(82124, 98235)); - poly.add(Point2LL(83179, 98691)); - poly.add(Point2LL(83434, 98950)); - poly.add(Point2LL(82751, 99026)); - poly.add(Point2LL(82528, 99019)); - poly.add(Point2LL(81605, 98854)); - poly.add(Point2LL(80401, 98686)); - poly.add(Point2LL(79191, 98595)); - poly.add(Point2LL(78191, 98441)); - poly.add(Point2LL(78998, 98299)); - poly.add(Point2LL(79747, 98179)); - poly.add(Point2LL(80960, 98095)); + Polygon& poly = test_polys.newLine(); + poly.push_back(Point2LL(82124, 98235)); + poly.push_back(Point2LL(83179, 98691)); + poly.push_back(Point2LL(83434, 98950)); + poly.push_back(Point2LL(82751, 99026)); + poly.push_back(Point2LL(82528, 99019)); + poly.push_back(Point2LL(81605, 98854)); + poly.push_back(Point2LL(80401, 98686)); + poly.push_back(Point2LL(79191, 98595)); + poly.push_back(Point2LL(78191, 98441)); + poly.push_back(Point2LL(78998, 98299)); + poly.push_back(Point2LL(79747, 98179)); + poly.push_back(Point2LL(80960, 98095)); EXPECT_TRUE(test_polys.inside(Point2LL(78315, 98440))) << "Point should be inside the polygons!"; } @@ -177,7 +180,7 @@ TEST_F(PolygonTest, isInsideTest) TEST_F(PolygonTest, isOnBorderTest) { Polygons test_triangle; - test_triangle.add(triangle); + test_triangle.push_back(triangle); EXPECT_FALSE(test_triangle.inside(Point2LL(200, 0), false)) << "Point is on the bottom edge of the triangle."; EXPECT_TRUE(test_triangle.inside(Point2LL(200, 0), true)) << "Point is on the bottom edge of the triangle."; @@ -188,7 +191,7 @@ TEST_F(PolygonTest, isOnBorderTest) TEST_F(PolygonTest, DISABLED_isInsideLineTest) // Disabled because this fails due to a bug in Clipper. { Polygons polys; - polys.add(line); + polys.push_back(line); EXPECT_FALSE(polys.inside(Point2LL(50, 0), false)) << "Should be outside since it is on the border and border is considered outside."; EXPECT_TRUE(polys.inside(Point2LL(50, 0), true)) << "Should be inside since it is on the border and border is considered inside."; @@ -214,7 +217,7 @@ TEST_F(PolygonTest, differenceClockwiseTest) { const SingleShape part = clockwise_donut.splitIntoParts()[0]; - const ConstPolygonRef outer = part.outerPolygon(); + const Polygon& outer = part.outerPolygon(); // Apply the shoelace formula to determine surface area. If it's negative, the polygon is counterclockwise. coord_t area = 0; for (size_t point_index = 0; point_index < outer.size(); point_index++) @@ -226,7 +229,7 @@ TEST_F(PolygonTest, differenceClockwiseTest) } EXPECT_LT(area, 0) << "Outer polygon should be counter-clockwise."; - const ConstPolygonRef inner = part[1]; + const Polygon& inner = part[1]; area = 0; for (size_t point_index = 0; point_index < inner.size(); point_index++) { @@ -256,11 +259,11 @@ TEST_F(PolygonTest, getEmptyHolesTest) TEST_F(PolygonTest, convexTestCube) { Polygons d_polygons; - PolygonRef d = d_polygons.newLine(); - d.add(Point2LL(0, 0)); - d.add(Point2LL(10, 0)); - d.add(Point2LL(10, 10)); - d.add(Point2LL(0, 10)); + Polygon& d = d_polygons.newLine(); + d.push_back(Point2LL(0, 0)); + d.push_back(Point2LL(10, 0)); + d.push_back(Point2LL(10, 10)); + d.push_back(Point2LL(0, 10)); d_polygons.makeConvex(); @@ -277,7 +280,7 @@ TEST_F(PolygonTest, convexTestCube) TEST_F(PolygonTest, convexHullStar) { Polygons d_polygons; - PolygonRef d = d_polygons.newLine(); + Polygon& d = d_polygons.newLine(); const int num_points = 10; const int outer_radius = 20; @@ -287,11 +290,11 @@ TEST_F(PolygonTest, convexHullStar) { coord_t x_outer = -std::cos(angle_step * i) * outer_radius; coord_t y_outer = -std::sin(angle_step * i) * outer_radius; - d.add(Point2LL(x_outer, y_outer)); + d.push_back(Point2LL(x_outer, y_outer)); coord_t x_inner = -std::cos(angle_step * (i + 0.5)) * inner_radius; coord_t y_inner = -std::sin(angle_step * (i + 0.5)) * inner_radius; - d.add(Point2LL(x_inner, y_inner)); + d.push_back(Point2LL(x_inner, y_inner)); } d_polygons.makeConvex(); @@ -313,11 +316,11 @@ TEST_F(PolygonTest, convexHullStar) TEST_F(PolygonTest, convexHullMultipleMinX) { Polygons d_polygons; - PolygonRef d = d_polygons.newLine(); - d.add(Point2LL(0, 0)); - d.add(Point2LL(0, -10)); - d.add(Point2LL(10, 0)); - d.add(Point2LL(0, 10)); + Polygon& d = d_polygons.newLine(); + d.push_back(Point2LL(0, 0)); + d.push_back(Point2LL(0, -10)); + d.push_back(Point2LL(10, 0)); + d.push_back(Point2LL(0, 10)); /* * x\ x\ @@ -339,15 +342,15 @@ TEST_F(PolygonTest, convexHullMultipleMinX) TEST_F(PolygonTest, convexTestCubeColinear) { Polygons d_polygons; - PolygonRef d = d_polygons.newLine(); - d.add(Point2LL(0, 0)); - d.add(Point2LL(5, 0)); - d.add(Point2LL(10, 0)); - d.add(Point2LL(10, 5)); - d.add(Point2LL(10, 10)); - d.add(Point2LL(5, 10)); - d.add(Point2LL(0, 10)); - d.add(Point2LL(0, 5)); + Polygon& d = d_polygons.newLine(); + d.push_back(Point2LL(0, 0)); + d.push_back(Point2LL(5, 0)); + d.push_back(Point2LL(10, 0)); + d.push_back(Point2LL(10, 5)); + d.push_back(Point2LL(10, 10)); + d.push_back(Point2LL(5, 10)); + d.push_back(Point2LL(0, 10)); + d.push_back(Point2LL(0, 5)); d_polygons.makeConvex(); @@ -364,15 +367,15 @@ TEST_F(PolygonTest, convexTestCubeColinear) TEST_F(PolygonTest, convexHullRemoveDuplicatePoints) { Polygons d_polygons; - PolygonRef d = d_polygons.newLine(); - d.add(Point2LL(0, 0)); - d.add(Point2LL(0, 0)); - d.add(Point2LL(10, 0)); - d.add(Point2LL(10, 0)); - d.add(Point2LL(10, 10)); - d.add(Point2LL(10, 10)); - d.add(Point2LL(0, 10)); - d.add(Point2LL(0, 10)); + Polygon& d = d_polygons.newLine(); + d.push_back(Point2LL(0, 0)); + d.push_back(Point2LL(0, 0)); + d.push_back(Point2LL(10, 0)); + d.push_back(Point2LL(10, 0)); + d.push_back(Point2LL(10, 10)); + d.push_back(Point2LL(10, 10)); + d.push_back(Point2LL(0, 10)); + d.push_back(Point2LL(0, 10)); d_polygons.makeConvex(); @@ -393,9 +396,9 @@ TEST_F(PolygonTest, removeSmallAreas_simple) auto test_square_2 = test_square; test_square_2.translate(Point2LL(0, 500)); auto d_polygons = Polygons{}; - d_polygons.add(test_square); - d_polygons.add(test_square_2); - d_polygons.add(triangle); + d_polygons.push_back(test_square); + d_polygons.push_back(test_square_2); + d_polygons.push_back(triangle); // for the simple case there should be no change. auto act_polygons = d_polygons; @@ -424,15 +427,15 @@ TEST_F(PolygonTest, removeSmallAreas_small_area) // add areas to polygons auto d_polygons = Polygons{}; - d_polygons.add(small_area_1); - d_polygons.add(small_area_2); - d_polygons.add(test_square); // area = 10000 micron^2 = 1e-2 mm^2 - d_polygons.add(triangle_1); + d_polygons.push_back(small_area_1); + d_polygons.push_back(small_area_2); + d_polygons.push_back(test_square); // area = 10000 micron^2 = 1e-2 mm^2 + d_polygons.push_back(triangle_1); // make an expected Polygons auto exp_polygons = Polygons{}; - exp_polygons.add(test_square); - exp_polygons.add(triangle_1); + exp_polygons.push_back(test_square); + exp_polygons.push_back(triangle_1); // for remove_holes == false, 2 poly removed auto act_polygons = d_polygons; @@ -458,8 +461,8 @@ TEST_F(PolygonTest, removeSmallAreas_hole) // add areas to polygons auto d_polygons = Polygons{}; - d_polygons.add(test_square); // area = 10000 micron^2 = 1e-2 mm^2 - d_polygons.add(small_hole_1); + d_polygons.push_back(test_square); // area = 10000 micron^2 = 1e-2 mm^2 + d_polygons.push_back(small_hole_1); // for remove_holes == false there should be no change. @@ -470,7 +473,7 @@ TEST_F(PolygonTest, removeSmallAreas_hole) // for remove_holes == true there should be one less poly. // make an expected Polygons auto exp_polygons = Polygons{}; - exp_polygons.add(test_square); + exp_polygons.push_back(test_square); act_polygons = d_polygons; act_polygons.removeSmallAreas(1e-3, true); twoPolygonsAreEqual(act_polygons, exp_polygons); @@ -488,25 +491,25 @@ TEST_F(PolygonTest, removeSmallAreas_hole_2) small_hole_1.translate(Point2LL(10, 10)); small_hole_2.translate(Point2LL(160, 160)); auto med_square_1 = Polygon{}; // area = 2500 micron^2 = 2.5e-3 mm^2 - med_square_1.add(Point2LL(0, 0)); - med_square_1.add(Point2LL(50, 0)); - med_square_1.add(Point2LL(50, 50)); - med_square_1.add(Point2LL(0, 50)); + med_square_1.push_back(Point2LL(0, 0)); + med_square_1.push_back(Point2LL(50, 0)); + med_square_1.push_back(Point2LL(50, 50)); + med_square_1.push_back(Point2LL(0, 50)); med_square_1.translate(Point2LL(150, 150)); // add areas to polygons auto d_polygons = Polygons{}; - d_polygons.add(test_square); // area = 10000 micron^2 = 1e-2 mm^2 - d_polygons.add(small_hole_1); - d_polygons.add(med_square_1); - d_polygons.add(small_hole_2); + d_polygons.push_back(test_square); // area = 10000 micron^2 = 1e-2 mm^2 + d_polygons.push_back(small_hole_1); + d_polygons.push_back(med_square_1); + d_polygons.push_back(small_hole_2); // for remove_holes == false, two polygons removed. auto act_polygons = d_polygons; // make an expected Polygons auto exp_polygons = Polygons{}; - exp_polygons.add(test_square); - exp_polygons.add(small_hole_1); + exp_polygons.push_back(test_square); + exp_polygons.push_back(small_hole_1); act_polygons.removeSmallAreas(3e-3, false); twoPolygonsAreEqual(act_polygons, exp_polygons); @@ -514,7 +517,7 @@ TEST_F(PolygonTest, removeSmallAreas_hole_2) act_polygons = d_polygons; // make an expected Polygons exp_polygons = Polygons{}; - exp_polygons.add(test_square); + exp_polygons.push_back(test_square); act_polygons.removeSmallAreas(3e-3, true); twoPolygonsAreEqual(act_polygons, exp_polygons); } @@ -542,21 +545,21 @@ TEST_F(PolygonTest, removeSmallAreas_complex) // add areas to polygons auto d_polygons = Polygons{}; - d_polygons.add(small_area_1); - d_polygons.add(small_area_2); - d_polygons.add(test_square); // area = 10000 micron^2 = 1e-2 mm^2 - d_polygons.add(small_hole_1); - d_polygons.add(small_hole_2); - d_polygons.add(triangle_1); + d_polygons.push_back(small_area_1); + d_polygons.push_back(small_area_2); + d_polygons.push_back(test_square); // area = 10000 micron^2 = 1e-2 mm^2 + d_polygons.push_back(small_hole_1); + d_polygons.push_back(small_hole_2); + d_polygons.push_back(triangle_1); // for remove_holes == false there should be 2 small areas removed. auto act_polygons = d_polygons; // make an expected Polygons auto exp_polygons = Polygons{}; - exp_polygons.add(test_square); // area = 10000 micron^2 = 1e-2 mm^2 - exp_polygons.add(small_hole_1); - exp_polygons.add(small_hole_2); - exp_polygons.add(triangle_1); + exp_polygons.push_back(test_square); // area = 10000 micron^2 = 1e-2 mm^2 + exp_polygons.push_back(small_hole_1); + exp_polygons.push_back(small_hole_2); + exp_polygons.push_back(triangle_1); act_polygons.removeSmallAreas(1e-3, false); twoPolygonsAreEqual(act_polygons, exp_polygons); @@ -564,10 +567,37 @@ TEST_F(PolygonTest, removeSmallAreas_complex) act_polygons = d_polygons; // make an expected Polygons exp_polygons = Polygons{}; - exp_polygons.add(test_square); - exp_polygons.add(triangle_1); // area = 10000 micron^2 = 1e-2 mm^2 + exp_polygons.push_back(test_square); + exp_polygons.push_back(triangle_1); // area = 10000 micron^2 = 1e-2 mm^2 act_polygons.removeSmallAreas(1e-3, true); twoPolygonsAreEqual(act_polygons, exp_polygons); } + +/* + * Test that we can iterate over segments of open/closed polylines and convert them to each other + */ +TEST_F(PolygonTest, openCloseLines) +{ + // make some line + OpenPolyline openPolyline; + openPolyline.emplace_back(0, 0); + openPolyline.emplace_back(1000, 0); + openPolyline.emplace_back(1000, 1000); + openPolyline.emplace_back(0, 1000); + + // Make some casts and check that the results are consistent + EXPECT_EQ(openPolyline.length(), 3000); + + ClosedPolyline& closedPolyline = openPolyline.toType(); + EXPECT_EQ(closedPolyline.length(), 4000); + + Polygon& polygon = openPolyline.toType(); + EXPECT_EQ(polygon.area(), 1000000); + + // Check advanced calculations on segment length + EXPECT_TRUE(openPolyline.shorterThan(3500)); + EXPECT_FALSE(closedPolyline.shorterThan(3500)); +} + } // namespace cura // NOLINTEND(*-magic-numbers) From a7385acab70b8647eb2db77d5538aa26c555c54b Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 16 Feb 2024 14:55:56 +0100 Subject: [PATCH 006/135] Renamed Polygons to Shape --- CMakeLists.txt | 2 +- benchmark/infill_benchmark.h | 10 +- benchmark/simplify_benchmark.h | 6 +- benchmark/wall_benchmark.h | 10 +- include/FffGcodeWriter.h | 12 +- include/InsetOrderOptimizer.h | 2 +- include/InterlockingGenerator.h | 10 +- include/LayerPlan.h | 28 +- include/PathOrderOptimizer.h | 4 +- include/PrimeTower.h | 10 +- include/SkeletalTrapezoidation.h | 4 +- include/SkirtBrim.h | 20 +- include/SupportInfillPart.h | 6 +- include/TopSurface.h | 4 +- include/TreeModelVolumes.h | 76 ++--- include/TreeSupport.h | 28 +- include/TreeSupportElement.h | 8 +- include/TreeSupportTipGenerator.h | 12 +- include/TreeSupportUtils.h | 34 +- include/WallToolPaths.h | 10 +- include/bridge.h | 6 +- include/communication/ArcusCommunication.h | 2 +- include/communication/CommandLine.h | 2 +- include/communication/Communication.h | 4 +- include/geometry/lines_set.h | 6 +- include/geometry/parts_view.h | 6 +- include/geometry/polygon.h | 8 +- include/geometry/polygons.h | 318 ------------------- include/geometry/single_shape.h | 4 +- include/infill.h | 26 +- include/infill/GyroidInfill.h | 4 +- include/infill/LightningDistanceField.h | 6 +- include/infill/LightningGenerator.h | 2 +- include/infill/LightningLayer.h | 10 +- include/infill/LightningTreeNode.h | 6 +- include/infill/ZigzagConnectorProcessor.h | 2 +- include/pathPlanning/Comb.h | 28 +- include/pathPlanning/LinePolygonsCrossings.h | 6 +- include/plugins/converters.h | 8 +- include/plugins/slots.h | 2 +- include/skin.h | 14 +- include/sliceDataStorage.h | 72 ++--- include/slicer.h | 4 +- include/support.h | 36 +-- include/utils/AABB.h | 6 +- include/utils/ExtrusionLine.h | 6 +- include/utils/ExtrusionSegment.h | 4 +- include/utils/ListPolyIt.h | 6 +- include/utils/OpenPolylineStitcher.h | 4 +- include/utils/PolygonConnector.h | 4 +- include/utils/PolygonsPointIndex.h | 6 +- include/utils/PolygonsSegmentIndex.h | 2 +- include/utils/SVG.h | 8 +- include/utils/Simplify.h | 2 +- include/utils/ToolpathVisualizer.h | 8 +- include/utils/VoxelUtils.h | 10 +- include/utils/polygonUtils.h | 52 +-- src/ConicalOverhang.cpp | 10 +- src/FffGcodeWriter.cpp | 90 +++--- src/FffPolygonGenerator.cpp | 8 +- src/InsetOrderOptimizer.cpp | 4 +- src/InterlockingGenerator.cpp | 62 ++-- src/LayerPlan.cpp | 26 +- src/Mold.cpp | 10 +- src/PrimeTower.cpp | 18 +- src/SkeletalTrapezoidation.cpp | 4 +- src/SkirtBrim.cpp | 66 ++-- src/TopSurface.cpp | 8 +- src/TreeModelVolumes.cpp | 130 ++++---- src/TreeSupport.cpp | 233 +++++++------- src/TreeSupportTipGenerator.cpp | 143 +++++---- src/WallToolPaths.cpp | 8 +- src/bridge.cpp | 18 +- src/communication/ArcusCommunication.cpp | 2 +- src/communication/CommandLine.cpp | 2 +- src/geometry/lines_set.cpp | 22 +- src/geometry/polygon.cpp | 12 +- src/geometry/{polygons.cpp => shape.cpp} | 138 ++++---- src/infill.cpp | 50 +-- src/infill/GyroidInfill.cpp | 4 +- src/infill/LightningDistanceField.cpp | 2 +- src/infill/LightningGenerator.cpp | 14 +- src/infill/LightningLayer.cpp | 10 +- src/infill/LightningTreeNode.cpp | 4 +- src/infill/SubDivCube.cpp | 4 +- src/infill/ZigzagConnectorProcessor.cpp | 2 +- src/multiVolumes.cpp | 14 +- src/pathPlanning/Comb.cpp | 18 +- src/plugins/converters.cpp | 4 +- src/raft.cpp | 8 +- src/settings/Settings.cpp | 6 +- src/skin.cpp | 84 ++--- src/sliceDataStorage.cpp | 54 ++-- src/slicer.cpp | 4 +- src/support.cpp | 182 +++++------ src/utils/AABB.cpp | 6 +- src/utils/ExtrusionSegment.cpp | 6 +- src/utils/ListPolyIt.cpp | 4 +- src/utils/PolygonConnector.cpp | 4 +- src/utils/PolygonsPointIndex.cpp | 4 +- src/utils/PolygonsSegmentIndex.cpp | 2 +- src/utils/PolylineStitcher.cpp | 2 +- src/utils/SVG.cpp | 8 +- src/utils/Simplify.cpp | 4 +- src/utils/ToolpathVisualizer.cpp | 14 +- src/utils/VoxelUtils.cpp | 16 +- src/utils/polygonUtils.cpp | 76 ++--- stress_benchmark/stress_benchmark.cpp | 8 +- tests/InfillTest.cpp | 22 +- tests/LayerPlanTest.cpp | 2 +- tests/PathOrderMonotonicTest.cpp | 8 +- tests/ReadTestPolygons.cpp | 8 +- tests/ReadTestPolygons.h | 4 +- tests/WallsComputationTest.cpp | 4 +- tests/arcus/ArcusCommunicationTest.cpp | 2 +- tests/integration/SlicePhaseTest.cpp | 2 +- tests/utils/AABBTest.cpp | 4 +- tests/utils/PolygonConnectorTest.cpp | 8 +- tests/utils/PolygonTest.cpp | 70 ++-- tests/utils/PolygonUtilsTest.cpp | 30 +- 120 files changed, 1236 insertions(+), 1556 deletions(-) delete mode 100644 include/geometry/polygons.h rename src/geometry/{polygons.cpp => shape.cpp} (87%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c62445789..ae414fbb20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,7 +152,7 @@ set(engine_SRCS # Except main.cpp. src/utils/VoxelUtils.cpp src/geometry/polygon.cpp - src/geometry/polygons.cpp + src/geometry/shape.cpp src/geometry/points_set.cpp src/geometry/single_shape.cpp src/geometry/parts_view.cpp diff --git a/benchmark/infill_benchmark.h b/benchmark/infill_benchmark.h index 459174eecc..a6a52b817a 100644 --- a/benchmark/infill_benchmark.h +++ b/benchmark/infill_benchmark.h @@ -14,14 +14,14 @@ class InfillTest : public benchmark::Fixture { public: Settings settings{}; - Polygons square_shape; - Polygons ff_holes; + Shape square_shape; + Shape ff_holes; std::vector all_paths; - Polygons outline_polygons; + Shape outline_polygons; EFillMethod pattern{ EFillMethod::LINES }; bool zig_zagify{ true }; bool connect_polygons{ true }; @@ -110,8 +110,8 @@ BENCHMARK_DEFINE_F(InfillTest, Infill_generate_connect)(benchmark::State& st) for (auto _ : st) { std::vector result_paths; - Polygons result_polygons; - Polygons result_lines; + Shape result_polygons; + Shape result_lines; infill.generate(result_paths, result_polygons, result_lines, settings, 0, SectionType::INFILL, nullptr, nullptr); } } diff --git a/benchmark/simplify_benchmark.h b/benchmark/simplify_benchmark.h index d3726bce65..a716c1fe41 100644 --- a/benchmark/simplify_benchmark.h +++ b/benchmark/simplify_benchmark.h @@ -31,7 +31,7 @@ class SimplifyTestFixture : public benchmark::Fixture std::filesystem::path(__FILE__).parent_path().append("tests/resources/slice_polygon_3.txt").string(), std::filesystem::path(__FILE__).parent_path().append("tests/resources/slice_polygon_4.txt").string() }; - std::vector shapes; + std::vector shapes; void SetUp(const ::benchmark::State& state) { @@ -48,7 +48,7 @@ BENCHMARK_DEFINE_F(SimplifyTestFixture, simplify_local)(benchmark::State& st) Simplify simplify(MM2INT(0.25), MM2INT(0.025), 50000); for (auto _ : st) { - Polygons simplified; + Shape simplified; for (const auto& polys : shapes) { benchmark::DoNotOptimize(simplified = simplify.polygon(polys)); @@ -62,7 +62,7 @@ BENCHMARK_DEFINE_F(SimplifyTestFixture, simplify_slot_noplugin)(benchmark::State { for (auto _ : st) { - Polygons simplified; + Shape simplified; for (const auto& polys : shapes) { benchmark::DoNotOptimize(simplified = slots::instance().modify(polys, MM2INT(0.25), MM2INT(0.025), 50000)); diff --git a/benchmark/wall_benchmark.h b/benchmark/wall_benchmark.h index d91f9d5831..6b43a4255e 100644 --- a/benchmark/wall_benchmark.h +++ b/benchmark/wall_benchmark.h @@ -27,8 +27,8 @@ class WallTestFixture : public benchmark::Fixture public: Settings settings{}; WallsComputation walls_computation{ settings, LayerIndex(100) }; - Polygons square_shape; - Polygons ff_holes; + Shape square_shape; + Shape ff_holes; bool outer_to_inner; SliceLayer layer; @@ -98,8 +98,8 @@ class HolesWallTestFixture : public benchmark::Fixture public: Settings settings{}; WallsComputation walls_computation{ settings, LayerIndex(100) }; - Polygons shape; - Polygons ff_holes; + Shape shape; + Shape ff_holes; bool outer_to_inner; SliceLayer layer; @@ -113,7 +113,7 @@ class HolesWallTestFixture : public benchmark::Fixture buffer << file.rdbuf(); const auto wkt = buffer.str(); - const auto shape = Polygons::fromWkt(buffer.str()); + const auto shape = Shape::fromWkt(buffer.str()); // Settings for a simple 2 walls, about as basic as possible. settings.add("alternate_extra_perimeter", "false"); diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index 46b9657968..23efe7b2c6 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -20,7 +20,7 @@ namespace cura { class AngleDegrees; -class Polygons; +class Shape; class SkinPart; class SliceDataStorage; class SliceMeshStorage; @@ -560,7 +560,7 @@ class FffGcodeWriter : public NoCopy LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, - const Polygons& area, + const Shape& area, const GCodePathConfig& config, EFillMethod pattern, const AngleDegrees skin_angle, @@ -593,7 +593,7 @@ class FffGcodeWriter : public NoCopy * \param last_position The position the print head is in before going to fill the part * \return The location near where to start filling the part */ - std::optional getSeamAvoidingLocation(const Polygons& filling_part, int filling_angle, Point2LL last_position) const; + std::optional getSeamAvoidingLocation(const Shape& filling_part, int filling_angle, Point2LL last_position) const; /*! * Add the g-code for ironing the top surface. @@ -638,7 +638,7 @@ class FffGcodeWriter : public NoCopy * \param gcodeLayer The initial planning of the g-code of the layer. * \return Whether any support skin was added to the layer plan. */ - bool addSupportRoofsToGCode(const SliceDataStorage& storage, const Polygons& support_roof_outlines, const GCodePathConfig& current_roof_config, LayerPlan& gcode_layer) const; + bool addSupportRoofsToGCode(const SliceDataStorage& storage, const Shape& support_roof_outlines, const GCodePathConfig& current_roof_config, LayerPlan& gcode_layer) const; /*! * Add the support bottoms to the layer plan \p gcodeLayer of the current @@ -708,8 +708,8 @@ class FffGcodeWriter : public NoCopy * \return true if there needs to be a skin edge support wall in this layer, otherwise false */ static bool partitionInfillBySkinAbove( - Polygons& infill_below_skin, - Polygons& infill_not_below_skin, + Shape& infill_below_skin, + Shape& infill_not_below_skin, const LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const SliceLayerPart& part, diff --git a/include/InsetOrderOptimizer.h b/include/InsetOrderOptimizer.h index 808abb99d6..a7a08a63f9 100644 --- a/include/InsetOrderOptimizer.h +++ b/include/InsetOrderOptimizer.h @@ -108,7 +108,7 @@ class InsetOrderOptimizer const LayerIndex layer_nr_; std::vector> inset_polys_; // vector of vectors holding the inset polygons - Polygons retraction_region_; // After printing an outer wall, move into this region so that retractions do not leave visible blobs. Calculated lazily if needed (see + Shape retraction_region_; // After printing an outer wall, move into this region so that retractions do not leave visible blobs. Calculated lazily if needed (see // retraction_region_calculated). /*! diff --git a/include/InterlockingGenerator.h b/include/InterlockingGenerator.h index 14fd39ec9e..d9359bd518 100644 --- a/include/InterlockingGenerator.h +++ b/include/InterlockingGenerator.h @@ -107,7 +107,7 @@ class InterlockingGenerator * \param detec The expand distance. (Not equal to offset, but a series of small offsets and differences). * \return A pair of polygons that repressent the 'borders' of a and b, but expanded 'perpendicularly'. */ - std::pair growBorderAreasPerpendicular(const Polygons& a, const Polygons& b, const coord_t& detect) const; + std::pair growBorderAreasPerpendicular(const Shape& a, const Shape& b, const coord_t& detect) const; /*! Special handling for thin strips of material. * @@ -133,7 +133,7 @@ class InterlockingGenerator * \param kernel The dilation kernel to give the returned voxel shell more thickness * \param[out] cells The output cells which elong to the shell */ - void addBoundaryCells(const std::vector& layers, const DilationKernel& kernel, std::unordered_set& cells) const; + void addBoundaryCells(const std::vector& layers, const DilationKernel& kernel, std::unordered_set& cells) const; /*! * Compute the regions occupied by both models. @@ -141,13 +141,13 @@ class InterlockingGenerator * A morphological close is performed so that we don't register small gaps between the two models as being separate. * \return layer_regions The computed layer regions */ - std::vector computeUnionedVolumeRegions() const; + std::vector computeUnionedVolumeRegions() const; /*! * Generate the polygons for the beams of a single cell * \return cell_area_per_mesh_per_layer The output polygons for each beam */ - std::vector> generateMicrostructure() const; + std::vector> generateMicrostructure() const; /*! * Change the outlines of the meshes with the computed interlocking structure. @@ -155,7 +155,7 @@ class InterlockingGenerator * \param cells The cells where we want to apply the interlocking structure. * \param layer_regions The total volume of the two meshes combined (and small gaps closed) */ - void applyMicrostructureToOutlines(const std::unordered_set& cells, const std::vector& layer_regions) const; + void applyMicrostructureToOutlines(const std::unordered_set& cells, const std::vector& layer_regions) const; static const coord_t ignored_gap_ = 100u; //!< Distance between models to be considered next to each other so that an interlocking structure will be generated there diff --git a/include/LayerPlan.h b/include/LayerPlan.h index 49cf0713e6..ca3ae2dd95 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -90,13 +90,13 @@ class LayerPlan : public NoCopy std::optional> next_layer_acc_jerk_; //!< If there is a next layer, the first acceleration and jerk it starts with. bool was_inside_; //!< Whether the last planned (extrusion) move was inside a layer part bool is_inside_; //!< Whether the destination of the next planned travel move is inside a layer part - Polygons comb_boundary_minimum_; //!< The minimum boundary within which to comb, or to move into when performing a retraction. - Polygons comb_boundary_preferred_; //!< The boundary preferably within which to comb, or to move into when performing a retraction. + Shape comb_boundary_minimum_; //!< The minimum boundary within which to comb, or to move into when performing a retraction. + Shape comb_boundary_preferred_; //!< The boundary preferably within which to comb, or to move into when performing a retraction. Comb* comb_; coord_t comb_move_inside_distance_; //!< Whenever using the minimum boundary for combing it tries to move the coordinates inside by this distance after calculating the combing. - Polygons bridge_wall_mask_; //!< The regions of a layer part that are not supported, used for bridging - Polygons overhang_mask_; //!< The regions of a layer part where the walls overhang - Polygons roofing_mask_; //!< The regions of a layer part where the walls are exposed to the air + Shape bridge_wall_mask_; //!< The regions of a layer part that are not supported, used for bridging + Shape overhang_mask_; //!< The regions of a layer part where the walls overhang + Shape roofing_mask_; //!< The regions of a layer part where the walls are exposed to the air const std::vector fan_speed_layer_time_settings_per_extruder_; @@ -176,7 +176,7 @@ class LayerPlan : public NoCopy */ ExtruderTrain* getLastPlannedExtruderTrain(); - const Polygons* getCombBoundaryInside() const; + const Shape* getCombBoundaryInside() const; LayerIndex getLayerNr() const; @@ -249,21 +249,21 @@ class LayerPlan : public NoCopy * * \param polys The unsupported areas of the part currently being processed that will require bridges. */ - void setBridgeWallMask(const Polygons& polys); + void setBridgeWallMask(const Shape& polys); /*! * Set overhang_mask. * * \param polys The overhung areas of the part currently being processed that will require modified print settings */ - void setOverhangMask(const Polygons& polys); + void setOverhangMask(const Shape& polys); /*! * Set roofing_mask. * * \param polys The areas of the part currently being processed that will require roofing. */ - void setRoofingMask(const Polygons& polys); + void setRoofingMask(const Shape& polys); /*! * Travel to a certain point, with all of the procedures necessary to do so. @@ -387,7 +387,7 @@ class LayerPlan : public NoCopy * If unset, this causes it to start near the last planned location. */ void addPolygonsByOptimizer( - const Polygons& polygons, + const Shape& polygons, const GCodePathConfig& config, const ZSeamConfig& z_seam_config = ZSeamConfig(), coord_t wall_0_wipe_dist = 0, @@ -517,7 +517,7 @@ class LayerPlan : public NoCopy * \param alternate_inset_direction_modifier Whether to alternate the direction of the walls for each inset. */ void addWalls( - const Polygons& walls, + const Shape& walls, const Settings& settings, const GCodePathConfig& default_config, const GCodePathConfig& roofing_config, @@ -574,7 +574,7 @@ class LayerPlan : public NoCopy * \param fan_speed Fan speed override for this path. */ void addLinesMonotonic( - const Polygons& area, + const Shape& area, const std::vector& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, @@ -755,9 +755,9 @@ class LayerPlan : public NoCopy * - If CombingMode::INFILL: Add the infill (infill only). * * \param boundary_type The boundary type to compute. - * \return the combing boundary or an empty Polygons if no combing is required + * \return the combing boundary or an empty Shape if no combing is required */ - Polygons computeCombBoundary(const CombBoundary boundary_type); + Shape computeCombBoundary(const CombBoundary boundary_type); }; } // namespace cura diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 1a7e3ed2e7..b8ecb9dfb1 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -107,7 +107,7 @@ class PathOrderOptimizer const Point2LL& start_point, const ZSeamConfig seam_config = ZSeamConfig(), const bool detect_loops = false, - const Polygons* combing_boundary = nullptr, + const Shape* combing_boundary = nullptr, const bool reverse_direction = false, const std::unordered_multimap& order_requirements = no_order_requirements_, const bool group_outer_walls = false) @@ -257,7 +257,7 @@ class PathOrderOptimizer /*! * Boundary to avoid when making travel moves. */ - const Polygons* combing_boundary_; + const Shape* combing_boundary_; /*! * Whether to check polylines to see if they are closed, before optimizing. diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 7cb1b95b29..95fa28e9be 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -26,7 +26,7 @@ class LayerPlan; class PrimeTower { private: - using MovesByExtruder = std::vector; + using MovesByExtruder = std::vector; using MovesByLayer = std::vector; size_t extruder_count_; //!< Number of extruders @@ -42,8 +42,8 @@ class PrimeTower MovesByExtruder prime_moves_; //!< For each extruder, the moves to be processed for actual priming. MovesByLayer base_extra_moves_; //!< For each layer and each extruder, the extra moves to be processed for better adhesion/strength - Polygons outer_poly_; //!< The outline of the outermost prime tower. - std::vector outer_poly_base_; //!< The outline of the layers having extra width for the base + Shape outer_poly_; //!< The outline of the outermost prime tower. + std::vector outer_poly_base_; //!< The outline of the layers having extra width for the base public: bool enabled_; //!< Whether the prime tower is enabled. @@ -108,12 +108,12 @@ class PrimeTower * \param[in] layer_nr The index of the layer * \return The outer polygon for the prime tower at the given layer */ - const Polygons& getOuterPoly(const LayerIndex& layer_nr) const; + const Shape& getOuterPoly(const LayerIndex& layer_nr) const; /*! * Get the outer polygon for the very first layer, which may be the priming polygon only, or a larger polygon if there is a base */ - const Polygons& getGroundPoly() const; + const Shape& getGroundPoly() const; private: /*! diff --git a/include/SkeletalTrapezoidation.h b/include/SkeletalTrapezoidation.h index 3c3cb581e5..153c3ac040 100644 --- a/include/SkeletalTrapezoidation.h +++ b/include/SkeletalTrapezoidation.h @@ -110,7 +110,7 @@ class SkeletalTrapezoidation * distance. */ SkeletalTrapezoidation( - const Polygons& polys, + const Shape& polys, const BeadingStrategy& beading_strategy, AngleRadians transitioning_angle, coord_t discretization_step_size, @@ -165,7 +165,7 @@ class SkeletalTrapezoidation * Another complication arises because the VD uses floating logic, which can result in zero-length segments after rounding to integers. * We therefore collapse edges and their whole cells afterwards. */ - void constructFromPolygons(const Polygons& polys); + void constructFromPolygons(const Shape& polys); node_t& makeNode(vd_t::vertex_type& vd_node, Point2LL p); //!< Get the node which the VD node maps to, or create a new mapping if there wasn't any yet. diff --git a/include/SkirtBrim.h b/include/SkirtBrim.h index af8cbe9f6e..18f126c49c 100644 --- a/include/SkirtBrim.h +++ b/include/SkirtBrim.h @@ -14,7 +14,7 @@ namespace cura { -class Polygons; +class Shape; class SliceDataStorage; constexpr coord_t min_brim_line_length = 3000u; //!< open polyline brim lines smaller than this will be removed @@ -28,7 +28,7 @@ class SkirtBrim struct Offset { Offset( - const std::variant& reference_outline_or_index, + const std::variant& reference_outline_or_index, const bool external_only, const coord_t offset_value, const coord_t total_offset, @@ -45,7 +45,7 @@ class SkirtBrim { } - std::variant reference_outline_or_index_; + std::variant reference_outline_or_index_; bool external_only_; //!< Wether to only offset outward from the reference polygons coord_t offset_value_; //!< Distance by which to offset from the reference coord_t total_offset_; //!< Total distance from the model @@ -112,7 +112,7 @@ class SkirtBrim * \param[out] starting_outlines The first layer outlines from which to compute the offsets. Returned as output parameter because pointers need to stay valid. * \return An ordered list of offsets to perform in the order in which they are to be performed. */ - std::vector generateBrimOffsetPlan(std::vector& starting_outlines); + std::vector generateBrimOffsetPlan(std::vector& starting_outlines); /*! * Generate the primary skirt/brim of the one skirt_brim_extruder or of all extruders simultaneously. @@ -122,7 +122,7 @@ class SkirtBrim * \param[in,out] allowed_areas_per_extruder The difference between the machine bed area (offsetted by the nozzle offset) and the covered_area. * \return The total length of the brim lines added by this method per extruder. */ - std::vector generatePrimaryBrim(std::vector& all_brim_offsets, Polygons& covered_area, std::vector& allowed_areas_per_extruder); + std::vector generatePrimaryBrim(std::vector& all_brim_offsets, Shape& covered_area, std::vector& allowed_areas_per_extruder); /*! * Generate the brim inside the ooze shield and draft shield @@ -133,7 +133,7 @@ class SkirtBrim * \param[in,out] brim_covered_area The area that was covered with brim before (in) and after (out) adding the shield brims * \param[in,out] allowed_areas_per_extruder The difference between the machine areas and the \p covered_area */ - void generateShieldBrim(Polygons& brim_covered_area, std::vector& allowed_areas_per_extruder); + void generateShieldBrim(Shape& brim_covered_area, std::vector& allowed_areas_per_extruder); /*! * \brief Get the reference outline of the first layer around which to @@ -146,7 +146,7 @@ class SkirtBrim * \param extruder_nr The extruder for which to get the outlines. -1 to include outliens for all extruders * \return The resulting reference polygons */ - Polygons getFirstLayerOutline(const int extruder_nr = -1); + Shape getFirstLayerOutline(const int extruder_nr = -1); /*! * The disallowed area around the internal holes of parts with other parts inside which would get an external brim. @@ -158,7 +158,7 @@ class SkirtBrim * \param extruder_nr The extruder for which to compute disallowed areas * \return The disallowed areas */ - Polygons getInternalHoleExclusionArea(const Polygons& outline, const int extruder_nr); + Shape getInternalHoleExclusionArea(const Shape& outline, const int extruder_nr); /*! * Generate a brim line with offset parameters given by \p offset from the \p starting_outlines and store it in the \ref storage. @@ -171,7 +171,7 @@ class SkirtBrim * \param[out] result Where to store the resulting brim line * \return The length of the added lines */ - coord_t generateOffset(const Offset& offset, Polygons& covered_area, std::vector& allowed_areas_per_extruder, SkirtBrimLine& result); + coord_t generateOffset(const Offset& offset, Shape& covered_area, std::vector& allowed_areas_per_extruder, SkirtBrimLine& result); /*! * Generate a skirt of extruders which don't yet comply with the minimum length requirement. @@ -184,7 +184,7 @@ class SkirtBrim * \param[in,out] allowed_areas_per_extruder The difference between the machine areas and the \p covered_area * \param[in,out] total_length The total length of the brim lines for each extruder. */ - void generateSecondarySkirtBrim(Polygons& covered_area, std::vector& allowed_areas_per_extruder, std::vector& total_length); + void generateSecondarySkirtBrim(Shape& covered_area, std::vector& allowed_areas_per_extruder, std::vector& total_length); public: /*! diff --git a/include/SupportInfillPart.h b/include/SupportInfillPart.h index d35d3e3462..74ca7a065d 100644 --- a/include/SupportInfillPart.h +++ b/include/SupportInfillPart.h @@ -30,7 +30,7 @@ class SupportInfillPart AABB outline_boundary_box_; //!< The boundary box for the infill area coord_t support_line_width_; //!< The support line width int inset_count_to_generate_; //!< The number of insets need to be generated from the outline. This is not the actual insets that will be generated. - std::vector> infill_area_per_combine_per_density_; //!< a list of separated sub-areas which requires different infill densities and combined thicknesses + std::vector> infill_area_per_combine_per_density_; //!< a list of separated sub-areas which requires different infill densities and combined thicknesses // for infill_areas[x][n], x means the density level and n means the thickness std::vector wall_toolpaths_; //!< Any walls go here, not in the areas, where they could be combined vertically (don't combine walls). Binned by inset_idx. @@ -39,10 +39,10 @@ class SupportInfillPart SupportInfillPart(const SingleShape& outline, coord_t support_line_width, bool use_fractional_config, int inset_count_to_generate = 0, coord_t custom_line_distance = 0); - const Polygons& getInfillArea() const; + const Shape& getInfillArea() const; }; -inline const Polygons& SupportInfillPart::getInfillArea() const +inline const Shape& SupportInfillPart::getInfillArea() const { // if there is no wall, we use the original outline as the infill area return outline_; diff --git a/include/TopSurface.h b/include/TopSurface.h index cdeb9b4a1b..d9f876c614 100644 --- a/include/TopSurface.h +++ b/include/TopSurface.h @@ -5,7 +5,7 @@ #define TOPSURFACE_H #include "GCodePathConfig.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" namespace cura { @@ -58,7 +58,7 @@ class TopSurface /*! * \brief The areas of top surface, for each layer. */ - Polygons areas; + Shape areas; }; } // namespace cura diff --git a/include/TreeModelVolumes.h b/include/TreeModelVolumes.h index 84b8e3cca3..892ad99e89 100644 --- a/include/TreeModelVolumes.h +++ b/include/TreeModelVolumes.h @@ -41,7 +41,7 @@ class TreeModelVolumes size_t current_mesh_idx, double progress_multiplier, double progress_offset, - const std::vector& additional_excluded_areas = std::vector()); + const std::vector& additional_excluded_areas = std::vector()); TreeModelVolumes(TreeModelVolumes&&) = default; TreeModelVolumes& operator=(TreeModelVolumes&&) = default; @@ -66,9 +66,9 @@ class TreeModelVolumes * \param radius The radius of the node of interest * \param layer_idx The layer of interest * \param min_xy_dist Is the minimum xy distance used. - * \return Polygons object + * \return Shape object */ - const Polygons& getCollision(coord_t radius, LayerIndex layer_idx, bool min_xy_dist = false); + const Shape& getCollision(coord_t radius, LayerIndex layer_idx, bool min_xy_dist = false); /*! * \brief Provides the areas that have to be avoided by the tree's branches to prevent collision with the model on this layer. Holes are removed. @@ -79,9 +79,9 @@ class TreeModelVolumes * \param radius The radius of the node of interest * \param layer_idx The layer of interest * \param min_xy_dist Is the minimum xy distance used. - * \return Polygons object + * \return Shape object */ - const Polygons& getCollisionHolefree(coord_t radius, LayerIndex layer_idx, bool min_xy_dist = false); + const Shape& getCollisionHolefree(coord_t radius, LayerIndex layer_idx, bool min_xy_dist = false); /*! @@ -89,9 +89,9 @@ class TreeModelVolumes * * The result is a 2D area that represents where if support were to be placed in and just dropped down it would not rest on support blocker. * \param layer_idx The layer of interest - * \return Polygons object + * \return Shape object */ - const Polygons& getAccumulatedPlaceable0(LayerIndex layer_idx); + const Shape& getAccumulatedPlaceable0(LayerIndex layer_idx); /*! * \brief Provides the areas that have to be avoided by the tree's branches @@ -108,24 +108,24 @@ class TreeModelVolumes * \param slow Is the propagation with the maximum move distance slow required. * \param to_model Does the avoidance allow good connections with the model. * \param min_xy_dist is the minimum xy distance used. - * \return Polygons object + * \return Shape object */ - const Polygons& getAvoidance(coord_t radius, LayerIndex layer_idx, AvoidanceType type, bool to_model = false, bool min_xy_dist = false); + const Shape& getAvoidance(coord_t radius, LayerIndex layer_idx, AvoidanceType type, bool to_model = false, bool min_xy_dist = false); /*! * \brief Provides the area represents all areas on the model where the branch does completely fit on the given layer. * \param radius The radius of the node of interest * \param layer_idx The layer of interest - * \return Polygons object + * \return Shape object */ - const Polygons& getPlaceableAreas(coord_t radius, LayerIndex layer_idx); + const Shape& getPlaceableAreas(coord_t radius, LayerIndex layer_idx); /*! * \brief Provides the area that represents the walls, as in the printed area, of the model. This is an abstract representation not equal with the outline. See * calculateWallRestrictions for better description. \param radius The radius of the node of interest. \param layer_idx The layer of interest. \param min_xy_dist is the minimum - * xy distance used. \return Polygons object + * xy distance used. \return Shape object */ - const Polygons& getWallRestriction(coord_t radius, LayerIndex layer_idx, bool min_xy_dist); + const Shape& getWallRestriction(coord_t radius, LayerIndex layer_idx, bool min_xy_dist); /*! * \brief Round \p radius upwards to either a multiple of radius_sample_resolution_ or a exponentially increasing value @@ -165,9 +165,9 @@ class TreeModelVolumes * \brief Extracts the relevant outline from a mesh * \param[in] mesh The mesh which outline will be extracted * \param layer_idx The layer which should be extracted from the mesh - * \return Polygons object representing the outline + * \return Shape object representing the outline */ - Polygons extractOutlineFromMesh(const SliceMeshStorage& mesh, LayerIndex layer_idx) const; + Shape extractOutlineFromMesh(const SliceMeshStorage& mesh, LayerIndex layer_idx) const; /*! @@ -243,7 +243,7 @@ class TreeModelVolumes calculateCollisionHolefree(std::deque{ RadiusLayerPair(key) }); } - Polygons safeOffset(const Polygons& me, coord_t distance, ClipperLib::JoinType jt, coord_t max_safe_step_distance, const Polygons& collision) const; + Shape safeOffset(const Shape& me, coord_t distance, ClipperLib::JoinType jt, coord_t max_safe_step_distance, const Shape& collision) const; /*! * \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model. @@ -337,7 +337,7 @@ class TreeModelVolumes * \return A wrapped optional reference of the requested area (if it was found, an empty optional if nothing was found) */ template - const std::optional> getArea(const std::unordered_map& cache, const KEY key) const; + const std::optional> getArea(const std::unordered_map& cache, const KEY key) const; bool checkSettingsEquality(const Settings& me, const Settings& other) const; @@ -348,9 +348,9 @@ class TreeModelVolumes * * \return A wrapped optional reference of the requested area (if it was found, an empty optional if nothing was found) */ - LayerIndex getMaxCalculatedLayer(coord_t radius, const std::unordered_map& map) const; + LayerIndex getMaxCalculatedLayer(coord_t radius, const std::unordered_map& map) const; - static Polygons calculateMachineBorderCollision(const Polygons&& machine_border); + static Shape calculateMachineBorderCollision(const Shape&& machine_border); /*! * \brief The maximum distance that the center point of a tree branch may move in consecutive layers if it has to avoid the model. @@ -427,25 +427,25 @@ class TreeModelVolumes coord_t increase_until_radius_; /*! - * \brief Polygons representing the limits of the printable area of the + * \brief Shape representing the limits of the printable area of the * machine */ - Polygons machine_border_; + Shape machine_border_; /*! - * \brief Polygons representing the printable area of the machine + * \brief Shape representing the printable area of the machine */ - Polygons machine_area_; + Shape machine_area_; /*! * \brief Storage for layer outlines and the corresponding settings of the meshes grouped by meshes with identical setting. */ - std::vector>> layer_outlines_; + std::vector>> layer_outlines_; /*! * \brief Storage for areas that should be avoided, like support blocker or previous generated trees. */ - std::vector anti_overhang_; + std::vector anti_overhang_; /*! * \brief Radii that can be ignored by ceilRadius as they will never be requested. @@ -471,52 +471,52 @@ class TreeModelVolumes * (ie there is no difference in behaviour for the user between * calculating the values each time vs caching the results). */ - mutable std::unordered_map collision_cache_; + mutable std::unordered_map collision_cache_; std::unique_ptr critical_collision_cache_ = std::make_unique(); - mutable std::unordered_map collision_cache_holefree_; + mutable std::unordered_map collision_cache_holefree_; std::unique_ptr critical_collision_cache_holefree_ = std::make_unique(); - mutable std::unordered_map accumulated_placeables_cache_radius_0_; + mutable std::unordered_map accumulated_placeables_cache_radius_0_; std::unique_ptr critical_accumulated_placeables_cache_radius_0_ = std::make_unique(); - mutable std::unordered_map avoidance_cache_collision_; + mutable std::unordered_map avoidance_cache_collision_; std::unique_ptr critical_avoidance_cache_collision_ = std::make_unique(); - mutable std::unordered_map avoidance_cache_; + mutable std::unordered_map avoidance_cache_; std::unique_ptr critical_avoidance_cache_ = std::make_unique(); - mutable std::unordered_map avoidance_cache_slow_; + mutable std::unordered_map avoidance_cache_slow_; std::unique_ptr critical_avoidance_cache_slow_ = std::make_unique(); - mutable std::unordered_map avoidance_cache_to_model_; + mutable std::unordered_map avoidance_cache_to_model_; std::unique_ptr critical_avoidance_cache_to_model_ = std::make_unique(); - mutable std::unordered_map avoidance_cache_to_model_slow_; + mutable std::unordered_map avoidance_cache_to_model_slow_; std::unique_ptr critical_avoidance_cache_to_model_slow_ = std::make_unique(); - mutable std::unordered_map placeable_areas_cache_; + mutable std::unordered_map placeable_areas_cache_; std::unique_ptr critical_placeable_areas_cache_ = std::make_unique(); /*! * \brief Caches to avoid holes smaller than the radius until which the radius is always increased, as they are free of holes. Also called safe avoidances, as they are safe * regarding not running into holes. */ - mutable std::unordered_map avoidance_cache_hole_; + mutable std::unordered_map avoidance_cache_hole_; std::unique_ptr critical_avoidance_cache_holefree_ = std::make_unique(); - mutable std::unordered_map avoidance_cache_hole_to_model_; + mutable std::unordered_map avoidance_cache_hole_to_model_; std::unique_ptr critical_avoidance_cache_holefree_to_model_ = std::make_unique(); /*! * \brief Caches to represent walls not allowed to be passed over. */ - mutable std::unordered_map wall_restrictions_cache_; + mutable std::unordered_map wall_restrictions_cache_; std::unique_ptr critical_wall_restrictions_cache_ = std::make_unique(); // A different cache for min_xy_dist as the maximal safe distance an influence area can be increased(guaranteed overlap of two walls in consecutive layer) is much smaller when // min_xy_dist is used. This causes the area of the wall restriction to be thinner and as such just using the min_xy_dist wall restriction would be slower. - mutable std::unordered_map wall_restrictions_cache_min_; + mutable std::unordered_map wall_restrictions_cache_min_; std::unique_ptr critical_wall_restrictions_cache_min_ = std::make_unique(); std::unique_ptr critical_progress_ = std::make_unique(); diff --git a/include/TreeSupport.h b/include/TreeSupport.h index 24f7c7009f..79e36edb1b 100644 --- a/include/TreeSupport.h +++ b/include/TreeSupport.h @@ -42,8 +42,8 @@ constexpr auto SUPPORT_TREE_EXPONENTIAL_FACTOR = 1.5; constexpr size_t SUPPORT_TREE_PRE_EXPONENTIAL_STEPS = 1; constexpr coord_t SUPPORT_TREE_COLLISION_RESOLUTION = 500; // Only has an effect if SUPPORT_TREE_USE_EXPONENTIAL_COLLISION_RESOLUTION is false -using PropertyAreasUnordered = std::unordered_map; -using PropertyAreas = std::map; +using PropertyAreasUnordered = std::unordered_map; +using PropertyAreas = std::map; /*! * \brief Generates a tree structure to support your models. @@ -159,10 +159,10 @@ class TreeSupport AreaIncreaseSettings settings, LayerIndex layer_idx, TreeSupportElement* parent, - const Polygons& relevant_offset, - Polygons& to_bp_data, - Polygons& to_model_data, - Polygons& increased, + const Shape& relevant_offset, + Shape& to_bp_data, + Shape& to_model_data, + Shape& increased, const coord_t overspeed, const bool mergelayer); @@ -236,7 +236,7 @@ class TreeSupport */ void generateBranchAreas( std::vector>& linear_data, - std::vector>& layer_tree_polygons, + std::vector>& layer_tree_polygons, const std::map& inverse_tree_order); /*! @@ -244,7 +244,7 @@ class TreeSupport * * \param layer_tree_polygons[in,out] Resulting branch areas with the layerindex they appear on. */ - void smoothBranchAreas(std::vector>& layer_tree_polygons); + void smoothBranchAreas(std::vector>& layer_tree_polygons); /*! * \brief Drop down areas that do rest non-gracefully on the model to ensure the branch actually rests on something. @@ -255,13 +255,13 @@ class TreeSupport * \param inverse_tree_order[in] A mapping that returns the child of every influence area. */ void dropNonGraciousAreas( - std::vector>& layer_tree_polygons, + std::vector>& layer_tree_polygons, const std::vector>& linear_data, - std::vector>>& dropped_down_areas, + std::vector>>& dropped_down_areas, const std::map& inverse_tree_order); - void filterFloatingLines(std::vector& support_layer_storage); + void filterFloatingLines(std::vector& support_layer_storage); /*! * \brief Generates Support Floor, ensures Support Roof can not cut of branches, and saves the branches as support to storage @@ -270,7 +270,7 @@ class TreeSupport * \param support_roof_storage[in] Areas where support was replaced with roof. * \param storage[in,out] The storage where the support should be stored. */ - void finalizeInterfaceAndSupportAreas(std::vector& support_layer_storage, std::vector& support_roof_storage, SliceDataStorage& storage); + void finalizeInterfaceAndSupportAreas(std::vector& support_layer_storage, std::vector& support_roof_storage, SliceDataStorage& storage); /*! * \brief Draws circles around result_on_layer points of the influence areas and applies some post processing. @@ -288,12 +288,12 @@ class TreeSupport /*! * \brief Areas that should have been support roof, but where the roof settings would not allow any lines to be generated. */ - std::vector additional_required_support_area; + std::vector additional_required_support_area; /*! * \brief A representation of already placed lines. Required for subtracting from new support areas. */ - std::vector placed_support_lines_support_areas; + std::vector placed_support_lines_support_areas; /*! * \brief Generator for model collision, avoidance and internal guide volumes. diff --git a/include/TreeSupportElement.h b/include/TreeSupportElement.h index 259f6017b9..3076883a30 100644 --- a/include/TreeSupportElement.h +++ b/include/TreeSupportElement.h @@ -10,7 +10,7 @@ #include "TreeModelVolumes.h" #include "TreeSupportBaseCircle.h" #include "TreeSupportEnums.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" @@ -95,7 +95,7 @@ struct TreeSupportElement RecreateInfluenceLimitArea(); } - TreeSupportElement(const TreeSupportElement& elem, Polygons* newArea = nullptr) + TreeSupportElement(const TreeSupportElement& elem, Shape* newArea = nullptr) : // copy constructor with possibility to set a new area target_height_(elem.target_height_) , target_position_(elem.target_position_) @@ -277,7 +277,7 @@ struct TreeSupportElement * \brief The resulting influence area. * Will only be set in the results of createLayerPathing, and will be nullptr inside! */ - Polygons* area_; + Shape* area_; /*! * \brief The resulting center point around which a circle will be drawn later. @@ -351,7 +351,7 @@ struct TreeSupportElement /*! * \brief Area that influence area has to be inside to conform to influence_area_limit_range. */ - Polygons influence_area_limit_area_; + Shape influence_area_limit_area_; /*! * \brief Additional locations that the tip should reach diff --git a/include/TreeSupportTipGenerator.h b/include/TreeSupportTipGenerator.h index 297bb8d927..6d7afcb3ae 100644 --- a/include/TreeSupportTipGenerator.h +++ b/include/TreeSupportTipGenerator.h @@ -40,8 +40,8 @@ class TreeSupportTipGenerator SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector>& move_bounds, - std::vector& additional_support_areas, - std::vector& placed_support_lines_support_areas); + std::vector& additional_support_areas, + std::vector& placed_support_lines_support_areas); private: enum class LineStatus @@ -121,7 +121,7 @@ class TreeSupportTipGenerator * \param result[out] The dropped overhang ares * \param roof[in] Whether the result is for roof generation. */ - void dropOverhangAreas(const SliceMeshStorage& mesh, std::vector& result, bool roof); + void dropOverhangAreas(const SliceMeshStorage& mesh, std::vector& result, bool roof); /*! * \brief Calculates which areas should be supported with roof, and saves these in roof support_roof_drawn @@ -174,7 +174,7 @@ class TreeSupportTipGenerator * \param storage[in] Background storage, required for adding roofs. * \param additional_support_areas[in] Areas that should have been roofs, but are now support, as they would not generate any lines as roof. */ - void removeUselessAddedPoints(std::vector>& move_bounds, SliceDataStorage& storage, std::vector& additional_support_areas); + void removeUselessAddedPoints(std::vector>& move_bounds, SliceDataStorage& storage, std::vector& additional_support_areas); /*! * \brief Contains config settings to avoid loading them in every function. This was done to improve readability of the code. @@ -296,12 +296,12 @@ class TreeSupportTipGenerator /*! * \brief Areas that will be saved as support roof */ - std::vector support_roof_drawn_; + std::vector support_roof_drawn_; /*! * \brief Areas that will be saved as support roof, originating from tips being replaced with roof areas. */ - std::vector roof_tips_drawn_; + std::vector roof_tips_drawn_; std::mutex critical_move_bounds_; std::mutex critical_roof_tips_; diff --git a/include/TreeSupportUtils.h b/include/TreeSupportUtils.h index d4fd828369..cae1d02c38 100644 --- a/include/TreeSupportUtils.h +++ b/include/TreeSupportUtils.h @@ -31,7 +31,7 @@ class TreeSupportUtils * \param poly[in] The Polygons object, of which its lines should be extended. * \return A Polygons object with explicit line from the last vertex of a Polygon to the first one added. */ - static LinesSet toPolylines(const Polygons& poly) + static LinesSet toPolylines(const Shape& poly) { #warning We should just cast it to a LineSet instead, but that's running for trouble yet LinesSet result; @@ -95,7 +95,7 @@ class TreeSupportUtils * \return A Polygons object that represents the resulting infill lines. */ [[nodiscard]] static LinesSet generateSupportInfillLines( - const Polygons& area, + const Shape& area, const TreeSupportSettings& config, bool roof, LayerIndex layer_idx, @@ -104,7 +104,7 @@ class TreeSupportUtils bool include_walls, bool generate_support_supporting = false) { - Polygons gaps; + Shape gaps; // As we effectivly use lines to place our supportPoints we may use the Infill class for it, while not made for it, it works perfectly. const EFillMethod pattern = generate_support_supporting ? EFillMethod::GRID : roof ? config.roof_pattern : config.support_pattern; @@ -156,7 +156,7 @@ class TreeSupportUtils zag_skip_count, pocket_size); - Polygons areas; + Shape areas; LinesSet lines; roof_computation.generate(toolpaths, areas, lines, config.settings, layer_idx, SectionType::SUPPORT, cross_fill_provider); lines.add(toPolylines(areas)); @@ -165,12 +165,12 @@ class TreeSupportUtils } /*! - * \brief Unions two Polygons. Ensures that if the input is non empty that the output also will be non empty. + * \brief Unions two Shape. Ensures that if the input is non empty that the output also will be non empty. * \param first[in] The first Polygon. * \param second[in] The second Polygon. - * \return The union of both Polygons + * \return The union of both Shape */ - [[nodiscard]] static Polygons safeUnion(const Polygons& first, const Polygons& second = Polygons()) + [[nodiscard]] static Shape safeUnion(const Shape& first, const Shape& second = Shape()) { // The unionPolygons function can slowly remove Polygons under certain circumstances, because of rounding issues (Polygons that have a thin area). // This does not cause a problem when actually using it on large areas, but as influence areas (representing centerpoints) can be very thin, this does occur so this ugly @@ -185,7 +185,7 @@ class TreeSupportUtils */ const bool was_empty = first.empty() && second.empty(); - Polygons result = first.unionPolygons(second); + Shape result = first.unionPolygons(second); if (result.empty() && ! was_empty) // Some error occurred. { @@ -199,19 +199,19 @@ class TreeSupportUtils /*! * \brief Offsets (increases the area of) a polygons object in multiple steps to ensure that it does not lag through over a given obstacle. - * \param me[in] Polygons object that has to be offset. + * \param me[in] Shape object that has to be offset. * \param distance[in] The distance by which me should be offset. Expects values >=0. * \param collision[in] The area representing obstacles. * \param last_step_offset_without_check[in] The most it is allowed to offset in one step. - * \param min_amount_offset[in] How many steps have to be done at least. As this uses round offset this increases the amount of vertices, which may be required if Polygons get + * \param min_amount_offset[in] How many steps have to be done at least. As this uses round offset this increases the amount of vertices, which may be required if Shape get * very small. Required as arcTolerance is not exposed in offset, which should result with a similar result, benefit may be eliminated by simplifying. \param * min_offset_per_step Don't get below this amount of offset per step taken. Fine-tune tradeoff between speed and accuracy. \param simplifier[in] Pointer to Simplify object if - * the offset operation also simplify the Polygon. Improves performance. \return The resulting Polygons object. + * the offset operation also simplify the Polygon. Improves performance. \return The resulting Shape object. */ - [[nodiscard]] static Polygons safeOffsetInc( - const Polygons& me, + [[nodiscard]] static Shape safeOffsetInc( + const Shape& me, coord_t distance, - const Polygons& collision, + const Shape& collision, coord_t safe_step_size, coord_t last_step_offset_without_check, size_t min_amount_offset, @@ -219,7 +219,7 @@ class TreeSupportUtils Simplify* simplifier) { bool do_final_difference = last_step_offset_without_check == 0; - Polygons ret = safeUnion(me); // Ensure sane input. + Shape ret = safeUnion(me); // Ensure sane input. if (distance == 0) { return (do_final_difference ? ret.difference(collision) : ret).unionPolygons(); @@ -289,7 +289,7 @@ class TreeSupportUtils * \param max_allowed_distance[in] The maximum distance a point may be moved. If not possible the point will be moved as far as possible in the direction of the outside of the * provided area. \return A Polyline object containing the moved points. */ - [[nodiscard]] static LinesSet movePointsOutside(const LinesSet& polylines, const Polygons& area, coord_t max_allowed_distance) + [[nodiscard]] static LinesSet movePointsOutside(const LinesSet& polylines, const Shape& area, coord_t max_allowed_distance) { LinesSet result; @@ -327,7 +327,7 @@ class TreeSupportUtils return result; } - [[nodiscard]] static VariableWidthLines polyLineToVWL(const Polygons& polylines, coord_t line_width) + [[nodiscard]] static VariableWidthLines polyLineToVWL(const Shape& polylines, coord_t line_width) { VariableWidthLines result; for (auto path : polylines) diff --git a/include/WallToolPaths.h b/include/WallToolPaths.h index 595c160ef4..7ac6a95c0f 100644 --- a/include/WallToolPaths.h +++ b/include/WallToolPaths.h @@ -26,7 +26,7 @@ class WallToolPaths * \param settings The settings as provided by the user */ WallToolPaths( - const Polygons& outline, + const Shape& outline, const coord_t nominal_bead_width, const size_t inset_count, const coord_t wall_0_inset, @@ -44,7 +44,7 @@ class WallToolPaths * \param settings The settings as provided by the user */ WallToolPaths( - const Polygons& outline, + const Shape& outline, const coord_t bead_width_0, const coord_t bead_width_x, const size_t inset_count, @@ -90,7 +90,7 @@ class WallToolPaths * If there are no walls, the outline will be returned. * \return The inner contour of the generated walls. */ - const Polygons& getInnerContour(); + const Shape& getInnerContour(); /*! * Removes empty paths from the toolpaths @@ -122,7 +122,7 @@ class WallToolPaths static void simplifyToolPaths(std::vector& toolpaths, const Settings& settings); private: - const Polygons& outline_; // toolpaths_; // class LinesSet; @@ -120,7 +120,7 @@ class LinesSet : public std::vector #warning rename this to removeDegenerateVerts void removeDegenerateVertsForEveryone(); - Polygons offset(coord_t distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; + Shape offset(coord_t distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; // Polygons offsetPolyLine(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, bool inputPolyIsClosed = false) const; /*! @@ -129,7 +129,7 @@ class LinesSet : public std::vector * kept, not the shape. \param outer_offset Offset relative to the original shape-outline towards the outside of the shape. Comparable to normal offset. \return The resulting * polygons. */ - Polygons tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; + Shape tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; }; } // namespace cura diff --git a/include/geometry/parts_view.h b/include/geometry/parts_view.h index 458ce956f8..2ce9c8a8fd 100644 --- a/include/geometry/parts_view.h +++ b/include/geometry/parts_view.h @@ -9,7 +9,7 @@ namespace cura { -class Polygons; +class Shape; class SingleShape; /*! @@ -19,9 +19,9 @@ class SingleShape; class PartsView : public std::vector> { public: - Polygons& polygons_; + Shape& polygons_; - PartsView(Polygons& polygons) + PartsView(Shape& polygons) : polygons_(polygons) { } diff --git a/include/geometry/polygon.h b/include/geometry/polygon.h index 80159f7f56..b06e286e12 100644 --- a/include/geometry/polygon.h +++ b/include/geometry/polygon.h @@ -9,13 +9,13 @@ namespace cura { -class Polygons; +class Shape; class ListPolyIt; class AngleDegrees; class Polygon : public GenericClosedPolyline { - friend class Polygons; + friend class Shape; public: Polygon() = default; @@ -48,7 +48,7 @@ class Polygon : public GenericClosedPolyline * * \param other The polygon with which to intersect this polygon. */ - Polygons intersection(const Polygon& other) const; + Shape intersection(const Polygon& other) const; double area() const { @@ -57,7 +57,7 @@ class Polygon : public GenericClosedPolyline Point2LL centerOfMass() const; - Polygons offset(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; + Shape offset(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; /*! * Smooth out small perpendicular segments and store the result in \p result. diff --git a/include/geometry/polygons.h b/include/geometry/polygons.h deleted file mode 100644 index e9440b3a25..0000000000 --- a/include/geometry/polygons.h +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (c) 2023 UltiMaker -// CuraEngine is released under the terms of the AGPLv3 or higher - -#ifndef GEOMETRY_POLYGONS_H -#define GEOMETRY_POLYGONS_H - -#include "geometry/lines_set.h" -#include "geometry/polygon.h" -#include "settings/types/Angle.h" - -namespace cura -{ - -class Polygon; -class Ratio; -class SingleShape; -class PartsView; - -class Polygons : public LinesSet -{ - friend class Polygon; - -public: - Polygons() = default; - - Polygons(const Polygons& other) = default; - - Polygons(Polygons&& other) = default; - - Polygons(const std::initializer_list& initializer) - : LinesSet(initializer) - { - } - - Polygons(const std::vector& paths) - : LinesSet(paths) - { - } - - Polygons& operator=(const Polygons& other); - - Polygons& operator=(Polygons&& other); - - void add(const Polygons& other); - - /*! - * Convert ClipperLib::PolyTree to a Polygons object, - * which uses ClipperLib::Paths instead of ClipperLib::PolyTree - */ - static Polygons toPolygons(ClipperLib::PolyTree& poly_tree); - - Polygons difference(const Polygons& other) const; - - Polygons unionPolygons(const Polygons& other, ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero) const; - - /*! - * Union all polygons with each other (When polygons.add(polygon) has been called for overlapping polygons) - */ - Polygons unionPolygons() const - { - return unionPolygons(Polygons()); - } - - Polygons intersection(const Polygons& other) const; - - - /*! - * Intersect polylines with this area Polygons object. - * - * \note Due to a clipper bug with polylines with nearly collinear segments, the polylines are cut up into separate polylines, and restitched back together at the end. - * - * \param polylines The (non-closed!) polylines to limit to the area of this Polygons object - * \param restitch Whether to stitch the resulting segments into longer polylines, or leave every segment as a single segment - * \param max_stitch_distance The maximum distance for two polylines to be stitched together with a segment - * \return The resulting polylines limited to the area of this Polygons object - */ - LinesSet intersectionPolyLines(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; - - /*! - * Add the front to each polygon so that the polygon is represented as a polyline - */ - void toPolylines(); - - /*! - * Split this poly line object into several line segment objects - * and store them in the \p result - */ - void splitPolylinesIntoSegments(Polygons& result) const; - Polygons splitPolylinesIntoSegments() const; - - /*! - * Split this polygon object into several line segment objects - * and store them in the \p result - */ - void splitPolygonsIntoSegments(Polygons& result) const; - Polygons splitPolygonsIntoSegments() const; - - Polygons xorPolygons(const Polygons& other, ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const; - - Polygons execute(ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const; - - /*! - * Check if we are inside the polygon. - * - * We do this by counting the number of polygons inside which this point lies. - * An odd number is inside, while an even number is outside. - * - * Returns false if outside, true if inside; if the point lies exactly on the border, will return \p border_result. - * - * \param p The point for which to check if it is inside this polygon - * \param border_result What to return when the point is exactly on the border - * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) - */ - bool inside(Point2LL p, bool border_result = false) const; - - /*! - * Find the polygon inside which point \p p resides. - * - * We do this by tracing from the point towards the positive X direction, - * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. - * We then find the polygon with an uneven number of crossings which is closest to \p p. - * - * If \p border_result, we return the first polygon which is exactly on \p p. - * - * \param p The point for which to check in which polygon it is. - * \param border_result Whether a point exactly on a polygon counts as inside - * \return The index of the polygon inside which the point \p p resides - */ - size_t findInside(Point2LL p, bool border_result = false) const; - - /*! - * Approximates the convex hull of the polygons. - * \p extra_outset Extra offset outward - * \return the convex hull (approximately) - * - */ - Polygons approxConvexHull(int extra_outset = 0) const; - - /*! - * Make each of the polygons convex - */ - void makeConvex(); - - /*! - * Compute the area enclosed within the polygons (minus holes) - * - * \return The area in square micron - */ - double area() const; - - /*! - * Smooth out small perpendicular segments - * Smoothing is performed by removing the inner most vertex of a line segment smaller than \p remove_length - * which has an angle with the next and previous line segment smaller than roughly 150* - * - * Note that in its current implementation this function doesn't remove line segments with an angle smaller than 30* - * Such would be the case for an N shape. - * - * \param remove_length The length of the largest segment removed - * \return The smoothed polygon - */ - Polygons smooth(int remove_length) const; - - /*! - * Smooth out sharp inner corners, by taking a shortcut which bypasses the corner - * - * \param angle The maximum angle of inner corners to be smoothed out - * \param shortcut_length The desired length of the shortcut line segment introduced (shorter shortcuts may be unavoidable) - * \return The resulting polygons - */ - Polygons smooth_outward(const AngleDegrees angle, int shortcut_length) const; - - Polygons smooth2(int remove_length, int min_area) const; //!< removes points connected to small lines - - void removeColinearEdges(const AngleRadians max_deviation_angle = AngleRadians(0.0005)); - - void scale(const Ratio& ratio); - - void translate(const Point2LL& delta); - - /*! - * Remove all but the polygons on the very outside. - * Exclude holes and parts within holes. - * \return the resulting polygons. - */ - Polygons getOutsidePolygons() const; - - /*! - * Exclude holes which have no parts inside of them. - * \return the resulting polygons. - */ - Polygons removeEmptyHoles() const; - - /*! - * Return hole polygons which have no parts inside of them. - * \return the resulting polygons. - */ - Polygons getEmptyHoles() const; - - /*! - * Split up the polygons into groups according to the even-odd rule. - * Each SingleShape in the result has an outline as first polygon, whereas the rest are holes. - */ - std::vector splitIntoParts(bool unionAll = false) const; - - /*! - * Sort the polygons into bins where each bin has polygons which are contained within one of the polygons in the previous bin. - * - * \warning When polygons are crossing each other the result is undefined. - */ - std::vector sortByNesting() const; - - /*! - * Split up the polygons into groups according to the even-odd rule. - * Each vector in the result has the index to an outline as first index, whereas the rest are indices to holes. - * - * \warning Note that this function reorders the polygons! - */ - PartsView splitIntoPartsView(bool unionAll = false); - - /*! - * Removes polygons with area smaller than \p min_area_size (note that min_area_size is in mm^2, not in micron^2). - * Unless \p remove_holes is true, holes are not removed even if their area is below \p min_area_size. - * However, holes that are contained within outlines whose area is below the threshold are removed though. - */ - void removeSmallAreas(const double min_area_size, const bool remove_holes = false); - - /*! - * Removes polygons with circumference smaller than \p min_circumference_size (in micron). - * Unless \p remove_holes is true, holes are not removed even if their circumference is below \p min_circumference_size. - * However, holes that are contained within outlines whose circumference is below the threshold are removed though. - */ - [[maybe_unused]] void removeSmallCircumference(const coord_t min_circumference_size, const bool remove_holes = false); - - /*! - * Removes polygons with circumference smaller than \p min_circumference_size (in micron) _and_ - * an area smaller then \p min_area_size (note that min_area_size is in mm^2, not in micron^2). - * Unless \p remove_holes is true, holes are not removed even if their circumference is - * below \p min_circumference_size and their area smaller then \p min_area_size. - * However, holes that are contained within outlines whose circumference is below the threshold are removed though. - */ - [[maybe_unused]] void removeSmallAreaCircumference(const double min_area_size, const coord_t min_circumference_size, const bool remove_holes = false); - - /*! - * Removes the same polygons from this set (and also empty polygons). - * Polygons are considered the same if all points lie within [same_distance] of their counterparts. - */ - Polygons removePolygon(const Polygons& to_be_removed, int same_distance = 0) const; - - Polygons processEvenOdd(ClipperLib::PolyFillType poly_fill_type = ClipperLib::PolyFillType::pftEvenOdd) const; - - /*! - * Ensure the polygon is manifold, by removing small areas where the polygon touches itself. - * ____ ____ - * | | | | - * | |____ ==> | / ____ - * """"| | """ / | - * |____| |____| - * - */ - void ensureManifold(); - - Point2LL min() const; - - Point2LL max() const; - - void applyMatrix(const PointMatrix& matrix); - - void applyMatrix(const Point3Matrix& matrix); - - Polygons offsetMulti(const std::vector& offset_dists) const; - - /*! - * @brief Export the polygon to a WKT string - * - * @param stream The stream to write to - */ - [[maybe_unused]] void writeWkt(std::ostream& stream) const; - - /*! - * @brief Import the polygon from a WKT string - * - * @param wkt The WKT string to read from - * @return Polygons The polygons read from the stream - */ - [[maybe_unused]] static Polygons fromWkt(const std::string& wkt); - -private: - /*! - * recursive part of \ref Polygons::removeEmptyHoles and \ref Polygons::getEmptyHoles - * \param node The node of the polygons part to process - * \param remove_holes Whether to remove empty holes or everything but the empty holes - * \param ret Where to store polygons which are not empty holes - */ - void removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Polygons& ret) const; - void splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const; - void sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const; - void splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Polygons& reordered, ClipperLib::PolyNode* node) const; -}; - -} // namespace cura - -namespace std -{ -#if 0 -template<> -struct hash -{ - size_t operator()(const cura::PolygonPointer& poly) const - { - const cura::ConstPolygonRef ref = *static_cast(poly); - return std::hash()(&*ref); - } -}; -#endif -} // namespace std - -#endif // GEOMETRY_POLYGONS_H diff --git a/include/geometry/single_shape.h b/include/geometry/single_shape.h index 733927ba2b..acd7737af6 100644 --- a/include/geometry/single_shape.h +++ b/include/geometry/single_shape.h @@ -4,7 +4,7 @@ #ifndef GEOMETRY_SINGLE_SHAPE_H #define GEOMETRY_SINGLE_SHAPE_H -#include "geometry/polygons.h" +#include "geometry/shape.h" #include "point2ll.h" namespace cura @@ -17,7 +17,7 @@ class Polygon; * * This class has little more functionality than Polygons, but serves to show that a specific instance is ordered such that the first Polygon is the outline and the rest are holes. */ -class SingleShape : public Polygons +class SingleShape : public Shape { public: Polygon& outerPolygon(); diff --git a/include/infill.h b/include/infill.h index 2c592ac8bc..daeba97d8f 100644 --- a/include/infill.h +++ b/include/infill.h @@ -35,8 +35,8 @@ class Infill // We skip ZigZag, Cross and Cross3D because they have their own algorithms. Eventually we want to replace all that with the new algorithm. // Cubic Subdivision ends lines in the center of the infill so it won't be effective. bool connect_polygons_{}; //!< Whether to connect as much polygons together into a single path - Polygons outer_contour_{}; //!< The area that originally needs to be filled with infill. The input of the algorithm. - Polygons inner_contour_{}; //!< The part of the contour that will get filled with an infill pattern. Equals outer_contour minus the extra infill walls. + Shape outer_contour_{}; //!< The area that originally needs to be filled with infill. The input of the algorithm. + Shape inner_contour_{}; //!< The part of the contour that will get filled with an infill pattern. Equals outer_contour minus the extra infill walls. coord_t infill_line_width_{}; //!< The line width of the infill lines to generate coord_t line_distance_{}; //!< The distance between two infill lines / polygons coord_t infill_overlap_{}; //!< the distance by which to overlap with the actual area within which to generate infill @@ -74,7 +74,7 @@ class Infill EFillMethod pattern, bool zig_zaggify, bool connect_polygons, - Polygons in_outline, + Shape in_outline, coord_t infill_line_width, coord_t line_distance, coord_t infill_overlap, @@ -104,7 +104,7 @@ class Infill EFillMethod pattern, bool zig_zaggify, bool connect_polygons, - Polygons in_outline, + Shape in_outline, coord_t infill_line_width, coord_t line_distance, coord_t infill_overlap, @@ -142,7 +142,7 @@ class Infill EFillMethod pattern, bool zig_zaggify, bool connect_polygons, - Polygons in_outline, + Shape in_outline, coord_t infill_line_width, coord_t line_distance, coord_t infill_overlap, @@ -202,7 +202,7 @@ class Infill */ void generate( std::vector& toolpaths, - Polygons& result_polygons, + Shape& result_polygons, LinesSet& result_lines, const Settings& settings, int layer_idx, @@ -210,7 +210,7 @@ class Infill const std::shared_ptr& cross_fill_provider = nullptr, const std::shared_ptr& lightning_layer = nullptr, const SliceMeshStorage* mesh = nullptr, - const Polygons& prevent_small_exposed_to_air = Polygons()); + const Shape& prevent_small_exposed_to_air = Shape()); /*! * Generate the wall toolpaths of an infill area. It will return the inner contour and set the inner-contour. @@ -224,9 +224,9 @@ class Infill * \param settings [in] A settings storage to use for generating variable-width walls. * \return The inner contour of the wall toolpaths */ - static Polygons generateWallToolPaths( + static Shape generateWallToolPaths( std::vector& toolpaths, - Polygons& outer_contour, + Shape& outer_contour, const size_t wall_line_count, const coord_t line_width, const coord_t infill_overlap, @@ -373,7 +373,7 @@ class Infill */ void _generate( std::vector& toolpaths, - Polygons& result_polygons, + Shape& result_polygons, LinesSet& result_lines, const Settings& settings, const std::shared_ptr& cross_fill_pattern = nullptr, @@ -391,14 +391,14 @@ class Infill * \param[in,out] result_polygons The polygons to be multiplied (input and output) * \param[in,out] result_lines The lines to be multiplied (input and output) */ - void multiplyInfill(Polygons& result_polygons, LinesSet& result_lines); + void multiplyInfill(Shape& result_polygons, LinesSet& result_lines); /*! * Generate gyroid infill * \param result_polylines (output) The resulting polylines * \param result_polygons (output) The resulting polygons, if zigzagging accidentally happened to connect gyroid lines in a circle. */ - void generateGyroidInfill(LinesSet& result_polylines, Polygons& result_polygons); + void generateGyroidInfill(LinesSet& result_polylines, Shape& result_polygons); /*! * Generate lightning fill aka minfill aka 'Ribbed Support Vault Infill', see Tricard,Claux,Lefebvre/'Ribbed Support Vaults for 3D Printing of Hollowed Objects' @@ -474,7 +474,7 @@ class Infill * \param[out] result_polygons The resulting polygons * \param[out] result_lines The resulting lines */ - void generateCrossInfill(const SierpinskiFillProvider& cross_fill_provider, Polygons& result_polygons, LinesSet& result_lines); + void generateCrossInfill(const SierpinskiFillProvider& cross_fill_provider, Shape& result_polygons, LinesSet& result_lines); /*! * Convert a mapping from scanline to line_segment-scanline-intersections (\p cut_list) into line segments, using the even-odd rule diff --git a/include/infill/GyroidInfill.h b/include/infill/GyroidInfill.h index e19018c0af..de5117876e 100644 --- a/include/infill/GyroidInfill.h +++ b/include/infill/GyroidInfill.h @@ -6,7 +6,7 @@ namespace cura { -class Polygons; +class Shape; class OpenPolyline; template @@ -37,7 +37,7 @@ class GyroidInfill * \param z The Z coordinate of this layer. Different Z coordinates cause the pattern to vary, producing a 3D * pattern. */ - static void generateTotalGyroidInfill(LinesSet& result_lines, bool zig_zaggify, coord_t line_distance, const Polygons& in_outline, coord_t z); + static void generateTotalGyroidInfill(LinesSet& result_lines, bool zig_zaggify, coord_t line_distance, const Shape& in_outline, coord_t z); private: }; diff --git a/include/infill/LightningDistanceField.h b/include/infill/LightningDistanceField.h index 728910ee5a..d9aa62b41a 100644 --- a/include/infill/LightningDistanceField.h +++ b/include/infill/LightningDistanceField.h @@ -29,7 +29,7 @@ class LightningDistanceField * \param current_overhang The overhang that needs to be supported on this * layer. */ - LightningDistanceField(const coord_t& radius, const Polygons& current_outline, const Polygons& current_overhang); + LightningDistanceField(const coord_t& radius, const Shape& current_outline, const Shape& current_overhang); /*! * Gets the next unsupported location to be supported by a new branch. @@ -76,13 +76,13 @@ class LightningDistanceField /*! * The total infill area on the current layer. */ - const Polygons& current_outline_; + const Shape& current_outline_; /*! * The overhang that gets introduced on this layer, which the infill will * need to support. */ - const Polygons& current_overhang_; + const Shape& current_overhang_; /*! * Represents a small discrete area of infill that needs to be supported. diff --git a/include/infill/LightningGenerator.h b/include/infill/LightningGenerator.h index 30a36e5b02..2cae273cbd 100644 --- a/include/infill/LightningGenerator.h +++ b/include/infill/LightningGenerator.h @@ -111,7 +111,7 @@ class LightningGenerator // "Just like Nicola used to make!" * * This is generated by \ref generateInitialInternalOverhangs. */ - std::vector overhang_per_layer; + std::vector overhang_per_layer; /*! * For each layer, the generated lightning paths. diff --git a/include/infill/LightningLayer.h b/include/infill/LightningLayer.h index 597c232ba6..6b74643570 100644 --- a/include/infill/LightningLayer.h +++ b/include/infill/LightningLayer.h @@ -36,8 +36,8 @@ class LightningLayer std::vector tree_roots; void generateNewTrees( - const Polygons& current_overhang, - const Polygons& current_outlines, + const Shape& current_overhang, + const Shape& current_outlines, const LocToLineGrid& outline_locator, const coord_t supporting_radius, const coord_t wall_supporting_radius); @@ -47,7 +47,7 @@ class LightningLayer */ GroundingLocation getBestGroundingLocation( const Point2LL& unsupported_location, - const Polygons& current_outlines, + const Shape& current_outlines, const LocToLineGrid& outline_locator, const coord_t supporting_radius, const coord_t wall_supporting_radius, @@ -63,12 +63,12 @@ class LightningLayer void reconnectRoots( std::vector& to_be_reconnected_tree_roots, - const Polygons& current_outlines, + const Shape& current_outlines, const LocToLineGrid& outline_locator, const coord_t supporting_radius, const coord_t wall_supporting_radius); - LinesSet convertToLines(const Polygons& limit_to_outline, const coord_t line_width) const; + LinesSet convertToLines(const Shape& limit_to_outline, const coord_t line_width) const; coord_t getWeightedDistance(const Point2LL& boundary_loc, const Point2LL& unsupported_location); diff --git a/include/infill/LightningTreeNode.h b/include/infill/LightningTreeNode.h index 124855b4ee..74a7496f62 100644 --- a/include/infill/LightningTreeNode.h +++ b/include/infill/LightningTreeNode.h @@ -11,7 +11,7 @@ #include "../utils/polygonUtils.h" #include "geometry/polygon.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" namespace cura { @@ -99,7 +99,7 @@ class LightningTreeNode : public std::enable_shared_from_this */ void propagateToNextLayer( std::vector& next_trees, - const Polygons& next_outlines, + const Shape& next_outlines, const LocToLineGrid& outline_locator, const coord_t prune_distance, const coord_t smooth_magnitude, @@ -201,7 +201,7 @@ class LightningTreeNode : public std::enable_shared_from_this /*! Reconnect trees from the layer above to the new outlines of the lower layer. * \return Wether or not the root is kept (false is no, true is yes). */ - bool realign(const Polygons& outlines, const LocToLineGrid& outline_locator, std::vector& rerooted_parts); + bool realign(const Shape& outlines, const LocToLineGrid& outline_locator, std::vector& rerooted_parts); struct RectilinearJunction { diff --git a/include/infill/ZigzagConnectorProcessor.h b/include/infill/ZigzagConnectorProcessor.h index a495ee5a8b..e0f349c429 100644 --- a/include/infill/ZigzagConnectorProcessor.h +++ b/include/infill/ZigzagConnectorProcessor.h @@ -12,7 +12,7 @@ namespace cura { class Polygon; -class Polygons; +class Shape; class PointMatrix; class OpenPolyline; template diff --git a/include/pathPlanning/Comb.h b/include/pathPlanning/Comb.h index 98276751c1..0104d16f61 100644 --- a/include/pathPlanning/Comb.h +++ b/include/pathPlanning/Comb.h @@ -60,7 +60,7 @@ class Comb Point2LL out_; //!< The point on the outside boundary SingleShape dest_part_; //!< The assembled inside-boundary SingleShape in which the dest_point lies. (will only be initialized when Crossing::dest_is_inside holds) std::optional dest_crossing_poly_; //!< The polygon of the part in which dest_point lies, which will be crossed (often will be the outside polygon) - const Polygons& boundary_inside_; //!< The inside boundary as in \ref Comb::boundary_inside + const Shape& boundary_inside_; //!< The inside boundary as in \ref Comb::boundary_inside const LocToLineGrid& inside_loc_to_line_; //!< The loc to line grid \ref Comb::inside_loc_to_line /*! @@ -77,7 +77,7 @@ class Comb const bool dest_is_inside, const unsigned int dest_part_idx, const unsigned int dest_part_boundary_crossing_poly_idx, - const Polygons& boundary_inside, + const Shape& boundary_inside, const LocToLineGrid& inside_loc_to_line); /*! @@ -100,7 +100,7 @@ class Comb * \param comber[in] The combing calculator which has references to the * offsets and boundaries to use in combing. */ - bool findOutside(const ExtruderTrain& train, const Polygons& outside, const Point2LL close_to, const bool fail_on_unavoidable_obstacles, Comb& comber); + bool findOutside(const ExtruderTrain& train, const Shape& outside, const Point2LL close_to, const bool fail_on_unavoidable_obstacles, Comb& comber); private: const Point2LL dest_point_; //!< Either the eventual startPoint or the eventual endPoint of this combing move @@ -119,7 +119,7 @@ class Comb * \return A pair of which the first is the crossing point on the inside boundary and the second the crossing point on the outside boundary */ std::shared_ptr> - findBestCrossing(const ExtruderTrain& train, const Polygons& outside, const Polygon& from, const Point2LL estimated_start, const Point2LL estimated_end, Comb& comber); + findBestCrossing(const ExtruderTrain& train, const Shape& outside, const Polygon& from, const Point2LL estimated_start, const Point2LL estimated_end, Comb& comber); }; @@ -136,15 +136,15 @@ class Comb static constexpr coord_t offset_dist_to_get_from_on_the_polygon_to_outside_ = 40; //!< in order to prevent on-boundary vs crossing boundary confusions (precision thing) static constexpr coord_t offset_extra_start_end_ = 100; //!< Distance to move start point and end point toward eachother to extra avoid collision with the boundaries. - Polygons boundary_inside_minimum_; //!< The boundary within which to comb. (Will be reordered by the partsView_inside_minimum) - Polygons boundary_inside_optimal_; //!< The boundary within which to comb. (Will be reordered by the partsView_inside_optimal) + Shape boundary_inside_minimum_; //!< The boundary within which to comb. (Will be reordered by the partsView_inside_minimum) + Shape boundary_inside_optimal_; //!< The boundary within which to comb. (Will be reordered by the partsView_inside_optimal) const PartsView parts_view_inside_minimum_; //!< Structured indices onto boundary_inside_minimum which shows which polygons belong to which part. const PartsView parts_view_inside_optimal_; //!< Structured indices onto boundary_inside_optimal which shows which polygons belong to which part. std::unique_ptr inside_loc_to_line_minimum_; //!< The SparsePointGridInclusive mapping locations to line segments of the inner boundary. std::unique_ptr inside_loc_to_line_optimal_; //!< The SparsePointGridInclusive mapping locations to line segments of the inner boundary. - std::unordered_map boundary_outside_; //!< The boundary outside of which to stay to avoid collision with other layer parts. This is a pointer cause we only + std::unordered_map boundary_outside_; //!< The boundary outside of which to stay to avoid collision with other layer parts. This is a pointer cause we only //!< compute it when we move outside the boundary (so not when there is only a single part in the layer) - std::unordered_map model_boundary_; //!< The boundary of the model itself + std::unordered_map model_boundary_; //!< The boundary of the model itself std::unordered_map> outside_loc_to_line_; //!< The SparsePointGridInclusive mapping locations to line segments of the outside boundary. std::unordered_map> model_boundary_loc_to_line_; //!< The SparsePointGridInclusive mapping locations to line segments of the model boundary @@ -159,7 +159,7 @@ class Comb /*! * Get the boundary_outside, which is an offset from the outlines of all meshes in the layer. Calculate it when it hasn't been calculated yet. */ - Polygons& getBoundaryOutside(const ExtruderTrain& train); + Shape& getBoundaryOutside(const ExtruderTrain& train); /*! * Get the SparsePointGridInclusive mapping locations to line segments of the model boundary. Calculate it when it hasn't been calculated yet. @@ -169,7 +169,7 @@ class Comb /*! * Get the boundary_outside, which is an offset from the outlines of all meshes in the layer. Calculate it when it hasn't been calculated yet. */ - Polygons& getModelBoundary(const ExtruderTrain& train); + Shape& getModelBoundary(const ExtruderTrain& train); /*! * Move the startPoint or endPoint inside when it should be inside @@ -179,9 +179,9 @@ class Comb * \param start_inside_poly[out] The polygon in which the point has been moved * \return Whether we have moved the point inside */ - bool moveInside(Polygons& boundary_inside, bool is_inside, LocToLineGrid* inside_loc_to_line, Point2LL& dest_point, size_t& start_inside_poly); + bool moveInside(Shape& boundary_inside, bool is_inside, LocToLineGrid* inside_loc_to_line, Point2LL& dest_point, size_t& start_inside_poly); - void moveCombPathInside(Polygons& boundary_inside, Polygons& boundary_inside_optimal, CombPath& comb_path_input, CombPath& comb_path_output); + void moveCombPathInside(Shape& boundary_inside, Shape& boundary_inside_optimal, CombPath& comb_path_input, CombPath& comb_path_output); public: /*! @@ -208,8 +208,8 @@ class Comb Comb( const SliceDataStorage& storage, const LayerIndex layer_nr, - const Polygons& comb_boundary_inside_minimum, - const Polygons& comb_boundary_inside_optimal, + const Shape& comb_boundary_inside_minimum, + const Shape& comb_boundary_inside_optimal, coord_t offset_from_outlines, coord_t travel_avoid_distance, coord_t move_inside_distance); diff --git a/include/pathPlanning/LinePolygonsCrossings.h b/include/pathPlanning/LinePolygonsCrossings.h index 68f4cfd97d..00a584cb9c 100644 --- a/include/pathPlanning/LinePolygonsCrossings.h +++ b/include/pathPlanning/LinePolygonsCrossings.h @@ -48,7 +48,7 @@ class LinePolygonsCrossings std::vector crossings_; //!< All crossings of polygons in the LinePolygonsCrossings::boundary with the scanline. - const Polygons& boundary_; //!< The boundary not to cross during combing. + const Shape& boundary_; //!< The boundary not to cross during combing. LocToLineGrid& loc_to_line_grid_; //!< Mapping from locations to line segments of \ref LinePolygonsCrossings::boundary Point2LL start_point_; //!< The start point of the scanline. Point2LL end_point_; //!< The end point of the scanline. @@ -125,7 +125,7 @@ class LinePolygonsCrossings * \param end the end point * \param dist_to_move_boundary_point_outside Distance used to move a point from a boundary so that it doesn't intersect with it anymore. (Precision issue) */ - LinePolygonsCrossings(const Polygons& boundary, LocToLineGrid& loc_to_line_grid, Point2LL& start, Point2LL& end, int64_t dist_to_move_boundary_point_outside) + LinePolygonsCrossings(const Shape& boundary, LocToLineGrid& loc_to_line_grid, Point2LL& start, Point2LL& end, int64_t dist_to_move_boundary_point_outside) : boundary_(boundary) , loc_to_line_grid_(loc_to_line_grid) , start_point_(start) @@ -146,7 +146,7 @@ class LinePolygonsCrossings * \return Whether combing succeeded, i.e. we didn't cross any gaps/other parts */ static bool comb( - const Polygons& boundary, + const Shape& boundary, LocToLineGrid& loc_to_line_grid, Point2LL startPoint, Point2LL endPoint, diff --git a/include/plugins/converters.h b/include/plugins/converters.h index 5a9d210d36..300ffd527e 100644 --- a/include/plugins/converters.h +++ b/include/plugins/converters.h @@ -80,12 +80,12 @@ struct handshake_response : public details::converter +struct simplify_request : public details::converter { value_type operator()(const native_value_type& polygons, const coord_t max_resolution, const coord_t max_deviation, const coord_t max_area_deviation) const; }; -struct simplify_response : public details::converter +struct simplify_response : public details::converter { native_value_type operator()([[maybe_unused]] const native_value_type& original_value, const value_type& message) const; }; @@ -100,14 +100,14 @@ struct postprocess_response : public details::converter +struct infill_generate_request : public details::converter { value_type operator()(const native_value_type& inner_contour, const std::string& pattern, const Settings& settings) const; }; struct infill_generate_response : public details:: - converter>, Polygons, LinesSet>> + converter>, Shape, LinesSet>> { native_value_type operator()(const value_type& message) const; }; diff --git a/include/plugins/slots.h b/include/plugins/slots.h index 01dd18f4e8..8d4c4dc538 100644 --- a/include/plugins/slots.h +++ b/include/plugins/slots.h @@ -51,7 +51,7 @@ struct simplify_default struct infill_generate_default { - std::tuple, Polygons, LinesSet> operator()([[maybe_unused]] auto&&... args) + std::tuple, Shape, LinesSet> operator()([[maybe_unused]] auto&&... args) { // this code is only reachable when no slot is registered while the infill type is requested to be // generated by a plugin; this should not be possible to set up in the first place. Return an empty diff --git a/include/skin.h b/include/skin.h index e0367cbf0c..fe7d555ef7 100644 --- a/include/skin.h +++ b/include/skin.h @@ -10,7 +10,7 @@ namespace cura { -class Polygons; +class Shape; class SkinPart; class SliceLayerPart; class SliceMeshStorage; @@ -96,7 +96,7 @@ class SkinInfillAreaComputation * above. The input is the area within the inner walls (or an empty Polygons * object). */ - void calculateTopSkin(const SliceLayerPart& part, Polygons& upskin); + void calculateTopSkin(const SliceLayerPart& part, Shape& upskin); /*! * \brief Calculate the basic areas which have air below. @@ -105,7 +105,7 @@ class SkinInfillAreaComputation * layers above. The input is the area within the inner walls (or an empty * Polygons object). */ - void calculateBottomSkin(const SliceLayerPart& part, Polygons& downskin); + void calculateBottomSkin(const SliceLayerPart& part, Shape& downskin); /*! * Apply skin expansion: @@ -116,7 +116,7 @@ class SkinInfillAreaComputation * \param[in,out] upskin The top skin areas to grow * \param[in,out] downskin The bottom skin areas to grow */ - void applySkinExpansion(const Polygons& original_outline, Polygons& upskin, Polygons& downskin); + void applySkinExpansion(const Shape& original_outline, Shape& upskin, Shape& downskin); /*! * Generate infill of a given part @@ -150,7 +150,7 @@ class SkinInfillAreaComputation * \param part Where to get the SkinParts to get the outline info from * \param roofing_layer_count The number of layers above the layer which we are looking into */ - Polygons generateFilledAreaAbove(SliceLayerPart& part, size_t roofing_layer_count); + Shape generateFilledAreaAbove(SliceLayerPart& part, size_t roofing_layer_count); /*! * Helper function to calculate and return the areas which are 'directly' above air. @@ -158,7 +158,7 @@ class SkinInfillAreaComputation * \param part Where to get the SkinParts to get the outline info from * \param flooring_layer_count The number of layers below the layer which we are looking into */ - Polygons generateFilledAreaBelow(SliceLayerPart& part, size_t flooring_layer_count); + Shape generateFilledAreaBelow(SliceLayerPart& part, size_t flooring_layer_count); protected: LayerIndex layer_nr_; //!< The index of the layer for which to generate the skins and infill. @@ -191,7 +191,7 @@ class SkinInfillAreaComputation * \param part_here The part for which to check. * \param layer2_nr The layer index from which to gather the outlines. */ - Polygons getOutlineOnLayer(const SliceLayerPart& part_here, const LayerIndex layer2_nr); + Shape getOutlineOnLayer(const SliceLayerPart& part_here, const LayerIndex layer2_nr); }; } // namespace cura diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 34ec3782ee..6b987c636a 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -44,10 +44,10 @@ class SkinPart public: SingleShape outline; //!< The skinOutline is the area which needs to be 100% filled to generate a proper top&bottom filling. It's filled by the "skin" module. Includes both //!< roofing and non-roofing. - Polygons skin_fill; //!< The part of the skin which is not roofing. - Polygons roofing_fill; //!< The inner infill which has air directly above - Polygons top_most_surface_fill; //!< The inner infill of the uppermost top layer which has air directly above. - Polygons bottom_most_surface_fill; //!< The inner infill of the bottommost bottom layer which has air directly below. + Shape skin_fill; //!< The part of the skin which is not roofing. + Shape roofing_fill; //!< The inner infill which has air directly above + Shape top_most_surface_fill; //!< The inner infill of the uppermost top layer which has air directly above. + Shape bottom_most_surface_fill; //!< The inner infill of the bottommost bottom layer which has air directly below. }; /*! @@ -64,10 +64,10 @@ class SliceLayerPart SingleShape outline; //!< The outline is the first member that is filled, and it's filled with polygons that match //!< a cross-section of the 3D model. The first polygon is the outer boundary polygon and the //!< rest are holes. - Polygons print_outline; //!< An approximation to the outline of what's actually printed, based on the outer wall. + Shape print_outline; //!< An approximation to the outline of what's actually printed, based on the outer wall. //!< Too small parts will be omitted compared to the outline. - Polygons spiral_wall; //!< The centerline of the wall used by spiralize mode. Only computed if spiralize mode is enabled. - Polygons inner_area; //!< The area of the outline, minus the walls. This will be filled with either skin or infill. + Shape spiral_wall; //!< The centerline of the wall used by spiralize mode. Only computed if spiralize mode is enabled. + Shape inner_area; //!< The area of the outline, minus the walls. This will be filled with either skin or infill. std::vector skin_parts; //!< The skin parts which are filled for 100% with lines and/or insets. std::vector wall_toolpaths; //!< toolpaths for walls, will replace(?) the insets. Binned by inset_idx. std::vector infill_wall_toolpaths; //!< toolpaths for the walls of the infill areas. Binned by inset_idx. @@ -77,7 +77,7 @@ class SliceLayerPart * Like SliceLayerPart::outline, this class member is not used to actually determine the feature area, * but is used to compute the inside comb boundary. */ - Polygons infill_area; + Shape infill_area; /*! * The areas which need to be filled with sparse (0-99%) infill. @@ -88,7 +88,7 @@ class SliceLayerPart * * If these polygons are not initialized, simply use the normal infill area. */ - std::optional infill_area_own; + std::optional infill_area_own; /*! * The areas which need to be filled with sparse (0-99%) infill for different thicknesses. @@ -135,21 +135,21 @@ class SliceLayerPart * infill_area[x] will lie fully inside infill_area[x+1]. * infill_area_per_combine_per_density.back()[0] == part.infill area initially */ - std::vector> infill_area_per_combine_per_density; + std::vector> infill_area_per_combine_per_density; /*! * Get the infill_area_own (or when it's not instantiated: the normal infill_area) * \see SliceLayerPart::infill_area_own * \return the own infill area */ - Polygons& getOwnInfillArea(); + Shape& getOwnInfillArea(); /*! * Get the infill_area_own (or when it's not instantiated: the normal infill_area) * \see SliceLayerPart::infill_area_own * \return the own infill area */ - const Polygons& getOwnInfillArea() const; + const Shape& getOwnInfillArea() const; /*! * Searches whether the part has any walls in the specified inset index @@ -183,7 +183,7 @@ class SliceLayer * * Note: Filled only when needed. */ - Polygons bottom_surface; + Shape bottom_surface; /*! * Get the all outlines of all layer parts in this layer. @@ -191,7 +191,7 @@ class SliceLayer * \param external_polys_only Whether to only include the outermost outline of each layer part * \return A collection of all the outline polygons */ - Polygons getOutlines(bool external_polys_only = false) const; + Shape getOutlines(bool external_polys_only = false) const; /*! * Get the all outlines of all layer parts in this layer. @@ -200,7 +200,7 @@ class SliceLayer * \param external_polys_only Whether to only include the outermost outline of each layer part * \param result The result: a collection of all the outline polygons */ - void getOutlines(Polygons& result, bool external_polys_only = false) const; + void getOutlines(Shape& result, bool external_polys_only = false) const; ~SliceLayer(); }; @@ -212,14 +212,14 @@ class SupportLayer { public: std::vector support_infill_parts; //!< a list of support infill parts - Polygons support_bottom; //!< Piece of support below the support and above the model. This must not overlap with any of the support_infill_parts or support_roof. - Polygons support_roof; //!< Piece of support above the support and below the model. This must not overlap with any of the support_infill_parts or support_bottom. + Shape support_bottom; //!< Piece of support below the support and above the model. This must not overlap with any of the support_infill_parts or support_roof. + Shape support_roof; //!< Piece of support above the support and below the model. This must not overlap with any of the support_infill_parts or support_bottom. // NOTE: This is _all_ of the support_roof, and as such, overlaps with support_fractional_roof! - Polygons support_fractional_roof; //!< If the support distance is not exactly a multiple of the layer height, + Shape support_fractional_roof; //!< If the support distance is not exactly a multiple of the layer height, // the first part of support just underneath the model needs to be printed at a fracional layer height. - Polygons support_mesh_drop_down; //!< Areas from support meshes which should be supported by more support - Polygons support_mesh; //!< Areas from support meshes which should NOT be supported by more support - Polygons anti_overhang; //!< Areas where no overhang should be detected. + Shape support_mesh_drop_down; //!< Areas from support meshes which should be supported by more support + Shape support_mesh; //!< Areas from support meshes which should NOT be supported by more support + Shape anti_overhang; //!< Areas where no overhang should be detected. /*! * Exclude the given polygons from the support infill areas and update the SupportInfillParts. @@ -227,7 +227,7 @@ class SupportLayer * \param exclude_polygons The polygons to exclude * \param exclude_polygons_boundary_box The boundary box for the polygons to exclude */ - void excludeAreasFromSupportInfillAreas(const Polygons& exclude_polygons, const AABB& exclude_polygons_boundary_box); + void excludeAreasFromSupportInfillAreas(const Shape& exclude_polygons, const AABB& exclude_polygons_boundary_box); /* Fill up the infill parts for the support with the given support polygons. The support polygons will be split into parts. This also takes into account fractional-height * support layers. @@ -242,7 +242,7 @@ class SupportLayer */ void fillInfillParts( const LayerIndex layer_nr, - const std::vector& support_fill_per_layer, + const std::vector& support_fill_per_layer, const coord_t support_line_width, const coord_t wall_line_count, const coord_t grow_layer_above = 0, @@ -284,10 +284,10 @@ class SliceMeshStorage std::vector infill_angles; //!< a list of angle values which is cycled through to determine the infill angle of each layer std::vector roofing_angles; //!< a list of angle values which is cycled through to determine the roofing angle of each layer std::vector skin_angles; //!< a list of angle values which is cycled through to determine the skin angle of each layer - std::vector overhang_areas; //!< For each layer the areas that are classified as overhang on this mesh. - std::vector full_overhang_areas; //!< For each layer the full overhang without the tangent of the overhang angle removed, such that the overhang area adjoins the + std::vector overhang_areas; //!< For each layer the areas that are classified as overhang on this mesh. + std::vector full_overhang_areas; //!< For each layer the full overhang without the tangent of the overhang angle removed, such that the overhang area adjoins the //!< areas of the next layers. - std::vector> overhang_points; //!< For each layer a list of points where point-overhang is detected. This is overhang that hasn't got any surface area, + std::vector> overhang_points; //!< For each layer a list of points where point-overhang is detected. This is overhang that hasn't got any surface area, //!< such as a corner pointing downwards. AABB3D bounding_box; //!< the mesh's bounding box @@ -339,7 +339,7 @@ class SliceMeshStorage struct SkirtBrimLine { LinesSet open_polylines; - Polygons closed_polygons; + Shape closed_polygons; }; class SliceDataStorage : public NoCopy @@ -359,21 +359,21 @@ class SliceDataStorage : public NoCopy LinesSet support_brim; //!< brim lines for support, going from the edge of the support inward. \note Not ordered by inset. // Storage for the outline of the raft-parts. Will be filled with lines when the GCode is generated. - Polygons raftBaseOutline; - Polygons raftInterfaceOutline; - Polygons raftSurfaceOutline; + Shape raftBaseOutline; + Shape raftInterfaceOutline; + Shape raftSurfaceOutline; int max_print_height_second_to_last_extruder; //!< Used in multi-extrusion: the layer number beyond which all models are printed with the same extruder std::vector max_print_height_per_extruder; //!< For each extruder the highest layer number at which it is used. std::vector max_print_height_order; //!< Ordered indices into max_print_height_per_extruder: back() will return the extruder number with the highest print height. std::vector spiralize_seam_vertex_indices; //!< the index of the seam vertex for each layer - std::vector spiralize_wall_outlines; //!< the wall outline polygons for each layer + std::vector spiralize_wall_outlines; //!< the wall outline polygons for each layer PrimeTower primeTower; - std::vector oozeShield; // oozeShield per layer - Polygons draft_protection_shield; //!< The polygons for a heightened skirt which protects from warping by gusts of wind and acts as a heated chamber. + std::vector oozeShield; // oozeShield per layer + Shape draft_protection_shield; //!< The polygons for a heightened skirt which protects from warping by gusts of wind and acts as a heated chamber. /*! * \brief Creates a new slice data storage that stores the slice data of the @@ -396,7 +396,7 @@ class SliceDataStorage : public NoCopy * \param external_polys_only Whether to disregard all hole polygons. * \param extruder_nr (optional) only give back outlines for this extruder (where the walls are printed with this extruder) */ - Polygons + Shape getLayerOutlines(const LayerIndex layer_nr, const bool include_support, const bool include_prime_tower, const bool external_polys_only = false, const int extruder_nr = -1) const; @@ -428,9 +428,9 @@ class SliceDataStorage : public NoCopy * Gets the border of the usable print area for this machine. * * \param extruder_nr The extruder for which to return the allowed areas. -1 if the areas allowed for all extruders should be returned. - * \return the Polygons representing the usable area of the print bed. + * \return the Shape representing the usable area of the print bed. */ - Polygons getMachineBorder(int extruder_nr = -1) const; + Shape getMachineBorder(int extruder_nr = -1) const; private: /*! diff --git a/include/slicer.h b/include/slicer.h index dd3b98c516..83d648f608 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -9,7 +9,7 @@ #include #include "geometry/polygon.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" #include "settings/EnumSettings.h" /* @@ -61,7 +61,7 @@ class SlicerLayer std::unordered_map face_idx_to_segment_idx; // topology int z = -1; - Polygons polygons; + Shape polygons; LinesSet openPolylines; /*! diff --git a/include/support.h b/include/support.h index 4f74df5a45..9d9eb71725 100644 --- a/include/support.h +++ b/include/support.h @@ -75,7 +75,7 @@ class AreaSupport * \param total_layer_count total number of layers */ static void - splitGlobalSupportAreasIntoSupportInfillParts(SliceDataStorage& storage, const std::vector& global_support_areas_per_layer, unsigned int total_layer_count); + splitGlobalSupportAreasIntoSupportInfillParts(SliceDataStorage& storage, const std::vector& global_support_areas_per_layer, unsigned int total_layer_count); /*! * Generate gradual support on the already generated support areas. This must be called after generateSupportAreas(). @@ -158,7 +158,7 @@ class AreaSupport const Settings& bottom_settings, const size_t mesh_idx, const size_t layer_count, - std::vector& support_areas); + std::vector& support_areas); /*! * Generate support bottom areas for a given mesh. @@ -172,7 +172,7 @@ class AreaSupport * \param mesh The mesh to generate support for. * \param global_support_areas_per_layer the global support areas on each layer. */ - static void generateSupportBottom(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector& global_support_areas_per_layer); + static void generateSupportBottom(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector& global_support_areas_per_layer); /*! * Generate support roof areas for a given mesh. @@ -186,7 +186,7 @@ class AreaSupport * \param mesh The mesh to generate support roof for. * \param global_support_areas_per_layer the global support areas on each layer. */ - static void generateSupportRoof(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector& global_support_areas_per_layer); + static void generateSupportRoof(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector& global_support_areas_per_layer); /*! * \brief Generate a single layer of support interface. @@ -206,12 +206,12 @@ class AreaSupport * \param[out] interface_polygons The resulting interface layer. Do not use `interface` in windows! */ static void generateSupportInterfaceLayer( - Polygons& support_areas, - const Polygons mesh_outlines, + Shape& support_areas, + const Shape mesh_outlines, const coord_t safety_offset, const coord_t outline_offset, const double minimum_interface_area, - Polygons& interface_polygons); + Shape& interface_polygons); /*! * \brief Join current support layer with the support of the layer above, @@ -221,7 +221,7 @@ class AreaSupport * \param supportLayer_this The overhang areas of the current layer at hand. * \return The joined support areas for this layer. */ - static Polygons join(const SliceDataStorage& storage, const Polygons& supportLayer_up, Polygons& supportLayer_this); + static Shape join(const SliceDataStorage& storage, const Shape& supportLayer_up, Shape& supportLayer_this); /*! * Move the support up from model (cut away polygons to ensure bottom z distance) @@ -239,9 +239,9 @@ class AreaSupport */ static void moveUpFromModel( const SliceDataStorage& storage, - Polygons& stair_removal, - Polygons& sloped_areas, - Polygons& support_areas, + Shape& stair_removal, + Shape& sloped_areas, + Shape& support_areas, const size_t layer_idx, const size_t bottom_empty_layer_count, const size_t bottom_stair_step_layer_count, @@ -272,7 +272,7 @@ class AreaSupport * \param layer_idx The layer for which to compute the overhang. * \return A pair of basic overhang and full overhang. */ - static std::pair computeBasicAndFullOverhang(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const LayerIndex& layer_idx); + static std::pair computeBasicAndFullOverhang(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const LayerIndex& layer_idx); /*! * \brief Adds tower pieces to the current support layer. @@ -290,10 +290,10 @@ class AreaSupport */ static void handleTowers( const Settings& settings, - const Polygons& xy_disallowed_area, - Polygons& supportLayer_this, - std::vector& tower_roofs, - std::vector>& overhang_points, + const Shape& xy_disallowed_area, + Shape& supportLayer_this, + std::vector& tower_roofs, + std::vector>& overhang_points, LayerIndex layer_idx, size_t layer_count); @@ -303,7 +303,7 @@ class AreaSupport * \param supportLayer_this The areas of the layer for which to handle the * wall struts. */ - static void handleWallStruts(const Settings& settings, Polygons& supportLayer_this); + static void handleWallStruts(const Settings& settings, Shape& supportLayer_this); /*! * Clean up the SupportInfillParts. @@ -323,7 +323,7 @@ class AreaSupport * \param layer_idx The layer for which the disallowed areas are to be calcualted * */ - static Polygons generateVaryingXYDisallowedArea(const SliceMeshStorage& storage, const LayerIndex layer_idx); + static Shape generateVaryingXYDisallowedArea(const SliceMeshStorage& storage, const LayerIndex layer_idx); }; diff --git a/include/utils/AABB.h b/include/utils/AABB.h index 57e3e8c2b6..bbd9a44367 100644 --- a/include/utils/AABB.h +++ b/include/utils/AABB.h @@ -10,7 +10,7 @@ namespace cura { class Polygon; -class Polygons; +class Shape; /* Axis aligned boundary box */ class AABB @@ -20,10 +20,10 @@ class AABB AABB(); //!< initializes with invalid min and max AABB(const Point2LL& min, const Point2LL& max); //!< initializes with given min and max - AABB(const Polygons& polys); //!< Computes the boundary box for the given polygons + AABB(const Shape& polys); //!< Computes the boundary box for the given polygons AABB(const Polygon& poly); //!< Computes the boundary box for the given polygons - void calculate(const Polygons& polys); //!< Calculates the aabb for the given polygons (throws away old min and max data of this aabb) + void calculate(const Shape& polys); //!< Calculates the aabb for the given polygons (throws away old min and max data of this aabb) void calculate(const Polygon& poly); //!< Calculates the aabb for the given polygon (throws away old min and max data of this aabb) /*! diff --git a/include/utils/ExtrusionLine.h b/include/utils/ExtrusionLine.h index f54b527073..d977ddc5d1 100644 --- a/include/utils/ExtrusionLine.h +++ b/include/utils/ExtrusionLine.h @@ -11,7 +11,7 @@ #include "ExtrusionJunction.h" #include "geometry/polygon.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" namespace cura { @@ -230,7 +230,7 @@ struct ExtrusionLine * Create a true-extrusion area shape for the path; this means that each junction follows the bead-width * set for that junction. */ - [[maybe_unused]] Polygons toExtrusionPolygons() const + [[maybe_unused]] Shape toExtrusionPolygons() const { Polygon poly; @@ -260,7 +260,7 @@ struct ExtrusionLine // backward pass add_line_direction(junctions_ | ranges::views::reverse); - Polygons paths; + Shape paths; paths.emplace_back(poly); ClipperLib::SimplifyPolygons(paths.getCallable(), ClipperLib::pftNonZero); return paths; diff --git a/include/utils/ExtrusionSegment.h b/include/utils/ExtrusionSegment.h index 2f888ada6c..ce4da45ad8 100644 --- a/include/utils/ExtrusionSegment.h +++ b/include/utils/ExtrusionSegment.h @@ -55,7 +55,7 @@ class ExtrusionSegment * Converts this segment to an outline of the area that the segment covers. * \return The area that would be covered by this extrusion segment. */ - Polygons toPolygons(); + Shape toPolygons(); /*! * Converts this segment to an outline of the area that the segment covers. @@ -63,7 +63,7 @@ class ExtrusionSegment * it will be included in the next extrusion move. Overrides class field * \ref is_reduced . */ - Polygons toPolygons(bool reduced); + Shape toPolygons(bool reduced); /*! * Discretize a variable-line-width extrusion segment into multiple diff --git a/include/utils/ListPolyIt.h b/include/utils/ListPolyIt.h index 11161beb1c..3a9eaf3dfd 100644 --- a/include/utils/ListPolyIt.h +++ b/include/utils/ListPolyIt.h @@ -14,7 +14,7 @@ namespace cura { class Polygon; -class Polygons; +class Shape; using ListPolygon = std::list; //!< A polygon represented by a linked list instead of a vector using ListPolygons = std::vector; //!< Polygons represented by a vector of linked lists instead of a vector of vectors @@ -115,7 +115,7 @@ class ListPolyIt * \param polys The polygons to convert * \param result The converted polygons */ - static void convertPolygonsToLists(const Polygons& polys, ListPolygons& result); + static void convertPolygonsToLists(const Shape& polys, ListPolygons& result); /*! * Convert Polygons to ListPolygons @@ -131,7 +131,7 @@ class ListPolyIt * \param list_polygons The polygons to convert * \param polygons The converted polygons */ - static void convertListPolygonsToPolygons(const ListPolygons& list_polygons, Polygons& polygons); + static void convertListPolygonsToPolygons(const ListPolygons& list_polygons, Shape& polygons); /*! * Convert ListPolygons to Polygons diff --git a/include/utils/OpenPolylineStitcher.h b/include/utils/OpenPolylineStitcher.h index a4576ba735..fd189fa818 100644 --- a/include/utils/OpenPolylineStitcher.h +++ b/include/utils/OpenPolylineStitcher.h @@ -7,12 +7,12 @@ #include "PolylineStitcher.h" #include "geometry/open_polyline.h" #include "geometry/polygon.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" namespace cura { -using OpenPolylineStitcher = PolylineStitcher, Polygons, OpenPolyline, Point2LL>; +using OpenPolylineStitcher = PolylineStitcher, Shape, OpenPolyline, Point2LL>; } // namespace cura #endif // UTILS_OPEN_POLYLINE_STITCHER_H diff --git a/include/utils/PolygonConnector.h b/include/utils/PolygonConnector.h index c9fa24d2f6..1526dc5cd1 100644 --- a/include/utils/PolygonConnector.h +++ b/include/utils/PolygonConnector.h @@ -76,7 +76,7 @@ class PolygonConnector /*! * Add polygons to be connected by a future call to \ref PolygonConnector::connect() */ - void add(const Polygons& input); + void add(const Shape& input); /*! * Add variable-width paths to be connected by a future call to @@ -99,7 +99,7 @@ class PolygonConnector * \param output_paths Paths that were connected as much as possible. These * are expected to be empty to start with. */ - void connect(Polygons& output_polygons, std::vector& output_paths); + void connect(Shape& output_polygons, std::vector& output_paths); protected: coord_t line_width_; //!< The distance between the line segments which connect two polygons. diff --git a/include/utils/PolygonsPointIndex.h b/include/utils/PolygonsPointIndex.h index cf38f1980e..92d83a8a2c 100644 --- a/include/utils/PolygonsPointIndex.h +++ b/include/utils/PolygonsPointIndex.h @@ -8,7 +8,7 @@ #include "geometry/point2ll.h" #include "geometry/polygon.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" namespace cura @@ -146,7 +146,7 @@ class PathsPointIndex } }; -using PolygonsPointIndex = PathsPointIndex; +using PolygonsPointIndex = PathsPointIndex; /*! @@ -170,7 +170,7 @@ struct PathsPointIndexLocator } }; -using PolygonsPointIndexLocator = PathsPointIndexLocator; +using PolygonsPointIndexLocator = PathsPointIndexLocator; } // namespace cura diff --git a/include/utils/PolygonsSegmentIndex.h b/include/utils/PolygonsSegmentIndex.h index ab37fa2f06..c0c5d395c9 100644 --- a/include/utils/PolygonsSegmentIndex.h +++ b/include/utils/PolygonsSegmentIndex.h @@ -18,7 +18,7 @@ class PolygonsSegmentIndex : public PolygonsPointIndex { public: PolygonsSegmentIndex(); - PolygonsSegmentIndex(const Polygons* polygons, unsigned int poly_idx, unsigned int point_idx); + PolygonsSegmentIndex(const Shape* polygons, unsigned int poly_idx, unsigned int point_idx); Point2LL from() const; diff --git a/include/utils/SVG.h b/include/utils/SVG.h index d362a74af5..2d0a9ced7b 100644 --- a/include/utils/SVG.h +++ b/include/utils/SVG.h @@ -99,7 +99,7 @@ class SVG : NoCopy void writeComment(const std::string& comment) const; - void writeAreas(const Polygons& polygons, const ColorObject color = Color::GRAY, const ColorObject outline_color = Color::BLACK, const double stroke_width = 1.0) const; + void writeAreas(const Shape& polygons, const ColorObject color = Color::GRAY, const ColorObject outline_color = Color::BLACK, const double stroke_width = 1.0) const; void writeAreas(const Polygon& polygon, const ColorObject color = Color::GRAY, const ColorObject outline_color = Color::BLACK, const double stroke_width = 1.0) const; @@ -107,7 +107,7 @@ class SVG : NoCopy void writePoints(const Polygon& poly, const bool write_coords = false, const double size = 5.0, const ColorObject color = Color::BLACK) const; - void writePoints(const Polygons& polygons, const bool write_coords = false, const double size = 5.0, const ColorObject color = Color::BLACK) const; + void writePoints(const Shape& polygons, const bool write_coords = false, const double size = 5.0, const ColorObject color = Color::BLACK) const; /*! * \brief Draws a polyline on the canvas. @@ -144,11 +144,11 @@ class SVG : NoCopy void writeText(const Point2LL& p, const std::string& txt, const ColorObject color = Color::BLACK, const double font_size = 10.0) const; - void writePolygons(const Polygons& polys, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; + void writePolygons(const Shape& polys, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; void writePolygon(const Polygon& poly, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; - void writePolylines(const Polygons& polys, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; + void writePolylines(const Shape& polys, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; void writePolyline(const Polygon& poly, const ColorObject color = Color::BLACK, const double stroke_width = 1.0) const; diff --git a/include/utils/Simplify.h b/include/utils/Simplify.h index 129c9057e3..9f40986d9e 100644 --- a/include/utils/Simplify.h +++ b/include/utils/Simplify.h @@ -82,7 +82,7 @@ class Simplify * \param polygons The polygons to simplify. * \return The simplified polygons. */ - Polygons polygon(const Polygons& polygons) const; + Shape polygon(const Shape& polygons) const; /*! * Simplify a polygon. diff --git a/include/utils/ToolpathVisualizer.h b/include/utils/ToolpathVisualizer.h index d71cf0c091..1a5b245cd7 100644 --- a/include/utils/ToolpathVisualizer.h +++ b/include/utils/ToolpathVisualizer.h @@ -21,11 +21,11 @@ class ToolpathVisualizer { } - void outline(const Polygons& input); + void outline(const Shape& input); void toolpaths(const std::vector& all_segments, bool rounded_visualization = true); - void underfill(const Polygons& underfills); - void overfill(const Polygons& overfills, const Polygons& double_overfills = Polygons()); - void width_legend(const Polygons& input, coord_t nozzle_size, coord_t max_dev, coord_t min_w, bool rounded_visualization); + void underfill(const Shape& underfills); + void overfill(const Shape& overfills, const Shape& double_overfills = Shape()); + void width_legend(const Shape& input, coord_t nozzle_size, coord_t max_dev, coord_t min_w, bool rounded_visualization); void widths(const std::vector& all_segments, coord_t nozzle_size, coord_t max_dev, coord_t min_w, bool rounded_visualization, bool exaggerate_widths = false); private: diff --git a/include/utils/VoxelUtils.h b/include/utils/VoxelUtils.h index d1b47e8883..7be999f7f0 100644 --- a/include/utils/VoxelUtils.h +++ b/include/utils/VoxelUtils.h @@ -92,7 +92,7 @@ class VoxelUtils * \param process_cell_func Function to perform on each voxel cell * \return Whether executing was stopped short as indicated by the \p cell_processing_function */ - bool walkPolygons(const Polygons& polys, coord_t z, const std::function& process_cell_func) const; + bool walkPolygons(const Shape& polys, coord_t z, const std::function& process_cell_func) const; /*! * Process voxels near the line segments of a polygon. @@ -105,13 +105,13 @@ class VoxelUtils * \param process_cell_func Function to perform on each voxel cell * \return Whether executing was stopped short as indicated by the \p cell_processing_function */ - bool walkDilatedPolygons(const Polygons& polys, coord_t z, const DilationKernel& kernel, const std::function& process_cell_func) const; + bool walkDilatedPolygons(const Shape& polys, coord_t z, const DilationKernel& kernel, const std::function& process_cell_func) const; private: /*! * \warning the \p polys is assumed to be translated by half the cell_size in xy already */ - bool _walkAreas(const Polygons& polys, coord_t z, const std::function& process_cell_func) const; + bool _walkAreas(const Shape& polys, coord_t z, const std::function& process_cell_func) const; public: /*! @@ -124,7 +124,7 @@ class VoxelUtils * \param process_cell_func Function to perform on each voxel cell * \return Whether executing was stopped short as indicated by the \p cell_processing_function */ - bool walkAreas(const Polygons& polys, coord_t z, const std::function& process_cell_func) const; + bool walkAreas(const Shape& polys, coord_t z, const std::function& process_cell_func) const; /*! * Process all voxels inside the area of a polygons object. @@ -137,7 +137,7 @@ class VoxelUtils * \param process_cell_func Function to perform on each voxel cell * \return Whether executing was stopped short as indicated by the \p cell_processing_function */ - bool walkDilatedAreas(const Polygons& polys, coord_t z, const DilationKernel& kernel, const std::function& process_cell_func) const; + bool walkDilatedAreas(const Shape& polys, coord_t z, const DilationKernel& kernel, const std::function& process_cell_func) const; /*! * Dilate with a kernel. diff --git a/include/utils/polygonUtils.h b/include/utils/polygonUtils.h index 156c130046..2bf7431d6d 100644 --- a/include/utils/polygonUtils.h +++ b/include/utils/polygonUtils.h @@ -152,9 +152,9 @@ class PolygonUtils /*! * Generate a grid of dots inside of the area of the \p polygons. */ - static std::vector spreadDotsArea(const Polygons& polygons, coord_t grid_size); + static std::vector spreadDotsArea(const Shape& polygons, coord_t grid_size); - static std::vector spreadDotsArea(const Polygons& polygons, Point2LL grid_size); + static std::vector spreadDotsArea(const Shape& polygons, Point2LL grid_size); /*! * Whether a polygon intersects with a line-segment. If true, the closest collision point to 'b' is stored in the result. @@ -162,7 +162,7 @@ class PolygonUtils static bool lineSegmentPolygonsIntersection( const Point2LL& a, const Point2LL& b, - const Polygons& current_outlines, + const Shape& current_outlines, const LocToLineGrid& outline_locator, Point2LL& result, const coord_t within_max_dist); @@ -207,7 +207,7 @@ class PolygonUtils * \param max_dist2 The squared maximal allowed distance from the point to the nearest polygon. * \return The index to the polygon onto which we have moved the point. */ - static size_t moveInside(const Polygons& polygons, Point2LL& from, int distance = 0, int64_t max_dist2 = std::numeric_limits::max()); + static size_t moveInside(const Shape& polygons, Point2LL& from, int distance = 0, int64_t max_dist2 = std::numeric_limits::max()); /** * \brief Moves the point \p from onto the nearest polygon or leaves the @@ -247,11 +247,11 @@ class PolygonUtils * \return The point on the polygon closest to \p from */ static ClosestPoint moveInside2( - const Polygons& polygons, + const Shape& polygons, Point2LL& from, const int distance = 0, const int64_t max_dist2 = std::numeric_limits::max(), - const Polygons* loc_to_line_polygons = nullptr, + const Shape* loc_to_line_polygons = nullptr, const LocToLineGrid* loc_to_line_grid = nullptr, const std::function& penalty_function = no_penalty_function); @@ -275,7 +275,7 @@ class PolygonUtils * \return The point on the polygon closest to \p from */ static ClosestPoint moveInside2( - const Polygons& loc_to_line_polygons, + const Shape& loc_to_line_polygons, const Polygon& polygon, Point2LL& from, const int distance = 0, @@ -298,7 +298,7 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The index to the polygon onto which we have moved the point. */ - static unsigned int moveOutside(const Polygons& polygons, Point2LL& from, int distance = 0, int64_t max_dist2 = std::numeric_limits::max()); + static unsigned int moveOutside(const Shape& polygons, Point2LL& from, int distance = 0, int64_t max_dist2 = std::numeric_limits::max()); /*! * Compute a point at a distance from a point on the boundary in orthogonal direction to the boundary. @@ -346,11 +346,11 @@ class PolygonUtils * \return The point on the polygon closest to \p from */ static ClosestPoint ensureInsideOrOutside( - const Polygons& polygons, + const Shape& polygons, Point2LL& from, int preferred_dist_inside, int64_t max_dist2 = std::numeric_limits::max(), - const Polygons* loc_to_line_polygons = nullptr, + const Shape* loc_to_line_polygons = nullptr, const LocToLineGrid* loc_to_line_grid = nullptr, const std::function& penalty_function = no_penalty_function); @@ -378,11 +378,11 @@ class PolygonUtils * \return The point on the polygon closest to \p from */ static ClosestPoint ensureInsideOrOutside( - const Polygons& polygons, + const Shape& polygons, Point2LL& from, const ClosestPoint& closest_polygon_point, int preferred_dist_inside, - const Polygons* loc_to_line_polygons = nullptr, + const Shape* loc_to_line_polygons = nullptr, const LocToLineGrid* loc_to_line_grid = nullptr, const std::function& penalty_function = no_penalty_function); @@ -420,7 +420,7 @@ class PolygonUtils * * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. */ - static ClosestPoint findClosest(Point2LL from, const Polygons& polygons, const std::function& penalty_function = no_penalty_function); + static ClosestPoint findClosest(Point2LL from, const Shape& polygons, const std::function& penalty_function = no_penalty_function); /*! * Find the point closest to \p from in the polygon \p polygon. @@ -437,7 +437,7 @@ class PolygonUtils * \param polys The polygons in which to search * \return The nearest vertex on the polygons */ - static PolygonsPointIndex findNearestVert(const Point2LL from, const Polygons& polys); + static PolygonsPointIndex findNearestVert(const Point2LL from, const Shape& polys); /*! * Find the nearest vertex to \p from in \p poly @@ -456,7 +456,7 @@ class PolygonUtils * \param square_size The cell size used to bundle line segments (also used to chop up lines so that multiple cells contain the same long line) * \return A bucket grid mapping spatial locations to poly-point indices into \p polygons */ - static std::unique_ptr createLocToLineGrid(const Polygons& polygons, int square_size); + static std::unique_ptr createLocToLineGrid(const Shape& polygons, int square_size); /*! * Find the line segment closest to a given point \p from within a cell-block of a size defined in the SparsePointGridInclusive \p loc_to_line @@ -471,7 +471,7 @@ class PolygonUtils * \return The nearest point on the polygon if the polygon was within a distance equal to the cell_size of the SparsePointGridInclusive */ static std::optional - findClose(Point2LL from, const Polygons& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function = no_penalty_function); + findClose(Point2LL from, const Shape& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function = no_penalty_function); /*! * Find the line segment closest to any point on \p from within cell-blocks of a size defined in the SparsePointGridInclusive \p destination_loc_to_line @@ -488,7 +488,7 @@ class PolygonUtils */ static std::vector> findClose( const Polygon& from, - const Polygons& destination, + const Shape& destination, const LocToLineGrid& destination_loc_to_line, const std::function& penalty_function = no_penalty_function); @@ -598,7 +598,7 @@ class PolygonUtils * polygon(s) */ static bool - polygonCollidesWithLineSegment(const Polygons& polys, const Point2LL& transformed_startPoint, const Point2LL& transformed_endPoint, PointMatrix transformation_matrix); + polygonCollidesWithLineSegment(const Shape& polys, const Point2LL& transformed_startPoint, const Point2LL& transformed_endPoint, PointMatrix transformation_matrix); /*! * Checks whether a given line segment collides with a given polygon(s). @@ -614,7 +614,7 @@ class PolygonUtils * \return whether the line segment collides with the boundary of the * polygon(s) */ - static bool polygonCollidesWithLineSegment(const Polygons& polys, const Point2LL& startPoint, const Point2LL& endPoint); + static bool polygonCollidesWithLineSegment(const Shape& polys, const Point2LL& startPoint, const Point2LL& endPoint); /*! * Checks whether two polygon groups intersect - does a BB hit check first and if that succeeds, the full intersection @@ -659,7 +659,7 @@ class PolygonUtils * two polygons. This will be between 0.0 (the polygons are exactly equal) * and 1.0 (the polygons are completely disjunct). */ - static double relativeHammingDistance(const Polygons& poly_a, const Polygons& poly_b); + static double relativeHammingDistance(const Shape& poly_a, const Shape& poly_b); /*! * Create an approximation of a circle. @@ -675,11 +675,11 @@ class PolygonUtils /*! * Connect all polygons to their holes using zero widths hole channels, so that the polygons and their outlines are connected together */ - static Polygons connect(const Polygons& input); + static Shape connect(const Shape& input); - static void fixSelfIntersections(const coord_t epsilon, Polygons& polygon); + static void fixSelfIntersections(const coord_t epsilon, Shape& polygon); - static Polygons unionManySmall(const Polygons& polygon); + static Shape unionManySmall(const Shape& polygon); /*! @@ -688,7 +688,7 @@ class PolygonUtils * \param aabb The AABB with which the polygon that has to be intersected with * \return A new Polygon that is said intersection */ - static Polygons clipPolygonWithAABB(const Polygons& src, const AABB& aabb); + static Shape clipPolygonWithAABB(const Shape& src, const AABB& aabb); /*! * Generate a few outset polygons around the given base, according to the given line width @@ -698,7 +698,7 @@ class PolygonUtils * \param line_width The actual line width to distance the polygons from each other (and from the base) * \return The generated outset polygons */ - static Polygons generateOutset(const Polygons& inner_poly, size_t count, coord_t line_width); + static Shape generateOutset(const Shape& inner_poly, size_t count, coord_t line_width); /*! * Generate inset polygons inside the given base, until there is no space left, according to the given line width @@ -708,7 +708,7 @@ class PolygonUtils * \param initial_inset The inset distance to be added to the first generated polygon * \return The generated inset polygons */ - static Polygons generateInset(const Polygons& outer_poly, coord_t line_width, coord_t initial_inset = 0); + static Shape generateInset(const Shape& outer_poly, coord_t line_width, coord_t initial_inset = 0); private: /*! diff --git a/src/ConicalOverhang.cpp b/src/ConicalOverhang.cpp index 1fb47ba079..1cf720b745 100644 --- a/src/ConicalOverhang.cpp +++ b/src/ConicalOverhang.cpp @@ -30,7 +30,7 @@ void ConicalOverhang::apply(Slicer* slicer, const Mesh& mesh) { // magically nothing happens when max_dist_from_lower_layer == 0 // below magic code solves that constexpr coord_t safe_dist = 20; - Polygons diff = layer_above.polygons.difference(layer.polygons.offset(-safe_dist)); + Shape diff = layer_above.polygons.difference(layer.polygons.offset(-safe_dist)); layer.polygons = layer.polygons.unionPolygons(diff); layer.polygons = layer.polygons.smooth(safe_dist); layer.polygons = Simplify(safe_dist, safe_dist / 2, 0).polygon(layer.polygons); @@ -42,7 +42,7 @@ void ConicalOverhang::apply(Slicer* slicer, const Mesh& mesh) // Get the current layer and split it into parts std::vector layerParts = layer.polygons.splitIntoParts(); // Get a copy of the layer above to prune away before we shrink it - Polygons above = layer_above.polygons; + Shape above = layer_above.polygons; // Now go through all the holes in the current layer and check if they intersect anything in the layer above // If not, then they're the top of a hole and should be cut from the layer above before the union @@ -52,15 +52,15 @@ void ConicalOverhang::apply(Slicer* slicer, const Mesh& mesh) { for (unsigned int hole_nr = 1; hole_nr < layerParts[part].size(); ++hole_nr) { - Polygons holePoly; + Shape holePoly; holePoly.push_back(layerParts[part][hole_nr]); if (maxHoleArea > 0.0 && INT2MM2(std::abs(holePoly.area())) < maxHoleArea) { - Polygons holeWithAbove = holePoly.intersection(above); + Shape holeWithAbove = holePoly.intersection(above); if (! holeWithAbove.empty()) { // The hole had some intersection with the above layer, check if it's a complete overlap - Polygons holeDifference = holePoly.xorPolygons(holeWithAbove); + Shape holeDifference = holePoly.xorPolygons(holeWithAbove); if (holeDifference.empty()) { // The hole was returned unchanged, so the layer above must completely cover it. Remove the hole from the layer above. diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 87c35cc46c..fa97716b73 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -578,7 +578,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; - Polygons raft_polygons; + Shape raft_polygons; std::optional last_planned_position = std::optional(); unsigned int current_extruder_nr = base_extruder_nr; @@ -629,14 +629,14 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) struct ParameterizedRaftPath { coord_t line_spacing; - Polygons outline; + Shape outline; }; std::vector raft_outline_paths; raft_outline_paths.emplace_back(ParameterizedRaftPath{ line_spacing, storage.raftBaseOutline }); if (storage.primeTower.enabled_) { - const Polygons& raft_outline_prime_tower = storage.primeTower.getOuterPoly(layer_nr); + const Shape& raft_outline_prime_tower = storage.primeTower.getOuterPoly(layer_nr); if (line_spacing_prime_tower == line_spacing) { // Base layer is shared with prime tower base @@ -788,7 +788,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Application::getInstance().communication_->sendLayerComplete(layer_nr, z, interface_layer_height); - Polygons raft_outline_path; + Shape raft_outline_path; const coord_t small_offset = gcode_layer.configs_storage_.raft_interface_config.getLineWidth() / 2; // Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. raft_outline_path = storage.raftInterfaceOutline.offset(-small_offset); @@ -959,7 +959,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) } Application::getInstance().communication_->sendLayerComplete(layer_nr, z, surface_layer_height); - Polygons raft_outline_path; + Shape raft_outline_path; const coord_t small_offset = gcode_layer.configs_storage_.raft_interface_config.getLineWidth() / 2; // Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. raft_outline_path = storage.raftSurfaceOutline.offset(-small_offset); @@ -989,7 +989,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_outline_path = raft_outline_path.difference(storage.primeTower.getOuterPoly(layer_nr)); } - for (const Polygons raft_island : raft_outline_path.splitIntoParts()) + for (const Shape raft_island : raft_outline_path.splitIntoParts()) { Infill infill_comp( EFillMethod::ZIG_ZAG, @@ -1644,7 +1644,7 @@ void FffGcodeWriter::addMeshLayerToGCode_meshSurfaceMode(const SliceMeshStorage& const SliceLayer* layer = &mesh.layers[gcode_layer.getLayerNr()]; - Polygons polygons; + Shape polygons; for (const SliceLayerPart& part : layer->parts) { polygons.add(part.outline); @@ -1824,7 +1824,7 @@ bool FffGcodeWriter::processMultiLayerInfill( const bool zig_zaggify_infill = mesh.settings.get("zig_zaggify_infill") || infill_pattern == EFillMethod::ZIG_ZAG; const bool connect_polygons = mesh.settings.get("connect_infill_polygons"); const size_t infill_multiplier = mesh.settings.get("infill_multiplier"); - Polygons infill_polygons; + Shape infill_polygons; LinesSet infill_lines; std::vector infill_paths = part.infill_wall_toolpaths; for (size_t density_idx = part.infill_area_per_combine_per_density.size() - 1; (int)density_idx >= 0; density_idx--) @@ -1944,7 +1944,7 @@ bool FffGcodeWriter::processSingleLayerInfill( const coord_t infill_line_width = mesh_config.infill_config[0].getLineWidth(); // Combine the 1 layer thick infill with the top/bottom skin and print that as one thing. - Polygons infill_polygons; + Shape infill_polygons; std::vector> wall_tool_paths; // All wall toolpaths binned by inset_idx (inner) and by density_idx (outer) LinesSet infill_lines; @@ -1976,12 +1976,12 @@ bool FffGcodeWriter::processSingleLayerInfill( return -static_cast(line_count) * line_width; }; - Polygons sparse_in_outline = part.infill_area_per_combine_per_density[last_idx][0]; + Shape sparse_in_outline = part.infill_area_per_combine_per_density[last_idx][0]; // if infill walls are required below the boundaries of skin regions above, partition the infill along the // boundary edge - Polygons infill_below_skin; - Polygons infill_not_below_skin; + Shape infill_below_skin; + Shape infill_not_below_skin; const bool hasSkinEdgeSupport = partitionInfillBySkinAbove(infill_below_skin, infill_not_below_skin, gcode_layer, mesh, part, infill_line_width); const auto pocket_size = mesh.settings.get("cross_infill_pocket_size"); @@ -2000,7 +2000,7 @@ bool FffGcodeWriter::processSingleLayerInfill( } LinesSet infill_lines_here; - Polygons infill_polygons_here; + Shape infill_polygons_here; // the highest density infill combines with the next to create a grid with density_factor 1 int infill_line_distance_here = infill_line_distance << (density_idx + 1); @@ -2041,7 +2041,7 @@ bool FffGcodeWriter::processSingleLayerInfill( infill_line_distance_here /= 2; } - Polygons in_outline = part.infill_area_per_combine_per_density[density_idx][0]; + Shape in_outline = part.infill_area_per_combine_per_density[density_idx][0]; std::shared_ptr lightning_layer; if (mesh.lightning_generator) @@ -2095,7 +2095,7 @@ bool FffGcodeWriter::processSingleLayerInfill( if (density_idx < last_idx) { const coord_t cut_offset = get_cut_offset(zig_zaggify_infill, infill_line_width, min_skin_below_wall_count); - Polygons tool = infill_below_skin.offset(static_cast(cut_offset)); + Shape tool = infill_below_skin.offset(static_cast(cut_offset)); infill_lines_here = tool.intersectionPolyLines(infill_lines_here); } infill_lines.add(infill_lines_here); @@ -2160,7 +2160,7 @@ bool FffGcodeWriter::processSingleLayerInfill( if (density_idx < last_idx) { const coord_t cut_offset = get_cut_offset(zig_zaggify_infill, infill_line_width, wall_line_count); - Polygons tool = sparse_in_outline.offset(static_cast(cut_offset)); + Shape tool = sparse_in_outline.offset(static_cast(cut_offset)); infill_lines_here = tool.intersectionPolyLines(infill_lines_here); } infill_lines.add(infill_lines_here); @@ -2280,8 +2280,8 @@ bool FffGcodeWriter::processSingleLayerInfill( } bool FffGcodeWriter::partitionInfillBySkinAbove( - Polygons& infill_below_skin, - Polygons& infill_not_below_skin, + Shape& infill_below_skin, + Shape& infill_not_below_skin, const LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const SliceLayerPart& part, @@ -2289,7 +2289,7 @@ bool FffGcodeWriter::partitionInfillBySkinAbove( { constexpr coord_t tiny_infill_offset = 20; const auto skin_edge_support_layers = mesh.settings.get("skin_edge_support_layers"); - Polygons skin_above_combined; // skin regions on the layers above combined with small gaps between + Shape skin_above_combined; // skin regions on the layers above combined with small gaps between // working from the highest layer downwards, combine the regions of skin on all the layers // but don't let the regions merge together @@ -2304,12 +2304,12 @@ bool FffGcodeWriter::partitionInfillBySkinAbove( for (const SkinPart& skin_part : part_i.skin_parts) { // Limit considered areas to the ones that should have infill underneath at the current layer. - const Polygons relevant_outline = skin_part.outline.intersection(part.getOwnInfillArea()); + const Shape relevant_outline = skin_part.outline.intersection(part.getOwnInfillArea()); if (! skin_above_combined.empty()) { // does this skin part overlap with any of the skin parts on the layers above? - const Polygons overlap = skin_above_combined.intersection(relevant_outline); + const Shape overlap = skin_above_combined.intersection(relevant_outline); if (! overlap.empty()) { // yes, it overlaps, need to leave a gap between this skin part and the others @@ -2328,7 +2328,7 @@ bool FffGcodeWriter::partitionInfillBySkinAbove( // ------- -------------------------- ---------- // expand the overlap region slightly to make a small gap - const Polygons overlap_expanded = overlap.offset(tiny_infill_offset); + const Shape overlap_expanded = overlap.offset(tiny_infill_offset); // subtract the expanded overlap region from the regions accumulated from higher layers skin_above_combined = skin_above_combined.difference(overlap_expanded); // subtract the expanded overlap region from this skin part and add the remainder to the overlap region @@ -2386,7 +2386,7 @@ bool FffGcodeWriter::partitionInfillBySkinAbove( // need to take skin/infill overlap that was added in SkinInfillAreaComputation::generateInfill() into account const coord_t infill_skin_overlap = mesh.settings.get((part.wall_toolpaths.size() > 1) ? "wall_line_width_x" : "wall_line_width_0") / 2; - const Polygons infill_below_skin_overlap = infill_below_skin.offset(-(infill_skin_overlap + tiny_infill_offset)); + const Shape infill_below_skin_overlap = infill_below_skin.offset(-(infill_skin_overlap + tiny_infill_offset)); return ! infill_below_skin_overlap.empty() && ! infill_not_below_skin.empty(); } @@ -2481,7 +2481,7 @@ bool FffGcodeWriter::processInsets( { // accumulate the outlines of all of the parts that are on the layer below - Polygons outlines_below; + Shape outlines_below; AABB boundaryBox(part.outline); for (const std::shared_ptr& mesh_ptr : storage.meshes) { @@ -2551,7 +2551,7 @@ bool FffGcodeWriter::processInsets( // subtract the outlines of the parts below this part to give the shapes of the unsupported regions and then // shrink those shapes so that any that are narrower than two times max_air_gap will be removed - Polygons compressed_air(part.outline.difference(outlines_below).offset(-max_air_gap)); + Shape compressed_air(part.outline.difference(outlines_below).offset(-max_air_gap)); // now expand the air regions by the same amount as they were shrunk plus half the outer wall line width // which is required because when the walls are being generated, the vertices do not fall on the part's outline @@ -2562,14 +2562,14 @@ bool FffGcodeWriter::processInsets( else { // clear to disable use of bridging settings - gcode_layer.setBridgeWallMask(Polygons()); + gcode_layer.setBridgeWallMask(Shape()); } const AngleDegrees overhang_angle = mesh.settings.get("wall_overhang_angle"); if (overhang_angle >= 90) { // clear to disable overhang detection - gcode_layer.setOverhangMask(Polygons()); + gcode_layer.setOverhangMask(Shape()); } else { @@ -2578,11 +2578,11 @@ bool FffGcodeWriter::processInsets( // expanded to take into account the overhang angle, the greater the overhang angle, the larger the supported area is // considered to be const coord_t overhang_width = layer_height * std::tan(overhang_angle / (180 / std::numbers::pi)); - Polygons overhang_region = part.outline.offset(-half_outer_wall_width).difference(outlines_below.offset(10 + overhang_width - half_outer_wall_width)).offset(10); + Shape overhang_region = part.outline.offset(-half_outer_wall_width).difference(outlines_below.offset(10 + overhang_width - half_outer_wall_width)).offset(10); gcode_layer.setOverhangMask(overhang_region); } - const auto roofing_mask = [&]() -> Polygons + const auto roofing_mask = [&]() -> Shape { const size_t roofing_layer_count = std::min(mesh.settings.get("roofing_layer_count"), mesh.settings.get("top_layers")); @@ -2609,11 +2609,11 @@ bool FffGcodeWriter::processInsets( else { // clear to disable use of bridging settings - gcode_layer.setBridgeWallMask(Polygons()); + gcode_layer.setBridgeWallMask(Shape()); // clear to disable overhang detection - gcode_layer.setOverhangMask(Polygons()); + gcode_layer.setOverhangMask(Shape()); // clear to disable use of roofing settings - gcode_layer.setRoofingMask(Polygons()); + gcode_layer.setRoofingMask(Shape()); } if (spiralize && extruder_nr == mesh.settings.get("wall_0_extruder_nr").extruder_nr_ && ! part.spiral_wall.empty()) @@ -2667,7 +2667,7 @@ bool FffGcodeWriter::processInsets( return added_something; } -std::optional FffGcodeWriter::getSeamAvoidingLocation(const Polygons& filling_part, int filling_angle, Point2LL last_position) const +std::optional FffGcodeWriter::getSeamAvoidingLocation(const Shape& filling_part, int filling_angle, Point2LL last_position) const { if (filling_part.empty()) { @@ -2855,7 +2855,7 @@ void FffGcodeWriter::processTopBottom( support_layer = &storage.support.supportLayers[support_layer_nr - (bridge_layer - 1)]; } - Polygons supported_skin_part_regions; + Shape supported_skin_part_regions; const double angle = bridgeAngle(mesh.settings, skin_part.skin_fill, storage, layer_nr, bridge_layer, support_layer, supported_skin_part_regions); @@ -2980,7 +2980,7 @@ void FffGcodeWriter::processSkinPrintFeature( LayerPlan& gcode_layer, const SliceMeshStorage& mesh, const size_t extruder_nr, - const Polygons& area, + const Shape& area, const GCodePathConfig& config, EFillMethod pattern, const AngleDegrees skin_angle, @@ -2990,7 +2990,7 @@ void FffGcodeWriter::processSkinPrintFeature( bool& added_something, double fan_speed) const { - Polygons skin_polygons; + Shape skin_polygons; LinesSet skin_lines; std::vector skin_paths; @@ -3048,7 +3048,7 @@ void FffGcodeWriter::processSkinPrintFeature( nullptr, nullptr, nullptr, - small_areas_on_surface ? Polygons() : exposed_to_air); + small_areas_on_surface ? Shape() : exposed_to_air); // add paths if (! skin_polygons.empty() || ! skin_lines.empty() || ! skin_paths.empty()) @@ -3364,7 +3364,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer { const coord_t support_line_width = default_support_line_width * (combine_idx + 1); - Polygons support_polygons; + Shape support_polygons; std::vector wall_toolpaths_here; LinesSet support_lines; const size_t max_density_idx = part.infill_area_per_combine_per_density_.size() - 1; @@ -3385,7 +3385,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer { support_line_distance_here /= 2; } - const Polygons& area = Simplify(infill_extruder.settings_).polygon(part.infill_area_per_combine_per_density_[density_idx][combine_idx]); + const Shape& area = Simplify(infill_extruder.settings_).polygon(part.infill_area_per_combine_per_density_[density_idx][combine_idx]); constexpr size_t wall_count = 0; // Walls are generated somewhere else, so their layers aren't vertically combined. const coord_t small_area_width = 0; @@ -3436,7 +3436,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer // to the start of the support does not go through the model we have to tell the slicer what the current location of the nozzle is // by adding a travel move to the end vertex of the last spiral. Of course, if the slicer could track the final location on the previous // layer then this wouldn't be necessary but that's not done due to the multi-threading. - const Polygons* last_wall_outline = storage.spiralize_wall_outlines[layer_nr - 1]; + const Shape* last_wall_outline = storage.spiralize_wall_outlines[layer_nr - 1]; if (last_wall_outline != nullptr) { gcode_layer.addTravel((*last_wall_outline)[0][storage.spiralize_seam_vertex_indices[layer_nr - 1]]); @@ -3541,7 +3541,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer bool FffGcodeWriter::addSupportRoofsToGCode( const SliceDataStorage& storage, - const Polygons& support_roof_outlines, + const Shape& support_roof_outlines, const GCodePathConfig& current_roof_config, LayerPlan& gcode_layer) const { @@ -3589,8 +3589,8 @@ bool FffGcodeWriter::addSupportRoofsToGCode( support_roof_line_distance *= roof_extruder.settings_.get("initial_layer_line_width_factor"); } - Polygons infill_outline = support_roof_outlines; - Polygons wall; + Shape infill_outline = support_roof_outlines; + Shape wall; // make sure there is a wall if this is on the first layer if (gcode_layer.getLayerNr() == 0) { @@ -3623,7 +3623,7 @@ bool FffGcodeWriter::addSupportRoofsToGCode( skip_some_zags, zag_skip_count, pocket_size); - Polygons roof_polygons; + Shape roof_polygons; std::vector roof_paths; LinesSet roof_lines; roof_computation.generate(roof_paths, roof_polygons, roof_lines, roof_extruder.settings_, gcode_layer.getLayerNr(), SectionType::SUPPORT); @@ -3740,7 +3740,7 @@ bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, L skip_some_zags, zag_skip_count, pocket_size); - Polygons bottom_polygons; + Shape bottom_polygons; std::vector bottom_paths; LinesSet bottom_lines; bottom_computation.generate(bottom_paths, bottom_polygons, bottom_lines, bottom_extruder.settings_, gcode_layer.getLayerNr(), SectionType::SUPPORT); diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 47b676c5e8..bc8d0093eb 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -605,7 +605,7 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz { // early out continue; } - Polygons new_outline = part.outline.intersection(other_part.getOwnInfillArea()); + Shape new_outline = part.outline.intersection(other_part.getOwnInfillArea()); if (new_outline.size() == 1) { // we don't have to call splitIntoParts, because a single polygon can only be a single part SingleShape outline_part_here; @@ -628,7 +628,7 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz } if (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { - const Polygons& own_infill_area = other_part.getOwnInfillArea(); + const Shape& own_infill_area = other_part.getOwnInfillArea(); std::vector cut_lines = own_infill_area.intersectionPolyLines(layer.openPolyLines); new_polylines.add(cut_lines); // NOTE: closed polygons will be represented as polylines, which will be closed automatically in the PathOrderOptimizer @@ -1003,7 +1003,7 @@ void FffPolygonGenerator::processDraftShield(SliceDataStorage& storage) const LayerIndex layer_skip{ 500 / layer_height + 1 }; - Polygons& draft_shield = storage.draft_protection_shield; + Shape& draft_shield = storage.draft_protection_shield; for (LayerIndex layer_nr = 0; layer_nr < storage.print_layer_count && layer_nr < draft_shield_layers; layer_nr += layer_skip) { constexpr bool around_support = true; @@ -1090,7 +1090,7 @@ void FffPolygonGenerator::processFuzzyWalls(SliceMeshStorage& mesh) unsigned int start_layer_nr = (mesh.settings.get("adhesion_type") == EPlatformAdhesion::BRIM) ? 1 : 0; // don't make fuzzy skin on first layer if there's a brim - auto hole_area = Polygons(); + auto hole_area = Shape(); std::function accumulate_is_in_hole = []([[maybe_unused]] const bool& prev_result, [[maybe_unused]] const ExtrusionJunction& junction) { diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 529ade9671..9ef4c14e15 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -94,7 +94,7 @@ bool InsetOrderOptimizer::addToLayer() bool added_something = false; constexpr bool detect_loops = false; - constexpr Polygons* combing_boundary = nullptr; + constexpr Shape* combing_boundary = nullptr; const auto group_outer_walls = settings_.get("group_outer_walls"); // When we alternate walls, also alternate the direction at which the first wall starts in. // On even layers we start with normal direction, on odd layers with inverted direction. @@ -203,7 +203,7 @@ InsetOrderOptimizer::value_type InsetOrderOptimizer::getRegionOrder(const std::v { // Create a polygon representing the inner area of the extrusion line; any // point inside this polygon is considered to the child of the extrusion line. - Polygons hole_polygons; + Shape hole_polygons; if (extrusion_line->is_closed_) { hole_polygons.push_back(extrusion_line->toPolygon()); diff --git a/src/InterlockingGenerator.cpp b/src/InterlockingGenerator.cpp index dcd8ff1628..b730c73669 100644 --- a/src/InterlockingGenerator.cpp +++ b/src/InterlockingGenerator.cpp @@ -69,16 +69,16 @@ void InterlockingGenerator::generateInterlockingStructure(std::vector& } } -std::pair InterlockingGenerator::growBorderAreasPerpendicular(const Polygons& a, const Polygons& b, const coord_t& detect) const +std::pair InterlockingGenerator::growBorderAreasPerpendicular(const Shape& a, const Shape& b, const coord_t& detect) const { const coord_t min_line = std::min(mesh_a_.mesh->settings_.get("min_wall_line_width"), mesh_b_.mesh->settings_.get("min_wall_line_width")); - const Polygons total_shrunk = a.offset(min_line).unionPolygons(b.offset(min_line)).offset(2 * -min_line); + const Shape total_shrunk = a.offset(min_line).unionPolygons(b.offset(min_line)).offset(2 * -min_line); - Polygons from_border_a = a.difference(total_shrunk); - Polygons from_border_b = b.difference(total_shrunk); + Shape from_border_a = a.difference(total_shrunk); + Shape from_border_b = b.difference(total_shrunk); - Polygons temp_a, temp_b; + Shape temp_a, temp_b; for (coord_t i = 0; i < (detect / min_line) + 2; ++i) { temp_a = from_border_a.offset(min_line); @@ -105,8 +105,8 @@ void InterlockingGenerator::handleThinAreas(const std::unordered_set const coord_t close_gaps = std::min(mesh_a_.mesh->settings_.get("line_width"), mesh_b_.mesh->settings_.get("line_width")) / 4; // Make an inclusionary polygon, to only actually handle thin areas near actual microstructures (so not in skin for example). - std::vector near_interlock_per_layer; - near_interlock_per_layer.assign(std::min(mesh_a_.layers.size(), mesh_b_.layers.size()), Polygons()); + std::vector near_interlock_per_layer; + near_interlock_per_layer.assign(std::min(mesh_a_.layers.size(), mesh_b_.layers.size()), Shape()); for (const auto& cell : has_all_meshes) { const Point3LL bottom_corner = vu_.toLowerCorner(cell); @@ -124,20 +124,20 @@ void InterlockingGenerator::handleThinAreas(const std::unordered_set // Only alter layers when they are present in both meshes, zip should take care if that. for (auto [layer_nr, layer] : ranges::views::zip(mesh_a_.layers, mesh_b_.layers) | ranges::views::enumerate) { - Polygons& polys_a = std::get<0>(layer).polygons; - Polygons& polys_b = std::get<1>(layer).polygons; + Shape& polys_a = std::get<0>(layer).polygons; + Shape& polys_b = std::get<1>(layer).polygons; const auto [from_border_a, from_border_b] = growBorderAreasPerpendicular(polys_a, polys_b, detect); // Get the areas of each mesh that are _not_ thin (large), by performing a morphological open. - const Polygons large_a{ polys_a.offset(-detect).offset(detect) }; - const Polygons large_b{ polys_b.offset(-detect).offset(detect) }; + const Shape large_a{ polys_a.offset(-detect).offset(detect) }; + const Shape large_b{ polys_b.offset(-detect).offset(detect) }; // Derive the area that the thin areas need to expand into (so the added areas to the thin strips) from the information we already have. - const Polygons thin_expansion_a{ + const Shape thin_expansion_a{ large_b.intersection(polys_a.difference(large_a).offset(expand)).intersection(near_interlock_per_layer[layer_nr]).intersection(from_border_a).offset(rounding_errors) }; - const Polygons thin_expansion_b{ + const Shape thin_expansion_b{ large_a.intersection(polys_b.difference(large_b).offset(expand)).intersection(near_interlock_per_layer[layer_nr]).intersection(from_border_b).offset(rounding_errors) }; @@ -156,7 +156,7 @@ void InterlockingGenerator::generateInterlockingStructure() const std::unordered_set& has_all_meshes = voxels_per_mesh[1]; has_any_mesh.merge(has_all_meshes); // perform union and intersection simultaneously. Cannibalizes voxels_per_mesh - const std::vector layer_regions = computeUnionedVolumeRegions(); + const std::vector layer_regions = computeUnionedVolumeRegions(); if (air_filtering_) { @@ -184,7 +184,7 @@ std::vector> InterlockingGenerator::getShellVoxel Slicer* mesh = (mesh_idx == 0) ? &mesh_a_ : &mesh_b_; std::unordered_set& mesh_voxels = voxels_per_mesh[mesh_idx]; - std::vector rotated_polygons_per_layer(mesh->layers.size()); + std::vector rotated_polygons_per_layer(mesh->layers.size()); for (size_t layer_nr = 0; layer_nr < mesh->layers.size(); layer_nr++) { SlicerLayer& layer = mesh->layers[layer_nr]; @@ -198,7 +198,7 @@ std::vector> InterlockingGenerator::getShellVoxel return voxels_per_mesh; } -void InterlockingGenerator::addBoundaryCells(const std::vector& layers, const DilationKernel& kernel, std::unordered_set& cells) const +void InterlockingGenerator::addBoundaryCells(const std::vector& layers, const DilationKernel& kernel, std::unordered_set& cells) const { auto voxel_emplacer = [&cells](GridPoint3 p) { @@ -210,7 +210,7 @@ void InterlockingGenerator::addBoundaryCells(const std::vector& layers { const coord_t z = static_cast(layer_nr); vu_.walkDilatedPolygons(layers[layer_nr], z, kernel, voxel_emplacer); - Polygons skin = layers[layer_nr]; + Shape skin = layers[layer_nr]; if (layer_nr > 0) { skin = skin.xorPolygons(layers[layer_nr - 1]); @@ -220,14 +220,14 @@ void InterlockingGenerator::addBoundaryCells(const std::vector& layers } } -std::vector InterlockingGenerator::computeUnionedVolumeRegions() const +std::vector InterlockingGenerator::computeUnionedVolumeRegions() const { const size_t max_layer_count = std::max(mesh_a_.layers.size(), mesh_b_.layers.size()) + 1; // introduce ghost layer on top for correct skin computation of topmost layer. - std::vector layer_regions(max_layer_count); + std::vector layer_regions(max_layer_count); for (LayerIndex layer_nr = 0; layer_nr < max_layer_count; layer_nr++) { - Polygons& layer_region = layer_regions[static_cast(layer_nr)]; + Shape& layer_region = layer_regions[static_cast(layer_nr)]; for (Slicer* mesh : { &mesh_a_, &mesh_b_ }) { if (layer_nr >= mesh->layers.size()) @@ -243,9 +243,9 @@ std::vector InterlockingGenerator::computeUnionedVolumeRegions() const return layer_regions; } -std::vector> InterlockingGenerator::generateMicrostructure() const +std::vector> InterlockingGenerator::generateMicrostructure() const { - std::vector> cell_area_per_mesh_per_layer; + std::vector> cell_area_per_mesh_per_layer; cell_area_per_mesh_per_layer.resize(2); cell_area_per_mesh_per_layer[0].resize(2); const coord_t beam_w_sum = beam_width_a_ + beam_width_b_; @@ -263,7 +263,7 @@ std::vector> InterlockingGenerator::generateMicrostructure poly.emplace_back(offset + Point2LL(0, area_size.Y)); } cell_area_per_mesh_per_layer[1] = cell_area_per_mesh_per_layer[0]; - for (Polygons& polys : cell_area_per_mesh_per_layer[1]) + for (Shape& polys : cell_area_per_mesh_per_layer[1]) { for (Polygon& poly : polys) { @@ -276,14 +276,14 @@ std::vector> InterlockingGenerator::generateMicrostructure return cell_area_per_mesh_per_layer; } -void InterlockingGenerator::applyMicrostructureToOutlines(const std::unordered_set& cells, const std::vector& layer_regions) const +void InterlockingGenerator::applyMicrostructureToOutlines(const std::unordered_set& cells, const std::vector& layer_regions) const { - std::vector> cell_area_per_mesh_per_layer = generateMicrostructure(); + std::vector> cell_area_per_mesh_per_layer = generateMicrostructure(); const PointMatrix unapply_rotation = rotation_.inverse(); const size_t max_layer_count = std::max(mesh_a_.layers.size(), mesh_b_.layers.size()); - std::vector structure_per_layer[2]; // for each mesh the structure on each layer + std::vector structure_per_layer[2]; // for each mesh the structure on each layer // Every `beam_layer_count` number of layers are combined to an interlocking beam layer // to store these we need ceil(max_layer_count / beam_layer_count) of these layers @@ -300,7 +300,7 @@ void InterlockingGenerator::applyMicrostructureToOutlines(const std::unordered_s { for (LayerIndex layer_nr = bottom_corner.z_; layer_nr < bottom_corner.z_ + cell_size_.z_ && layer_nr < max_layer_count; layer_nr += beam_layer_count_) { - Polygons areas_here = cell_area_per_mesh_per_layer[static_cast(layer_nr / beam_layer_count_) % cell_area_per_mesh_per_layer.size()][mesh_idx]; + Shape areas_here = cell_area_per_mesh_per_layer[static_cast(layer_nr / beam_layer_count_) % cell_area_per_mesh_per_layer.size()][mesh_idx]; areas_here.translate(Point2LL(bottom_corner.x_, bottom_corner.y_)); structure_per_layer[mesh_idx][static_cast(layer_nr / beam_layer_count_)].add(areas_here); } @@ -311,7 +311,7 @@ void InterlockingGenerator::applyMicrostructureToOutlines(const std::unordered_s { for (size_t layer_nr = 0; layer_nr < structure_per_layer[mesh_idx].size(); layer_nr++) { - Polygons& layer_structure = structure_per_layer[mesh_idx][layer_nr]; + Shape& layer_structure = structure_per_layer[mesh_idx][layer_nr]; layer_structure = layer_structure.unionPolygons(); layer_structure.applyMatrix(unapply_rotation); } @@ -327,11 +327,11 @@ void InterlockingGenerator::applyMicrostructureToOutlines(const std::unordered_s break; } - Polygons layer_outlines = layer_regions[layer_nr]; + Shape layer_outlines = layer_regions[layer_nr]; layer_outlines.applyMatrix(unapply_rotation); - const Polygons areas_here = structure_per_layer[mesh_idx][layer_nr / static_cast(beam_layer_count_)].intersection(layer_outlines); - const Polygons& areas_other = structure_per_layer[! mesh_idx][layer_nr / static_cast(beam_layer_count_)]; + const Shape areas_here = structure_per_layer[mesh_idx][layer_nr / static_cast(beam_layer_count_)].intersection(layer_outlines); + const Shape& areas_other = structure_per_layer[! mesh_idx][layer_nr / static_cast(beam_layer_count_)]; SlicerLayer& layer = mesh->layers[layer_nr]; layer.polygons = layer.polygons diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 31fddba043..e17ed0c99b 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -66,7 +66,7 @@ GCodePath* LayerPlan::getLatestPathWithConfig( return ret; } -const Polygons* LayerPlan::getCombBoundaryInside() const +const Shape* LayerPlan::getCombBoundaryInside() const { return &comb_boundary_preferred_; } @@ -151,9 +151,9 @@ ExtruderTrain* LayerPlan::getLastPlannedExtruderTrain() return last_planned_extruder_; } -Polygons LayerPlan::computeCombBoundary(const CombBoundary boundary_type) +Shape LayerPlan::computeCombBoundary(const CombBoundary boundary_type) { - Polygons comb_boundary; + Shape comb_boundary; const CombingMode mesh_combing_mode = Application::getInstance().current_slice_->scene.current_mesh_group->settings.get("retraction_combing"); if (mesh_combing_mode != CombingMode::OFF && (layer_nr_ >= 0 || mesh_combing_mode != CombingMode::NO_SKIN)) { @@ -213,7 +213,7 @@ Polygons LayerPlan::computeCombBoundary(const CombBoundary boundary_type) } else if (combing_mode == CombingMode::NO_OUTER_SURFACES) { - Polygons top_and_bottom_most_fill; + Shape top_and_bottom_most_fill; for (const SliceLayerPart& outer_surface_part : layer.parts) { for (const SkinPart& skin_part : outer_surface_part.skin_parts) @@ -602,7 +602,7 @@ void LayerPlan::addPolygon( } void LayerPlan::addPolygonsByOptimizer( - const Polygons& polygons, + const Shape& polygons, const GCodePathConfig& config, const ZSeamConfig& z_seam_config, coord_t wall_0_wipe_dist, @@ -1242,7 +1242,7 @@ void LayerPlan::addInfillWall(const ExtrusionLine& wall, const GCodePathConfig& } void LayerPlan::addWalls( - const Polygons& walls, + const Shape& walls, const Settings& settings, const GCodePathConfig& default_config, const GCodePathConfig& roofing_config, @@ -1278,7 +1278,7 @@ void LayerPlan::addLinesByOptimizer( const bool reverse_print_direction, const std::unordered_multimap& order_requirements) { - Polygons boundary; + Shape boundary; if (enable_travel_optimization && ! comb_boundary_minimum_.empty()) { // use the combing boundary inflated so that all infill lines are inside the boundary @@ -1422,7 +1422,7 @@ void LayerPlan::addLinesInGivenOrder( } void LayerPlan::addLinesMonotonic( - const Polygons& area, + const Shape& area, const std::vector& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, @@ -1433,7 +1433,7 @@ void LayerPlan::addLinesMonotonic( const Ratio flow_ratio, const double fan_speed) { - const Polygons exclude_areas = area.tubeShape(exclude_distance, exclude_distance); + const Shape exclude_areas = area.tubeShape(exclude_distance, exclude_distance); const coord_t exclude_dist2 = exclude_distance * exclude_distance; const Point2LL last_position = getLastPlannedPositionOrStartingPosition(); @@ -1511,7 +1511,7 @@ void LayerPlan::spiralizeWallSlice( } const int n_points = wall.size(); - Polygons last_wall_polygons; + Shape last_wall_polygons; last_wall_polygons.push_back(last_wall); const int max_dist2 = config.getLineWidth() * config.getLineWidth() * 4; // (2 * lineWidth)^2; @@ -2557,17 +2557,17 @@ size_t LayerPlan::getExtruder() const return extruder_plans_.back().extruder_nr_; } -void LayerPlan::setBridgeWallMask(const Polygons& polys) +void LayerPlan::setBridgeWallMask(const Shape& polys) { bridge_wall_mask_ = polys; } -void LayerPlan::setOverhangMask(const Polygons& polys) +void LayerPlan::setOverhangMask(const Shape& polys) { overhang_mask_ = polys; } -void LayerPlan::setRoofingMask(const Polygons& polys) +void LayerPlan::setRoofingMask(const Shape& polys) { roofing_mask_ = polys; } diff --git a/src/Mold.cpp b/src/Mold.cpp index c9ac159a39..1399c20a35 100644 --- a/src/Mold.cpp +++ b/src/Mold.cpp @@ -47,11 +47,11 @@ void Mold::process(std::vector& slicer_list) } const coord_t layer_height = scene.current_mesh_group->settings.get("layer_height"); - std::vector mold_outline_above_per_mesh; // the outer outlines of the layer above without the original model(s) being cut out + std::vector mold_outline_above_per_mesh; // the outer outlines of the layer above without the original model(s) being cut out mold_outline_above_per_mesh.resize(slicer_list.size()); for (int layer_nr = layer_count - 1; layer_nr >= 0; layer_nr--) { - Polygons all_original_mold_outlines; // outlines of all models for which to generate a mold (insides of all molds) + Shape all_original_mold_outlines; // outlines of all models for which to generate a mold (insides of all molds) // first generate outlines for (unsigned int mesh_idx = 0; mesh_idx < slicer_list.size(); mesh_idx++) @@ -77,7 +77,7 @@ void Mold::process(std::vector& slicer_list) SlicerLayer& layer = slicer.layers[layer_nr]; - Polygons model_outlines = layer.polygons.unionPolygons(layer.openPolylines.offset(open_polyline_width / 2)); + Shape model_outlines = layer.polygons.unionPolygons(layer.openPolylines.offset(open_polyline_width / 2)); layer.openPolylines.clear(); all_original_mold_outlines.add(model_outlines); @@ -87,7 +87,7 @@ void Mold::process(std::vector& slicer_list) } else { - Polygons& mold_outline_above = mold_outline_above_per_mesh[mesh_idx]; // the outside of the mold on the layer above + Shape& mold_outline_above = mold_outline_above_per_mesh[mesh_idx]; // the outside of the mold on the layer above layer.polygons = mold_outline_above.offset(-inset).unionPolygons(model_outlines.offset(width, ClipperLib::jtRound)); } @@ -95,7 +95,7 @@ void Mold::process(std::vector& slicer_list) if (roof_layer_count > 0 && layer_nr > 0) { LayerIndex layer_nr_below = std::max(0, static_cast(layer_nr - roof_layer_count)); - Polygons roofs = slicer.layers[layer_nr_below].polygons.offset(width, ClipperLib::jtRound); // TODO: don't compute offset twice! + Shape roofs = slicer.layers[layer_nr_below].polygons.offset(width, ClipperLib::jtRound); // TODO: don't compute offset twice! layer.polygons = layer.polygons.unionPolygons(roofs); } diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index cb8b110a4c..103ccabbca 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -133,14 +133,14 @@ void PrimeTower::generatePaths_denseInfill() const coord_t required_volume = MM3_2INT(scene.extruders[extruder_nr].settings_.get("prime_tower_min_volume")); const Ratio flow = scene.extruders[extruder_nr].settings_.get("prime_tower_flow"); coord_t current_volume = 0; - Polygons& prime_moves = prime_moves_[extruder_nr]; + Shape& prime_moves = prime_moves_[extruder_nr]; // Create the walls of the prime tower. unsigned int wall_nr = 0; for (; current_volume < required_volume; wall_nr++) { // Create a new polygon with an offset from the outer polygon. - Polygons polygons = outer_poly_.offset(-cumulative_inset - wall_nr * line_width - line_width / 2); + Shape polygons = outer_poly_.offset(-cumulative_inset - wall_nr * line_width - line_width / 2); prime_moves.add(polygons); current_volume += polygons.length() * line_width * layer_height * flow; if (polygons.empty()) // Don't continue. We won't ever reach the required volume because it doesn't fit. @@ -173,7 +173,7 @@ void PrimeTower::generatePaths_denseInfill() // Only the most inside extruder needs to fill the inside of the prime tower if (extruder_nr == extruder_order_.back()) { - Polygons base_extra_moves = PolygonUtils::generateInset(outer_poly_, line_width, cumulative_inset); + Shape base_extra_moves = PolygonUtils::generateInset(outer_poly_, line_width, cumulative_inset); if (! base_extra_moves.empty()) { base_extra_moves_[extruder_nr].push_back(base_extra_moves); @@ -249,16 +249,16 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext { // Actual prime pattern const GCodePathConfig& config = gcode_layer.configs_storage_.prime_tower_config_per_extruder[extruder_nr]; - const Polygons& pattern = prime_moves_[extruder_nr]; + const Shape& pattern = prime_moves_[extruder_nr]; gcode_layer.addPolygonsByOptimizer(pattern, config); } - const std::vector& pattern_extra_brim = base_extra_moves_[extruder_nr]; + const std::vector& pattern_extra_brim = base_extra_moves_[extruder_nr]; if (absolute_layer_number < pattern_extra_brim.size()) { // Extra rings for stronger base const GCodePathConfig& config = gcode_layer.configs_storage_.prime_tower_config_per_extruder[extruder_nr]; - const Polygons& pattern = pattern_extra_brim[absolute_layer_number]; + const Shape& pattern = pattern_extra_brim[absolute_layer_number]; gcode_layer.addPolygonsByOptimizer(pattern, config); } } @@ -267,7 +267,7 @@ void PrimeTower::subtractFromSupport(SliceDataStorage& storage) { for (size_t layer = 0; layer <= (size_t)storage.max_print_height_second_to_last_extruder + 1 && layer < storage.support.supportLayers.size(); layer++) { - const Polygons outside_polygon = getOuterPoly(layer).getOutsidePolygons(); + const Shape outside_polygon = getOuterPoly(layer).getOutsidePolygons(); AABB outside_polygon_boundary_box(outside_polygon); SupportLayer& support_layer = storage.support.supportLayers[layer]; // take the differences of the support infill parts and the prime tower area @@ -275,7 +275,7 @@ void PrimeTower::subtractFromSupport(SliceDataStorage& storage) } } -const Polygons& PrimeTower::getOuterPoly(const LayerIndex& layer_nr) const +const Shape& PrimeTower::getOuterPoly(const LayerIndex& layer_nr) const { const LayerIndex absolute_layer_nr = layer_nr + Raft::getTotalExtraLayers(); if (absolute_layer_nr < outer_poly_base_.size()) @@ -288,7 +288,7 @@ const Polygons& PrimeTower::getOuterPoly(const LayerIndex& layer_nr) const } } -const Polygons& PrimeTower::getGroundPoly() const +const Shape& PrimeTower::getGroundPoly() const { return getOuterPoly(-Raft::getTotalExtraLayers()); } diff --git a/src/SkeletalTrapezoidation.cpp b/src/SkeletalTrapezoidation.cpp index 26bf3135ae..9c578a185b 100644 --- a/src/SkeletalTrapezoidation.cpp +++ b/src/SkeletalTrapezoidation.cpp @@ -370,7 +370,7 @@ void SkeletalTrapezoidation::computeSegmentCellRange( } SkeletalTrapezoidation::SkeletalTrapezoidation( - const Polygons& polys, + const Shape& polys, const BeadingStrategy& beading_strategy, AngleRadians transitioning_angle, coord_t discretization_step_size, @@ -392,7 +392,7 @@ SkeletalTrapezoidation::SkeletalTrapezoidation( constructFromPolygons(polys); } -void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys) +void SkeletalTrapezoidation::constructFromPolygons(const Shape& polys) { vd_edge_to_he_edge_.clear(); vd_node_to_he_node_.clear(); diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 6bc084817f..8856a19a58 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -64,7 +64,7 @@ SkirtBrim::SkirtBrim(SliceDataStorage& storage) } } -std::vector SkirtBrim::generateBrimOffsetPlan(std::vector& starting_outlines) +std::vector SkirtBrim::generateBrimOffsetPlan(std::vector& starting_outlines) { std::vector all_brim_offsets; @@ -112,23 +112,23 @@ std::vector SkirtBrim::generateBrimOffsetPlan(std::vector starting_outlines(extruder_count_); + std::vector starting_outlines(extruder_count_); std::vector all_brim_offsets = generateBrimOffsetPlan(starting_outlines); constexpr LayerIndex layer_nr = 0; constexpr bool include_support = true; const bool include_prime_tower = adhesion_type_ == EPlatformAdhesion::SKIRT; const bool has_prime_tower = storage_.primeTower.enabled_; - Polygons covered_area = storage_.getLayerOutlines(layer_nr, include_support, include_prime_tower, /*external_polys_only*/ false); + Shape covered_area = storage_.getLayerOutlines(layer_nr, include_support, include_prime_tower, /*external_polys_only*/ false); - std::vector allowed_areas_per_extruder(extruder_count_); + std::vector allowed_areas_per_extruder(extruder_count_); for (int extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) { if (! extruder_is_used_[extruder_nr]) { continue; } - Polygons machine_area = storage_.getMachineBorder(extruder_nr); + Shape machine_area = storage_.getMachineBorder(extruder_nr); allowed_areas_per_extruder[extruder_nr] = machine_area.difference(covered_area); if (external_polys_only_[extruder_nr]) { @@ -182,7 +182,7 @@ void SkirtBrim::generate() } } -std::vector SkirtBrim::generatePrimaryBrim(std::vector& all_brim_offsets, Polygons& covered_area, std::vector& allowed_areas_per_extruder) +std::vector SkirtBrim::generatePrimaryBrim(std::vector& all_brim_offsets, Shape& covered_area, std::vector& allowed_areas_per_extruder) { std::vector total_length(extruder_count_, 0U); @@ -223,14 +223,14 @@ std::vector SkirtBrim::generatePrimaryBrim(std::vector& all_bri return total_length; } -Polygons SkirtBrim::getInternalHoleExclusionArea(const Polygons& outline, const int extruder_nr) +Shape SkirtBrim::getInternalHoleExclusionArea(const Shape& outline, const int extruder_nr) { assert(extruder_nr >= 0); const Settings& settings = Application::getInstance().current_slice_->scene.extruders[extruder_nr].settings_; // If brim is external_only, the distance between the external brim of a part inside a hole and the inside hole of the outer part. const coord_t hole_brim_distance = settings.get("brim_inside_margin"); - Polygons ret; + Shape ret; std::vector parts = outline.splitIntoParts(); for (const SingleShape& part : parts) { @@ -238,25 +238,25 @@ Polygons SkirtBrim::getInternalHoleExclusionArea(const Polygons& outline, const { Polygon hole_poly = part[hole_idx]; hole_poly.reverse(); - Polygons disallowed_region = hole_poly.offset(10u).difference(hole_poly.offset(-line_widths_[extruder_nr] / 2 - hole_brim_distance)); + Shape disallowed_region = hole_poly.offset(10u).difference(hole_poly.offset(-line_widths_[extruder_nr] / 2 - hole_brim_distance)); ret = ret.unionPolygons(disallowed_region); } } return ret; } -coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, std::vector& allowed_areas_per_extruder, SkirtBrimLine& result) +coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std::vector& allowed_areas_per_extruder, SkirtBrimLine& result) { coord_t length_added; - Polygons brim; - Polygons newly_covered; + Shape brim; + Shape newly_covered; { - if (std::holds_alternative(offset.reference_outline_or_index_)) + if (std::holds_alternative(offset.reference_outline_or_index_)) { - Polygons* reference_outline = std::get(offset.reference_outline_or_index_); + Shape* reference_outline = std::get(offset.reference_outline_or_index_); if (offset.external_only_) { // prevent unioning of external polys enclosed by other parts, e.g. a small part inside a hollow cylinder. - for (Polygons& polys : reference_outline->sortByNesting()) + for (Shape& polys : reference_outline->sortByNesting()) { // offset external polygons of islands contained within another part in each batch for (Polygon& poly : polys) { @@ -285,7 +285,7 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, const int reference_idx = std::get(offset.reference_outline_or_index_); auto offset_dist = line_widths_[offset.extruder_nr_]; - Polygons local_brim; + Shape local_brim; auto closed_polygons_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].closed_polygons.offset(offset_dist, ClipperLib::jtRound); local_brim.add(closed_polygons_brim); @@ -336,9 +336,9 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Polygons& covered_area, return length_added; } -Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) +Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) { - Polygons first_layer_outline; + Shape first_layer_outline; Settings& global_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; int reference_extruder_nr = skirt_brim_extruder_nr_; assert(! (reference_extruder_nr == -1 && extruder_nr == -1) && "We should only request the outlines of all layers when the brim is being generated for only one material"); @@ -356,7 +356,7 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) constexpr bool include_support = true; const bool include_prime_tower = ! has_prime_tower; // include manually otherwise - first_layer_outline = Polygons(); + first_layer_outline = Shape(); int skirt_height = 0; for (const auto& extruder : Application::getInstance().current_slice_->scene.extruders) { @@ -381,7 +381,7 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) first_layer_outline = first_layer_outline.unionPolygons(storage_.primeTower.getGroundPoly()); } - Polygons shields; + Shape shields; if (has_ooze_shield_) { shields = storage_.oozeShield[0]; @@ -406,7 +406,7 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) constexpr bool external_outlines_only = false; // Remove manually below. first_layer_outline = storage_.getLayerOutlines(layer_nr, include_support, include_prime_tower, external_outlines_only, extruder_nr); first_layer_outline = first_layer_outline.unionPolygons(); // To guard against overlapping outlines, which would produce holes according to the even-odd rule. - Polygons first_layer_empty_holes; + Shape first_layer_empty_holes; if (external_only) { first_layer_empty_holes = first_layer_outline.getEmptyHoles(); @@ -427,7 +427,7 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) // |+-+| |+--+| // +---+ +----+ const coord_t primary_extruder_skirt_brim_line_width = line_widths_[reference_extruder_nr]; - Polygons model_brim_covered_area = first_layer_outline.offset( + Shape model_brim_covered_area = first_layer_outline.offset( primary_extruder_skirt_brim_line_width * (primary_line_count + primary_line_count % 2), ClipperLib::jtRound); // always leave a gap of an even number of brim lines, so that it fits if it's generating brim from both sides if (external_only) @@ -460,7 +460,7 @@ Polygons SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) return first_layer_outline; } -void SkirtBrim::generateShieldBrim(Polygons& brim_covered_area, std::vector& allowed_areas_per_extruder) +void SkirtBrim::generateShieldBrim(Shape& brim_covered_area, std::vector& allowed_areas_per_extruder) { int extruder_nr = skirt_brim_extruder_nr_; if (extruder_nr < 0) @@ -485,7 +485,7 @@ void SkirtBrim::generateShieldBrim(Polygons& brim_covered_area, std::vector& allowed_areas_per_extruder, std::vector& total_length) +void SkirtBrim::generateSecondarySkirtBrim(Shape& covered_area, std::vector& allowed_areas_per_extruder, std::vector& total_length) { constexpr coord_t bogus_total_offset = 0u; // Doesn't matter. The offsets won't be sorted here. constexpr bool is_last = false; // Doesn't matter. Isn't used in the algorithm below. for (int extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) { bool first = true; - Polygons reference_outline = covered_area; + Shape reference_outline = covered_area; while (total_length[extruder_nr] < skirt_brim_minimal_length_[extruder_nr]) { decltype(Offset::reference_outline_or_index_) ref_polys_or_idx = nullptr; @@ -604,12 +604,12 @@ void SkirtBrim::generateSupportBrim() SupportLayer& support_layer = storage_.support.supportLayers[0]; - Polygons support_outline; + Shape support_outline; for (SupportInfillPart& part : support_layer.support_infill_parts) { support_outline.add(part.outline_); } - const Polygons brim_area = support_outline.difference(support_outline.offset(-brim_width)); + const Shape brim_area = support_outline.difference(support_outline.offset(-brim_width)); support_layer.excludeAreasFromSupportInfillAreas(brim_area, AABB(brim_area)); coord_t offset_distance = brim_line_width / 2; @@ -617,7 +617,7 @@ void SkirtBrim::generateSupportBrim() { offset_distance -= brim_line_width; - Polygons brim_line = support_outline.offset(offset_distance, ClipperLib::jtRound); + Shape brim_line = support_outline.offset(offset_distance, ClipperLib::jtRound); // Remove small inner skirt and brim holes. Holes have a negative area, remove anything smaller then multiplier x extrusion "area" for (size_t n = 0; n < brim_line.size(); n++) diff --git a/src/TopSurface.cpp b/src/TopSurface.cpp index c1b2c3fa57..5d6eb35b0d 100644 --- a/src/TopSurface.cpp +++ b/src/TopSurface.cpp @@ -19,7 +19,7 @@ TopSurface::TopSurface() void TopSurface::setAreasFromMeshAndLayerNumber(SliceMeshStorage& mesh, size_t layer_number) { // The top surface is all parts of the mesh where there's no mesh above it, so find the layer above it first. - Polygons mesh_above; + Shape mesh_above; if (layer_number < mesh.layers.size() - 1) { mesh_above = mesh.layers[layer_number + 1].getOutlines(); @@ -86,7 +86,7 @@ bool TopSurface::ironing(const SliceDataStorage& storage, const SliceMeshStorage // Align the edge of the ironing line with the edge of the outer wall ironing_inset -= ironing_flow * line_width / 2; } - Polygons ironed_areas = areas.offset(ironing_inset); + Shape ironed_areas = areas.offset(ironing_inset); Infill infill_generator( pattern, @@ -107,7 +107,7 @@ bool TopSurface::ironing(const SliceDataStorage& storage, const SliceMeshStorage infill_origin, skip_line_stitching); std::vector ironing_paths; - Polygons ironing_polygons; + Shape ironing_polygons; LinesSet ironing_lines; infill_generator.generate(ironing_paths, ironing_polygons, ironing_lines, mesh.settings, layer.getLayerNr(), SectionType::IRONING); @@ -157,7 +157,7 @@ bool TopSurface::ironing(const SliceDataStorage& storage, const SliceMeshStorage { const coord_t max_adjacent_distance = line_spacing * 1.1; // Lines are considered adjacent - meaning they need to be printed in monotonic order - if spaced 1 line apart, with 10% extra play. - layer.addLinesMonotonic(Polygons(), ironing_lines, line_config, SpaceFillType::PolyLines, AngleRadians(direction), max_adjacent_distance); + layer.addLinesMonotonic(Shape(), ironing_lines, line_config, SpaceFillType::PolyLines, AngleRadians(direction), max_adjacent_distance); } added = true; } diff --git a/src/TreeModelVolumes.cpp b/src/TreeModelVolumes.cpp index 6d058ffd8c..4e81c848f0 100644 --- a/src/TreeModelVolumes.cpp +++ b/src/TreeModelVolumes.cpp @@ -26,7 +26,7 @@ TreeModelVolumes::TreeModelVolumes( size_t current_mesh_idx, double progress_multiplier, double progress_offset, - const std::vector& additional_excluded_areas) + const std::vector& additional_excluded_areas) : max_move_{ std::max(max_move - 2, coord_t(0)) } , // -2 to avoid rounding errors max_move_slow_{ std::max(max_move_slow - 2, coord_t(0)) } @@ -37,7 +37,7 @@ TreeModelVolumes::TreeModelVolumes( , machine_border_{ calculateMachineBorderCollision(storage.getMachineBorder()) } , machine_area_{ storage.getMachineBorder() } { - anti_overhang_ = std::vector(storage.support.supportLayers.size(), Polygons()); + anti_overhang_ = std::vector(storage.support.supportLayers.size(), Shape()); std::unordered_map mesh_to_layeroutline_idx; // Get, for all participating meshes, simplification settings, and support settings that can be set per mesh. @@ -64,7 +64,7 @@ TreeModelVolumes::TreeModelVolumes( if (! added) { mesh_to_layeroutline_idx[mesh_idx] = layer_outlines_.size(); - layer_outlines_.emplace_back(mesh.settings, std::vector(storage.support.supportLayers.size(), Polygons())); + layer_outlines_.emplace_back(mesh.settings, std::vector(storage.support.supportLayers.size(), Shape())); } } @@ -116,7 +116,7 @@ TreeModelVolumes::TreeModelVolumes( { return; // Can't break as parallel_for wont allow it, this is equivalent to a continue. } - Polygons outline = extractOutlineFromMesh(mesh_l, layer_idx); + Shape outline = extractOutlineFromMesh(mesh_l, layer_idx); layer_outlines_[mesh_to_layeroutline_idx[mesh_idx_l]].second[layer_idx].add(outline); }); } @@ -328,10 +328,10 @@ void TreeModelVolumes::precalculate(coord_t max_layer) dur_col_avo); } -const Polygons& TreeModelVolumes::getCollision(coord_t radius, LayerIndex layer_idx, bool min_xy_dist) +const Shape& TreeModelVolumes::getCollision(coord_t radius, LayerIndex layer_idx, bool min_xy_dist) { const coord_t orig_radius = radius; - std::optional> result; + std::optional> result; if (! min_xy_dist) { radius += current_min_xy_dist_delta_; @@ -361,10 +361,10 @@ const Polygons& TreeModelVolumes::getCollision(coord_t radius, LayerIndex layer_ return getCollision(orig_radius, layer_idx, min_xy_dist); } -const Polygons& TreeModelVolumes::getCollisionHolefree(coord_t radius, LayerIndex layer_idx, bool min_xy_dist) +const Shape& TreeModelVolumes::getCollisionHolefree(coord_t radius, LayerIndex layer_idx, bool min_xy_dist) { const coord_t orig_radius = radius; - std::optional> result; + std::optional> result; if (! min_xy_dist) { radius += current_min_xy_dist_delta_; @@ -391,7 +391,7 @@ const Polygons& TreeModelVolumes::getCollisionHolefree(coord_t radius, LayerInde return getCollisionHolefree(orig_radius, layer_idx, min_xy_dist); } -const Polygons& TreeModelVolumes::getAccumulatedPlaceable0(LayerIndex layer_idx) +const Shape& TreeModelVolumes::getAccumulatedPlaceable0(LayerIndex layer_idx) { { std::lock_guard critical_section_support_max_layer_nr(*critical_accumulated_placeables_cache_radius_0_); @@ -404,7 +404,7 @@ const Polygons& TreeModelVolumes::getAccumulatedPlaceable0(LayerIndex layer_idx) return getAccumulatedPlaceable0(layer_idx); } -const Polygons& TreeModelVolumes::getAvoidance(coord_t radius, LayerIndex layer_idx, AvoidanceType type, bool to_model, bool min_xy_dist) +const Shape& TreeModelVolumes::getAvoidance(coord_t radius, LayerIndex layer_idx, AvoidanceType type, bool to_model, bool min_xy_dist) { if (layer_idx == 0) // What on the layer directly above buildplate do i have to avoid to reach the buildplate ... { @@ -413,7 +413,7 @@ const Polygons& TreeModelVolumes::getAvoidance(coord_t radius, LayerIndex layer_ const coord_t orig_radius = radius; - std::optional> result; + std::optional> result; radius += (min_xy_dist ? 0 : current_min_xy_dist_delta_); radius = ceilRadius(radius); @@ -425,7 +425,7 @@ const Polygons& TreeModelVolumes::getAvoidance(coord_t radius, LayerIndex layer_ const RadiusLayerPair key{ radius, layer_idx }; - std::unordered_map* cache_ptr = nullptr; + std::unordered_map* cache_ptr = nullptr; std::mutex* mutex_ptr = nullptr; switch (type) { @@ -489,9 +489,9 @@ const Polygons& TreeModelVolumes::getAvoidance(coord_t radius, LayerIndex layer_ return getAvoidance(orig_radius, layer_idx, type, to_model, min_xy_dist); // retrive failed and correct result was calculated. Now it has to be retrived. } -const Polygons& TreeModelVolumes::getPlaceableAreas(coord_t radius, LayerIndex layer_idx) +const Shape& TreeModelVolumes::getPlaceableAreas(coord_t radius, LayerIndex layer_idx) { - std::optional> result; + std::optional> result; const coord_t orig_radius = radius; radius = ceilRadius(radius); RadiusLayerPair key{ radius, layer_idx }; @@ -520,7 +520,7 @@ const Polygons& TreeModelVolumes::getPlaceableAreas(coord_t radius, LayerIndex l } -const Polygons& TreeModelVolumes::getWallRestriction(coord_t radius, LayerIndex layer_idx, bool min_xy_dist) +const Shape& TreeModelVolumes::getWallRestriction(coord_t radius, LayerIndex layer_idx, bool min_xy_dist) { if (layer_idx == 0) // Should never be requested as there will be no going below layer 0 ..., but just to be sure some semi-sane catch. Alternative would be empty Polygon. { @@ -530,12 +530,12 @@ const Polygons& TreeModelVolumes::getWallRestriction(coord_t radius, LayerIndex const coord_t orig_radius = radius; min_xy_dist = min_xy_dist && current_min_xy_dist_delta_ > 0; - std::optional> result; + std::optional> result; radius = ceilRadius(radius); const RadiusLayerPair key{ radius, layer_idx }; - std::unordered_map* cache_ptr = min_xy_dist ? &wall_restrictions_cache_min_ : &wall_restrictions_cache_; + std::unordered_map* cache_ptr = min_xy_dist ? &wall_restrictions_cache_min_ : &wall_restrictions_cache_; { std::lock_guard critical_section(min_xy_dist ? *critical_wall_restrictions_cache_min_ : *critical_wall_restrictions_cache_); result = getArea(*cache_ptr, key); @@ -568,16 +568,16 @@ bool TreeModelVolumes::checkSettingsEquality(const Settings& me, const Settings& return TreeSupportSettings(me) == TreeSupportSettings(other); } -Polygons TreeModelVolumes::extractOutlineFromMesh(const SliceMeshStorage& mesh, LayerIndex layer_idx) const +Shape TreeModelVolumes::extractOutlineFromMesh(const SliceMeshStorage& mesh, LayerIndex layer_idx) const { // Similar to SliceDataStorage.getLayerOutlines but only for one mesh instead of for all of them. constexpr bool external_polys_only = false; - Polygons total; + Shape total; if (mesh.settings.get("infill_mesh") || mesh.settings.get("anti_overhang_mesh")) { - return Polygons(); + return Shape(); } const SliceLayer& layer = mesh.layers[layer_idx]; @@ -592,7 +592,7 @@ Polygons TreeModelVolumes::extractOutlineFromMesh(const SliceMeshStorage& mesh, return Simplify(maximum_resolution, maximum_deviation, maximum_area_deviation).polygon(total); } -LayerIndex TreeModelVolumes::getMaxCalculatedLayer(coord_t radius, const std::unordered_map& map) const +LayerIndex TreeModelVolumes::getMaxCalculatedLayer(coord_t radius, const std::unordered_map& map) const { LayerIndex max_layer = -1; @@ -620,12 +620,12 @@ void TreeModelVolumes::calculateCollision(const std::deque& key { const coord_t radius = keys[i].first; RadiusLayerPair key(radius, 0); - std::unordered_map data_outer; - std::unordered_map data_placeable_outer; + std::unordered_map data_outer; + std::unordered_map data_placeable_outer; for (const auto outline_idx : ranges::views::iota(0UL, layer_outlines_.size())) { - std::unordered_map data; - std::unordered_map data_placeable; + std::unordered_map data; + std::unordered_map data_placeable; const coord_t layer_height = layer_outlines_[outline_idx].first.get("layer_height"); const bool support_rests_on_this_model = layer_outlines_[outline_idx].first.get("support_type") == ESupportType::EVERYWHERE; @@ -652,7 +652,7 @@ void TreeModelVolumes::calculateCollision(const std::deque& key for (const auto layer_idx : ranges::views::iota(min_layer_bottom, max_required_layer + 1)) { key.second = layer_idx; - Polygons collision_areas = machine_border_; + Shape collision_areas = machine_border_; if (size_t(layer_idx) < layer_outlines_[outline_idx].second.size()) { collision_areas.add(layer_outlines_[outline_idx].second[layer_idx]); @@ -676,11 +676,11 @@ void TreeModelVolumes::calculateCollision(const std::deque& key if ((support_rests_on_this_model || precalculation_finished_ || ! precalculated_) && radius == 0 && layer_idx < coord_t(1 + keys[i].second)) { data[key] = data[key].unionPolygons(); - Polygons above = data[RadiusLayerPair(radius, layer_idx + 1)]; - above = above.unionPolygons(max_anti_overhang_layer >= layer_idx + 1 ? anti_overhang_[layer_idx] : Polygons()); + Shape above = data[RadiusLayerPair(radius, layer_idx + 1)]; + above = above.unionPolygons(max_anti_overhang_layer >= layer_idx + 1 ? anti_overhang_[layer_idx] : Shape()); // Empty polygons on condition: Just to be sure the area is correctly unioned as otherwise difference may behave unexpectedly. - Polygons placeable = data[key].unionPolygons().difference(above); + Shape placeable = data[key].unionPolygons().difference(above); data_placeable[RadiusLayerPair(radius, layer_idx + 1)] = data_placeable[RadiusLayerPair(radius, layer_idx + 1)].unionPolygons(placeable); } } @@ -721,7 +721,7 @@ void TreeModelVolumes::calculateCollision(const std::deque& key // It is assumed to be better to not support an overhang<90� than to risk fusing to it. data[key].add(layer_outlines_[outline_idx].second[layer_idx + layer_offset].offset(radius + required_range_x)); } - data[key] = data[key].unionPolygons(max_anti_overhang_layer >= layer_idx ? anti_overhang_[layer_idx].offset(radius) : Polygons()); + data[key] = data[key].unionPolygons(max_anti_overhang_layer >= layer_idx ? anti_overhang_[layer_idx].offset(radius) : Shape()); } for (const auto layer_idx : ranges::views::iota(static_cast(keys[i].second) + 1UL, max_required_layer + 1UL) | ranges::views::reverse) @@ -781,13 +781,13 @@ void TreeModelVolumes::calculateCollisionHolefree(const std::deque data; + std::unordered_map data; for (RadiusLayerPair key : keys) { // Logically increase the collision by increase_until_radius const coord_t radius = key.first; const coord_t increase_radius_ceil = ceilRadius(increase_until_radius_, false) - ceilRadius(radius, true); - Polygons col = getCollision(increase_until_radius_, layer_idx, false).offset(EPSILON - increase_radius_ceil, ClipperLib::jtRound).unionPolygons(); + Shape col = getCollision(increase_until_radius_, layer_idx, false).offset(EPSILON - increase_radius_ceil, ClipperLib::jtRound).unionPolygons(); // ^^^ That last 'unionPolygons' is important as otherwise holes(in form of lines that will increase to holes in a later step) can get unioned onto the area. col = simplifier_.polygon(col); data[RadiusLayerPair(radius, layer_idx)] = col; @@ -818,12 +818,12 @@ void TreeModelVolumes::calculateAccumulatedPlaceable0(const LayerIndex max_layer spdlog::debug("Requested calculation for value already calculated ?"); return; } - Polygons accumulated_placeable_0 + Shape accumulated_placeable_0 = start_layer == 1 ? machine_area_ : getAccumulatedPlaceable0(start_layer - 1).offset(FUDGE_LENGTH + (current_min_xy_dist_ + current_min_xy_dist_delta_)); // ^^^ The calculation here is done on the areas that are increased by xy_distance, but the result is saved without xy_distance, // so here it "restores" the previous state to continue calculating from about where it ended. // It would be better to ensure placeable areas of radius 0 do not include the xy distance, and removing the code compensating for it here and in calculatePlaceables. - std::vector> data(max_layer + 1, std::pair(-1, Polygons())); + std::vector> data(max_layer + 1, std::pair(-1, Shape())); for (LayerIndex layer = start_layer; layer <= max_layer; layer++) { @@ -867,26 +867,26 @@ void TreeModelVolumes::calculateCollisionAvoidance(const std::deque> data(max_required_layer + 1, std::pair(RadiusLayerPair(radius, -1), Polygons())); + std::vector> data(max_required_layer + 1, std::pair(RadiusLayerPair(radius, -1), Shape())); RadiusLayerPair key(radius, 0); - Polygons latest_avoidance = getAvoidance(radius, start_layer - 1, AvoidanceType::COLLISION, true, true); + Shape latest_avoidance = getAvoidance(radius, start_layer - 1, AvoidanceType::COLLISION, true, true); for (const LayerIndex layer : ranges::views::iota(static_cast(start_layer), max_required_layer + 1UL)) { key.second = layer; - Polygons col = getCollision(radius, layer, true); + Shape col = getCollision(radius, layer, true); latest_avoidance = safeOffset(latest_avoidance, -max_move_, ClipperLib::jtRound, -max_step_move, col); - Polygons placeable0RadiusCompensated = getAccumulatedPlaceable0(layer).offset(-std::max(radius, increase_until_radius_), ClipperLib::jtRound); + Shape placeable0RadiusCompensated = getAccumulatedPlaceable0(layer).offset(-std::max(radius, increase_until_radius_), ClipperLib::jtRound); latest_avoidance = latest_avoidance.difference(placeable0RadiusCompensated).unionPolygons(getCollision(radius, layer, true)); - Polygons next_latest_avoidance = simplifier_.polygon(latest_avoidance); + Shape next_latest_avoidance = simplifier_.polygon(latest_avoidance); latest_avoidance = next_latest_avoidance.unionPolygons(latest_avoidance); // ^^^ Ensure the simplification only causes the avoidance to become larger. // If the deviation of the simplification causes the avoidance to become smaller than it should be it can cause issues, if it is larger the worst case is that the // xy distance is effectively increased by deviation. If there would be an option to ensure the resulting polygon only gets larger by simplifying, it should improve // performance further. - data[layer] = std::pair(key, latest_avoidance); + data[layer] = std::pair(key, latest_avoidance); } { @@ -899,11 +899,11 @@ void TreeModelVolumes::calculateCollisionAvoidance(const std::deque= 0); - Polygons ret = me; + Shape ret = me; for (size_t i = 0; i < steps; ++i) { @@ -944,7 +944,7 @@ void TreeModelVolumes::calculateAvoidance(const std::deque& key const coord_t offset_speed = slow ? max_move_slow_ : max_move_; const coord_t max_step_move = std::max(1.9 * radius, current_min_xy_dist_ * 1.9); RadiusLayerPair key(radius, 0); - Polygons latest_avoidance; + Shape latest_avoidance; LayerIndex start_layer; { std::lock_guard critical_section(*(slow ? critical_avoidance_cache_slow_ : holefree ? critical_avoidance_cache_holefree_ : critical_avoidance_cache_)); @@ -956,7 +956,7 @@ void TreeModelVolumes::calculateAvoidance(const std::deque& key return; } start_layer = std::max(start_layer, LayerIndex(1)); // Ensure StartLayer is at least 1 as if no avoidance was calculated getMaxCalculatedLayer returns -1 - std::vector> data(max_required_layer + 1, std::pair(RadiusLayerPair(radius, -1), Polygons())); + std::vector> data(max_required_layer + 1, std::pair(RadiusLayerPair(radius, -1), Shape())); latest_avoidance = getAvoidance(radius, start_layer - 1, type, false, true); // minDist as the delta was already added, also avoidance for layer 0 will return the collision. @@ -965,7 +965,7 @@ void TreeModelVolumes::calculateAvoidance(const std::deque& key for (const LayerIndex layer : ranges::views::iota(static_cast(start_layer), max_required_layer + 1UL)) { key.second = layer; - Polygons col; + Shape col; if ((slow && radius < increase_until_radius_ + current_min_xy_dist_delta_) || holefree) { col = getCollisionHolefree(radius, layer, true); @@ -976,13 +976,13 @@ void TreeModelVolumes::calculateAvoidance(const std::deque& key } latest_avoidance = safeOffset(latest_avoidance, -offset_speed, ClipperLib::jtRound, -max_step_move, col); - Polygons next_latest_avoidance = simplifier_.polygon(latest_avoidance); + Shape next_latest_avoidance = simplifier_.polygon(latest_avoidance); latest_avoidance = next_latest_avoidance.unionPolygons(latest_avoidance); // ^^^ Ensure the simplification only causes the avoidance to become larger. // If the deviation of the simplification causes the avoidance to become smaller than it should be it can cause issues, if it is larger the worst case is that the // xy distance is effectively increased by deviation. If there would be an option to ensure the resulting polygon only gets larger by simplifying, it should improve // performance further. - data[layer] = std::pair(key, latest_avoidance); + data[layer] = std::pair(key, latest_avoidance); } { @@ -1013,7 +1013,7 @@ void TreeModelVolumes::calculatePlaceables(const std::deque& ke { const coord_t radius = keys[key_idx].first; const LayerIndex max_required_layer = keys[key_idx].second; - std::vector> data(max_required_layer + 1, std::pair(RadiusLayerPair(radius, -1), Polygons())); + std::vector> data(max_required_layer + 1, std::pair(RadiusLayerPair(radius, -1), Shape())); RadiusLayerPair key(radius, 0); LayerIndex start_layer; @@ -1029,17 +1029,17 @@ void TreeModelVolumes::calculatePlaceables(const std::deque& ke if (start_layer == 0) { - data[0] = std::pair(key, machine_border_.difference(getCollision(radius, 0, true))); + data[0] = std::pair(key, machine_border_.difference(getCollision(radius, 0, true))); start_layer = 1; } for (const LayerIndex layer : ranges::views::iota(static_cast(start_layer), max_required_layer + 1)) { key.second = layer; - Polygons placeable = getPlaceableAreas(0, layer); + Shape placeable = getPlaceableAreas(0, layer); placeable = simplifier_.polygon(placeable); // it is faster to do this here in each thread than once in calculateCollision. placeable = placeable.offset(-(radius + (current_min_xy_dist_ + current_min_xy_dist_delta_))).unionPolygons(); - data[layer] = std::pair(key, placeable); + data[layer] = std::pair(key, placeable); } { @@ -1087,8 +1087,8 @@ void TreeModelVolumes::calculateAvoidanceToModel(const std::deque> data(max_required_layer + 1, std::pair(RadiusLayerPair(radius, -1), Polygons())); + Shape latest_avoidance; + std::vector> data(max_required_layer + 1, std::pair(RadiusLayerPair(radius, -1), Shape())); RadiusLayerPair key(radius, 0); LayerIndex start_layer; @@ -1113,7 +1113,7 @@ void TreeModelVolumes::calculateAvoidanceToModel(const std::deque(start_layer), max_required_layer + 1)) { key.second = layer; - Polygons col = getCollision(radius, layer, true); + Shape col = getCollision(radius, layer, true); if ((slow && radius < increase_until_radius_ + current_min_xy_dist_delta_) || holefree) { @@ -1125,13 +1125,13 @@ void TreeModelVolumes::calculateAvoidanceToModel(const std::deque(key, latest_avoidance); + data[layer] = std::pair(key, latest_avoidance); } { @@ -1202,8 +1202,8 @@ void TreeModelVolumes::calculateWallRestrictions(const std::deque data; - std::unordered_map data_min; + std::unordered_map data; + std::unordered_map data_min; { std::lock_guard critical_section(*critical_wall_restrictions_cache_); @@ -1218,12 +1218,12 @@ void TreeModelVolumes::calculateWallRestrictions(const std::deque 0) { - Polygons wall_restriction_min = simplifier_.polygon(getCollision(0, layer_idx, true).intersection(getCollision(radius, layer_idx_below, true))); + Shape wall_restriction_min = simplifier_.polygon(getCollision(0, layer_idx, true).intersection(getCollision(radius, layer_idx_below, true))); data_min.emplace(key, wall_restriction_min); } } @@ -1271,22 +1271,22 @@ coord_t TreeModelVolumes::ceilRadius(coord_t radius) const } template -const std::optional> TreeModelVolumes::getArea(const std::unordered_map& cache, const KEY key) const +const std::optional> TreeModelVolumes::getArea(const std::unordered_map& cache, const KEY key) const { const auto it = cache.find(key); if (it != cache.end()) { - return std::optional>{ it->second }; + return std::optional>{ it->second }; } else { - return std::optional>(); + return std::optional>(); } } -Polygons TreeModelVolumes::calculateMachineBorderCollision(const Polygons&& machine_border) +Shape TreeModelVolumes::calculateMachineBorderCollision(const Shape&& machine_border) { - Polygons machine_volume_border = machine_border.offset(MM2INT(1000.0)); // Put a border of 1 meter around the print volume so that we don't collide. + Shape machine_volume_border = machine_border.offset(MM2INT(1000.0)); // Put a border of 1 meter around the print volume so that we don't collide. machine_volume_border = machine_volume_border.difference(machine_border); // Subtract the actual volume from the collision area. return machine_volume_border; } diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 15e012223f..a9d8c3ab4a 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -94,7 +94,7 @@ TreeSupport::TreeSupport(const SliceDataStorage& storage) mesh.first.setActualZ(known_z); } - placed_support_lines_support_areas = std::vector(storage.support.supportLayers.size(), Polygons()); + placed_support_lines_support_areas = std::vector(storage.support.supportLayers.size(), Shape()); } void TreeSupport::generateSupportAreas(SliceDataStorage& storage) @@ -117,11 +117,11 @@ void TreeSupport::generateSupportAreas(SliceDataStorage& storage) storage.support.supportLayers .size()); // Value is the area where support may be placed. As this is calculated in CreateLayerPathing it is saved and reused in drawAreas. - additional_required_support_area = std::vector(storage.support.supportLayers.size(), Polygons()); + additional_required_support_area = std::vector(storage.support.supportLayers.size(), Shape()); spdlog::info("Processing support tree mesh group {} of {} containing {} meshes.", counter + 1, grouped_meshes.size(), grouped_meshes[counter].second.size()); - std::vector exclude(storage.support.supportLayers.size()); + std::vector exclude(storage.support.supportLayers.size()); auto t_start = std::chrono::high_resolution_clock::now(); // get all already existing support areas and exclude them @@ -130,7 +130,7 @@ void TreeSupport::generateSupportAreas(SliceDataStorage& storage) LayerIndex(storage.support.supportLayers.size()), [&](const LayerIndex layer_idx) { - Polygons exlude_at_layer; + Shape exlude_at_layer; exlude_at_layer.add(storage.support.supportLayers[layer_idx].support_bottom); exlude_at_layer.add(storage.support.supportLayers[layer_idx].support_roof); for (auto part : storage.support.supportLayers[layer_idx].support_infill_parts) @@ -227,7 +227,7 @@ void TreeSupport::precalculate(const SliceDataStorage& storage, std::vector max_layer) // iterates over multiple meshes @@ -328,28 +328,27 @@ void TreeSupport::mergeHelper( continue; } - Polygons relevant_infl; - Polygons relevant_redu; + Shape relevant_infl; + Shape relevant_redu; if (merging_to_bp) { relevant_infl = to_bp_areas.count(influence.first) ? to_bp_areas.at(influence.first) - : Polygons(); // influence.first is a new element => not required to check if it was changed + : Shape(); // influence.first is a new element => not required to check if it was changed relevant_redu = insert_bp_areas.count(reduced_check.first) ? insert_bp_areas[reduced_check.first] - : (to_bp_areas.count(reduced_check.first) ? to_bp_areas.at(reduced_check.first) : Polygons()); + : (to_bp_areas.count(reduced_check.first) ? to_bp_areas.at(reduced_check.first) : Shape()); } else { - relevant_infl = to_model_areas.count(influence.first) ? to_model_areas.at(influence.first) : Polygons(); - relevant_redu = insert_model_areas.count(reduced_check.first) - ? insert_model_areas[reduced_check.first] - : (to_model_areas.count(reduced_check.first) ? to_model_areas.at(reduced_check.first) : Polygons()); + relevant_infl = to_model_areas.count(influence.first) ? to_model_areas.at(influence.first) : Shape(); + relevant_redu = insert_model_areas.count(reduced_check.first) ? insert_model_areas[reduced_check.first] + : (to_model_areas.count(reduced_check.first) ? to_model_areas.at(reduced_check.first) : Shape()); } const bool red_bigger = config.getCollisionRadius(reduced_check.first) > config.getCollisionRadius(influence.first); - std::pair smaller_rad = red_bigger ? std::pair(influence.first, relevant_infl) - : std::pair(reduced_check.first, relevant_redu); - std::pair bigger_rad = red_bigger ? std::pair(reduced_check.first, relevant_redu) - : std::pair(influence.first, relevant_infl); + std::pair smaller_rad + = red_bigger ? std::pair(influence.first, relevant_infl) : std::pair(reduced_check.first, relevant_redu); + std::pair bigger_rad + = red_bigger ? std::pair(reduced_check.first, relevant_redu) : std::pair(influence.first, relevant_infl); const coord_t real_radius_delta = std::abs(config.getRadius(bigger_rad.first) - config.getRadius(smaller_rad.first)); const coord_t smaller_collision_radius = config.getCollisionRadius(smaller_rad.first); @@ -369,7 +368,7 @@ void TreeSupport::mergeHelper( // a branch (of the larger collision radius) placed in this intersection, has already engulfed the branch of the smaller collision radius. // Because of this a merge may happen even if the influence areas (that represent possible center points of branches) do not intersect yet. // Remember that collision radius <= real radius as otherwise this assumption would be false. - const Polygons small_rad_increased_by_big_minus_small = TreeSupportUtils::safeOffsetInc( + const Shape small_rad_increased_by_big_minus_small = TreeSupportUtils::safeOffsetInc( smaller_rad.second, real_radius_delta, volumes_.getCollision(smaller_collision_radius, layer_idx - 1, use_min_radius), @@ -378,7 +377,7 @@ void TreeSupport::mergeHelper( 0, config.support_line_distance / 2, &config.simplifier); - Polygons intersect = small_rad_increased_by_big_minus_small.intersection(bigger_rad.second); + Shape intersect = small_rad_increased_by_big_minus_small.intersection(bigger_rad.second); if (intersect.area() > 1) // dont use empty as a line is not empty, but for this use-case it very well may be (and would be one layer down as union does not keep lines) @@ -419,11 +418,11 @@ void TreeSupport::mergeHelper( const auto getIntersectInfluence = [&](const PropertyAreasUnordered& insert_infl, const PropertyAreas& infl_areas) { - const Polygons infl_small = insert_infl.count(smaller_rad.first) ? insert_infl.at(smaller_rad.first) - : (infl_areas.count(smaller_rad.first) ? infl_areas.at(smaller_rad.first) : Polygons()); - const Polygons infl_big = insert_infl.count(bigger_rad.first) ? insert_infl.at(bigger_rad.first) - : (infl_areas.count(bigger_rad.first) ? infl_areas.at(bigger_rad.first) : Polygons()); - const Polygons small_rad_increased_by_big_minus_small_infl = TreeSupportUtils::safeOffsetInc( + const Shape infl_small = insert_infl.count(smaller_rad.first) ? insert_infl.at(smaller_rad.first) + : (infl_areas.count(smaller_rad.first) ? infl_areas.at(smaller_rad.first) : Shape()); + const Shape infl_big = insert_infl.count(bigger_rad.first) ? insert_infl.at(bigger_rad.first) + : (infl_areas.count(bigger_rad.first) ? infl_areas.at(bigger_rad.first) : Shape()); + const Shape small_rad_increased_by_big_minus_small_infl = TreeSupportUtils::safeOffsetInc( infl_small, real_radius_delta, volumes_.getCollision(smaller_collision_radius, layer_idx - 1, use_min_radius), @@ -436,11 +435,11 @@ void TreeSupport::mergeHelper( infl_big); // If the one with the bigger radius with the lower radius removed overlaps we can merge. }; - Polygons intersect_influence; + Shape intersect_influence; intersect_influence = TreeSupportUtils::safeUnion(intersect, getIntersectInfluence(insert_influence, influence_areas)); // Rounding errors again. Do not ask me where or why. - Polygons intersect_to_model; + Shape intersect_to_model; if (merging_to_bp && config.support_rests_on_model) { intersect_to_model = getIntersectInfluence(insert_model_areas, to_model_areas); @@ -464,7 +463,7 @@ void TreeSupport::mergeHelper( erase.emplace_back(reduced_check.first); erase.emplace_back(influence.first); - const Polygons merge + const Shape merge = intersect.unionPolygons(intersect_to_model).offset(config.getRadius(key), ClipperLib::jtRound).difference(volumes_.getCollision(0, layer_idx - 1)); // ^^^ Regular union should be preferable here as Polygons tend to only become smaller through rounding errors (smaller!=has smaller area as holes have a // negative area.). @@ -544,7 +543,7 @@ void TreeSupport::mergeInfluenceAreas(PropertyAreasUnordered& to_bp_areas, Prope [&](size_t idx) // +=2 as in the beginning only uneven buckets will be filled { idx = idx * 2 + 1; // this is eqivalent to a parallel for(size_t idx=1;idx& input_pair : buckets_area[idx]) + for (const std::pair& input_pair : buckets_area[idx]) { AABB outer_support_wall_aabb = AABB(input_pair.second); outer_support_wall_aabb.expand(config.getRadius(input_pair.first)); @@ -592,16 +591,16 @@ void TreeSupport::mergeInfluenceAreas(PropertyAreasUnordered& to_bp_areas, Prope influence_areas.erase(del); } - for (const std::pair& tup : insert_main[i]) + for (const std::pair& tup : insert_main[i]) { to_bp_areas.emplace(tup); } - for (const std::pair& tup : insert_secondary[i]) + for (const std::pair& tup : insert_secondary[i]) { to_model_areas.emplace(tup); } - for (const std::pair& tup : insert_influence[i]) + for (const std::pair& tup : insert_influence[i]) { influence_areas.emplace(tup); } @@ -631,15 +630,15 @@ std::optional TreeSupport::increaseSingleArea( AreaIncreaseSettings settings, LayerIndex layer_idx, TreeSupportElement* parent, - const Polygons& relevant_offset, - Polygons& to_bp_data, - Polygons& to_model_data, - Polygons& increased, + const Shape& relevant_offset, + Shape& to_bp_data, + Shape& to_model_data, + Shape& increased, const coord_t overspeed, const bool mergelayer) { TreeSupportElement current_elem(parent); // Also increases DTT by one. - Polygons check_layer_data; + Shape check_layer_data; if (settings.increase_radius_) { current_elem.effective_radius_height_ += 1; @@ -717,13 +716,13 @@ std::optional TreeSupport::increaseSingleArea( return true; } - Polygons to_bp_data_2; + Shape to_bp_data_2; if (current_elem.to_buildplate_) { // Regular union as output will not be used later => this area should always be a subset of the safeUnion one. to_bp_data_2 = increased.difference(volumes_.getAvoidance(next_radius, layer_idx - 1, settings.type_, false, settings.use_min_distance_)).unionPolygons(); } - Polygons to_model_data_2; + Shape to_model_data_2; if (config.support_rests_on_model && ! current_elem.to_buildplate_) { to_model_data_2 = increased @@ -735,7 +734,7 @@ std::optional TreeSupport::increaseSingleArea( settings.use_min_distance_)) .unionPolygons(); } - Polygons check_layer_data_2 = current_elem.to_buildplate_ ? to_bp_data_2 : to_model_data_2; + Shape check_layer_data_2 = current_elem.to_buildplate_ ? to_bp_data_2 : to_model_data_2; return check_layer_data_2.area() > 1; }; @@ -764,8 +763,8 @@ std::optional TreeSupport::increaseSingleArea( // wall of the bowl if possible. if (config.getCollisionRadius(current_elem) < config.increase_radius_until_radius && config.getCollisionRadius(current_elem) < config.getRadius(current_elem)) { - Polygons new_to_bp_data; - Polygons new_to_model_data; + Shape new_to_bp_data; + Shape new_to_model_data; if (current_elem.to_buildplate_) { @@ -851,7 +850,7 @@ std::optional TreeSupport::increaseSingleArea( { if (current_elem.to_buildplate_) { - Polygons limited_to_bp = to_bp_data.intersection((current_elem.influence_area_limit_area_)); + Shape limited_to_bp = to_bp_data.intersection((current_elem.influence_area_limit_area_)); if (limited_to_bp.area() > 1) { to_bp_data = limited_to_bp; @@ -861,7 +860,7 @@ std::optional TreeSupport::increaseSingleArea( } else { - Polygons limited_to_model_data = to_model_data.intersection((current_elem.influence_area_limit_area_)); + Shape limited_to_model_data = to_model_data.intersection((current_elem.influence_area_limit_area_)); if (limited_to_model_data.area() > 1) { to_bp_data = to_bp_data.intersection((current_elem.influence_area_limit_area_)); @@ -899,10 +898,10 @@ void TreeSupport::increaseAreas( TreeSupportElement* parent = last_layer[idx]; TreeSupportElement elem(parent); // Also increases dtt. // Abstract representation of the model outline. If an influence area would move through it, it could teleport through a wall. - const Polygons wall_restriction = volumes_.getWallRestriction(config.getCollisionRadius(*parent), layer_idx, parent->use_min_xy_dist_); + const Shape wall_restriction = volumes_.getWallRestriction(config.getCollisionRadius(*parent), layer_idx, parent->use_min_xy_dist_); - Polygons to_bp_data; - Polygons to_model_data; + Shape to_bp_data; + Shape to_model_data; coord_t radius = config.getCollisionRadius(elem); // When the radius increases, the outer "support wall" of the branch will have been moved farther away from the center (as this is the definition of radius). @@ -962,8 +961,8 @@ void TreeSupport::increaseAreas( const coord_t fast_speed = config.maximum_move_distance + extra_speed; const coord_t slow_speed = config.maximum_move_distance_slow + extra_speed + extra_slow_speed; - Polygons offset_slow; - Polygons offset_fast; + Shape offset_slow; + Shape offset_fast; bool add = false; bool bypass_merge = false; @@ -1083,7 +1082,7 @@ void TreeSupport::increaseAreas( false); // Only do not move when already in a no hole avoidance with the regular xy distance. } - Polygons inc_wo_collision; + Shape inc_wo_collision; // Check whether it is faster to calculate the area increased with the fast speed independently from the slow area, or time could be saved by reusing the slow area to // calculate the fast one. Calculated by comparing the steps saved when calculating independently with the saved steps when not. const bool offset_independent_faster = (radius / safe_movement_distance - (((config.maximum_move_distance + extra_speed) < (radius + safe_movement_distance)) ? 1 : 0)) @@ -1145,8 +1144,8 @@ void TreeSupport::increaseAreas( { // If the area becomes for whatever reason something that clipper sees as a line, offset would stop working, so ensure that even if if wrongly would be a line, // it still actually has an area that can be increased - Polygons lines_offset = TreeSupportUtils::toPolylines(*parent->area_).offset(EPSILON); - Polygons base_error_area = parent->area_->unionPolygons(lines_offset); + Shape lines_offset = TreeSupportUtils::toPolylines(*parent->area_).offset(EPSILON); + Shape base_error_area = parent->area_->unionPolygons(lines_offset); result = increaseSingleArea(settings, layer_idx, parent, base_error_area, to_bp_data, to_model_data, inc_wo_collision, settings.increase_speed_, mergelayer); if (fast_speed < settings.increase_speed_) @@ -1233,7 +1232,7 @@ void TreeSupport::increaseAreas( if (add) { - Polygons max_influence_area = TreeSupportUtils::safeUnion( + Shape max_influence_area = TreeSupportUtils::safeUnion( inc_wo_collision.difference(volumes_.getCollision(radius, layer_idx - 1, elem.use_min_xy_dist_)), TreeSupportUtils::safeUnion(to_bp_data, to_model_data)); // ^^^ Note: union seems useless, but some rounding errors somewhere can cause to_bp_data to be slightly bigger than it should be @@ -1242,7 +1241,7 @@ void TreeSupport::increaseAreas( std::lock_guard critical_section_newLayer(critical_sections); if (bypass_merge) { - Polygons* new_area = new Polygons(max_influence_area); + Shape* new_area = new Shape(max_influence_area); TreeSupportElement* next = new TreeSupportElement(elem, new_area); bypass_merge_areas.emplace_back(next); } @@ -1339,10 +1338,10 @@ void TreeSupport::createLayerPathing(std::vector>& new_element = ! move_bounds[layer_idx - 1].empty(); // Save calculated elements to output, and allocate Polygons on heap, as they will not be changed again. - for (std::pair tup : influence_areas) + for (std::pair tup : influence_areas) { const TreeSupportElement elem = tup.first; - Polygons* new_area = new Polygons(TreeSupportUtils::safeUnion(tup.second)); + Shape* new_area = new Shape(TreeSupportUtils::safeUnion(tup.second)); TreeSupportElement* next = new TreeSupportElement(elem, new_area); move_bounds[layer_idx - 1].emplace(next); @@ -1417,13 +1416,13 @@ bool TreeSupport::setToModelContact(std::vector>& set = true; } - Polygons valid_place_area; + Shape valid_place_area; // Check for every layer upwards, up to the point where this influence area was created (either by initial insert or merge) if the branch could be placed on it, and highest // up layer index. for (LayerIndex layer_check = layer_idx; check->next_height_ >= layer_check; layer_check++) { - Polygons check_valid_place_area = check->area_->intersection(volumes_.getPlaceableAreas(config.getCollisionRadius(*check), layer_check)); + Shape check_valid_place_area = check->area_->intersection(volumes_.getPlaceableAreas(config.getCollisionRadius(*check), layer_check)); if (! check_valid_place_area.empty()) { @@ -1494,7 +1493,7 @@ bool TreeSupport::setToModelContact(std::vector>& else // can not add graceful => just place it here and hope for the best { Point2LL best = first_elem->next_position_; - Polygons valid_place_area + Shape valid_place_area = first_elem->area_->difference(volumes_.getAvoidance(config.getCollisionRadius(first_elem), layer_idx, AvoidanceType::COLLISION, first_elem->use_min_xy_dist_)); if (! valid_place_area.inside(best, true)) @@ -1634,7 +1633,7 @@ void TreeSupport::createNodesFromArea(std::vector> void TreeSupport::generateBranchAreas( std::vector>& linear_data, - std::vector>& layer_tree_polygons, + std::vector>& layer_tree_polygons, const std::map& inverse_tree_order) { double progress_total = TREE_PROGRESS_PRECALC_AVO + TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_GENERATE_NODES + TREE_PROGRESS_AREA_CALC; @@ -1650,7 +1649,7 @@ void TreeSupport::generateBranchAreas( } } - std::vector linear_inserts(linear_data.size()); + std::vector linear_inserts(linear_data.size()); const size_t progress_inserts_check_interval = std::max(linear_data.size() / progress_report_steps, size_t(1)); std::mutex critical_sections; @@ -1688,9 +1687,9 @@ void TreeSupport::generateBranchAreas( } coord_t max_speed_sqd = 0; - std::function generateArea = [&](coord_t offset) + std::function generateArea = [&](coord_t offset) { - Polygons poly; + Shape poly; for (std::pair movement : movement_directions) { @@ -1738,7 +1737,7 @@ void TreeSupport::generateBranchAreas( { // Simulate the path the nozzle will take on the outermost wall. // If multiple parts exist, the outer line will not go all around the support part potentially causing support material to be printed mid air. - Polygons nozzle_path = linear_inserts[idx].offset(-config.support_line_width / 2); + Shape nozzle_path = linear_inserts[idx].offset(-config.support_line_width / 2); if (nozzle_path.splitIntoParts(false).size() > 1) { // Just try to make the area a tiny bit larger. @@ -1748,7 +1747,7 @@ void TreeSupport::generateBranchAreas( // if larger area did not fix the problem, all parts off the nozzle path that do not contain the center point are removed, hoping for the best if (nozzle_path.splitIntoParts(false).size() > 1) { - Polygons polygons_with_correct_center; + Shape polygons_with_correct_center; for (SingleShape part : nozzle_path.splitIntoParts(false)) { if (part.inside(elem->result_on_layer_, true)) @@ -1791,7 +1790,7 @@ void TreeSupport::generateBranchAreas( } } -void TreeSupport::smoothBranchAreas(std::vector>& layer_tree_polygons) +void TreeSupport::smoothBranchAreas(std::vector>& layer_tree_polygons) { double progress_total = TREE_PROGRESS_PRECALC_AVO + TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_GENERATE_NODES + TREE_PROGRESS_AREA_CALC + TREE_PROGRESS_GENERATE_BRANCH_AREAS; const coord_t max_radius_change_per_layer = 1 + config.support_line_width / 2; // This is the upper limit a radius may change per layer. +1 to avoid rounding errors. @@ -1799,15 +1798,15 @@ void TreeSupport::smoothBranchAreas(std::vector(layer_tree_polygons.size(), 1UL) - 1UL)) { - std::vector> processing; + std::vector> processing; processing.insert(processing.end(), layer_tree_polygons[layer_idx].begin(), layer_tree_polygons[layer_idx].end()); - std::vector>> update_next(processing.size()); // With this a lock can be avoided. + std::vector>> update_next(processing.size()); // With this a lock can be avoided. cura::parallel_for( 0, processing.size(), [&](const size_t processing_idx) { - std::pair data_pair = processing[processing_idx]; + std::pair data_pair = processing[processing_idx]; coord_t max_outer_wall_distance = 0; bool do_something = false; @@ -1825,21 +1824,21 @@ void TreeSupport::smoothBranchAreas(std::vectorparents_) { if (config.getRadius(*parent) != config.getCollisionRadius(*parent)) { update_next[processing_idx].emplace_back( - std::pair(parent, layer_tree_polygons[layer_idx + 1][parent].intersection(max_allowed_area))); + std::pair(parent, layer_tree_polygons[layer_idx + 1][parent].intersection(max_allowed_area))); } } } }); - for (std::vector> data_vector : update_next) + for (std::vector> data_vector : update_next) { - for (std::pair data_pair : data_vector) + for (std::pair data_pair : data_vector) { layer_tree_polygons[layer_idx + 1][data_pair.first] = data_pair.second; } @@ -1855,25 +1854,25 @@ void TreeSupport::smoothBranchAreas(std::vector updated_last_iteration; for (const auto layer_idx : ranges::views::iota(0UL, std::max(layer_tree_polygons.size(), 1UL) - 1UL) | ranges::views::reverse) { - std::vector> processing; + std::vector> processing; processing.insert(processing.end(), layer_tree_polygons[layer_idx].begin(), layer_tree_polygons[layer_idx].end()); - std::vector> update_next( + std::vector> update_next( processing.size(), - std::pair(nullptr, Polygons())); // With this a lock can be avoided. + std::pair(nullptr, Shape())); // With this a lock can be avoided. cura::parallel_for( 0, processing.size(), [&](const size_t processing_idx) { - std::pair data_pair = processing[processing_idx]; + std::pair data_pair = processing[processing_idx]; bool do_something = false; - Polygons max_allowed_area; + Shape max_allowed_area; for (size_t idx = 0; idx < data_pair.first->parents_.size(); idx++) { TreeSupportElement* parent = data_pair.first->parents_[idx]; const coord_t max_outer_line_increase = max_radius_change_per_layer; - Polygons result = layer_tree_polygons[layer_idx + 1][parent].offset(max_outer_line_increase); + Shape result = layer_tree_polygons[layer_idx + 1][parent].offset(max_outer_line_increase); const Point2LL direction = data_pair.first->result_on_layer_ - parent->result_on_layer_; // Move the polygons object. for (auto& outer : result) @@ -1889,16 +1888,16 @@ void TreeSupport::smoothBranchAreas(std::vector(data_pair.first, result); + update_next[processing_idx] = std::pair(data_pair.first, result); } } }); updated_last_iteration.clear(); - for (std::pair data_pair : update_next) + for (std::pair data_pair : update_next) { if (data_pair.first != nullptr) { @@ -1913,9 +1912,9 @@ void TreeSupport::smoothBranchAreas(std::vector>& layer_tree_polygons, + std::vector>& layer_tree_polygons, const std::vector>& linear_data, - std::vector>>& dropped_down_areas, + std::vector>>& dropped_down_areas, const std::map& inverse_tree_order) { cura::parallel_for( @@ -1928,7 +1927,7 @@ void TreeSupport::dropNonGraciousAreas( && ! elem->to_buildplate_; // If an element has no child, it connects to whatever is below as no support further down for it will exist. if (non_gracious_model_contact) { - Polygons rest_support = layer_tree_polygons[linear_data[idx].first][elem].intersection(volumes_.getAccumulatedPlaceable0(linear_data[idx].first)); + Shape rest_support = layer_tree_polygons[linear_data[idx].first][elem].intersection(volumes_.getAccumulatedPlaceable0(linear_data[idx].first)); for (LayerIndex counter = 1; rest_support.area() > 1 && counter < linear_data[idx].first; ++counter) { rest_support = rest_support.difference(volumes_.getCollision(0, linear_data[idx].first - counter)); @@ -1939,7 +1938,7 @@ void TreeSupport::dropNonGraciousAreas( } -void TreeSupport::filterFloatingLines(std::vector& support_layer_storage) +void TreeSupport::filterFloatingLines(std::vector& support_layer_storage) { const auto t_start = std::chrono::high_resolution_clock::now(); @@ -1947,7 +1946,7 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora const coord_t open_close_distance = config.fill_outline_gaps ? config.min_feature_size / 2 - 5 : config.min_wall_line_width / 2 - 5; // based on calculation in WallToolPath const double small_area_length = INT2MM(static_cast(config.support_line_width) / 2); - std::function reversePolygon = [&](Polygons& poly) + std::function reversePolygon = [&](Shape& poly) { for (size_t idx = 0; idx < poly.size(); idx++) { @@ -1956,7 +1955,7 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora }; - std::vector support_holes(support_layer_storage.size(), Polygons()); + std::vector support_holes(support_layer_storage.size(), Shape()); // Extract all holes as polygon objects cura::parallel_for( 0, @@ -1969,17 +1968,17 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora .offset(-open_close_distance); support_layer_storage[layer_idx].removeSmallAreas(small_area_length * small_area_length, false); - std::vector parts = support_layer_storage[layer_idx].sortByNesting(); + std::vector parts = support_layer_storage[layer_idx].sortByNesting(); if (parts.size() <= 1) { return; } - Polygons holes_original; + Shape holes_original; for (const size_t idx : ranges::views::iota(1UL, parts.size())) { - Polygons area = parts[idx]; + Shape area = parts[idx]; reversePolygon(area); holes_original.add(area); } @@ -1988,14 +1987,14 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora const auto t_union = std::chrono::high_resolution_clock::now(); - std::vector> holeparts(support_layer_storage.size()); + std::vector> holeparts(support_layer_storage.size()); // Split all holes into parts cura::parallel_for( 0, support_layer_storage.size(), [&](const LayerIndex layer_idx) { - for (Polygons hole : support_holes[layer_idx].splitIntoParts()) + for (Shape hole : support_holes[layer_idx].splitIntoParts()) { holeparts[layer_idx].emplace_back(hole); } @@ -2015,11 +2014,11 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora return; } - Polygons outer_walls + Shape outer_walls = TreeSupportUtils::toPolylines(support_layer_storage[layer_idx - 1].getOutsidePolygons()) .tubeShape(closing_dist, 0); //.unionPolygons(volumes_.getCollision(0, layer_idx - 1, true).offset(-(config.support_line_width+config.xy_min_distance))); - Polygons holes_below; + Shape holes_below; for (auto poly : holeparts[layer_idx - 1]) { @@ -2051,7 +2050,7 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora const auto t_hole_rest_ordering = std::chrono::high_resolution_clock::now(); std::unordered_set removed_holes_by_idx; - std::vector valid_holes(support_holes.size(), Polygons()); + std::vector valid_holes(support_holes.size(), Shape()); // Check which holes have to be removed as they do not rest on anything. Only keep holes that have to be removed for (const size_t layer_idx : ranges::views::iota(1UL, support_holes.size())) { @@ -2085,7 +2084,7 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora else { valid_holes[layer_idx].add(hole); - holeparts[layer_idx][idx] = Polygons(); // all remaining holes will have to be removed later, so removing the hole means it is confirmed valid! + holeparts[layer_idx][idx] = Shape(); // all remaining holes will have to be removed later, so removing the hole means it is confirmed valid! } } removed_holes_by_idx = next_removed_holes_by_idx; @@ -2126,7 +2125,7 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_stora dur_hole_removal); } -void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& support_layer_storage, std::vector& support_roof_storage, SliceDataStorage& storage) +void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& support_layer_storage, std::vector& support_roof_storage, SliceDataStorage& storage) { InterfacePreference interface_pref = config.interface_preference; // InterfacePreference::SUPPORT_LINES_OVERWRITE_INTERFACE; double progress_total = TREE_PROGRESS_PRECALC_AVO + TREE_PROGRESS_PRECALC_COLL + TREE_PROGRESS_GENERATE_NODES + TREE_PROGRESS_AREA_CALC + TREE_PROGRESS_GENERATE_BRANCH_AREAS @@ -2158,22 +2157,22 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor case InterfacePreference::INTERFACE_LINES_OVERWRITE_SUPPORT: { - Polygons interface_lines = TreeSupportUtils::generateSupportInfillLines( - storage.support.supportLayers[layer_idx].support_roof, - config, - true, - layer_idx, - config.support_roof_line_distance, - storage.support.cross_fill_provider, - true) - .offset(config.support_roof_line_width / 2); + Shape interface_lines = TreeSupportUtils::generateSupportInfillLines( + storage.support.supportLayers[layer_idx].support_roof, + config, + true, + layer_idx, + config.support_roof_line_distance, + storage.support.cross_fill_provider, + true) + .offset(config.support_roof_line_width / 2); support_layer_storage[layer_idx] = support_layer_storage[layer_idx].difference(interface_lines); } break; case InterfacePreference::SUPPORT_LINES_OVERWRITE_INTERFACE: { - Polygons tree_lines; + Shape tree_lines; tree_lines = tree_lines.unionPolygons(TreeSupportUtils::generateSupportInfillLines( support_layer_storage[layer_idx], config, @@ -2196,8 +2195,8 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor // Subtract support floors from the support area and add them to the support floor instead. if (config.support_bottom_layers > 0 && ! support_layer_storage[layer_idx].empty()) { - Polygons floor_layer = storage.support.supportLayers[layer_idx].support_bottom; - Polygons layer_outset = support_layer_storage[layer_idx].offset(config.support_bottom_offset).difference(volumes_.getCollision(0, layer_idx, false)); + Shape floor_layer = storage.support.supportLayers[layer_idx].support_bottom; + Shape layer_outset = support_layer_storage[layer_idx].offset(config.support_bottom_offset).difference(volumes_.getCollision(0, layer_idx, false)); size_t layers_below = 0; while (layers_below <= config.support_bottom_layers) { @@ -2249,8 +2248,8 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector& suppor void TreeSupport::drawAreas(std::vector>& move_bounds, SliceDataStorage& storage) { - std::vector support_layer_storage(move_bounds.size()); - std::vector support_roof_storage(move_bounds.size()); + std::vector support_layer_storage(move_bounds.size()); + std::vector support_roof_storage(move_bounds.size()); std::map inverse_tree_order; // In the tree structure only the parents can be accessed. Inverse this to be able to access the children. std::vector> @@ -2281,8 +2280,8 @@ void TreeSupport::drawAreas(std::vector>& move_bou } - // Reorder the processed data by layers again. The map also could be a vector>: - std::vector> layer_tree_polygons(move_bounds.size()); + // Reorder the processed data by layers again. The map also could be a vector>: + std::vector> layer_tree_polygons(move_bounds.size()); const auto t_start = std::chrono::high_resolution_clock::now(); // Generate the circles that will be the branches. @@ -2295,14 +2294,14 @@ void TreeSupport::drawAreas(std::vector>& move_bou const auto t_smooth = std::chrono::high_resolution_clock::now(); // Drop down all trees that connect non gracefully with the model. - std::vector>> dropped_down_areas(linear_data.size()); + std::vector>> dropped_down_areas(linear_data.size()); dropNonGraciousAreas(layer_tree_polygons, linear_data, dropped_down_areas, inverse_tree_order); const auto t_drop = std::chrono::high_resolution_clock::now(); // single threaded combining all dropped down support areas to the right layers. ONLY COPYS DATA! for (const coord_t i : ranges::views::iota(0UL, dropped_down_areas.size())) { - for (std::pair pair : dropped_down_areas[i]) + for (std::pair pair : dropped_down_areas[i]) { support_layer_storage[pair.first].add(pair.second); } @@ -2314,7 +2313,7 @@ void TreeSupport::drawAreas(std::vector>& move_bou layer_tree_polygons.size(), [&](const size_t layer_idx) { - for (std::pair data_pair : layer_tree_polygons[layer_idx]) + for (std::pair data_pair : layer_tree_polygons[layer_idx]) { if (data_pair.first->missing_roof_layers_ > data_pair.first->distance_to_top_ && TreeSupportUtils::generateSupportInfillLines(data_pair.second, config, true, layer_idx, config.support_roof_line_distance, nullptr, true).empty()) @@ -2342,7 +2341,7 @@ void TreeSupport::drawAreas(std::vector>& move_bou // Only copies data! for (const auto layer_idx : ranges::views::iota(0UL, layer_tree_polygons.size())) { - for (std::pair data_pair : layer_tree_polygons[layer_idx]) + for (std::pair data_pair : layer_tree_polygons[layer_idx]) { ((data_pair.first->missing_roof_layers_ > data_pair.first->distance_to_top_) ? support_roof_storage : support_layer_storage)[layer_idx].add(data_pair.second); } diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 32eaee596d..70e42ee1a3 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -57,8 +57,8 @@ TreeSupportTipGenerator::TreeSupportTipGenerator(const SliceMeshStorage& mesh, T , tip_roof_size_(force_tip_to_roof_ ? config_.min_radius * config_.min_radius * std::numbers::pi : 0) , force_minimum_roof_area_(use_fake_roof_ || SUPPORT_TREE_MINIMUM_ROOF_AREA_HARD_LIMIT) , already_inserted_(mesh.overhang_areas.size()) - , support_roof_drawn_(mesh.overhang_areas.size(), Polygons()) - , roof_tips_drawn_(mesh.overhang_areas.size(), Polygons()) + , support_roof_drawn_(mesh.overhang_areas.size(), Shape()) + , roof_tips_drawn_(mesh.overhang_areas.size(), Shape()) { const double support_overhang_angle = mesh.settings.get("support_angle"); const coord_t max_overhang_speed = (support_overhang_angle < TAU / 4) ? (coord_t)(tan(support_overhang_angle) * config_.layer_height) : std::numeric_limits::max(); @@ -407,7 +407,7 @@ std::shared_ptr TreeSupportTipGenerator::generateCrossFi return nullptr; } -void TreeSupportTipGenerator::dropOverhangAreas(const SliceMeshStorage& mesh, std::vector& result, bool roof) +void TreeSupportTipGenerator::dropOverhangAreas(const SliceMeshStorage& mesh, std::vector& result, bool roof) { std::mutex critical; @@ -422,13 +422,13 @@ void TreeSupportTipGenerator::dropOverhangAreas(const SliceMeshStorage& mesh, st return; // This is a continue if imagined in a loop context. } - Polygons relevant_forbidden = volumes_.getCollision(roof ? 0 : config_.getRadius(0), layer_idx, ! xy_overrides_); + Shape relevant_forbidden = volumes_.getCollision(roof ? 0 : config_.getRadius(0), layer_idx, ! xy_overrides_); // ^^^ Take the least restrictive avoidance possible // Technically this also makes support blocker smaller, which is wrong as they do not have a xy_distance, but it should be good enough. - Polygons model_outline = volumes_.getCollision(0, layer_idx, ! xy_overrides_).offset(-config_.xy_min_distance, ClipperLib::jtRound); + Shape model_outline = volumes_.getCollision(0, layer_idx, ! xy_overrides_).offset(-config_.xy_min_distance, ClipperLib::jtRound); - Polygons overhang_regular = TreeSupportUtils::safeOffsetInc( + Shape overhang_regular = TreeSupportUtils::safeOffsetInc( mesh.overhang_areas[layer_idx + z_distance_delta_], roof ? roof_outset_ : support_outset_, relevant_forbidden, @@ -437,11 +437,11 @@ void TreeSupportTipGenerator::dropOverhangAreas(const SliceMeshStorage& mesh, st 1, config_.support_line_distance / 2, &config_.simplifier); - Polygons remaining_overhang = mesh.overhang_areas[layer_idx + z_distance_delta_] - .offset(roof ? roof_outset_ : support_outset_) - .difference(overhang_regular) - .intersection(relevant_forbidden) - .difference(model_outline); + Shape remaining_overhang = mesh.overhang_areas[layer_idx + z_distance_delta_] + .offset(roof ? roof_outset_ : support_outset_) + .difference(overhang_regular) + .intersection(relevant_forbidden) + .difference(model_outline); for (size_t lag_ctr = 1; lag_ctr <= max_overhang_insert_lag_ && layer_idx - coord_t(lag_ctr) >= 1 && ! remaining_overhang.empty(); lag_ctr++) { { @@ -449,7 +449,7 @@ void TreeSupportTipGenerator::dropOverhangAreas(const SliceMeshStorage& mesh, st result[layer_idx - lag_ctr].add(remaining_overhang); } - Polygons relevant_forbidden_below = volumes_.getCollision(roof ? 0 : config_.getRadius(0), layer_idx - lag_ctr, ! xy_overrides_).offset(EPSILON); + Shape relevant_forbidden_below = volumes_.getCollision(roof ? 0 : config_.getRadius(0), layer_idx - lag_ctr, ! xy_overrides_).offset(EPSILON); remaining_overhang = remaining_overhang.intersection(relevant_forbidden_below).unionPolygons().difference(model_outline); } }); @@ -465,9 +465,9 @@ void TreeSupportTipGenerator::dropOverhangAreas(const SliceMeshStorage& mesh, st void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& mesh) { - std::vector potential_support_roofs(mesh.overhang_areas.size(), Polygons()); + std::vector potential_support_roofs(mesh.overhang_areas.size(), Shape()); std::mutex critical_potential_support_roofs; - std::vector dropped_overhangs(mesh.overhang_areas.size(), Polygons()); + std::vector dropped_overhangs(mesh.overhang_areas.size(), Shape()); if (xy_overrides_) { @@ -486,19 +486,19 @@ void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& m // Roof does not have a radius, so remove it using offset. Note that there is no 0 radius avoidance, and it would not be identical with the avoidance offset with // -radius. This is intentional here, as support roof is still valid if only a part of the tip may reach it. - Polygons forbidden_here = volumes_ - .getAvoidance( - config_.getRadius(0), - layer_idx, - (only_gracious_ || ! config_.support_rests_on_model) ? AvoidanceType::FAST : AvoidanceType::COLLISION, - config_.support_rests_on_model, - ! xy_overrides_) - .offset(-config_.getRadius(0), ClipperLib::jtRound); + Shape forbidden_here = volumes_ + .getAvoidance( + config_.getRadius(0), + layer_idx, + (only_gracious_ || ! config_.support_rests_on_model) ? AvoidanceType::FAST : AvoidanceType::COLLISION, + config_.support_rests_on_model, + ! xy_overrides_) + .offset(-config_.getRadius(0), ClipperLib::jtRound); // todo Since arachnea the assumption that an area smaller then line_width is not printed is no longer true all such safeOffset should have config.support_line_width // replaced with another setting. It should still work in most cases, but it should be possible to create a situation where a overhang outset lags though a wall. I will // take a look at this later. - Polygons full_overhang_area = TreeSupportUtils::safeOffsetInc( + Shape full_overhang_area = TreeSupportUtils::safeOffsetInc( mesh.full_overhang_areas[layer_idx + z_distance_delta_].unionPolygons(dropped_overhangs[layer_idx]), roof_outset_, forbidden_here, @@ -510,14 +510,14 @@ void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& m for (LayerIndex dtt_roof = 0; dtt_roof < support_roof_layers_ && layer_idx - dtt_roof >= 1; dtt_roof++) { - const Polygons forbidden_next = volumes_ - .getAvoidance( - config_.getRadius(0), - layer_idx - (dtt_roof + 1), - (only_gracious_ || ! config_.support_rests_on_model) ? AvoidanceType::FAST : AvoidanceType::COLLISION, - config_.support_rests_on_model, - ! xy_overrides_) - .offset(-config_.getRadius(0), ClipperLib::jtRound); + const Shape forbidden_next = volumes_ + .getAvoidance( + config_.getRadius(0), + layer_idx - (dtt_roof + 1), + (only_gracious_ || ! config_.support_rests_on_model) ? AvoidanceType::FAST : AvoidanceType::COLLISION, + config_.support_rests_on_model, + ! xy_overrides_) + .offset(-config_.getRadius(0), ClipperLib::jtRound); full_overhang_area = full_overhang_area.difference(forbidden_next); @@ -555,7 +555,7 @@ void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& m .unionPolygons(potential_support_roofs[layer_idx]); }); - std::vector additional_support_roofs(mesh.overhang_areas.size(), Polygons()); + std::vector additional_support_roofs(mesh.overhang_areas.size(), Shape()); cura::parallel_for( 0, @@ -566,18 +566,18 @@ void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& m { // Roof does not have a radius, so remove it using offset. Note that there is no 0 radius avoidance, and it would not be identical with the avoidance offset with // -radius. This is intentional here, as support roof is still valid if only a part of the tip may reach it. - Polygons forbidden_here = volumes_ - .getAvoidance( - config_.getRadius(0), - layer_idx, - (only_gracious_ || ! config_.support_rests_on_model) ? AvoidanceType::FAST : AvoidanceType::COLLISION, - config_.support_rests_on_model, - ! xy_overrides_) - .offset(-(config_.getRadius(0)), ClipperLib::jtRound); + Shape forbidden_here = volumes_ + .getAvoidance( + config_.getRadius(0), + layer_idx, + (only_gracious_ || ! config_.support_rests_on_model) ? AvoidanceType::FAST : AvoidanceType::COLLISION, + config_.support_rests_on_model, + ! xy_overrides_) + .offset(-(config_.getRadius(0)), ClipperLib::jtRound); if (! force_minimum_roof_area_) { - Polygons fuzzy_area = Polygons(); + Shape fuzzy_area = Shape(); // the roof will be combined with roof above and below, to see if a part of this roof may be part of a valid roof further up/down. // This prevents the situation where a roof gets removed even tough its area would contribute to a (better) printable roof area further down. @@ -591,7 +591,7 @@ void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& m fuzzy_area = fuzzy_area.unionPolygons(); fuzzy_area.removeSmallAreas(std::max(minimum_roof_area_, tip_roof_size_)); - for (Polygons potential_roof : potential_support_roofs[layer_idx].difference(forbidden_here).splitIntoParts()) + for (Shape potential_roof : potential_support_roofs[layer_idx].difference(forbidden_here).splitIntoParts()) { if (! potential_roof.intersection(fuzzy_area).empty()) { @@ -601,7 +601,7 @@ void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& m } else { - Polygons valid_roof = potential_support_roofs[layer_idx].difference(forbidden_here); + Shape valid_roof = potential_support_roofs[layer_idx].difference(forbidden_here); valid_roof.removeSmallAreas(std::max(minimum_roof_area_, tip_roof_size_)); additional_support_roofs[layer_idx].add(valid_roof); } @@ -642,7 +642,7 @@ void TreeSupportTipGenerator::addPointAsInfluenceArea( { circle.push_back(p.first + corner); } - Polygons area = circle.offset(0); + Shape area = circle.offset(0); { std::lock_guard critical_section_movebounds(critical_move_bounds_); if (! already_inserted_[insert_layer].count(p.first / ((config_.min_radius + 1) / 10))) @@ -663,7 +663,7 @@ void TreeSupportTipGenerator::addPointAsInfluenceArea( skip_ovalisation, support_tree_limit_branch_reach_, support_tree_branch_reach_limit_); - elem->area_ = new Polygons(area); + elem->area_ = new Shape(area); for (Point2LL target : additional_ovalization_targets) { @@ -699,7 +699,7 @@ void TreeSupportTipGenerator::addLinesAsInfluenceAreas( { roof_circle.push_back(p.first + corner * std::max(config_.min_radius / TreeSupportBaseCircle::base_radius, coord_t(1))); } - Polygons area = roof_circle.offset(0); + Shape area = roof_circle.offset(0); return ! TreeSupportUtils::generateSupportInfillLines(area, config_, true, insert_layer_idx - dtt_roof_tip, support_roof_line_distance_, cross_fill_provider_, true) .empty(); }; @@ -728,7 +728,7 @@ void TreeSupportTipGenerator::addLinesAsInfluenceAreas( } // Add all tips as roof to the roof storage. - Polygons added_roofs; + Shape added_roofs; for (LineInformation line : lines) { for (std::pair p : line) @@ -787,7 +787,7 @@ void TreeSupportTipGenerator::addLinesAsInfluenceAreas( void TreeSupportTipGenerator::removeUselessAddedPoints( std::vector>& move_bounds, SliceDataStorage& storage, - std::vector& additional_support_areas) + std::vector& additional_support_areas) { cura::parallel_for( 0, @@ -797,9 +797,9 @@ void TreeSupportTipGenerator::removeUselessAddedPoints( if (layer_idx + 1 < storage.support.supportLayers.size()) { std::vector to_be_removed; - Polygons roof_on_layer_above = use_fake_roof_ ? support_roof_drawn_[layer_idx + 1] - : storage.support.supportLayers[layer_idx + 1].support_roof.unionPolygons(additional_support_areas[layer_idx + 1]); - Polygons roof_on_layer + Shape roof_on_layer_above = use_fake_roof_ ? support_roof_drawn_[layer_idx + 1] + : storage.support.supportLayers[layer_idx + 1].support_roof.unionPolygons(additional_support_areas[layer_idx + 1]); + Shape roof_on_layer = use_fake_roof_ ? support_roof_drawn_[layer_idx] : storage.support.supportLayers[layer_idx].support_roof.unionPolygons(additional_support_areas[layer_idx]); for (TreeSupportElement* elem : move_bounds[layer_idx]) @@ -838,8 +838,8 @@ void TreeSupportTipGenerator::generateTips( SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector>& move_bounds, - std::vector& additional_support_areas, - std::vector& placed_support_lines_support_areas) + std::vector& additional_support_areas, + std::vector& placed_support_lines_support_areas) { std::vector> new_tips(move_bounds.size()); @@ -869,7 +869,7 @@ void TreeSupportTipGenerator::generateTips( return; // This is a continue if imagined in a loop context. } - Polygons relevant_forbidden = volumes_.getAvoidance( + Shape relevant_forbidden = volumes_.getAvoidance( config_.getRadius(0), layer_idx, (only_gracious_ || ! config_.support_rests_on_model) ? AvoidanceType::FAST : AvoidanceType::COLLISION, @@ -880,7 +880,7 @@ void TreeSupportTipGenerator::generateTips( = relevant_forbidden.offset(EPSILON) .unionPolygons(); // Prevent rounding errors down the line, points placed directly on the line of the forbidden area may not be added otherwise. - std::function(const Polygons&, bool, LayerIndex)> generateLines = [&](const Polygons& area, bool roof, LayerIndex generate_layer_idx) + std::function(const Shape&, bool, LayerIndex)> generateLines = [&](const Shape& area, bool roof, LayerIndex generate_layer_idx) { coord_t upper_line_distance = support_supporting_branch_distance_; coord_t line_distance = std::max(roof ? support_roof_line_distance_ : support_tree_branch_distance_, upper_line_distance); @@ -897,21 +897,21 @@ void TreeSupportTipGenerator::generateTips( }; - std::vector> overhang_processing; + std::vector> overhang_processing; // ^^^ Every overhang has saved if a roof should be generated for it. // This can NOT be done in the for loop as an area may NOT have a roof even if it is larger than the minimum_roof_area when it is only larger because of the support // horizontal expansion and it would not have a roof if the overhang is offset by support roof horizontal expansion instead. (At least this is the current behavior // of the regular support) - Polygons core_overhang = mesh.overhang_areas[layer_idx + z_distance_delta_]; + Shape core_overhang = mesh.overhang_areas[layer_idx + z_distance_delta_]; if (support_roof_layers_ && layer_idx + 1 < support_roof_drawn_.size()) { core_overhang = core_overhang.difference(support_roof_drawn_[layer_idx]); - for (Polygons roof_part : support_roof_drawn_[layer_idx + 1] - .difference(support_roof_drawn_[layer_idx]) - .splitIntoParts(true)) // If there is a roof, the roof will be one layer above the tips. + for (Shape roof_part : support_roof_drawn_[layer_idx + 1] + .difference(support_roof_drawn_[layer_idx]) + .splitIntoParts(true)) // If there is a roof, the roof will be one layer above the tips. { //^^^Technically one should also subtract the avoidance of radius 0 (similarly how calculated in calculateRoofArea), as there can be some rounding errors // introduced since then. But this does not fully prevent some rounding errors either way, so just handle the error later. @@ -919,7 +919,7 @@ void TreeSupportTipGenerator::generateTips( } } - Polygons overhang_regular = TreeSupportUtils::safeOffsetInc( + Shape overhang_regular = TreeSupportUtils::safeOffsetInc( core_overhang, support_outset_, relevant_forbidden, @@ -928,8 +928,7 @@ void TreeSupportTipGenerator::generateTips( 1, config_.support_line_distance / 2, &config_.simplifier); - Polygons remaining_overhang - = core_overhang.offset(support_outset_).difference(overhang_regular.offset(config_.support_line_width * 0.5)).intersection(relevant_forbidden); + Shape remaining_overhang = core_overhang.offset(support_outset_).difference(overhang_regular.offset(config_.support_line_width * 0.5)).intersection(relevant_forbidden); // Offset ensures that areas that could be supported by a part of a support line, are not considered unsupported overhang @@ -943,7 +942,7 @@ void TreeSupportTipGenerator::generateTips( ? std::min(config_.support_line_width / 8, extra_outset - extra_total_offset_acc) : std::min(circle_length_to_half_linewidth_change, extra_outset - extra_total_offset_acc); extra_total_offset_acc += offset_current_step; - Polygons overhang_offset = TreeSupportUtils::safeOffsetInc( + Shape overhang_offset = TreeSupportUtils::safeOffsetInc( overhang_regular, 1.5 * extra_total_offset_acc, volumes_.getCollision(0, layer_idx, true), @@ -954,7 +953,7 @@ void TreeSupportTipGenerator::generateTips( &config_.simplifier); remaining_overhang = remaining_overhang.difference(overhang_offset.unionPolygons(support_roof_drawn_[layer_idx].offset(1.5 * extra_total_offset_acc))) .unionPolygons(); // overhang_offset is combined with roof, as all area that has a roof, is already supported by said roof. - Polygons next_overhang = TreeSupportUtils::safeOffsetInc( + Shape next_overhang = TreeSupportUtils::safeOffsetInc( remaining_overhang, extra_total_offset_acc, volumes_.getCollision(0, layer_idx, true), @@ -971,7 +970,7 @@ void TreeSupportTipGenerator::generateTips( // (while adding them an infinite amount of layers down would technically be closer the setting description, it would not produce reasonable results. ) if (xy_overrides_) { - for (Polygons& remaining_overhang_part : remaining_overhang.splitIntoParts(false)) + for (Shape& remaining_overhang_part : remaining_overhang.splitIntoParts(false)) { if (remaining_overhang_part.area() <= MM2_2INT(minimum_support_area_)) { @@ -1003,7 +1002,7 @@ void TreeSupportTipGenerator::generateTips( for (size_t lag_ctr = 1; lag_ctr <= max_overhang_insert_lag_ && ! overhang_lines.empty() && layer_idx - coord_t(lag_ctr) >= 1; lag_ctr++) { // get least restricted avoidance for layer_idx-lag_ctr - Polygons relevant_forbidden_below = volumes_.getAvoidance( + Shape relevant_forbidden_below = volumes_.getAvoidance( config_.getRadius(0), layer_idx - lag_ctr, (only_gracious_ || ! config_.support_rests_on_model) ? AvoidanceType::FAST : AvoidanceType::COLLISION, @@ -1046,15 +1045,15 @@ void TreeSupportTipGenerator::generateTips( overhang_regular.removeSmallAreas(minimum_support_area_); - for (Polygons support_part : overhang_regular.splitIntoParts(true)) + for (Shape support_part : overhang_regular.splitIntoParts(true)) { overhang_processing.emplace_back(support_part, false); } - for (std::pair overhang_pair : overhang_processing) + for (std::pair overhang_pair : overhang_processing) { const bool roof_allowed_for_this_part = overhang_pair.second; - Polygons overhang_outset = overhang_pair.first; + Shape overhang_outset = overhang_pair.first; const size_t min_support_points = std::max(coord_t(1), std::min(coord_t(EPSILON), overhang_outset.length() / connect_length_)); std::vector overhang_lines; @@ -1081,7 +1080,7 @@ void TreeSupportTipGenerator::generateTips( only_lines = false; // Add the outer wall (of the overhang) to ensure it is correct supported instead. // Try placing the support points in a way that they fully support the outer wall, instead of just the with half of the support line width. - Polygons reduced_overhang_outset = overhang_outset.offset(-config_.support_line_width / 2.2); + Shape reduced_overhang_outset = overhang_outset.offset(-config_.support_line_width / 2.2); // ^^^ It's assumed that even small overhangs are over one line width wide, so lets try to place the support points in a way that the full support area // generated from them will support the overhang. // (If this is not done it may only be half). This WILL NOT be the case when supporting an angle of about < 60� so there is a fallback, as some support is @@ -1106,7 +1105,7 @@ void TreeSupportTipGenerator::generateTips( if (overhang_lines.empty()) // some error handling and logging { - Polygons enlarged_overhang_outset = overhang_outset.offset(config_.getRadius(0) + FUDGE_LENGTH / 2, ClipperLib::jtRound).difference(relevant_forbidden); + Shape enlarged_overhang_outset = overhang_outset.offset(config_.getRadius(0) + FUDGE_LENGTH / 2, ClipperLib::jtRound).difference(relevant_forbidden); polylines = ensureMaximumDistancePolyline(TreeSupportUtils::toPolylines(enlarged_overhang_outset), connect_length_, min_support_points, true); overhang_lines = convertLinesToInternal(polylines, layer_idx); diff --git a/src/WallToolPaths.cpp b/src/WallToolPaths.cpp index 163685eff2..6b8f708366 100644 --- a/src/WallToolPaths.cpp +++ b/src/WallToolPaths.cpp @@ -23,7 +23,7 @@ namespace cura { WallToolPaths::WallToolPaths( - const Polygons& outline, + const Shape& outline, const coord_t nominal_bead_width, const size_t inset_count, const coord_t wall_0_inset, @@ -47,7 +47,7 @@ WallToolPaths::WallToolPaths( } WallToolPaths::WallToolPaths( - const Polygons& outline, + const Shape& outline, const coord_t bead_width_0, const coord_t bead_width_x, const size_t inset_count, @@ -87,7 +87,7 @@ const std::vector& WallToolPaths::generate() // Simplify outline for boost::voronoi consumption. Absolutely no self intersections or near-self intersections allowed: // TODO: Open question: Does this indeed fix all (or all-but-one-in-a-million) cases for manifold but otherwise possibly complex polygons? - Polygons prepared_outline = outline_.offset(-open_close_distance).offset(open_close_distance * 2).offset(-open_close_distance); + Shape prepared_outline = outline_.offset(-open_close_distance).offset(open_close_distance * 2).offset(-open_close_distance); scripta::log("prepared_outline_0", prepared_outline, section_type_, layer_idx_); prepared_outline.removeSmallAreas(small_area_length_ * small_area_length_, false); prepared_outline = Simplify(settings_).polygon(prepared_outline); @@ -415,7 +415,7 @@ void WallToolPaths::separateOutInnerContour() inner_contour_ = inner_contour_.processEvenOdd(); } -const Polygons& WallToolPaths::getInnerContour() +const Shape& WallToolPaths::getInnerContour() { if (! toolpaths_generated_ && inset_count_ > 0) { diff --git a/src/bridge.cpp b/src/bridge.cpp index 7d4842e673..69b20a9280 100644 --- a/src/bridge.cpp +++ b/src/bridge.cpp @@ -14,21 +14,21 @@ namespace cura double bridgeAngle( const Settings& settings, - const Polygons& skin_outline, + const Shape& skin_outline, const SliceDataStorage& storage, const unsigned layer_nr, const unsigned bridge_layer, const SupportLayer* support_layer, - Polygons& supported_regions) + Shape& supported_regions) { assert(! skin_outline.empty()); AABB boundary_box(skin_outline); // To detect if we have a bridge, first calculate the intersection of the current layer with the previous layer. // This gives us the islands that the layer rests on. - Polygons islands; + Shape islands; - Polygons prev_layer_outline; // we also want the complete outline of the previous layer + Shape prev_layer_outline; // we also want the complete outline of the previous layer const Ratio sparse_infill_max_density = settings.get("bridge_sparse_infill_max_density"); @@ -45,7 +45,7 @@ double bridgeAngle( for (const SliceLayerPart& prev_layer_part : mesh.layers[layer_nr - bridge_layer].parts) { - Polygons solid_below(prev_layer_part.outline); + Shape solid_below(prev_layer_part.outline); if (bridge_layer == 1 && part_has_sparse_infill) { solid_below = solid_below.difference(prev_layer_part.getOwnInfillArea()); @@ -76,7 +76,7 @@ double bridgeAngle( { prev_layer_outline.add(support_layer->support_roof); // not intersected with skin - Polygons supported_skin(skin_outline.intersection(support_layer->support_roof)); + Shape supported_skin(skin_outline.intersection(support_layer->support_roof)); if (! supported_skin.empty()) { supported_regions.add(supported_skin); @@ -92,7 +92,7 @@ double bridgeAngle( { prev_layer_outline.add(support_part.getInfillArea()); // not intersected with skin - Polygons supported_skin(skin_outline.intersection(support_part.getInfillArea())); + Shape supported_skin(skin_outline.intersection(support_part.getInfillArea())); if (! supported_skin.empty()) { supported_regions.add(supported_skin); @@ -112,7 +112,7 @@ double bridgeAngle( if (support_threshold > 0 && (supported_regions.area() / (skin_outline.area() + 1)) < support_threshold) { - Polygons bb_poly; + Shape bb_poly; bb_poly.push_back(boundary_box.toPolygon()); // airBelow is the region below the skin that is not supported, it extends well past the boundary of the skin. @@ -120,7 +120,7 @@ double bridgeAngle( // the air boundary do appear to be supported const coord_t bb_max_dim = std::max(boundary_box.max_.X - boundary_box.min_.X, boundary_box.max_.Y - boundary_box.min_.Y); - const Polygons air_below(bb_poly.offset(bb_max_dim).difference(prev_layer_outline).offset(-10)); + const Shape air_below(bb_poly.offset(bb_max_dim).difference(prev_layer_outline).offset(-10)); std::vector skin_perimeter_lines; for (const Polygon& poly : skin_outline) diff --git a/src/communication/ArcusCommunication.cpp b/src/communication/ArcusCommunication.cpp index de009d204a..29d7dc0872 100644 --- a/src/communication/ArcusCommunication.cpp +++ b/src/communication/ArcusCommunication.cpp @@ -449,7 +449,7 @@ void ArcusCommunication::sendPolygon(const PrintFeatureType& type, const Polygon path_compiler->sendPolygon(type, polygon, line_width, line_thickness, velocity); } -void ArcusCommunication::sendPolygons(const PrintFeatureType& type, const Polygons& polygons, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity) +void ArcusCommunication::sendPolygons(const PrintFeatureType& type, const Shape& polygons, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity) { for (const std::vector& polygon : polygons) { diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index 2adb959cf1..6890c3f762 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -55,7 +55,7 @@ void CommandLine::sendOptimizedLayerData() void CommandLine::sendPolygon(const PrintFeatureType&, const Polygon&, const coord_t&, const coord_t&, const Velocity&) { } -void CommandLine::sendPolygons(const PrintFeatureType&, const Polygons&, const coord_t&, const coord_t&, const Velocity&) +void CommandLine::sendPolygons(const PrintFeatureType&, const Shape&, const coord_t&, const coord_t&, const Velocity&) { } void CommandLine::setExtruderForSend(const ExtruderTrain&) diff --git a/src/geometry/lines_set.cpp b/src/geometry/lines_set.cpp index 82f5715d54..0291e9c305 100644 --- a/src/geometry/lines_set.cpp +++ b/src/geometry/lines_set.cpp @@ -7,7 +7,7 @@ #include "geometry/open_polyline.h" #include "geometry/polygon.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" #include "geometry/polyline_type.h" namespace cura @@ -102,26 +102,26 @@ coord_t LinesSet::length() const } template -Polygons LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const +Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const { return offset(outer_offset).difference(offset(-inner_offset)); } template -Polygons LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const +Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const { if (distance == 0) { - return Polygons(getCallable()); + return Shape(getCallable()); } - Polygons temp; + Shape temp; const ClipperLib::Paths* actual_polygons = &getCallable(); - Polygons ret; + Shape ret; ClipperLib::EndType end_type; if constexpr (LineType::type_ == PolylineType::Filled) { - temp = Polygons(getCallable()).unionPolygons(); + temp = Shape(getCallable()).unionPolygons(); actual_polygons = &temp.getCallable(); end_type = ClipperLib::etClosedPolygon; } @@ -218,8 +218,8 @@ template void LinesSet::removeAt(size_t index); template void LinesSet::splitIntoSegments(LinesSet& result) const; template LinesSet LinesSet::splitIntoSegments() const; template coord_t LinesSet::length() const; -template Polygons LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; -template Polygons LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; +template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; template void LinesSet::removeDegenerateVertsForEveryone(); template void LinesSet::addIfNotEmpty(const OpenPolyline& line); template void LinesSet::addIfNotEmpty(OpenPolyline&& line); @@ -230,8 +230,8 @@ template void LinesSet::removeAt(size_t index); template void LinesSet::splitIntoSegments(LinesSet& result) const; template LinesSet LinesSet::splitIntoSegments() const; template coord_t LinesSet::length() const; -template Polygons LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; -template Polygons LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; +template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; template void LinesSet::removeDegenerateVertsForEveryone(); template void LinesSet::addIfNotEmpty(const Polygon& line); template void LinesSet::addIfNotEmpty(Polygon&& line); diff --git a/src/geometry/polygon.cpp b/src/geometry/polygon.cpp index 517b3708ed..67e6db362b 100644 --- a/src/geometry/polygon.cpp +++ b/src/geometry/polygon.cpp @@ -26,14 +26,14 @@ // #include "utils/PolylineStitcher.h" #include "geometry/point3_matrix.h" #include "geometry/point_matrix.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" namespace cura { -Polygons Polygon::intersection(const Polygon& other) const +Shape Polygon::intersection(const Polygon& other) const { - Polygons ret; + Shape ret; ClipperLib::Clipper clipper(clipper_init); clipper.AddPath(*this, ClipperLib::ptSubject, true); clipper.AddPath(other, ClipperLib::ptClip, true); @@ -614,13 +614,13 @@ Point2LL Polygon::centerOfMass() const } } -Polygons Polygon::offset(int distance, ClipperLib::JoinType join_type, double miter_limit) const +Shape Polygon::offset(int distance, ClipperLib::JoinType join_type, double miter_limit) const { if (distance == 0) { - return Polygons({ *this }); + return Shape({ *this }); } - Polygons ret; + Shape ret; ClipperLib::ClipperOffset clipper(miter_limit, 10.0); clipper.AddPath(*this, join_type, ClipperLib::etClosedPolygon); clipper.MiterLimit = miter_limit; diff --git a/src/geometry/polygons.cpp b/src/geometry/shape.cpp similarity index 87% rename from src/geometry/polygons.cpp rename to src/geometry/shape.cpp index 31c4ceb875..a1b7b86b68 100644 --- a/src/geometry/polygons.cpp +++ b/src/geometry/shape.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "geometry/polygons.h" +#include "geometry/shape.h" #include @@ -27,17 +27,17 @@ namespace cura { -Polygons Polygons::approxConvexHull(int extra_outset) const +Shape Shape::approxConvexHull(int extra_outset) const { constexpr int overshoot = MM2INT(100); // 10cm (hard-coded value). - Polygons convex_hull; + Shape convex_hull; // Perform the offset for each polygon one at a time. // This is necessary because the polygons may overlap, in which case the offset could end up in an infinite loop. // See http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperOffset/_Body.htm for (const ClipperLib::Path& path : (*this)) { - Polygons offset_result; + Shape offset_result; ClipperLib::ClipperOffset offsetter(1.2, 10.0); offsetter.AddPath(path, ClipperLib::jtRound, ClipperLib::etClosedPolygon); offsetter.Execute(offset_result.getCallable(), overshoot); @@ -47,7 +47,7 @@ Polygons Polygons::approxConvexHull(int extra_outset) const return convex_hull.unionPolygons().offset(-overshoot + extra_outset, ClipperLib::jtRound); } -void Polygons::makeConvex() +void Shape::makeConvex() { // early out if there is nothing to do if (empty()) @@ -100,9 +100,9 @@ void Polygons::makeConvex() *this = { convexified }; } -Polygons Polygons::difference(const Polygons& other) const +Shape Shape::difference(const Shape& other) const { - Polygons ret; + Shape ret; ClipperLib::Clipper clipper(clipper_init); clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); clipper.AddPaths(other.getCallable(), ClipperLib::ptClip, true); @@ -110,9 +110,9 @@ Polygons Polygons::difference(const Polygons& other) const return ret; } -Polygons Polygons::unionPolygons(const Polygons& other, ClipperLib::PolyFillType fill_type) const +Shape Shape::unionPolygons(const Shape& other, ClipperLib::PolyFillType fill_type) const { - Polygons ret; + Shape ret; ClipperLib::Clipper clipper(clipper_init); clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); clipper.AddPaths(other.getCallable(), ClipperLib::ptSubject, true); @@ -120,9 +120,9 @@ Polygons Polygons::unionPolygons(const Polygons& other, ClipperLib::PolyFillType return ret; } -Polygons Polygons::intersection(const Polygons& other) const +Shape Shape::intersection(const Shape& other) const { - Polygons ret; + Shape ret; ClipperLib::Clipper clipper(clipper_init); clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); clipper.AddPaths(other.getCallable(), ClipperLib::ptClip, true); @@ -130,24 +130,24 @@ Polygons Polygons::intersection(const Polygons& other) const return ret; } -Polygons& Polygons::operator=(const Polygons& other) +Shape& Shape::operator=(const Shape& other) { LinesSet::operator=(other); return *this; } -Polygons& Polygons::operator=(Polygons&& other) +Shape& Shape::operator=(Shape&& other) { LinesSet::operator=(other); return *this; } -void Polygons::add(const Polygons& other) +void Shape::add(const Shape& other) { std::copy(other.begin(), other.end(), std::back_inserter(*this)); } -bool Polygons::inside(Point2LL p, bool border_result) const +bool Shape::inside(Point2LL p, bool border_result) const { int poly_count_inside = 0; for (const ClipperLib::Path& poly : *this) @@ -162,7 +162,7 @@ bool Polygons::inside(Point2LL p, bool border_result) const return (poly_count_inside % 2) == 1; } -size_t Polygons::findInside(Point2LL p, bool border_result) const +size_t Shape::findInside(Point2LL p, bool border_result) const { if (size() < 1) { @@ -227,7 +227,7 @@ size_t Polygons::findInside(Point2LL p, bool border_result) const return ret; } -LinesSet Polygons::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const +LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const { LinesSet split_polylines = polylines.splitIntoSegments(); @@ -242,7 +242,7 @@ LinesSet Polygons::intersectionPolyLines(const LinesSet result_lines; - Polygons result_polygons; + Shape result_polygons; const coord_t snap_distance = 10_mu; OpenPolylineStitcher::stitch(ret, result_lines, result_polygons, max_stitch_distance, snap_distance); ret = std::move(result_lines); @@ -259,9 +259,9 @@ LinesSet Polygons::intersectionPolyLines(const LinesSet& offset_dists) const +Shape Shape::offsetMulti(const std::vector& offset_dists) const { // we need as many offset-dists as points assert(pointCount() == offset_dists.size()); - Polygons ret; + Shape ret; size_t i = 0; for (const ClipperLib::Path& poly_line : (*this) | ranges::views::filter( @@ -337,9 +337,9 @@ Polygons Polygons::offsetMulti(const std::vector& offset_dists) const return ret; } -Polygons Polygons::getOutsidePolygons() const +Shape Shape::getOutsidePolygons() const { - Polygons ret; + Shape ret; ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree poly_tree; constexpr bool paths_are_closed_polys = true; @@ -354,9 +354,9 @@ Polygons Polygons::getOutsidePolygons() const return ret; } -Polygons Polygons::removeEmptyHoles() const +Shape Shape::removeEmptyHoles() const { - Polygons ret; + Shape ret; ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree poly_tree; constexpr bool paths_are_closed_polys = true; @@ -368,9 +368,9 @@ Polygons Polygons::removeEmptyHoles() const return ret; } -Polygons Polygons::getEmptyHoles() const +Shape Shape::getEmptyHoles() const { - Polygons ret; + Shape ret; ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree poly_tree; constexpr bool paths_are_closed_polys = true; @@ -382,7 +382,7 @@ Polygons Polygons::getEmptyHoles() const return ret; } -void Polygons::removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Polygons& ret) const +void Shape::removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Shape& ret) const { for (int outer_poly_idx = 0; outer_poly_idx < node.ChildCount(); outer_poly_idx++) { @@ -403,7 +403,7 @@ void Polygons::removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& } } -void Polygons::removeSmallAreas(const double min_area_size, const bool remove_holes) +void Shape::removeSmallAreas(const double min_area_size, const bool remove_holes) { auto new_end = end(); if (remove_holes) @@ -467,14 +467,14 @@ void Polygons::removeSmallAreas(const double min_area_size, const bool remove_ho resize(new_end - begin()); } -void Polygons::removeSmallCircumference(const coord_t min_circumference_size, const bool remove_holes) +void Shape::removeSmallCircumference(const coord_t min_circumference_size, const bool remove_holes) { removeSmallAreaCircumference(0.0, min_circumference_size, remove_holes); } -void Polygons::removeSmallAreaCircumference(const double min_area_size, const coord_t min_circumference_size, const bool remove_holes) +void Shape::removeSmallAreaCircumference(const double min_area_size, const coord_t min_circumference_size, const bool remove_holes) { - Polygons new_polygon; + Shape new_polygon; bool outline_is_removed = false; for (const Polygon& poly : (*this)) @@ -510,9 +510,9 @@ void Polygons::removeSmallAreaCircumference(const double min_area_size, const co *this = new_polygon; } -Polygons Polygons::removePolygon(const Polygons& to_be_removed, int same_distance) const +Shape Shape::removePolygon(const Shape& to_be_removed, int same_distance) const { - Polygons result; + Shape result; for (size_t poly_keep_idx = 0; poly_keep_idx < size(); poly_keep_idx++) { const Polygon& poly_keep = (*this)[poly_keep_idx]; @@ -562,23 +562,23 @@ Polygons Polygons::removePolygon(const Polygons& to_be_removed, int same_distanc return result; } -Polygons Polygons::processEvenOdd(ClipperLib::PolyFillType poly_fill_type) const +Shape Shape::processEvenOdd(ClipperLib::PolyFillType poly_fill_type) const { - Polygons ret; + Shape ret; ClipperLib::Clipper clipper(clipper_init); clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); clipper.Execute(ClipperLib::ctUnion, ret.getCallable(), poly_fill_type); return ret; } -Polygons Polygons::toPolygons(ClipperLib::PolyTree& poly_tree) +Shape Shape::toPolygons(ClipperLib::PolyTree& poly_tree) { - Polygons ret; + Shape ret; ClipperLib::PolyTreeToPaths(poly_tree, ret.getCallable()); return ret; } -[[maybe_unused]] Polygons Polygons::fromWkt(const std::string& wkt) +[[maybe_unused]] Shape Shape::fromWkt(const std::string& wkt) { typedef boost::geometry::model::d2::point_xy point_type; typedef boost::geometry::model::polygon polygon_type; @@ -586,7 +586,7 @@ Polygons Polygons::toPolygons(ClipperLib::PolyTree& poly_tree) polygon_type poly; boost::geometry::read_wkt(wkt, poly); - Polygons ret; + Shape ret; Polygon outer; for (const auto& point : poly.outer()) @@ -608,7 +608,7 @@ Polygons Polygons::toPolygons(ClipperLib::PolyTree& poly_tree) return ret; } -[[maybe_unused]] void Polygons::writeWkt(std::ostream& stream) const +[[maybe_unused]] void Shape::writeWkt(std::ostream& stream) const { stream << "POLYGON ("; const auto paths_str = (*this) @@ -629,9 +629,9 @@ Polygons Polygons::toPolygons(ClipperLib::PolyTree& poly_tree) stream << ")"; } -Polygons Polygons::smooth_outward(const AngleDegrees max_angle, int shortcut_length) const +Shape Shape::smooth_outward(const AngleDegrees max_angle, int shortcut_length) const { - Polygons ret; + Shape ret; for (const Polygon& poly : (*this)) { if (poly.size() < 3) @@ -652,9 +652,9 @@ Polygons Polygons::smooth_outward(const AngleDegrees max_angle, int shortcut_len return ret; } -Polygons Polygons::smooth(int remove_length) const +Shape Shape::smooth(int remove_length) const { - Polygons ret; + Shape ret; for (const Polygon& poly : (*this)) { if (poly.size() < 3) @@ -676,9 +676,9 @@ Polygons Polygons::smooth(int remove_length) const return ret; } -Polygons Polygons::smooth2(int remove_length, int min_area) const +Shape Shape::smooth2(int remove_length, int min_area) const { - Polygons ret; + Shape ret; for (const Polygon& poly : (*this)) { if (poly.size() == 0) @@ -702,9 +702,9 @@ Polygons Polygons::smooth2(int remove_length, int min_area) const return ret; } -void Polygons::removeColinearEdges(const AngleRadians max_deviation_angle) +void Shape::removeColinearEdges(const AngleRadians max_deviation_angle) { - Polygons& thiss = *this; + Shape& thiss = *this; for (size_t p = 0; p < size(); p++) { thiss[p].removeColinearEdges(max_deviation_angle); @@ -716,7 +716,7 @@ void Polygons::removeColinearEdges(const AngleRadians max_deviation_angle) } } -void Polygons::scale(const Ratio& ratio) +void Shape::scale(const Ratio& ratio) { if (ratio == 1.) { @@ -732,7 +732,7 @@ void Polygons::scale(const Ratio& ratio) } } -void Polygons::translate(const Point2LL& delta) +void Shape::translate(const Point2LL& delta) { if (delta.X != 0 || delta.Y != 0) { @@ -743,7 +743,7 @@ void Polygons::translate(const Point2LL& delta) } } -double Polygons::area() const +double Shape::area() const { return std::accumulate( begin(), @@ -763,7 +763,7 @@ double Polygons::area() const return area; } -std::vector Polygons::splitIntoParts(bool unionAll) const +std::vector Shape::splitIntoParts(bool unionAll) const { std::vector ret; ClipperLib::Clipper clipper(clipper_init); @@ -778,7 +778,7 @@ std::vector Polygons::splitIntoParts(bool unionAll) const return ret; } -void Polygons::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const +void Shape::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const { for (int n = 0; n < node->ChildCount(); n++) { @@ -794,9 +794,9 @@ void Polygons::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, st } } -std::vector Polygons::sortByNesting() const +std::vector Shape::sortByNesting() const { - std::vector ret; + std::vector ret; ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree resultPolyTree; clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); @@ -806,7 +806,7 @@ std::vector Polygons::sortByNesting() const return ret; } -void Polygons::sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const +void Shape::sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const { for (int n = 0; n < node->ChildCount(); n++) { @@ -820,9 +820,9 @@ void Polygons::sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, con } } -PartsView Polygons::splitIntoPartsView(bool unionAll) +PartsView Shape::splitIntoPartsView(bool unionAll) { - Polygons reordered; + Shape reordered; PartsView partsView(*this); ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree resultPolyTree; @@ -838,7 +838,7 @@ PartsView Polygons::splitIntoPartsView(bool unionAll) return partsView; } -void Polygons::splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Polygons& reordered, ClipperLib::PolyNode* node) const +void Shape::splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Shape& reordered, ClipperLib::PolyNode* node) const { for (int n = 0; n < node->ChildCount(); n++) { @@ -856,7 +856,7 @@ void Polygons::splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Poly } } -void Polygons::ensureManifold() +void Shape::ensureManifold() { std::vector duplicate_locations; std::unordered_set poly_locations; @@ -871,7 +871,7 @@ void Polygons::ensureManifold() poly_locations.emplace(p); } } - Polygons removal_dots; + Shape removal_dots; for (const Point2LL& p : duplicate_locations) { Polygon& dot = removal_dots.newLine(); @@ -886,7 +886,7 @@ void Polygons::ensureManifold() } } -Point2LL Polygons::min() const +Point2LL Shape::min() const { Point2LL ret = Point2LL(POINT_MAX, POINT_MAX); @@ -902,7 +902,7 @@ Point2LL Polygons::min() const return ret; } -Point2LL Polygons::max() const +Point2LL Shape::max() const { Point2LL ret = Point2LL(POINT_MIN, POINT_MIN); @@ -918,7 +918,7 @@ Point2LL Polygons::max() const return ret; } -void Polygons::applyMatrix(const PointMatrix& matrix) +void Shape::applyMatrix(const PointMatrix& matrix) { for (Polygon& polygon : *this) { @@ -926,7 +926,7 @@ void Polygons::applyMatrix(const PointMatrix& matrix) } } -void Polygons::applyMatrix(const Point3Matrix& matrix) +void Shape::applyMatrix(const Point3Matrix& matrix) { for (Polygon& polygon : *this) { diff --git a/src/infill.cpp b/src/infill.cpp index b6ba03fecb..ac03b60253 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -53,9 +53,9 @@ static inline int computeScanSegmentIdx(int x, int line_width) namespace cura { -Polygons Infill::generateWallToolPaths( +Shape Infill::generateWallToolPaths( std::vector& toolpaths, - Polygons& outer_contour, + Shape& outer_contour, const size_t wall_line_count, const coord_t line_width, const coord_t infill_overlap, @@ -66,7 +66,7 @@ Polygons Infill::generateWallToolPaths( outer_contour = outer_contour.offset(infill_overlap); scripta::log("infill_outer_contour", outer_contour, section_type, layer_idx, scripta::CellVDI{ "infill_overlap", infill_overlap }); - Polygons inner_contour; + Shape inner_contour; if (wall_line_count > 0) { constexpr coord_t wall_0_inset = 0; // Don't apply any outer wall inset for these. That's just for the outer wall. @@ -83,7 +83,7 @@ Polygons Infill::generateWallToolPaths( void Infill::generate( std::vector& toolpaths, - Polygons& result_polygons, + Shape& result_polygons, LinesSet& result_lines, const Settings& settings, int layer_idx, @@ -91,7 +91,7 @@ void Infill::generate( const std::shared_ptr& cross_fill_provider, const std::shared_ptr& lightning_trees, const SliceMeshStorage* mesh, - const Polygons& prevent_small_exposed_to_air) + const Shape& prevent_small_exposed_to_air) { if (outer_contour_.empty()) { @@ -110,7 +110,7 @@ void Infill::generate( const auto too_small_length = INT2MM(static_cast(infill_line_width_) / 2.0); // Split the infill region in a narrow region and the normal region. - Polygons small_infill = inner_contour_; + Shape small_infill = inner_contour_; inner_contour_ = inner_contour_.offset(-small_area_width_ / 2); inner_contour_.removeSmallAreas(too_small_length * too_small_length, true); inner_contour_ = inner_contour_.offset(small_area_width_ / 2); @@ -179,7 +179,7 @@ void Infill::generate( { zig_zaggify_ = false; } - Polygons generated_result_polygons; + Shape generated_result_polygons; LinesSet generated_result_lines; _generate(toolpaths, generated_result_polygons, generated_result_lines, settings, cross_fill_provider, lightning_trees, mesh); @@ -192,8 +192,8 @@ void Infill::generate( else { //_generate may clear() the generated_result_lines, but this is an output variable that may contain data before we start. - // So make sure we provide it with a Polygons that is safe to clear and only add stuff to result_lines. - Polygons generated_result_polygons; + // So make sure we provide it with a Shape that is safe to clear and only add stuff to result_lines. + Shape generated_result_polygons; LinesSet generated_result_lines; _generate(toolpaths, generated_result_polygons, generated_result_lines, settings, cross_fill_provider, lightning_trees, mesh); @@ -229,7 +229,7 @@ void Infill::generate( PolygonConnector connector(infill_line_width_); connector.add(result_polygons); connector.add(toolpaths); - Polygons connected_polygons; + Shape connected_polygons; std::vector connected_paths; connector.connect(connected_polygons, connected_paths); result_polygons = connected_polygons; @@ -251,7 +251,7 @@ void Infill::generate( void Infill::_generate( std::vector& toolpaths, - Polygons& result_polygons, + Shape& result_polygons, LinesSet& result_lines, const Settings& settings, const std::shared_ptr& cross_fill_provider, @@ -354,7 +354,7 @@ void Infill::_generate( result_lines = simplifier.polyline(result_lines); } -void Infill::multiplyInfill(Polygons& result_polygons, LinesSet& result_lines) +void Infill::multiplyInfill(Shape& result_polygons, LinesSet& result_lines) { if (pattern_ == EFillMethod::CONCENTRIC) { @@ -365,13 +365,13 @@ void Infill::multiplyInfill(Polygons& result_polygons, LinesSet& r coord_t offset = (odd_multiplier) ? infill_line_width_ : infill_line_width_ / 2; // Get the first offset these are mirrored from the original center line - Polygons result; - Polygons first_offset; + Shape result; + Shape first_offset; { - const Polygons first_offset_lines = result_lines.offset(offset); // make lines on both sides of the input lines - const Polygons first_offset_polygons_inward = result_polygons.offset(-offset); // make lines on the inside of the input polygons - const Polygons first_offset_polygons_outward = result_polygons.offset(offset); // make lines on the other side of the input polygons - const Polygons first_offset_polygons = first_offset_polygons_outward.difference(first_offset_polygons_inward); + const Shape first_offset_lines = result_lines.offset(offset); // make lines on both sides of the input lines + const Shape first_offset_polygons_inward = result_polygons.offset(-offset); // make lines on the inside of the input polygons + const Shape first_offset_polygons_outward = result_polygons.offset(offset); // make lines on the other side of the input polygons + const Shape first_offset_polygons = first_offset_polygons_outward.difference(first_offset_polygons_inward); first_offset = first_offset_lines.unionPolygons( first_offset_polygons); // usually we only have either lines or polygons, but this code also handles an infill pattern which generates both if (zig_zaggify_) @@ -385,13 +385,13 @@ void Infill::multiplyInfill(Polygons& result_polygons, LinesSet& r // depended on whether these lines should be connected or not. if (infill_multiplier_ > 3) { - Polygons reference_polygons = first_offset; + Shape reference_polygons = first_offset; const size_t multiplier = infill_multiplier_ / 2; const int extra_offset = mirror_offset_ ? -infill_line_width_ : infill_line_width_; for (size_t infill_line = 1; infill_line < multiplier; ++infill_line) { - Polygons extra_polys = reference_polygons.offset(extra_offset); + Shape extra_polys = reference_polygons.offset(extra_offset); result.add(extra_polys); reference_polygons = std::move(extra_polys); } @@ -416,7 +416,7 @@ void Infill::multiplyInfill(Polygons& result_polygons, LinesSet& r } } -void Infill::generateGyroidInfill(LinesSet& result_lines, Polygons& result_polygons) +void Infill::generateGyroidInfill(LinesSet& result_lines, Shape& result_polygons) { LinesSet line_segments; GyroidInfill::generateTotalGyroidInfill(line_segments, zig_zaggify_, line_distance_, inner_contour_, z_); @@ -437,7 +437,7 @@ void Infill::generateConcentricInfill(std::vector& toolpaths { const coord_t min_area = infill_line_width_ * infill_line_width_; - Polygons current_inset = inner_contour_; + Shape current_inset = inner_contour_; Simplify simplifier(settings); while (true) { @@ -520,7 +520,7 @@ void Infill::generateCubicSubDivInfill(LinesSet& result, const Sli result = outer_contour_.offset(infill_overlap_).intersectionPolyLines(uncropped, restitch); } -void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provider, Polygons& result_polygons, LinesSet& result_lines) +void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provider, Shape& result_polygons, LinesSet& result_lines) { Polygon cross_pattern_polygon = cross_fill_provider.generate(pattern_, z_, infill_line_width_, pocket_size_); @@ -531,7 +531,7 @@ void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provid if (zig_zaggify_) { - Polygons cross_pattern_polygons; + Shape cross_pattern_polygons; cross_pattern_polygons.push_back(cross_pattern_polygon); result_polygons.add(inner_contour_.intersection(cross_pattern_polygons)); } @@ -644,7 +644,7 @@ void Infill::generateLinearBasedInfill( return; } - Polygons outline = inner_contour_; // Make a copy. We'll be rotating this outline to make intersections always horizontal, for better performance. + Shape outline = inner_contour_; // Make a copy. We'll be rotating this outline to make intersections always horizontal, for better performance. outline.applyMatrix(rotation_matrix); coord_t shift = extra_shift + this->shift_; diff --git a/src/infill/GyroidInfill.cpp b/src/infill/GyroidInfill.cpp index e956fee723..fcb87d562a 100644 --- a/src/infill/GyroidInfill.cpp +++ b/src/infill/GyroidInfill.cpp @@ -5,7 +5,7 @@ #include "geometry/open_polyline.h" #include "geometry/polygon.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" #include "utils/AABB.h" #include "utils/linearAlg2D.h" @@ -20,7 +20,7 @@ GyroidInfill::~GyroidInfill() { } -void GyroidInfill::generateTotalGyroidInfill(LinesSet& result_lines, bool zig_zaggify, coord_t line_distance, const Polygons& in_outline, coord_t z) +void GyroidInfill::generateTotalGyroidInfill(LinesSet& result_lines, bool zig_zaggify, coord_t line_distance, const Shape& in_outline, coord_t z) { // generate infill based on the gyroid equation: sin_x * cos_y + sin_y * cos_z + sin_z * cos_x = 0 // kudos to the author of the Slic3r implementation equation code, the equation code here is based on that diff --git a/src/infill/LightningDistanceField.cpp b/src/infill/LightningDistanceField.cpp index 18f67f4128..efc18dfcb8 100644 --- a/src/infill/LightningDistanceField.cpp +++ b/src/infill/LightningDistanceField.cpp @@ -10,7 +10,7 @@ namespace cura constexpr coord_t radius_per_cell_size = 6; // The cell-size should be small compared to the radius, but not so small as to be inefficient. -LightningDistanceField::LightningDistanceField(const coord_t& radius, const Polygons& current_outline, const Polygons& current_overhang) +LightningDistanceField::LightningDistanceField(const coord_t& radius, const Shape& current_outline, const Shape& current_overhang) : cell_size_(radius / radius_per_cell_size) , grid_(cell_size_) , supporting_radius_(radius) diff --git a/src/infill/LightningGenerator.cpp b/src/infill/LightningGenerator.cpp index a5a7749655..574a2625bf 100644 --- a/src/infill/LightningGenerator.cpp +++ b/src/infill/LightningGenerator.cpp @@ -48,19 +48,19 @@ void LightningGenerator::generateInitialInternalOverhangs(const SliceMeshStorage const auto infill_line_width = mesh.settings.get("infill_line_width"); const coord_t infill_wall_offset = -infill_wall_line_count * infill_line_width; - Polygons infill_area_above; + Shape infill_area_above; // Iterate from top to bottom, to subtract the overhang areas above from the overhang areas on the layer below, to get only overhang in the top layer where it is overhanging. for (int layer_nr = mesh.layers.size() - 1; layer_nr >= 0; layer_nr--) { const SliceLayer& current_layer = mesh.layers[layer_nr]; - Polygons infill_area_here; + Shape infill_area_here; for (auto& part : current_layer.parts) { infill_area_here.add(part.getOwnInfillArea().offset(infill_wall_offset)); } // Remove the part of the infill area that is already supported by the walls. - Polygons overhang = infill_area_here.offset(-wall_supporting_radius).difference(infill_area_above); + Shape overhang = infill_area_here.offset(-wall_supporting_radius).difference(infill_area_above); overhang_per_layer[layer_nr] = overhang; infill_area_above = std::move(infill_area_here); @@ -80,8 +80,8 @@ void LightningGenerator::generateTrees(const SliceMeshStorage& mesh) const auto infill_line_width = mesh.settings.get("infill_line_width"); const coord_t infill_wall_offset = -infill_wall_line_count * infill_line_width; - std::vector infill_outlines; - infill_outlines.insert(infill_outlines.end(), mesh.layers.size(), Polygons()); + std::vector infill_outlines; + infill_outlines.insert(infill_outlines.end(), mesh.layers.size(), Shape()); // For-each layer from top to bottom: for (int layer_id = mesh.layers.size() - 1; layer_id >= 0; layer_id--) @@ -100,7 +100,7 @@ void LightningGenerator::generateTrees(const SliceMeshStorage& mesh) for (int layer_id = top_layer_id; layer_id >= 0; layer_id--) { LightningLayer& current_lightning_layer = lightning_layers[layer_id]; - Polygons& current_outlines = infill_outlines[layer_id]; + Shape& current_outlines = infill_outlines[layer_id]; const auto& outlines_locator = *outlines_locator_ptr; // register all trees propagated from the previous layer as to-be-reconnected @@ -115,7 +115,7 @@ void LightningGenerator::generateTrees(const SliceMeshStorage& mesh) { return; } - const Polygons& below_outlines = infill_outlines[layer_id - 1]; + const Shape& below_outlines = infill_outlines[layer_id - 1]; outlines_locator_ptr = PolygonUtils::createLocToLineGrid(below_outlines, locator_cell_size); const auto& below_outlines_locator = *outlines_locator_ptr; diff --git a/src/infill/LightningLayer.cpp b/src/infill/LightningLayer.cpp index c48e4ab902..2383549d38 100644 --- a/src/infill/LightningLayer.cpp +++ b/src/infill/LightningLayer.cpp @@ -45,8 +45,8 @@ void LightningLayer::fillLocator(SparseLightningTreeNodeGrid& tree_node_locator) } void LightningLayer::generateNewTrees( - const Polygons& current_overhang, - const Polygons& current_outlines, + const Shape& current_overhang, + const Shape& current_outlines, const LocToLineGrid& outlines_locator, const coord_t supporting_radius, const coord_t wall_supporting_radius) @@ -80,7 +80,7 @@ void LightningLayer::generateNewTrees( GroundingLocation LightningLayer::getBestGroundingLocation( const Point2LL& unsupported_location, - const Polygons& current_outlines, + const Shape& current_outlines, const LocToLineGrid& outline_locator, const coord_t supporting_radius, const coord_t wall_supporting_radius, @@ -143,7 +143,7 @@ bool LightningLayer::attach(const Point2LL& unsupported_location, const Groundin void LightningLayer::reconnectRoots( std::vector& to_be_reconnected_tree_roots, - const Polygons& current_outlines, + const Shape& current_outlines, const LocToLineGrid& outline_locator, const coord_t supporting_radius, const coord_t wall_supporting_radius) @@ -217,7 +217,7 @@ void LightningLayer::reconnectRoots( } // Returns 'added someting'. -LinesSet LightningLayer::convertToLines(const Polygons& limit_to_outline, const coord_t line_width) const +LinesSet LightningLayer::convertToLines(const Shape& limit_to_outline, const coord_t line_width) const { LinesSet result_lines; if (tree_roots.empty()) diff --git a/src/infill/LightningTreeNode.cpp b/src/infill/LightningTreeNode.cpp index 09ad8a69b1..1d61c082df 100644 --- a/src/infill/LightningTreeNode.cpp +++ b/src/infill/LightningTreeNode.cpp @@ -65,7 +65,7 @@ LightningTreeNodeSPtr LightningTreeNode::addChild(LightningTreeNodeSPtr& new_chi void LightningTreeNode::propagateToNextLayer( std::vector& next_trees, - const Polygons& next_outlines, + const Shape& next_outlines, const LocToLineGrid& outline_locator, const coord_t prune_distance, const coord_t smooth_magnitude, @@ -170,7 +170,7 @@ LightningTreeNodeSPtr LightningTreeNode::closestNode(const Point2LL& loc) return result; } -bool LightningTreeNode::realign(const Polygons& outlines, const LocToLineGrid& outline_locator, std::vector& rerooted_parts) +bool LightningTreeNode::realign(const Shape& outlines, const LocToLineGrid& outline_locator, std::vector& rerooted_parts) { if (outlines.empty()) { diff --git a/src/infill/SubDivCube.cpp b/src/infill/SubDivCube.cpp index 83c43b2d8e..f528d56a21 100644 --- a/src/infill/SubDivCube.cpp +++ b/src/infill/SubDivCube.cpp @@ -6,7 +6,7 @@ #include #include "geometry/polygon.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" #include "settings/types/Angle.h" //For the infill angle. #include "sliceDataStorage.h" #include "utils/math.h" @@ -230,7 +230,7 @@ coord_t SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, const LayerI return 2; *distance2 = 0; } - Polygons collide; + Shape collide; for (const SliceLayerPart& part : mesh.layers[layer_nr].parts) { collide.add(part.infill_area); diff --git a/src/infill/ZigzagConnectorProcessor.cpp b/src/infill/ZigzagConnectorProcessor.cpp index d31527194a..ac97deaa0e 100644 --- a/src/infill/ZigzagConnectorProcessor.cpp +++ b/src/infill/ZigzagConnectorProcessor.cpp @@ -8,7 +8,7 @@ #include "geometry/open_polyline.h" #include "geometry/point_matrix.h" #include "geometry/polygon.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" using namespace cura; diff --git a/src/multiVolumes.cpp b/src/multiVolumes.cpp index 7ff6317869..a43c7612e4 100644 --- a/src/multiVolumes.cpp +++ b/src/multiVolumes.cpp @@ -88,7 +88,7 @@ void generateMultipleVolumesOverlap(std::vector& volumes) aabb.expandXY(overlap); // expand to account for the case where two models and their bounding boxes are adjacent along the X or Y-direction for (LayerIndex layer_nr = 0; layer_nr < volume->layers.size(); layer_nr++) { - Polygons all_other_volumes; + Shape all_other_volumes; for (Slicer* other_volume : volumes) { if (other_volume->mesh->settings_.get("infill_mesh") || other_volume->mesh->settings_.get("anti_overhang_mesh") @@ -118,10 +118,10 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: Slicer& cutting_mesh_volume = *volumes[carving_mesh_idx]; for (LayerIndex layer_nr = 0; layer_nr < cutting_mesh_volume.layers.size(); layer_nr++) { - Polygons& cutting_mesh_polygons = cutting_mesh_volume.layers[layer_nr].polygons; + Shape& cutting_mesh_polygons = cutting_mesh_volume.layers[layer_nr].polygons; LinesSet& cutting_mesh_polylines = cutting_mesh_volume.layers[layer_nr].openPolylines; - Polygons cutting_mesh_area_recomputed; - Polygons* cutting_mesh_area; + Shape cutting_mesh_area_recomputed; + Shape* cutting_mesh_area; coord_t surface_line_width = cutting_mesh.settings_.get("wall_line_width_0"); { // compute cutting_mesh_area if (cutting_mesh.settings_.get("magic_mesh_surface_mode") == ESurfaceMode::BOTH) @@ -149,7 +149,7 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: } } - Polygons new_outlines; + Shape new_outlines; LinesSet new_polylines; for (unsigned int carved_mesh_idx = 0; carved_mesh_idx < volumes.size(); carved_mesh_idx++) { @@ -160,9 +160,9 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: continue; } Slicer& carved_volume = *volumes[carved_mesh_idx]; - Polygons& carved_mesh_layer = carved_volume.layers[layer_nr].polygons; + Shape& carved_mesh_layer = carved_volume.layers[layer_nr].polygons; - Polygons intersection = cutting_mesh_polygons.intersection(carved_mesh_layer); + Shape intersection = cutting_mesh_polygons.intersection(carved_mesh_layer); new_outlines.add(intersection); if (cutting_mesh.settings_.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) // niet te geleuven { diff --git a/src/pathPlanning/Comb.cpp b/src/pathPlanning/Comb.cpp index 7fe25ec014..f5410d4e16 100644 --- a/src/pathPlanning/Comb.cpp +++ b/src/pathPlanning/Comb.cpp @@ -29,7 +29,7 @@ LocToLineGrid& Comb::getOutsideLocToLine(const ExtruderTrain& train) return *outside_loc_to_line_[train.extruder_nr_]; } -Polygons& Comb::getBoundaryOutside(const ExtruderTrain& train) +Shape& Comb::getBoundaryOutside(const ExtruderTrain& train) { if (boundary_outside_[train.extruder_nr_].empty()) { @@ -39,7 +39,7 @@ Polygons& Comb::getBoundaryOutside(const ExtruderTrain& train) return boundary_outside_[train.extruder_nr_]; } -Polygons& Comb::getModelBoundary(const ExtruderTrain& train) +Shape& Comb::getModelBoundary(const ExtruderTrain& train) { if (model_boundary_[train.extruder_nr_].empty()) { @@ -61,8 +61,8 @@ LocToLineGrid& Comb::getModelBoundaryLocToLine(const ExtruderTrain& train) Comb::Comb( const SliceDataStorage& storage, const LayerIndex layer_nr, - const Polygons& comb_boundary_inside_minimum, - const Polygons& comb_boundary_inside_optimal, + const Shape& comb_boundary_inside_minimum, + const Shape& comb_boundary_inside_optimal, coord_t comb_boundary_offset, coord_t travel_avoid_distance, coord_t move_inside_distance) @@ -374,7 +374,7 @@ bool Comb::calc( } // Try to move comb_path_input points inside by the amount of `move_inside_distance` and see if the points are still in boundary_inside_optimal, add result in comb_path_output -void Comb::moveCombPathInside(Polygons& boundary_inside, Polygons& boundary_inside_optimal, CombPath& comb_path_input, CombPath& comb_path_output) +void Comb::moveCombPathInside(Shape& boundary_inside, Shape& boundary_inside_optimal, CombPath& comb_path_input, CombPath& comb_path_output) { const coord_t dist = move_inside_distance_; const coord_t dist2 = dist * dist; @@ -409,7 +409,7 @@ Comb::Crossing::Crossing( const bool dest_is_inside, const unsigned int dest_part_idx, const unsigned int dest_part_boundary_crossing_poly_idx, - const Polygons& boundary_inside, + const Shape& boundary_inside, const LocToLineGrid& inside_loc_to_line) : dest_is_inside_(dest_is_inside) , boundary_inside_(boundary_inside) @@ -424,7 +424,7 @@ Comb::Crossing::Crossing( } } -bool Comb::moveInside(Polygons& boundary_inside, bool is_inside, LocToLineGrid* inside_loc_to_line, Point2LL& dest_point, size_t& inside_poly) +bool Comb::moveInside(Shape& boundary_inside, bool is_inside, LocToLineGrid* inside_loc_to_line, Point2LL& dest_point, size_t& inside_poly) { if (is_inside) { @@ -513,7 +513,7 @@ void Comb::Crossing::findCrossingInOrMid(const PartsView& partsView_inside, cons } } -bool Comb::Crossing::findOutside(const ExtruderTrain& train, const Polygons& outside, const Point2LL close_to, const bool fail_on_unavoidable_obstacles, Comb& comber) +bool Comb::Crossing::findOutside(const ExtruderTrain& train, const Shape& outside, const Point2LL close_to, const bool fail_on_unavoidable_obstacles, Comb& comber) { out_ = in_or_mid_; if (dest_is_inside_ || outside.inside(in_or_mid_, true)) // start in_between @@ -556,7 +556,7 @@ bool Comb::Crossing::findOutside(const ExtruderTrain& train, const Polygons& out std::shared_ptr> Comb::Crossing::findBestCrossing( const ExtruderTrain& train, - const Polygons& outside, + const Shape& outside, const Polygon& from, const Point2LL estimated_start, const Point2LL estimated_end, diff --git a/src/plugins/converters.cpp b/src/plugins/converters.cpp index e249dd7ef0..b6525c102d 100644 --- a/src/plugins/converters.cpp +++ b/src/plugins/converters.cpp @@ -210,7 +210,7 @@ infill_generate_request::value_type infill_generate_response::native_value_type infill_generate_response::operator()(const infill_generate_response::value_type& message) const { VariableWidthLines toolpaths; - Polygons result_polygons; + Shape result_polygons; LinesSet result_lines; for (auto& tool_path : message.tool_paths().tool_paths()) @@ -231,7 +231,7 @@ infill_generate_response::native_value_type infill_generate_response::operator() for (auto& polygon_msg : message.polygons().polygons()) { - Polygons polygon{}; + Shape polygon{}; Polygon outline{}; for (auto& path_msg : polygon_msg.outline().path()) diff --git a/src/raft.cpp b/src/raft.cpp index 4b27f0911f..0266366ec2 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -38,7 +38,7 @@ void Raft::generate(SliceDataStorage& storage) const coord_t max_raft_distance = std::max(std::max(raft_base_margin, raft_interface_margin), raft_surface_margin); if (storage.draft_protection_shield.size() > 0) { - Polygons draft_shield_raft + Shape draft_shield_raft = storage.draft_protection_shield .offset(shield_line_width_layer0) // start half a line width outside shield .difference(storage.draft_protection_shield.offset(-max_raft_distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield @@ -48,8 +48,8 @@ void Raft::generate(SliceDataStorage& storage) } if (storage.oozeShield.size() > 0 && storage.oozeShield[0].size() > 0) { - const Polygons& ooze_shield = storage.oozeShield[0]; - Polygons ooze_shield_raft = ooze_shield + const Shape& ooze_shield = storage.oozeShield[0]; + Shape ooze_shield_raft = ooze_shield .offset(shield_line_width_layer0) // start half a line width outside shield .difference(ooze_shield.offset(-max_raft_distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield storage.raftBaseOutline = storage.raftBaseOutline.unionPolygons(ooze_shield_raft); @@ -57,7 +57,7 @@ void Raft::generate(SliceDataStorage& storage) storage.raftInterfaceOutline = storage.raftInterfaceOutline.unionPolygons(ooze_shield_raft); } - const auto remove_inside_corners = [](Polygons& outline, bool remove_inside_corners, coord_t smoothing, coord_t line_width) + const auto remove_inside_corners = [](Shape& outline, bool remove_inside_corners, coord_t smoothing, coord_t line_width) { if (remove_inside_corners) { diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index 1432e0af35..63570f3b4d 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -19,7 +19,7 @@ #include "ExtruderTrain.h" #include "Slice.h" #include "geometry/polygon.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" #include "settings/EnumSettings.h" #include "settings/FlowTempGraph.h" #include "settings/types/Angle.h" @@ -258,11 +258,11 @@ FlowTempGraph Settings::get(const std::string& key) const } template<> -Polygons Settings::get(const std::string& key) const +Shape Settings::get(const std::string& key) const { std::string value_string = get(key); - Polygons result; + Shape result; if (value_string.empty()) { return result; // Empty at this point. diff --git a/src/skin.cpp b/src/skin.cpp index 587f4cceac..1cf9720964 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -55,9 +55,9 @@ SkinInfillAreaComputation::SkinInfillAreaComputation(const LayerIndex& layer_nr, * * this function may only read/write the skin and infill from the *current* layer. */ -Polygons SkinInfillAreaComputation::getOutlineOnLayer(const SliceLayerPart& part_here, const LayerIndex layer2_nr) +Shape SkinInfillAreaComputation::getOutlineOnLayer(const SliceLayerPart& part_here, const LayerIndex layer2_nr) { - Polygons result; + Shape result; if (layer2_nr >= static_cast(mesh_.layers.size())) { return result; @@ -126,15 +126,15 @@ void SkinInfillAreaComputation::generateSkinAndInfillAreas() void SkinInfillAreaComputation::generateSkinAndInfillAreas(SliceLayerPart& part) { // Make a copy of the outline which we later intersect and union with the resized skins to ensure the resized skin isn't too large or removed completely. - Polygons top_skin; + Shape top_skin; if (top_layer_count_ > 0) { - top_skin = Polygons(part.inner_area); + top_skin = Shape(part.inner_area); } - Polygons bottom_skin; + Shape bottom_skin; if (bottom_layer_count_ > 0 || layer_nr_ < LayerIndex(initial_bottom_layer_count_)) { - bottom_skin = Polygons(part.inner_area); + bottom_skin = Shape(part.inner_area); } calculateBottomSkin(part, bottom_skin); @@ -143,7 +143,7 @@ void SkinInfillAreaComputation::generateSkinAndInfillAreas(SliceLayerPart& part) applySkinExpansion(part.inner_area, top_skin, bottom_skin); // Now combine the resized top skin and bottom skin. - Polygons skin = top_skin.unionPolygons(bottom_skin); + Shape skin = top_skin.unionPolygons(bottom_skin); skin.removeSmallAreas(MIN_AREA_SIZE); // Create infill area irrespective if the infill is to be generated or not(would be used for bridging). @@ -167,7 +167,7 @@ void SkinInfillAreaComputation::generateSkinAndInfillAreas(SliceLayerPart& part) * * this function may only read/write the skin and infill from the *current* layer. */ -void SkinInfillAreaComputation::calculateBottomSkin(const SliceLayerPart& part, Polygons& downskin) +void SkinInfillAreaComputation::calculateBottomSkin(const SliceLayerPart& part, Shape& downskin) { if (bottom_layer_count_ == 0 && initial_bottom_layer_count_ == 0) { @@ -178,7 +178,7 @@ void SkinInfillAreaComputation::calculateBottomSkin(const SliceLayerPart& part, return; // don't subtract anything form the downskin } LayerIndex bottom_check_start_layer_idx{ std::max(LayerIndex{ 0 }, LayerIndex{ layer_nr_ - bottom_layer_count_ }) }; - Polygons not_air = getOutlineOnLayer(part, bottom_check_start_layer_idx); + Shape not_air = getOutlineOnLayer(part, bottom_check_start_layer_idx); if (! no_small_gaps_heuristic_) { for (int downskin_layer_nr = bottom_check_start_layer_idx + 1; downskin_layer_nr < layer_nr_; downskin_layer_nr++) @@ -194,7 +194,7 @@ void SkinInfillAreaComputation::calculateBottomSkin(const SliceLayerPart& part, downskin = downskin.difference(not_air); // skin overlaps with the walls } -void SkinInfillAreaComputation::calculateTopSkin(const SliceLayerPart& part, Polygons& upskin) +void SkinInfillAreaComputation::calculateTopSkin(const SliceLayerPart& part, Shape& upskin) { if (layer_nr_ > LayerIndex(mesh_.layers.size()) - top_layer_count_ || top_layer_count_ <= 0) { @@ -203,7 +203,7 @@ void SkinInfillAreaComputation::calculateTopSkin(const SliceLayerPart& part, Pol return; } - Polygons not_air = getOutlineOnLayer(part, layer_nr_ + top_layer_count_); + Shape not_air = getOutlineOnLayer(part, layer_nr_ + top_layer_count_); if (! no_small_gaps_heuristic_) { for (int upskin_layer_nr = layer_nr_ + 1; upskin_layer_nr < layer_nr_ + top_layer_count_; upskin_layer_nr++) @@ -227,7 +227,7 @@ void SkinInfillAreaComputation::calculateTopSkin(const SliceLayerPart& part, Pol * * this function may only read/write the skin and infill from the *current* layer. */ -void SkinInfillAreaComputation::applySkinExpansion(const Polygons& original_outline, Polygons& upskin, Polygons& downskin) +void SkinInfillAreaComputation::applySkinExpansion(const Shape& original_outline, Shape& upskin, Shape& downskin) { const coord_t min_width = mesh_.settings.get("min_skin_width_for_expansion") / 2; @@ -238,13 +238,13 @@ void SkinInfillAreaComputation::applySkinExpansion(const Polygons& original_outl // The expansion is only applied to that opened shape. if (bottom_skin_expand_distance_ != 0) { - const Polygons expanded = downskin.offset(-min_width).offset(min_width + bottom_skin_expand_distance_); + const Shape expanded = downskin.offset(-min_width).offset(min_width + bottom_skin_expand_distance_); // And then re-joined with the original part that was not offset, to retain parts smaller than min_width. downskin = downskin.unionPolygons(expanded); } if (top_skin_expand_distance_ != 0) { - const Polygons expanded = upskin.offset(-min_width).offset(min_width + top_skin_expand_distance_); + const Shape expanded = upskin.offset(-min_width).offset(min_width + top_skin_expand_distance_); upskin = upskin.unionPolygons(expanded); } } @@ -326,7 +326,7 @@ void SkinInfillAreaComputation::generateRoofingFillAndSkinFill(SliceLayerPart& p const size_t roofing_layer_count = std::min(mesh_.settings.get("roofing_layer_count"), mesh_.settings.get("top_layers")); const coord_t skin_overlap = mesh_.settings.get("skin_overlap_mm"); - Polygons filled_area_above = generateFilledAreaAbove(part, roofing_layer_count); + Shape filled_area_above = generateFilledAreaAbove(part, roofing_layer_count); skin_part.roofing_fill = skin_part.outline.difference(filled_area_above); skin_part.skin_fill = skin_part.outline.intersection(filled_area_above); @@ -344,14 +344,14 @@ void SkinInfillAreaComputation::generateRoofingFillAndSkinFill(SliceLayerPart& p * * this function may only read the skin and infill from the *current* layer. */ -Polygons SkinInfillAreaComputation::generateFilledAreaAbove(SliceLayerPart& part, size_t roofing_layer_count) +Shape SkinInfillAreaComputation::generateFilledAreaAbove(SliceLayerPart& part, size_t roofing_layer_count) { - Polygons filled_area_above = getOutlineOnLayer(part, layer_nr_ + roofing_layer_count); + Shape filled_area_above = getOutlineOnLayer(part, layer_nr_ + roofing_layer_count); if (! no_small_gaps_heuristic_) { for (int layer_nr_above = layer_nr_ + 1; layer_nr_above < layer_nr_ + roofing_layer_count; layer_nr_above++) { - Polygons outlines_above = getOutlineOnLayer(part, layer_nr_above); + Shape outlines_above = getOutlineOnLayer(part, layer_nr_above); filled_area_above = filled_area_above.intersection(outlines_above); } } @@ -363,7 +363,7 @@ Polygons SkinInfillAreaComputation::generateFilledAreaAbove(SliceLayerPart& part // has air below (fixes https://github.com/Ultimaker/Cura/issues/2656) // set air_below to the skin area for the current layer that has air below it - Polygons air_below = getOutlineOnLayer(part, layer_nr_).difference(getOutlineOnLayer(part, layer_nr_ - 1)); + Shape air_below = getOutlineOnLayer(part, layer_nr_).difference(getOutlineOnLayer(part, layer_nr_ - 1)); if (! air_below.empty()) { @@ -380,21 +380,21 @@ Polygons SkinInfillAreaComputation::generateFilledAreaAbove(SliceLayerPart& part * * this function may only read the skin and infill from the *current* layer. */ -Polygons SkinInfillAreaComputation::generateFilledAreaBelow(SliceLayerPart& part, size_t flooring_layer_count) +Shape SkinInfillAreaComputation::generateFilledAreaBelow(SliceLayerPart& part, size_t flooring_layer_count) { if (layer_nr_ < flooring_layer_count) { return {}; } const int lowest_flooring_layer = layer_nr_ - flooring_layer_count; - Polygons filled_area_below = getOutlineOnLayer(part, lowest_flooring_layer); + Shape filled_area_below = getOutlineOnLayer(part, lowest_flooring_layer); if (! no_small_gaps_heuristic_) { const int next_lowest_flooring_layer = lowest_flooring_layer + 1; for (int layer_nr_below = next_lowest_flooring_layer; layer_nr_below < layer_nr_; layer_nr_below++) { - Polygons outlines_below = getOutlineOnLayer(part, layer_nr_below); + Shape outlines_below = getOutlineOnLayer(part, layer_nr_below); filled_area_below = filled_area_below.intersection(outlines_below); } } @@ -413,8 +413,8 @@ void SkinInfillAreaComputation::generateInfillSupport(SliceMeshStorage& mesh) SliceLayer& layer = mesh.layers[layer_idx]; SliceLayer& layer_above = mesh.layers[layer_idx + 1]; - Polygons inside_above; - Polygons infill_above; + Shape inside_above; + Shape infill_above; for (SliceLayerPart& part_above : layer_above.parts) { inside_above.add(part_above.infill_area); @@ -423,17 +423,17 @@ void SkinInfillAreaComputation::generateInfillSupport(SliceMeshStorage& mesh) for (SliceLayerPart& part : layer.parts) { - const Polygons& infill_area = part.infill_area; + const Shape& infill_area = part.infill_area; if (infill_area.empty()) { continue; } - const Polygons unsupported = infill_area.offset(-max_dist_from_lower_layer); - const Polygons basic_overhang = unsupported.difference(inside_above); - const Polygons overhang_extented = basic_overhang.offset(max_dist_from_lower_layer + 50); // +50 for easier joining with support from layer above - const Polygons full_overhang = overhang_extented.difference(inside_above); - const Polygons infill_support = infill_above.unionPolygons(full_overhang); + const Shape unsupported = infill_area.offset(-max_dist_from_lower_layer); + const Shape basic_overhang = unsupported.difference(inside_above); + const Shape overhang_extented = basic_overhang.offset(max_dist_from_lower_layer + 50); // +50 for easier joining with support from layer above + const Shape full_overhang = overhang_extented.difference(inside_above); + const Shape infill_support = infill_above.unionPolygons(full_overhang); part.infill_area_own = infill_support.intersection(part.getOwnInfillArea()); } @@ -472,7 +472,7 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) { assert((part.infill_area_per_combine_per_density.empty() && "infill_area_per_combine_per_density is supposed to be uninitialized")); - const Polygons& infill_area = Infill::generateWallToolPaths( + const Shape& infill_area = Infill::generateWallToolPaths( part.infill_wall_toolpaths, part.getOwnInfillArea(), infill_wall_count, @@ -489,7 +489,7 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) // note: no need to copy part.infill_area, cause it's the empty vector anyway continue; } - Polygons less_dense_infill = infill_area; // one step less dense with each infill_step + Shape less_dense_infill = infill_area; // one step less dense with each infill_step for (size_t infill_step = 0; infill_step < max_infill_steps; infill_step++) { LayerIndex min_layer = layer_idx + infill_step * gradual_infill_step_layer_count + static_cast(layer_skip_count); @@ -503,7 +503,7 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) break; } const SliceLayer& upper_layer = mesh.layers[static_cast(upper_layer_idx)]; - Polygons relevent_upper_polygons; + Shape relevent_upper_polygons; for (const SliceLayerPart& upper_layer_part : upper_layer.parts) { if (! upper_layer_part.boundaryBox.hit(part.boundaryBox)) @@ -520,12 +520,12 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) } // add new infill_area_per_combine for the current density part.infill_area_per_combine_per_density.emplace_back(); - std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); - const Polygons more_dense_infill = infill_area.difference(less_dense_infill); + std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); + const Shape more_dense_infill = infill_area.difference(less_dense_infill); infill_area_per_combine_current_density.push_back(more_dense_infill); } part.infill_area_per_combine_per_density.emplace_back(); - std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); + std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); infill_area_per_combine_current_density.push_back(infill_area); part.infill_area_own = std::nullopt; // clear infill_area_own, it's not needed any more. assert(! part.infill_area_per_combine_per_density.empty() && "infill_area_per_combine_per_density is now initialized"); @@ -581,13 +581,13 @@ void SkinInfillAreaComputation::combineInfillLayers(SliceMeshStorage& mesh) { for (unsigned int density_idx = 0; density_idx < part.infill_area_per_combine_per_density.size(); density_idx++) { // go over each density of gradual infill (these density areas overlap!) - std::vector& infill_area_per_combine = part.infill_area_per_combine_per_density[density_idx]; - Polygons result; + std::vector& infill_area_per_combine = part.infill_area_per_combine_per_density[density_idx]; + Shape result; for (SliceLayerPart& lower_layer_part : lower_layer->parts) { if (part.boundaryBox.hit(lower_layer_part.boundaryBox)) { - Polygons intersection = infill_area_per_combine[combine_count_here - 1].intersection(lower_layer_part.infill_area).offset(-200).offset(200); + Shape intersection = infill_area_per_combine[combine_count_here - 1].intersection(lower_layer_part.infill_area).offset(-200).offset(200); result.add(intersection); // add area to be thickened infill_area_per_combine[combine_count_here - 1] = infill_area_per_combine[combine_count_here - 1].difference(intersection); // remove thickened area from less thick layer here @@ -608,7 +608,7 @@ void SkinInfillAreaComputation::combineInfillLayers(SliceMeshStorage& mesh) lower_density_idx <= max_lower_density_idx && lower_density_idx < lower_layer_part.infill_area_per_combine_per_density.size(); lower_density_idx++) { - std::vector& lower_infill_area_per_combine = lower_layer_part.infill_area_per_combine_per_density[lower_density_idx]; + std::vector& lower_infill_area_per_combine = lower_layer_part.infill_area_per_combine_per_density[lower_density_idx]; lower_infill_area_per_combine[0] = lower_infill_area_per_combine[0].difference(intersection); // remove thickened area from lower (single thickness) layer } @@ -633,10 +633,10 @@ void SkinInfillAreaComputation::generateTopAndBottomMostSkinFill(SliceLayerPart& { for (SkinPart& skin_part : part.skin_parts) { - Polygons filled_area_above = generateFilledAreaAbove(part, 1); + Shape filled_area_above = generateFilledAreaAbove(part, 1); skin_part.top_most_surface_fill = skin_part.outline.difference(filled_area_above); - Polygons filled_area_below = generateFilledAreaBelow(part, 1); + Shape filled_area_below = generateFilledAreaBelow(part, 1); skin_part.bottom_most_surface_fill = skin_part.skin_fill.difference(filled_area_below); } } diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 521ad63c61..fba4619210 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -32,12 +32,12 @@ SupportStorage::~SupportStorage() supportLayers.clear(); } -Polygons& SliceLayerPart::getOwnInfillArea() +Shape& SliceLayerPart::getOwnInfillArea() { - return const_cast(const_cast(this)->getOwnInfillArea()); + return const_cast(const_cast(this)->getOwnInfillArea()); } -const Polygons& SliceLayerPart::getOwnInfillArea() const +const Shape& SliceLayerPart::getOwnInfillArea() const { if (infill_area_own) { @@ -68,14 +68,14 @@ SliceLayer::~SliceLayer() { } -Polygons SliceLayer::getOutlines(bool external_polys_only) const +Shape SliceLayer::getOutlines(bool external_polys_only) const { - Polygons ret; + Shape ret; getOutlines(ret, external_polys_only); return ret; } -void SliceLayer::getOutlines(Polygons& result, bool external_polys_only) const +void SliceLayer::getOutlines(Shape& result, bool external_polys_only) const { for (const SliceLayerPart& part : parts) { @@ -266,7 +266,7 @@ SliceDataStorage::SliceDataStorage() machine_size.include(machine_max); } -Polygons +Shape SliceDataStorage::getLayerOutlines(const LayerIndex layer_nr, const bool include_support, const bool include_prime_tower, const bool external_polys_only, const int extruder_nr) const { @@ -279,7 +279,7 @@ Polygons case Raft::LayerType::RaftInterface: case Raft::LayerType::RaftSurface: { - const Polygons* raftOutline; + const Shape* raftOutline; bool use_current_extruder_for_raft = extruder_nr == -1; switch (layer_type) @@ -298,7 +298,7 @@ Polygons break; default: assert(false && "unreachable due to outer switch statement"); - return Polygons(); + return Shape(); } if (include_support && use_current_extruder_for_raft) @@ -306,7 +306,7 @@ Polygons if (external_polys_only) { std::vector parts = raftOutline->splitIntoParts(); - Polygons result; + Shape result; for (SingleShape& part : parts) { result.push_back(part.outerPolygon()); @@ -320,14 +320,14 @@ Polygons } else { - return Polygons(); + return Shape(); } break; } case Raft::LayerType::Airgap: case Raft::LayerType::Model: { - Polygons total; + Shape total; if (layer_nr >= 0) { for (const std::shared_ptr& mesh : meshes) @@ -370,7 +370,7 @@ Polygons } default: assert(false && "unreachable as switch statement is exhaustive"); - return Polygons(); + return Shape(); } } @@ -564,11 +564,11 @@ bool SliceDataStorage::getExtruderPrimeBlobEnabled(const size_t extruder_nr) con return train.settings_.get("prime_blob_enable"); } -Polygons SliceDataStorage::getMachineBorder(int checking_extruder_nr) const +Shape SliceDataStorage::getMachineBorder(int checking_extruder_nr) const { const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; - Polygons border; + Shape border; border.emplace_back(); Polygon& outline = border.back(); switch (mesh_group_settings.get("machine_shape")) @@ -592,7 +592,7 @@ Polygons SliceDataStorage::getMachineBorder(int checking_extruder_nr) const break; } - Polygons disallowed_areas = mesh_group_settings.get("machine_disallowed_areas"); + Shape disallowed_areas = mesh_group_settings.get("machine_disallowed_areas"); disallowed_areas = disallowed_areas.unionPolygons(); // union overlapping disallowed areas // The disallowed areas are expressed in buildplate-centered coordinates, but the models @@ -629,12 +629,12 @@ Polygons SliceDataStorage::getMachineBorder(int checking_extruder_nr) const } Point2LL translation(extruder_settings.get("machine_nozzle_offset_x"), extruder_settings.get("machine_nozzle_offset_y")); prime_pos -= translation; - Polygons prime_polygons; + Shape prime_polygons; prime_polygons.emplace_back(PolygonUtils::makeCircle(prime_pos, prime_clearance, std::numbers::pi / 32)); disallowed_areas = disallowed_areas.unionPolygons(prime_polygons); } - Polygons disallowed_all_extruders; + Shape disallowed_all_extruders; bool first = true; for (size_t extruder_nr = 0; extruder_nr < extruder_is_used.size(); extruder_nr++) { @@ -644,7 +644,7 @@ Polygons SliceDataStorage::getMachineBorder(int checking_extruder_nr) const } Settings& extruder_settings = Application::getInstance().current_slice_->scene.extruders[extruder_nr].settings_; Point2LL translation(extruder_settings.get("machine_nozzle_offset_x"), extruder_settings.get("machine_nozzle_offset_y")); - Polygons extruder_border = disallowed_areas; + Shape extruder_border = disallowed_areas; extruder_border.translate(translation); if (first) { @@ -658,7 +658,7 @@ Polygons SliceDataStorage::getMachineBorder(int checking_extruder_nr) const } disallowed_all_extruders.processEvenOdd(ClipperLib::pftNonZero); // prevent overlapping disallowed areas from XORing - Polygons border_all_extruders = border; // each extruders border areas must be limited to the global border, which is the union of all extruders borders + Shape border_all_extruders = border; // each extruders border areas must be limited to the global border, which is the union of all extruders borders if (mesh_group_settings.has("nozzle_offsetting_for_disallowed_areas") && mesh_group_settings.get("nozzle_offsetting_for_disallowed_areas")) { for (size_t extruder_nr = 0; extruder_nr < extruder_is_used.size(); extruder_nr++) @@ -678,7 +678,7 @@ Polygons SliceDataStorage::getMachineBorder(int checking_extruder_nr) const } Settings& other_extruder_settings = Application::getInstance().current_slice_->scene.extruders[other_extruder_nr].settings_; Point2LL other_translation(other_extruder_settings.get("machine_nozzle_offset_x"), other_extruder_settings.get("machine_nozzle_offset_y")); - Polygons translated_border = border; + Shape translated_border = border; translated_border.translate(translation - other_translation); border_all_extruders = border_all_extruders.intersection(translated_border); } @@ -690,7 +690,7 @@ Polygons SliceDataStorage::getMachineBorder(int checking_extruder_nr) const } -void SupportLayer::excludeAreasFromSupportInfillAreas(const Polygons& exclude_polygons, const AABB& exclude_polygons_boundary_box) +void SupportLayer::excludeAreasFromSupportInfillAreas(const Shape& exclude_polygons, const AABB& exclude_polygons_boundary_box) { // record the indexes that need to be removed and do that after std::list to_remove_part_indices; // LIFO for removing @@ -706,7 +706,7 @@ void SupportLayer::excludeAreasFromSupportInfillAreas(const Polygons& exclude_po continue; } - Polygons result_polygons = support_infill_part.outline_.difference(exclude_polygons); + Shape result_polygons = support_infill_part.outline_.difference(exclude_polygons); // if no smaller parts get generated, this mean this part should be removed. if (result_polygons.empty()) @@ -751,16 +751,16 @@ void SupportLayer::excludeAreasFromSupportInfillAreas(const Polygons& exclude_po void SupportLayer::fillInfillParts( const LayerIndex layer_nr, - const std::vector& support_fill_per_layer, + const std::vector& support_fill_per_layer, const coord_t support_line_width, const coord_t wall_line_count, const coord_t grow_layer_above /*has default 0*/, const bool unionAll /*has default false*/, const coord_t custom_line_distance /*has default 0*/) { - const Polygons& support_this_layer = support_fill_per_layer[layer_nr]; - const Polygons& support_layer_above - = (layer_nr + 1) >= support_fill_per_layer.size() || layer_nr <= 0 ? Polygons() : support_fill_per_layer[layer_nr + 1].offset(grow_layer_above); + const Shape& support_this_layer = support_fill_per_layer[layer_nr]; + const Shape& support_layer_above + = (layer_nr + 1) >= support_fill_per_layer.size() || layer_nr <= 0 ? Shape() : support_fill_per_layer[layer_nr + 1].offset(grow_layer_above); const auto all_support_areas_in_layer = { support_this_layer.difference(support_layer_above), support_this_layer.intersection(support_layer_above) }; bool use_fractional_config = true; for (auto& support_areas : all_support_areas_in_layer) diff --git a/src/slicer.cpp b/src/slicer.cpp index 751ea6ea3c..f5ef5c3882 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -1073,8 +1073,8 @@ void Slicer::makePolygons(Mesh& mesh, SlicingTolerance slicing_tolerance, std::v for (const auto& part : parts) { - Polygons holes; - Polygons outline; + Shape holes; + Shape outline; for (const Polygon& poly : part) { const auto area = poly.area(); diff --git a/src/support.cpp b/src/support.cpp index f617a32d25..af3b41cc01 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -77,7 +77,7 @@ bool AreaSupport::handleSupportModifierMesh(SliceDataStorage& storage, const Set void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( SliceDataStorage& storage, - const std::vector& global_support_areas_per_layer, + const std::vector& global_support_areas_per_layer, unsigned int total_layer_count) { if (total_layer_count == 0) @@ -105,7 +105,7 @@ void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( wall_line_count_this_layer++; } - const Polygons& global_support_areas = global_support_areas_per_layer[layer_nr]; + const Shape& global_support_areas = global_support_areas_per_layer[layer_nr]; if (global_support_areas.size() == 0 || layer_nr < min_layer || layer_nr > max_layer) { // Initialize support_infill_parts empty @@ -213,13 +213,13 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) { SupportInfillPart& support_infill_part = support_infill_parts[part_idx]; - Polygons original_area = support_infill_part.getInfillArea(); + Shape original_area = support_infill_part.getInfillArea(); if (original_area.empty()) { continue; } // NOTE: This both generates the walls _and_ returns the _actual_ infill area (the one _without_ walls) for use in the rest of the method. - const Polygons infill_area = Infill::generateWallToolPaths( + const Shape infill_area = Infill::generateWallToolPaths( support_infill_part.wall_toolpaths_, original_area, support_infill_part.inset_count_to_generate_, @@ -231,7 +231,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) const AABB& this_part_boundary_box = support_infill_part.outline_boundary_box_; // calculate density areas for this island - Polygons less_dense_support = infill_area; // one step less dense with each density_step + Shape less_dense_support = infill_area; // one step less dense with each density_step for (unsigned int density_step = 0; density_step < max_density_steps; ++density_step) { LayerIndex actual_min_layer{ layer_nr + density_step * gradual_support_step_layer_count + static_cast(layer_skip_count) }; @@ -247,7 +247,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) // compute intersections with relevant upper parts const std::vector upper_infill_parts = storage.support.supportLayers[upper_layer_idx].support_infill_parts; - Polygons relevant_upper_polygons; + Shape relevant_upper_polygons; for (unsigned int upper_part_idx = 0; upper_part_idx < upper_infill_parts.size(); ++upper_part_idx) { if (support_infill_part.outline_.empty()) @@ -288,13 +288,13 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) // add new infill_area_per_combine_per_density for the current density support_infill_part.infill_area_per_combine_per_density_.emplace_back(); - std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); - const Polygons more_dense_support = infill_area.difference(less_dense_support); + std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); + const Shape more_dense_support = infill_area.difference(less_dense_support); support_area_current_density.push_back(more_dense_support); } support_infill_part.infill_area_per_combine_per_density_.emplace_back(); - std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); + std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); support_area_current_density.push_back(infill_area); assert(support_infill_part.infill_area_per_combine_per_density_.size() != 0 && "support_infill_part.infill_area_per_combine_per_density should now be initialized"); @@ -363,8 +363,8 @@ void AreaSupport::combineSupportInfillLayers(SliceDataStorage& storage) } for (unsigned int density_idx = 0; density_idx < part.infill_area_per_combine_per_density_.size(); ++density_idx) { // go over each density of gradual infill (these density areas overlap!) - std::vector& infill_area_per_combine = part.infill_area_per_combine_per_density_[density_idx]; - Polygons result; + std::vector& infill_area_per_combine = part.infill_area_per_combine_per_density_[density_idx]; + Shape result; for (SupportInfillPart& lower_layer_part : lower_layer.support_infill_parts) { if (! part.outline_boundary_box_.hit(lower_layer_part.outline_boundary_box_)) @@ -372,7 +372,7 @@ void AreaSupport::combineSupportInfillLayers(SliceDataStorage& storage) continue; } - Polygons intersection = infill_area_per_combine[combine_count_here - 1].intersection(lower_layer_part.getInfillArea()).offset(-200).offset(200); + Shape intersection = infill_area_per_combine[combine_count_here - 1].intersection(lower_layer_part.getInfillArea()).offset(-200).offset(200); if (intersection.size() <= 0) { continue; @@ -399,7 +399,7 @@ void AreaSupport::combineSupportInfillLayers(SliceDataStorage& storage) lower_density_idx <= max_lower_density_idx && lower_density_idx < lower_layer_part.infill_area_per_combine_per_density_.size(); lower_density_idx++) { - std::vector& lower_infill_area_per_combine = lower_layer_part.infill_area_per_combine_per_density_[lower_density_idx]; + std::vector& lower_infill_area_per_combine = lower_layer_part.infill_area_per_combine_per_density_[lower_density_idx]; lower_infill_area_per_combine[0] = lower_infill_area_per_combine[0].difference(intersection); // remove thickened area from lower (single thickness) layer } @@ -428,9 +428,9 @@ void AreaSupport::cleanup(SliceDataStorage& storage) } else { - for (const std::vector& infill_area_per_combine_this_density : part.infill_area_per_combine_per_density_) + for (const std::vector& infill_area_per_combine_this_density : part.infill_area_per_combine_per_density_) { - for (const Polygons& infill_area_this_combine_this_density : infill_area_per_combine_this_density) + for (const Shape& infill_area_this_combine_this_density : infill_area_per_combine_this_density) { // remove small areas which were introduced by rounding errors in comparing the same area on two consecutive layer if (! infill_area_this_combine_this_density.empty() && infill_area_this_combine_this_density.area() > support_line_width * support_line_width) @@ -455,9 +455,9 @@ void AreaSupport::cleanup(SliceDataStorage& storage) } } -Polygons AreaSupport::join(const SliceDataStorage& storage, const Polygons& supportLayer_up, Polygons& supportLayer_this) +Shape AreaSupport::join(const SliceDataStorage& storage, const Shape& supportLayer_up, Shape& supportLayer_this) { - Polygons joined; + Shape joined; const Settings& infill_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings.get("support_infill_extruder_nr").settings_; const AngleRadians conical_support_angle = infill_settings.get("support_conical_angle"); @@ -476,7 +476,7 @@ Polygons AreaSupport::join(const SliceDataStorage& storage, const Polygons& supp { const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; // Don't go outside the build volume. - Polygons machine_volume_border; + Shape machine_volume_border; switch (mesh_group_settings.get("machine_shape")) { case BuildPlateShape::ELLIPTIC: @@ -554,8 +554,8 @@ Polygons AreaSupport::join(const SliceDataStorage& storage, const Polygons& supp machine_volume_border = machine_volume_border.offset(-adhesion_size); const coord_t conical_smallest_breadth = infill_settings.get("support_conical_min_width"); - Polygons insetted = supportLayer_up.offset(-conical_smallest_breadth / 2); - Polygons small_parts = supportLayer_up.difference(insetted.offset(conical_smallest_breadth / 2 + 20)); + Shape insetted = supportLayer_up.offset(-conical_smallest_breadth / 2); + Shape small_parts = supportLayer_up.difference(insetted.offset(conical_smallest_breadth / 2 + 20)); joined = supportLayer_this.unionPolygons(supportLayer_up.offset(conical_support_offset)).unionPolygons(small_parts).intersection(machine_volume_border); } else @@ -601,7 +601,7 @@ void AreaSupport::generateOverhangAreas(SliceDataStorage& storage) void AreaSupport::generateSupportAreas(SliceDataStorage& storage) { - std::vector global_support_areas_per_layer; + std::vector global_support_areas_per_layer; global_support_areas_per_layer.resize(storage.print_layer_count); int max_layer_nr_support_mesh_filled; @@ -664,8 +664,8 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage) support_meshes_handled = true; } } - std::vector mesh_support_areas_per_layer; - mesh_support_areas_per_layer.resize(storage.print_layer_count, Polygons()); + std::vector mesh_support_areas_per_layer; + mesh_support_areas_per_layer.resize(storage.print_layer_count, Shape()); generateSupportAreasForMesh(storage, *infill_settings, *roof_settings, *bottom_settings, mesh_idx, storage.print_layer_count, mesh_support_areas_per_layer); for (size_t layer_idx = 0; layer_idx < storage.print_layer_count; layer_idx++) @@ -674,7 +674,7 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage) } } - for (Polygons& support_areas : global_support_areas_per_layer) + for (Shape& support_areas : global_support_areas_per_layer) { support_areas = support_areas.unionPolygons(); } @@ -800,7 +800,7 @@ void AreaSupport::generateOverhangAreasForMesh(SliceDataStorage& storage, SliceM storage.print_layer_count, [&](const size_t layer_idx) { - std::pair basic_and_full_overhang = computeBasicAndFullOverhang(storage, mesh, layer_idx); + std::pair basic_and_full_overhang = computeBasicAndFullOverhang(storage, mesh, layer_idx); mesh.overhang_areas[layer_idx] = basic_and_full_overhang.first; // Store the results. mesh.full_overhang_areas[layer_idx] = basic_and_full_overhang.second; scripta::log("support_basic_overhang_area", basic_and_full_overhang.first, SectionType::SUPPORT, layer_idx); @@ -808,7 +808,7 @@ void AreaSupport::generateOverhangAreasForMesh(SliceDataStorage& storage, SliceM }); } -Polygons AreaSupport::generateVaryingXYDisallowedArea(const SliceMeshStorage& storage, const LayerIndex layer_idx) +Shape AreaSupport::generateVaryingXYDisallowedArea(const SliceMeshStorage& storage, const LayerIndex layer_idx) { const auto& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; const Simplify simplify{ mesh_group_settings }; @@ -820,7 +820,7 @@ Polygons AreaSupport::generateVaryingXYDisallowedArea(const SliceMeshStorage& st constexpr auto close_dist = 20; - Polygons layer_current = simplify.polygon(storage.layers[layer_idx].getOutlines().offset(-close_dist).offset(close_dist)); + Shape layer_current = simplify.polygon(storage.layers[layer_idx].getOutlines().offset(-close_dist).offset(close_dist)); using point_pair_t = std::pair; using poly_point_key = std::tuple; @@ -833,7 +833,7 @@ Polygons AreaSupport::generateVaryingXYDisallowedArea(const SliceMeshStorage& st { double support_distance; double delta_z; - Polygons layer_delta; + Shape layer_delta; }; std::vector z_distances_layer_deltas; @@ -949,7 +949,7 @@ Polygons AreaSupport::generateVaryingXYDisallowedArea(const SliceMeshStorage& st } const auto smooth_dist = xy_distance / 2.0; - Polygons varying_xy_disallowed_areas = layer_current + Shape varying_xy_disallowed_areas = layer_current // offset using the varying offset distances we calculated previously .offsetMulti(varying_offsets) // close operation to smooth the x/y disallowed area boundary. With varying xy distances we see some jumps in the boundary. @@ -980,7 +980,7 @@ void AreaSupport::generateSupportAreasForMesh( const Settings& bottom_settings, const size_t mesh_idx, const size_t layer_count, - std::vector& support_areas) + std::vector& support_areas) { SliceMeshStorage& mesh = *storage.meshes[mesh_idx]; @@ -1008,11 +1008,11 @@ void AreaSupport::generateSupportAreasForMesh( } // Compute the areas that are disallowed by the X/Y distance. - std::vector xy_disallowed_per_layer; + std::vector xy_disallowed_per_layer; xy_disallowed_per_layer.resize(layer_count); - std::vector sloped_areas_per_layer; + std::vector sloped_areas_per_layer; sloped_areas_per_layer.resize(layer_count); - sloped_areas_per_layer[0] = Polygons(); + sloped_areas_per_layer[0] = Shape(); // simplified processing for bottom layer - just ensure support clears part by XY distance const coord_t xy_distance = infill_settings.get("support_xy_distance"); const coord_t xy_distance_overhang = infill_settings.get("support_xy_distance_overhang"); @@ -1035,7 +1035,7 @@ void AreaSupport::generateSupportAreasForMesh( layer_count, [&](const size_t layer_idx) { - const Polygons outlines = storage.getLayerOutlines(layer_idx, no_support, no_prime_tower); + const Shape outlines = storage.getLayerOutlines(layer_idx, no_support, no_prime_tower); // Build sloped areas. We need this for the stair-stepping later on. // Specifically, sloped areass are used in 'moveUpFromModel' to prevent a stair step happening over an area where there isn't a slope. @@ -1066,8 +1066,8 @@ void AreaSupport::generateSupportAreasForMesh( // we also want to use the min XY distance when the support is resting on a sloped surface so we calculate the area of the // layer below that protrudes beyond the current layer's area and combine it with the current layer's overhang disallowed area - Polygons minimum_xy_disallowed_areas = mesh.layers[layer_idx].getOutlines().offset(xy_distance_overhang); - Polygons varying_xy_disallowed_areas = generateVaryingXYDisallowedArea(mesh, layer_idx); + Shape minimum_xy_disallowed_areas = mesh.layers[layer_idx].getOutlines().offset(xy_distance_overhang); + Shape varying_xy_disallowed_areas = generateVaryingXYDisallowedArea(mesh, layer_idx); xy_disallowed_per_layer[layer_idx] = minimum_xy_disallowed_areas.unionPolygons(varying_xy_disallowed_areas); scripta::log("support_xy_disallowed_areas", xy_disallowed_per_layer[layer_idx], SectionType::SUPPORT, layer_idx); } @@ -1078,8 +1078,8 @@ void AreaSupport::generateSupportAreasForMesh( } }); - std::vector tower_roofs; - Polygons stair_removal; // polygons to subtract from support because of stair-stepping + std::vector tower_roofs; + Shape stair_removal; // polygons to subtract from support because of stair-stepping const bool is_support_mesh_nondrop_place_holder = is_support_mesh_place_holder && ! mesh.settings.get("support_mesh_drop_down"); const bool is_support_mesh_drop_down_place_holder = is_support_mesh_place_holder && mesh.settings.get("support_mesh_drop_down"); @@ -1122,7 +1122,7 @@ void AreaSupport::generateSupportAreasForMesh( for (size_t layer_idx = layer_count - 1 - layer_z_distance_top; layer_idx != static_cast(-1); layer_idx--) { - Polygons layer_this = mesh.full_overhang_areas[layer_idx + layer_z_distance_top]; + Shape layer_this = mesh.full_overhang_areas[layer_idx + layer_z_distance_top]; if (extension_offset && ! is_support_mesh_place_holder) { @@ -1131,11 +1131,11 @@ void AreaSupport::generateSupportAreasForMesh( // model outline and the support is effectively calculating a voronoi. The offset is first applied to // the support and next to the model to ensure that the expanded support area is connected to the original // support area. Please note that the horizontal expansion is rounded down to an integer offset_per_step. - Polygons model_outline = storage.getLayerOutlines(layer_idx, no_support, no_prime_tower); + Shape model_outline = storage.getLayerOutlines(layer_idx, no_support, no_prime_tower); const coord_t offset_per_step = support_line_width / 2; // perform a small offset we don't enlarge small features of the support - Polygons horizontal_expansion = layer_this; + Shape horizontal_expansion = layer_this; for (coord_t offset_cumulative = 0; offset_cumulative <= extension_offset; offset_cumulative += offset_per_step) { horizontal_expansion = horizontal_expansion.offset(offset_per_step); @@ -1156,9 +1156,9 @@ void AreaSupport::generateSupportAreasForMesh( if (layer_idx + 1 < layer_count) { // join with support from layer up - const Polygons empty; - const Polygons* layer_above = (layer_idx < support_areas.size()) ? &support_areas[layer_idx + 1] : ∅ - const Polygons model_mesh_on_layer + const Shape empty; + const Shape* layer_above = (layer_idx < support_areas.size()) ? &support_areas[layer_idx + 1] : ∅ + const Shape model_mesh_on_layer = (layer_idx > 0) && ! is_support_mesh_nondrop_place_holder ? storage.getLayerOutlines(layer_idx, no_support, no_prime_tower) : empty; if (is_support_mesh_nondrop_place_holder) { @@ -1184,7 +1184,7 @@ void AreaSupport::generateSupportAreasForMesh( constexpr size_t tower_top_layer_count = 6; // number of layers after which to conclude that a tiny support area needs a tower if (layer_idx < layer_count - tower_top_layer_count && layer_idx >= tower_top_layer_count + bottom_empty_layer_count) { - Polygons tiny_tower_here; + Shape tiny_tower_here; tiny_tower_here.add(polygon_part); tower_roofs.emplace_back(tiny_tower_here); } @@ -1234,7 +1234,7 @@ void AreaSupport::generateSupportAreasForMesh( // do stuff for when support on buildplate only if (support_type == ESupportType::PLATFORM_ONLY) { - Polygons touching_buildplate = support_areas[0]; // TODO: not working for conical support! + Shape touching_buildplate = support_areas[0]; // TODO: not working for conical support! const AngleRadians conical_support_angle = infill_settings.get("support_conical_angle"); coord_t conical_support_offset; if (conical_support_angle > 0) @@ -1248,7 +1248,7 @@ void AreaSupport::generateSupportAreasForMesh( const bool conical_support = infill_settings.get("support_conical_enabled") && conical_support_angle != 0; for (LayerIndex layer_idx = 1; layer_idx < storage.support.supportLayers.size(); layer_idx++) { - const Polygons& layer = support_areas[layer_idx]; + const Shape& layer = support_areas[layer_idx]; if (conical_support) { // with conical support the next layer is allowed to be larger than the previous @@ -1299,13 +1299,13 @@ void AreaSupport::generateSupportAreasForMesh( // Procedure to remove floating support for (size_t layer_idx = 1; layer_idx < layer_count - 1; layer_idx++) { - Polygons& layer_this = support_areas[layer_idx]; + Shape& layer_this = support_areas[layer_idx]; if (! layer_this.empty()) { - Polygons& layer_below = support_areas[layer_idx - 1]; - Polygons& layer_above = support_areas[layer_idx + 1]; - Polygons surrounding_layer = layer_above.unionPolygons(layer_below); + Shape& layer_below = support_areas[layer_idx - 1]; + Shape& layer_above = support_areas[layer_idx + 1]; + Shape surrounding_layer = layer_above.unionPolygons(layer_below); layer_this = layer_this.intersection(surrounding_layer); } } @@ -1324,9 +1324,9 @@ void AreaSupport::generateSupportAreasForMesh( void AreaSupport::moveUpFromModel( const SliceDataStorage& storage, - Polygons& stair_removal, - Polygons& sloped_areas, - Polygons& support_areas, + Shape& stair_removal, + Shape& sloped_areas, + Shape& support_areas, const size_t layer_idx, const size_t bottom_empty_layer_count, const size_t bottom_stair_step_layer_count, @@ -1389,9 +1389,9 @@ void AreaSupport::moveUpFromModel( const size_t bottom_layer_nr = layer_idx - bottom_empty_layer_count; constexpr bool no_support = false; constexpr bool no_prime_tower = false; - const Polygons bottom_outline = storage.getLayerOutlines(bottom_layer_nr, no_support, no_prime_tower); + const Shape bottom_outline = storage.getLayerOutlines(bottom_layer_nr, no_support, no_prime_tower); - Polygons to_be_removed; + Shape to_be_removed; if (bottom_stair_step_layer_count <= 1) { to_be_removed = bottom_outline; @@ -1401,13 +1401,13 @@ void AreaSupport::moveUpFromModel( to_be_removed = stair_removal.unionPolygons(bottom_outline); if (layer_idx % bottom_stair_step_layer_count == 0) { // update stairs for next step - const Polygons supporting_bottom = storage.getLayerOutlines(bottom_layer_nr - 1, no_support, no_prime_tower); - const Polygons allowed_step_width = supporting_bottom.offset(support_bottom_stair_step_width).intersection(sloped_areas); + const Shape supporting_bottom = storage.getLayerOutlines(bottom_layer_nr - 1, no_support, no_prime_tower); + const Shape allowed_step_width = supporting_bottom.offset(support_bottom_stair_step_width).intersection(sloped_areas); const int64_t step_bottom_layer_nr = bottom_layer_nr - bottom_stair_step_layer_count + 1; if (step_bottom_layer_nr >= 0) { - const Polygons step_bottom_outline = storage.getLayerOutlines(step_bottom_layer_nr, no_support, no_prime_tower); + const Shape step_bottom_outline = storage.getLayerOutlines(step_bottom_layer_nr, no_support, no_prime_tower); stair_removal = step_bottom_outline.intersection(allowed_step_width); } else @@ -1431,9 +1431,9 @@ void AreaSupport::moveUpFromModel( * ^^^^^^^^^ overhang extensions * ^^^^^^^^^^^^^^ overhang */ -std::pair AreaSupport::computeBasicAndFullOverhang(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const LayerIndex& layer_idx) +std::pair AreaSupport::computeBasicAndFullOverhang(const SliceDataStorage& storage, const SliceMeshStorage& mesh, const LayerIndex& layer_idx) { - const Polygons outlines = mesh.layers[layer_idx].getOutlines(); + const Shape outlines = mesh.layers[layer_idx].getOutlines(); constexpr bool no_support = false; constexpr bool no_prime_tower = false; @@ -1449,29 +1449,29 @@ std::pair AreaSupport::computeBasicAndFullOverhang(const Sli // To avoids generating support for textures on vertical surfaces, a moving average // is taken over smooth_height. The smooth_height is currently an educated guess // that we might want to expose to the frontend in the future. - Polygons outlines_below = storage.getLayerOutlines(layer_idx - 1, no_support, no_prime_tower).offset(max_dist_from_lower_layer); + Shape outlines_below = storage.getLayerOutlines(layer_idx - 1, no_support, no_prime_tower).offset(max_dist_from_lower_layer); for (int layer_idx_offset = 2; layer_idx - layer_idx_offset >= 0 && layer_idx_offset <= layers_below; layer_idx_offset++) { auto outlines_below_ = storage.getLayerOutlines(layer_idx - layer_idx_offset, no_support, no_prime_tower).offset(max_dist_from_lower_layer * layer_idx_offset); outlines_below = outlines_below.unionPolygons(outlines_below_); } - Polygons basic_overhang = outlines.difference(outlines_below); + Shape basic_overhang = outlines.difference(outlines_below); const SupportLayer& support_layer = storage.support.supportLayers[layer_idx]; if (! support_layer.anti_overhang.empty()) { // Merge anti overhang into one polygon, otherwise overlapping polygons // will create opposite effect. - Polygons merged_polygons = support_layer.anti_overhang.unionPolygons(); + Shape merged_polygons = support_layer.anti_overhang.unionPolygons(); basic_overhang = basic_overhang.difference(merged_polygons); } - Polygons overhang_extended = basic_overhang + Shape overhang_extended = basic_overhang // +0.1mm for easier joining with support from layer above .offset(max_dist_from_lower_layer * layers_below + MM2INT(0.1)); - Polygons full_overhang = overhang_extended.intersection(outlines); + Shape full_overhang = overhang_extended.intersection(outlines); return std::make_pair(basic_overhang, full_overhang); } @@ -1503,7 +1503,7 @@ void AreaSupport::detectOverhangPoints(const SliceDataStorage& storage, SliceMes continue; } - const Polygons overhang = part.outline.difference(storage.support.supportLayers[layer_idx].anti_overhang); + const Shape overhang = part.outline.difference(storage.support.supportLayers[layer_idx].anti_overhang); if (! overhang.empty()) { scripta::log("support_overhangs", overhang, SectionType::SUPPORT, layer_idx); @@ -1515,10 +1515,10 @@ void AreaSupport::detectOverhangPoints(const SliceDataStorage& storage, SliceMes void AreaSupport::handleTowers( const Settings& settings, - const Polygons& xy_disallowed_area, - Polygons& supportLayer_this, - std::vector& tower_roofs, - std::vector>& overhang_points, + const Shape& xy_disallowed_area, + Shape& supportLayer_this, + std::vector& tower_roofs, + std::vector>& overhang_points, LayerIndex layer_idx, size_t layer_count) { @@ -1527,7 +1527,7 @@ void AreaSupport::handleTowers( { return; } - std::vector& overhang_points_here = overhang_points[layer_overhang_point]; // may be changed if an overhang point has a (smaller) overhang point directly below + std::vector& overhang_points_here = overhang_points[layer_overhang_point]; // may be changed if an overhang point has a (smaller) overhang point directly below // handle new tower rooftops if (overhang_points_here.size() > 0) { @@ -1535,16 +1535,16 @@ void AreaSupport::handleTowers( if (layer_overhang_point < static_cast(layer_count) && ! overhang_points[layer_overhang_point - 1].empty()) { const auto max_tower_supported_diameter = settings.get("support_tower_maximum_supported_diameter"); - std::vector& overhang_points_below = overhang_points[layer_overhang_point - 1]; - for (Polygons& poly_here : overhang_points_here) + std::vector& overhang_points_below = overhang_points[layer_overhang_point - 1]; + for (Shape& poly_here : overhang_points_here) { - for (const Polygons& poly_below : overhang_points_below) + for (const Shape& poly_below : overhang_points_below) { poly_here = poly_here.difference(poly_below.offset(max_tower_supported_diameter * 2)); } } } - for (Polygons& poly : overhang_points_here) + for (Shape& poly : overhang_points_here) { if (poly.size() > 0) { @@ -1571,7 +1571,7 @@ void AreaSupport::handleTowers( tower_roof_expansion_distance = layer_thickness / tan_tower_roof_angle; } - for (Polygons& tower_roof : tower_roofs + for (Shape& tower_roof : tower_roofs | ranges::views::filter( [](const auto& poly) { @@ -1582,7 +1582,7 @@ void AreaSupport::handleTowers( if (tower_roof.area() < tower_diameter * tower_diameter) { - Polygons model_outline = xy_disallowed_area; + Shape model_outline = xy_disallowed_area; // Rather than offsetting the tower with tower_roof_expansion_distance we do this step wise to achieve two things // - prevent support from folding around the model @@ -1618,7 +1618,7 @@ void AreaSupport::handleTowers( } } -void AreaSupport::handleWallStruts(const Settings& settings, Polygons& supportLayer_this) +void AreaSupport::handleWallStruts(const Settings& settings, Shape& supportLayer_this) { const coord_t max_tower_supported_diameter = settings.get("support_tower_maximum_supported_diameter"); const coord_t tower_diameter = settings.get("support_tower_diameter"); @@ -1651,7 +1651,7 @@ void AreaSupport::handleWallStruts(const Settings& settings, Polygons& supportLa if (width < max_tower_supported_diameter) { Point2LL mid = (poly[best] + poly[(best + 1) % poly.size()]) / 2; - Polygons struts; + Shape struts; Polygon& strut = struts.newLine(); strut.push_back(mid + Point2LL(tower_diameter / 2, tower_diameter / 2)); strut.push_back(mid + Point2LL(-tower_diameter / 2, tower_diameter / 2)); @@ -1663,7 +1663,7 @@ void AreaSupport::handleWallStruts(const Settings& settings, Polygons& supportLa } } -void AreaSupport::generateSupportBottom(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector& global_support_areas_per_layer) +void AreaSupport::generateSupportBottom(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector& global_support_areas_per_layer) { const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; const coord_t layer_height = mesh_group_settings.get("layer_height"); @@ -1686,19 +1686,19 @@ void AreaSupport::generateSupportBottom(SliceDataStorage& storage, const SliceMe for (LayerIndex layer_idx = support_layers.size() - 1; layer_idx >= static_cast(z_distance_bottom); --layer_idx) { const unsigned int bottom_layer_idx_below = std::max(0, int(layer_idx) - int(bottom_layer_count) - int(z_distance_bottom)); - Polygons mesh_outlines; + Shape mesh_outlines; for (double layer_idx_below = bottom_layer_idx_below; std::round(layer_idx_below) < (int)(layer_idx - z_distance_bottom); layer_idx_below += z_skip) { mesh_outlines.add(mesh.layers[std::round(layer_idx_below)].getOutlines()); } - Polygons bottoms; + Shape bottoms; generateSupportInterfaceLayer(global_support_areas_per_layer[layer_idx], mesh_outlines, bottom_line_width, bottom_outline_offset, minimum_bottom_area, bottoms); support_layers[layer_idx].support_bottom.add(bottoms); scripta::log("support_interface_bottoms", bottoms, SectionType::SUPPORT, layer_idx); } } -void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector& global_support_areas_per_layer) +void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector& global_support_areas_per_layer) { const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; const coord_t layer_height = mesh_group_settings.get("layer_height"); @@ -1723,12 +1723,12 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh const LayerIndex top_layer_idx_above{ std::min(LayerIndex{ support_layers.size() - 1 }, LayerIndex{ layer_idx + roof_layer_count + z_distance_top }) }; // Maximum layer of the model that generates support roof. - Polygons mesh_outlines; + Shape mesh_outlines; for (double layer_idx_above = top_layer_idx_above; layer_idx_above > layer_idx + z_distance_top; layer_idx_above -= z_skip) { mesh_outlines.add(mesh.layers[std::round(layer_idx_above)].getOutlines()); } - Polygons roofs; + Shape roofs; generateSupportInterfaceLayer(global_support_areas_per_layer[layer_idx], mesh_outlines, roof_line_width, roof_outline_offset, minimum_roof_area, roofs); support_layers[layer_idx].support_roof.add(roofs); if (layer_idx > 0 && layer_idx < support_layers.size() - 1) @@ -1748,7 +1748,7 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh int lower = static_cast(layer_idx); int upper = std::min(static_cast(layer_idx + roof_layer_count + z_distance_top + 5), static_cast(global_support_areas_per_layer.size()) - 1); - for (Polygons& global_support : global_support_areas_per_layer | ranges::views::slice(lower, upper)) + for (Shape& global_support : global_support_areas_per_layer | ranges::views::slice(lower, upper)) { global_support = global_support.difference(support_layer.support_roof); } @@ -1756,14 +1756,14 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh } void AreaSupport::generateSupportInterfaceLayer( - Polygons& support_areas, - const Polygons colliding_mesh_outlines, + Shape& support_areas, + const Shape colliding_mesh_outlines, const coord_t safety_offset, const coord_t outline_offset, const double minimum_interface_area, - Polygons& interface_polygons) + Shape& interface_polygons) { - Polygons model = colliding_mesh_outlines.unionPolygons(); + Shape model = colliding_mesh_outlines.unionPolygons(); interface_polygons = support_areas.offset(safety_offset / 2).intersection(model); interface_polygons = interface_polygons.offset(safety_offset).intersection(support_areas); // Make sure we don't generate any models that are not printable. if (outline_offset != 0) diff --git a/src/utils/AABB.cpp b/src/utils/AABB.cpp index dcd7f786e2..0a8cf58d57 100644 --- a/src/utils/AABB.cpp +++ b/src/utils/AABB.cpp @@ -6,7 +6,7 @@ #include #include "geometry/polygon.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" #include "utils/linearAlg2D.h" namespace cura @@ -25,7 +25,7 @@ AABB::AABB(const Point2LL& min, const Point2LL& max) { } -AABB::AABB(const Polygons& polys) +AABB::AABB(const Shape& polys) : min_(POINT_MAX, POINT_MAX) , max_(POINT_MIN, POINT_MIN) { @@ -69,7 +69,7 @@ coord_t AABB::distanceSquared(const AABB& other) const }); } -void AABB::calculate(const Polygons& polys) +void AABB::calculate(const Shape& polys) { min_ = Point2LL(POINT_MAX, POINT_MAX); max_ = Point2LL(POINT_MIN, POINT_MIN); diff --git a/src/utils/ExtrusionSegment.cpp b/src/utils/ExtrusionSegment.cpp index 81caac1243..0d0a078d54 100644 --- a/src/utils/ExtrusionSegment.cpp +++ b/src/utils/ExtrusionSegment.cpp @@ -10,14 +10,14 @@ namespace cura { -Polygons ExtrusionSegment::toPolygons() +Shape ExtrusionSegment::toPolygons() { return toPolygons(is_reduced_); } -Polygons ExtrusionSegment::toPolygons(bool reduced) +Shape ExtrusionSegment::toPolygons(bool reduced) { - Polygons ret; + Shape ret; const Point2LL vec = to_.p_ - from_.p_; const coord_t vec_length = vSize(vec); diff --git a/src/utils/ListPolyIt.cpp b/src/utils/ListPolyIt.cpp index f2644744b8..1f8929896d 100644 --- a/src/utils/ListPolyIt.cpp +++ b/src/utils/ListPolyIt.cpp @@ -14,7 +14,7 @@ namespace cura { -void ListPolyIt::convertPolygonsToLists(const Polygons& polys, ListPolygons& result) +void ListPolyIt::convertPolygonsToLists(const Shape& polys, ListPolygons& result) { for (const Polygon& poly : polys) { @@ -42,7 +42,7 @@ void ListPolyIt::convertPolygonToList(const Polygon& poly, ListPolygon& result) } -void ListPolyIt::convertListPolygonsToPolygons(const ListPolygons& list_polygons, Polygons& polygons) +void ListPolyIt::convertListPolygonsToPolygons(const ListPolygons& list_polygons, Shape& polygons) { for (unsigned int poly_idx = 0; poly_idx < polygons.size(); poly_idx++) { diff --git a/src/utils/PolygonConnector.cpp b/src/utils/PolygonConnector.cpp index 2b95247630..e8f3f3c33b 100644 --- a/src/utils/PolygonConnector.cpp +++ b/src/utils/PolygonConnector.cpp @@ -14,7 +14,7 @@ PolygonConnector::PolygonConnector(const coord_t line_width) { } -void PolygonConnector::add(const Polygons& input) +void PolygonConnector::add(const Shape& input) { for (const Polygon& poly : input) { @@ -33,7 +33,7 @@ void PolygonConnector::add(const std::vector& input) } } -void PolygonConnector::connect(Polygons& output_polygons, std::vector& output_paths) +void PolygonConnector::connect(Shape& output_polygons, std::vector& output_paths) { std::vector result_polygons = connectGroup(input_polygons_); for (const Polygon& polygon : result_polygons) diff --git a/src/utils/PolygonsPointIndex.cpp b/src/utils/PolygonsPointIndex.cpp index 6a26c2b37b..44a45fb49f 100644 --- a/src/utils/PolygonsPointIndex.cpp +++ b/src/utils/PolygonsPointIndex.cpp @@ -3,13 +3,13 @@ #include "utils/PolygonsPointIndex.h" -#include "geometry/polygons.h" +#include "geometry/shape.h" namespace cura { template<> -const Polygon& PathsPointIndex::getPolygon() const +const Polygon& PathsPointIndex::getPolygon() const { return (*polygons_)[poly_idx_]; } diff --git a/src/utils/PolygonsSegmentIndex.cpp b/src/utils/PolygonsSegmentIndex.cpp index 0b402a03f6..46f226a4c7 100644 --- a/src/utils/PolygonsSegmentIndex.cpp +++ b/src/utils/PolygonsSegmentIndex.cpp @@ -11,7 +11,7 @@ PolygonsSegmentIndex::PolygonsSegmentIndex() { } -PolygonsSegmentIndex::PolygonsSegmentIndex(const Polygons* polygons, unsigned int poly_idx, unsigned int point_idx) +PolygonsSegmentIndex::PolygonsSegmentIndex(const Shape* polygons, unsigned int poly_idx, unsigned int point_idx) : PolygonsPointIndex(polygons, poly_idx, point_idx) { } diff --git a/src/utils/PolylineStitcher.cpp b/src/utils/PolylineStitcher.cpp index 4fb09b1f9b..0155e36044 100644 --- a/src/utils/PolylineStitcher.cpp +++ b/src/utils/PolylineStitcher.cpp @@ -212,7 +212,7 @@ void PolylineStitcher::stitch( template void OpenPolylineStitcher::stitch( const LinesSet& lines, LinesSet& result_lines, - Polygons& result_polygons, + Shape& result_polygons, coord_t max_stitch_distance, coord_t snap_distance); diff --git a/src/utils/SVG.cpp b/src/utils/SVG.cpp index a4fef6d1f7..faba7f9a91 100644 --- a/src/utils/SVG.cpp +++ b/src/utils/SVG.cpp @@ -156,7 +156,7 @@ void SVG::writeComment(const std::string& comment) const fprintf(out_, "\n", comment.c_str()); } -void SVG::writeAreas(const Polygons& polygons, const ColorObject color, const ColorObject outline_color, const double stroke_width) const +void SVG::writeAreas(const Shape& polygons, const ColorObject color, const ColorObject outline_color, const double stroke_width) const { std::vector parts = polygons.splitIntoParts(); for (auto part_it = parts.rbegin(); part_it != parts.rend(); ++part_it) @@ -219,7 +219,7 @@ void SVG::writePoints(const Polygon& poly, const bool write_coords, const double } } -void SVG::writePoints(const Polygons& polygons, const bool write_coords, const double size, const ColorObject color) const +void SVG::writePoints(const Shape& polygons, const bool write_coords, const double size, const ColorObject color) const { for (const Polygon& poly : polygons) { @@ -335,7 +335,7 @@ void SVG::writeText(const Point2LL& p, const std::string& txt, const ColorObject txt.c_str()); } -void SVG::writePolygons(const Polygons& polys, const ColorObject color, const double stroke_width) const +void SVG::writePolygons(const Shape& polys, const ColorObject color, const double stroke_width) const { for (const Polygon& poly : polys) { @@ -378,7 +378,7 @@ void SVG::writePolygon(const Polygon& poly, const ColorObject color, const doubl } -void SVG::writePolylines(const Polygons& polys, const ColorObject color, const double stroke_width) const +void SVG::writePolylines(const Shape& polys, const ColorObject color, const double stroke_width) const { for (const Polygon& poly : polys) { diff --git a/src/utils/Simplify.cpp b/src/utils/Simplify.cpp index 24d92e7643..44699bc4b1 100644 --- a/src/utils/Simplify.cpp +++ b/src/utils/Simplify.cpp @@ -25,9 +25,9 @@ Simplify::Simplify(const Settings& settings) { } -Polygons Simplify::polygon(const Polygons& polygons) const +Shape Simplify::polygon(const Shape& polygons) const { - Polygons result; + Shape result; for (size_t i = 0; i < polygons.size(); ++i) { result.addIfNotEmpty(polygon(polygons[i])); diff --git a/src/utils/ToolpathVisualizer.cpp b/src/utils/ToolpathVisualizer.cpp index c8d06c878d..213f3ee2a3 100644 --- a/src/utils/ToolpathVisualizer.cpp +++ b/src/utils/ToolpathVisualizer.cpp @@ -8,7 +8,7 @@ namespace cura { -void ToolpathVisualizer::outline(const Polygons& input) +void ToolpathVisualizer::outline(const Shape& input) { svg_.writeAreas(input, SVG::Color::GRAY, SVG::Color::NONE, 2); svg_.nextLayer(); @@ -18,13 +18,13 @@ void ToolpathVisualizer::toolpaths(const std::vector& all_segm { for (double w = .9; w > .25; w = 1.0 - (1.0 - w) * 1.2) { - Polygons polys; + Shape polys; for (size_t segment_idx = 0; segment_idx < all_segments.size(); segment_idx++) { ExtrusionSegment s = all_segments[segment_idx]; s.from_.w_ *= w / .9; s.to_.w_ *= w / .9; - Polygons covered = s.toPolygons(false); + Shape covered = s.toPolygons(false); polys.add(covered); } int c = 255 - 200 * (w - .25); @@ -40,12 +40,12 @@ void ToolpathVisualizer::toolpaths(const std::vector& all_segm } -void ToolpathVisualizer::underfill(const Polygons& underfills) +void ToolpathVisualizer::underfill(const Shape& underfills) { svg_.writeAreas(underfills, SVG::ColorObject(0, 128, 255), SVG::Color::NONE); svg_.nextLayer(); } -void ToolpathVisualizer::overfill(const Polygons& overfills, const Polygons& double_overfills) +void ToolpathVisualizer::overfill(const Shape& overfills, const Shape& double_overfills) { svg_.writeAreas(overfills, SVG::ColorObject(255, 128, 0), SVG::Color::NONE); svg_.nextLayer(); @@ -56,7 +56,7 @@ void ToolpathVisualizer::overfill(const Polygons& overfills, const Polygons& dou } } -void ToolpathVisualizer::width_legend(const Polygons& input, coord_t nozzle_size, coord_t max_dev, coord_t min_w, bool rounded_visualization) +void ToolpathVisualizer::width_legend(const Shape& input, coord_t nozzle_size, coord_t max_dev, coord_t min_w, bool rounded_visualization) { auto to_string = [](double v) { @@ -143,7 +143,7 @@ void ToolpathVisualizer::widths( // } s.from_.w_ *= w / .9; s.to_.w_ *= w / .9; - Polygons covered = s.toPolygons(); + Shape covered = s.toPolygons(); svg_.writeAreas(covered, SVG::ColorObject(clr.x_, clr.y_, clr.z_), SVG::Color::NONE); } } diff --git a/src/utils/VoxelUtils.cpp b/src/utils/VoxelUtils.cpp index 4b9f38db89..6d2f28173d 100644 --- a/src/utils/VoxelUtils.cpp +++ b/src/utils/VoxelUtils.cpp @@ -95,7 +95,7 @@ bool VoxelUtils::walkLine(Point3LL start, Point3LL end, const std::function& process_cell_func) const +bool VoxelUtils::walkPolygons(const Shape& polys, coord_t z, const std::function& process_cell_func) const { for (const Polygon& poly : polys) { @@ -113,9 +113,9 @@ bool VoxelUtils::walkPolygons(const Polygons& polys, coord_t z, const std::funct return true; } -bool VoxelUtils::walkDilatedPolygons(const Polygons& polys, coord_t z, const DilationKernel& kernel, const std::function& process_cell_func) const +bool VoxelUtils::walkDilatedPolygons(const Shape& polys, coord_t z, const DilationKernel& kernel, const std::function& process_cell_func) const { - Polygons translated = polys; + Shape translated = polys; const Point3LL translation = (Point3LL(1, 1, 1) - kernel.kernel_size_ % 2) * cell_size_ / 2; if (translation.x_ && translation.y_) { @@ -124,9 +124,9 @@ bool VoxelUtils::walkDilatedPolygons(const Polygons& polys, coord_t z, const Dil return walkPolygons(translated, z + translation.z_, dilate(kernel, process_cell_func)); } -bool VoxelUtils::walkAreas(const Polygons& polys, coord_t z, const std::function& process_cell_func) const +bool VoxelUtils::walkAreas(const Shape& polys, coord_t z, const std::function& process_cell_func) const { - Polygons translated = polys; + Shape translated = polys; const Point3LL translation = -cell_size_ / 2; // offset half a cell so that the dots of spreadDotsArea are centered on the middle of the cell isntead of the lower corners. if (translation.x_ && translation.y_) { @@ -135,7 +135,7 @@ bool VoxelUtils::walkAreas(const Polygons& polys, coord_t z, const std::function return _walkAreas(translated, z, process_cell_func); } -bool VoxelUtils::_walkAreas(const Polygons& polys, coord_t z, const std::function& process_cell_func) const +bool VoxelUtils::_walkAreas(const Shape& polys, coord_t z, const std::function& process_cell_func) const { std::vector skin_points = PolygonUtils::spreadDotsArea(polys, Point2LL(cell_size_.x_, cell_size_.y_)); for (Point2LL p : skin_points) @@ -149,9 +149,9 @@ bool VoxelUtils::_walkAreas(const Polygons& polys, coord_t z, const std::functio return true; } -bool VoxelUtils::walkDilatedAreas(const Polygons& polys, coord_t z, const DilationKernel& kernel, const std::function& process_cell_func) const +bool VoxelUtils::walkDilatedAreas(const Shape& polys, coord_t z, const DilationKernel& kernel, const std::function& process_cell_func) const { - Polygons translated = polys; + Shape translated = polys; const Point3LL translation = (Point3LL(1, 1, 1) - kernel.kernel_size_ % 2) * cell_size_ / 2 // offset half a cell when using a n even kernel - cell_size_ / 2; // offset half a cell so that the dots of spreadDotsArea are centered on the middle of the cell isntead of the lower corners. if (translation.x_ && translation.y_) diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index e89f735f04..1f667741e0 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -95,17 +95,17 @@ void PolygonUtils::spreadDots(PolygonsPointIndex start, PolygonsPointIndex end, assert(result.size() == n_dots && "we didn't generate as many wipe locations as we asked for."); } -std::vector PolygonUtils::spreadDotsArea(const Polygons& polygons, coord_t grid_size) +std::vector PolygonUtils::spreadDotsArea(const Shape& polygons, coord_t grid_size) { return spreadDotsArea(polygons, Point2LL(grid_size, grid_size)); } -std::vector PolygonUtils::spreadDotsArea(const Polygons& polygons, Point2LL grid_size) +std::vector PolygonUtils::spreadDotsArea(const Shape& polygons, Point2LL grid_size) { std::vector dummy_toolpaths; Settings dummy_settings; Infill infill_gen(EFillMethod::LINES, false, false, polygons, 0, grid_size.X, 0, 1, 0, 0, 0, 0, 0); - Polygons result_polygons; + Shape result_polygons; LinesSet result_lines; infill_gen.generate(dummy_toolpaths, result_polygons, result_lines, dummy_settings, 0, SectionType::DOTS); // FIXME: @jellespijker make sure the propper layer nr is used std::vector result; @@ -132,7 +132,7 @@ std::vector PolygonUtils::spreadDotsArea(const Polygons& polygons, Poi bool PolygonUtils::lineSegmentPolygonsIntersection( const Point2LL& a, const Point2LL& b, - const Polygons& current_outlines, + const Shape& current_outlines, const LocToLineGrid& outline_locator, Point2LL& result, const coord_t within_max_dist) @@ -245,17 +245,17 @@ Point2LL PolygonUtils::moveInsideDiagonally(ClosestPoint point_on_boundary, int6 } } -unsigned int PolygonUtils::moveOutside(const Polygons& polygons, Point2LL& from, int distance, int64_t maxDist2) +unsigned int PolygonUtils::moveOutside(const Shape& polygons, Point2LL& from, int distance, int64_t maxDist2) { return moveInside(polygons, from, -distance, maxDist2); } ClosestPoint PolygonUtils::moveInside2( - const Polygons& polygons, + const Shape& polygons, Point2LL& from, const int distance, const int64_t max_dist2, - const Polygons* loc_to_line_polygons, + const Shape* loc_to_line_polygons, const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) { @@ -272,7 +272,7 @@ ClosestPoint PolygonUtils::moveInside2( } ClosestPoint PolygonUtils::moveInside2( - const Polygons& loc_to_line_polygons, + const Shape& loc_to_line_polygons, const Polygon& polygon, Point2LL& from, const int distance, @@ -331,7 +331,7 @@ ClosestPoint PolygonUtils::_moveInside2(const ClosestPoint& closest_polygon_poin /* * Implementation assumes moving inside, but moving outside should just as well be possible. */ -size_t PolygonUtils::moveInside(const Polygons& polygons, Point2LL& from, int distance, int64_t maxDist2) +size_t PolygonUtils::moveInside(const Shape& polygons, Point2LL& from, int distance, int64_t maxDist2) { Point2LL ret = from; int64_t bestDist2 = std::numeric_limits::max(); @@ -621,11 +621,11 @@ Point2LL PolygonUtils::moveInside(const ClosestPoint& cpp, const int distance) } ClosestPoint PolygonUtils::ensureInsideOrOutside( - const Polygons& polygons, + const Shape& polygons, Point2LL& from, int preferred_dist_inside, int64_t max_dist2, - const Polygons* loc_to_line_polygons, + const Shape* loc_to_line_polygons, const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) { @@ -634,11 +634,11 @@ ClosestPoint PolygonUtils::ensureInsideOrOutside( } ClosestPoint PolygonUtils::ensureInsideOrOutside( - const Polygons& polygons, + const Shape& polygons, Point2LL& from, const ClosestPoint& closest_polygon_point, int preferred_dist_inside, - const Polygons* loc_to_line_polygons, + const Shape* loc_to_line_polygons, const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) { @@ -674,7 +674,7 @@ ClosestPoint PolygonUtils::ensureInsideOrOutside( // The offset is performed on the closest reference polygon in order to save computation time { const coord_t offset = (is_outside_boundary) ? -preferred_dist_inside : preferred_dist_inside; // perform inset on outer boundary and outset on holes - Polygons insetted + Shape insetted = closest_poly.offset(offset / 2); // perform less inset, because chances are (thin parts of) the polygon will disappear, given that moveInside did an overshoot if (insetted.size() == 0) { @@ -688,7 +688,7 @@ ClosestPoint PolygonUtils::ensureInsideOrOutside( { // Insetting from the reference polygon ended up outside another polygon. // Perform an offset on all polygons instead. - Polygons all_insetted = polygons.offset(-preferred_dist_inside); + Shape all_insetted = polygons.offset(-preferred_dist_inside); ClosestPoint overall_inside = findClosest(from, all_insetted, penalty_function); bool overall_is_inside = polygons.inside(overall_inside.location_); if (overall_is_inside != (preferred_dist_inside > 0)) @@ -862,7 +862,7 @@ ClosestPoint PolygonUtils::findNearestClosest(Point2LL from, const Polygon& poly return ClosestPoint(best, bestPos, &polygon); } -ClosestPoint PolygonUtils::findClosest(Point2LL from, const Polygons& polygons, const std::function& penalty_function) +ClosestPoint PolygonUtils::findClosest(Point2LL from, const Shape& polygons, const std::function& penalty_function) { ClosestPoint none; @@ -944,7 +944,7 @@ ClosestPoint PolygonUtils::findClosest(Point2LL from, const Polygon& polygon, co return ClosestPoint(best, bestPos, &polygon); } -PolygonsPointIndex PolygonUtils::findNearestVert(const Point2LL from, const Polygons& polys) +PolygonsPointIndex PolygonUtils::findNearestVert(const Point2LL from, const Shape& polys) { int64_t best_dist2 = std::numeric_limits::max(); PolygonsPointIndex closest_vert; @@ -980,7 +980,7 @@ unsigned int PolygonUtils::findNearestVert(const Point2LL from, const Polygon& p return closest_vert_idx; } -std::unique_ptr PolygonUtils::createLocToLineGrid(const Polygons& polygons, int square_size) +std::unique_ptr PolygonUtils::createLocToLineGrid(const Shape& polygons, int square_size) { unsigned int n_points = 0; for (const auto& poly : polygons) @@ -1008,7 +1008,7 @@ std::unique_ptr PolygonUtils::createLocToLineGrid(const Polygons& * * We could skip the duplication by keeping a vector of vectors of bools. */ -std::optional PolygonUtils::findClose(Point2LL from, const Polygons& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function) +std::optional PolygonUtils::findClose(Point2LL from, const Shape& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function) { std::vector near_lines = loc_to_line.getNearby(from, loc_to_line.getCellSize()); @@ -1042,7 +1042,7 @@ std::optional PolygonUtils::findClose(Point2LL from, const Polygon } std::vector> - PolygonUtils::findClose(const Polygon& from, const Polygons& destination, const LocToLineGrid& destination_loc_to_line, const std::function& penalty_function) + PolygonUtils::findClose(const Polygon& from, const Shape& destination, const LocToLineGrid& destination_loc_to_line, const std::function& penalty_function) { std::vector> ret; int p0_idx = from.size() - 1; @@ -1300,7 +1300,7 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const Polygon& poly, const Poi } bool PolygonUtils::polygonCollidesWithLineSegment( - const Polygons& polys, + const Shape& polys, const Point2LL& transformed_startPoint, const Point2LL& transformed_endPoint, PointMatrix transformation_matrix) @@ -1321,7 +1321,7 @@ bool PolygonUtils::polygonCollidesWithLineSegment( } -bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, const Point2LL& startPoint, const Point2LL& endPoint) +bool PolygonUtils::polygonCollidesWithLineSegment(const Shape& polys, const Point2LL& startPoint, const Point2LL& endPoint) { if (endPoint == startPoint) { @@ -1390,7 +1390,7 @@ void PolygonUtils::findAdjacentPolygons( } } -double PolygonUtils::relativeHammingDistance(const Polygons& poly_a, const Polygons& poly_b) +double PolygonUtils::relativeHammingDistance(const Shape& poly_a, const Shape& poly_b) { const double area_a = std::abs(poly_a.area()); const double area_b = std::abs(poly_b.area()); @@ -1423,7 +1423,7 @@ double PolygonUtils::relativeHammingDistance(const Polygons& poly_a, const Polyg return 0.0; // All points are inside the other polygon, regardless of where the vertices are along the edges. } - const Polygons symmetric_difference = poly_a.xorPolygons(poly_b); + const Shape symmetric_difference = poly_a.xorPolygons(poly_b); const double hamming_distance = symmetric_difference.area(); return hamming_distance / total_area; } @@ -1439,9 +1439,9 @@ Polygon PolygonUtils::makeCircle(const Point2LL mid, const coord_t radius, const } -Polygons PolygonUtils::connect(const Polygons& input) +Shape PolygonUtils::connect(const Shape& input) { - Polygons ret; + Shape ret; std::vector parts = input.splitIntoParts(true); for (SingleShape& part : parts) { @@ -1483,7 +1483,7 @@ Polygons PolygonUtils::connect(const Polygons& input) /* Note: Also tries to solve for near-self intersections, when epsilon >= 1 */ -void PolygonUtils::fixSelfIntersections(const coord_t epsilon, Polygons& polygon) +void PolygonUtils::fixSelfIntersections(const coord_t epsilon, Shape& polygon) { if (epsilon < 1) { @@ -1534,14 +1534,14 @@ void PolygonUtils::fixSelfIntersections(const coord_t epsilon, Polygons& polygon ClipperLib::SimplifyPolygons(polygon.getCallable()); } -Polygons PolygonUtils::unionManySmall(const Polygons& polygon) +Shape PolygonUtils::unionManySmall(const Shape& polygon) { if (polygon.size() < 8) { return polygon.unionPolygons(); } - Polygons a, b; + Shape a, b; a.reserve(polygon.size() / 2); b.reserve(a.size() + 1); for (const auto& [i, path] : polygon | ranges::views::enumerate) @@ -1551,9 +1551,9 @@ Polygons PolygonUtils::unionManySmall(const Polygons& polygon) return unionManySmall(a).unionPolygons(unionManySmall(b)); } -Polygons PolygonUtils::clipPolygonWithAABB(const Polygons& src, const AABB& aabb) +Shape PolygonUtils::clipPolygonWithAABB(const Shape& src, const AABB& aabb) { - Polygons out; + Shape out; out.reserve(src.size()); for (const auto path : src) { @@ -1562,7 +1562,7 @@ Polygons PolygonUtils::clipPolygonWithAABB(const Polygons& src, const AABB& aabb const size_t cnt = path.size(); if (cnt < 3) { - return Polygons(); + return Shape(); } enum class Side @@ -1621,11 +1621,11 @@ Polygons PolygonUtils::clipPolygonWithAABB(const Polygons& src, const AABB& aabb return out; } -Polygons PolygonUtils::generateOutset(const Polygons& inner_poly, size_t count, coord_t line_width) +Shape PolygonUtils::generateOutset(const Shape& inner_poly, size_t count, coord_t line_width) { - Polygons outset; + Shape outset; - Polygons current_outset; + Shape current_outset; for (size_t index = 0; index < count; ++index) { current_outset = index == 0 ? inner_poly.offset(line_width / 2) : current_outset.offset(line_width); @@ -1635,11 +1635,11 @@ Polygons PolygonUtils::generateOutset(const Polygons& inner_poly, size_t count, return outset; } -Polygons PolygonUtils::generateInset(const Polygons& outer_poly, coord_t line_width, coord_t initial_inset) +Shape PolygonUtils::generateInset(const Shape& outer_poly, coord_t line_width, coord_t initial_inset) { - Polygons inset; + Shape inset; - Polygons current_inset = outer_poly.offset(-(initial_inset + line_width / 2)); + Shape current_inset = outer_poly.offset(-(initial_inset + line_width / 2)); while (! current_inset.empty()) { inset.add(current_inset); diff --git a/stress_benchmark/stress_benchmark.cpp b/stress_benchmark/stress_benchmark.cpp index ee2d80b584..a55ee0a6f2 100644 --- a/stress_benchmark/stress_benchmark.cpp +++ b/stress_benchmark/stress_benchmark.cpp @@ -53,7 +53,7 @@ struct Resource return wkt_file.stem().string(); } - std::vector polygons() const + std::vector polygons() const { using point_type = boost::geometry::model::d2::point_xy; using polygon_type = boost::geometry::model::polygon; @@ -71,11 +71,11 @@ struct Resource boost::geometry::read_wkt(buffer.str(), boost_polygons); - std::vector polygons; + std::vector polygons; for (const auto& boost_polygon : boost_polygons) { - cura::Polygons polygon; + cura::Shape polygon; cura::Polygon outer; for (const auto& point : boost_polygon.outer()) @@ -145,7 +145,7 @@ std::vector getResources() void handleChildProcess(const auto& shapes, const auto& settings) { cura::SliceLayer layer; - for (const cura::Polygons& shape : shapes) + for (const cura::Shape& shape : shapes) { layer.parts.emplace_back(); cura::SliceLayerPart& part = layer.parts.back(); diff --git a/tests/InfillTest.cpp b/tests/InfillTest.cpp index aa95cab94c..157404288f 100644 --- a/tests/InfillTest.cpp +++ b/tests/InfillTest.cpp @@ -73,11 +73,11 @@ class InfillTestParameters // Parameters used to generate the infill: InfillParameters params; - Polygons outline_polygons; + Shape outline_polygons; // Resulting infill: - Polygons result_lines; - Polygons result_polygons; + Shape result_lines; + Shape result_polygons; std::string name; @@ -89,7 +89,7 @@ class InfillTestParameters { } - InfillTestParameters(const InfillParameters& params, const size_t& test_polygon_id, Polygons outline_polygons, Polygons result_lines, Polygons result_polygons) + InfillTestParameters(const InfillParameters& params, const size_t& test_polygon_id, Shape outline_polygons, Shape result_lines, Shape result_polygons) : valid(true) , fail_reason("__") , params(params) @@ -149,7 +149,7 @@ void writeTestcaseSVG(const InfillTestParameters& params) } #endif // TEST_INFILL_SVG_OUTPUT -InfillTestParameters generateInfillToTest(const InfillParameters& params, const size_t& test_polygon_id, const Polygons& outline_polygons) +InfillTestParameters generateInfillToTest(const InfillParameters& params, const size_t& test_polygon_id, const Shape& outline_polygons) { auto layers = std::vector(200, SlicerLayer{}); scripta::setAll(layers); @@ -176,8 +176,8 @@ InfillTestParameters generateInfillToTest(const InfillParameters& params, const Settings infill_settings; std::vector result_paths; - Polygons result_polygons; - Polygons result_lines; + Shape result_polygons; + Shape result_lines; infill.generate(result_paths, result_polygons, result_lines, infill_settings, 1, SectionType::INFILL, nullptr, nullptr); InfillTestParameters result = InfillTestParameters(params, test_polygon_id, outline_polygons, result_lines, result_polygons); @@ -190,7 +190,7 @@ std::vector generateInfillTests() constexpr bool do_connect_polygons = true; constexpr bool dont_connect_polygons = false; - std::vector shapes; + std::vector shapes; if (! readTestPolygons(POLYGON_FILENAMES, shapes)) { return { InfillTestParameters() }; // return an invalid singleton, that'll trip up the 'file read' assertion in the TEST_P's @@ -220,7 +220,7 @@ std::vector generateInfillTests() std::vector parameters_list; size_t test_polygon_id = 0; - for (const Polygons& polygons : shapes) + for (const Shape& polygons : shapes) { for (const EFillMethod& method : methods) { @@ -283,11 +283,11 @@ TEST_P(InfillTest, TestInfillSanity) ASSERT_LT((coord_t)out_infill_area, (coord_t)max_expected_infill_area) << "Infill area should be less than the maximum area to be covered."; const coord_t maximum_error = 10_mu; // potential rounding error - const Polygons padded_shape_outline = params.outline_polygons.offset(INFILL_LINE_WIDTH / 2); + const Shape padded_shape_outline = params.outline_polygons.offset(INFILL_LINE_WIDTH / 2); constexpr bool restitch = false; // No need to restitch polylines - that would introduce stitching errors. ASSERT_LE(std::abs(padded_shape_outline.intersectionPolyLines(params.result_lines, restitch).polyLineLength() - params.result_lines.polyLineLength()), maximum_error) << "Infill (lines) should not be outside target polygon."; - Polygons result_polygon_lines = params.result_polygons; + Shape result_polygon_lines = params.result_polygons; for (Polygon& poly : result_polygon_lines) { poly.add(poly.front()); diff --git a/tests/LayerPlanTest.cpp b/tests/LayerPlanTest.cpp index 933244dbbc..071ec2c37e 100644 --- a/tests/LayerPlanTest.cpp +++ b/tests/LayerPlanTest.cpp @@ -356,7 +356,7 @@ class AddTravelTest : public LayerPlanTest, public testing::WithParamInterfaceretraction_wipe_config_per_extruder[0].retraction_config.retraction_min_travel_distance = settings->get("retraction_min_travel"); // Update the copy that the storage has of this. settings->add("retraction_combing_max_distance", parameters.is_long_combing ? "1" : "10000"); - Polygons slice_data; + Shape slice_data; switch (parameters.scene) { case OPEN: diff --git a/tests/PathOrderMonotonicTest.cpp b/tests/PathOrderMonotonicTest.cpp index 6d4a10a760..108d1178ed 100644 --- a/tests/PathOrderMonotonicTest.cpp +++ b/tests/PathOrderMonotonicTest.cpp @@ -71,9 +71,9 @@ constexpr coord_t shift = 0; constexpr coord_t max_resolution = 10; constexpr coord_t max_deviation = 5; -bool getInfillLines(const std::string& filename, const AngleRadians& angle, Polygons& output) +bool getInfillLines(const std::string& filename, const AngleRadians& angle, Shape& output) { - std::vector shapes; + std::vector shapes; if (! readTestPolygons(filename, shapes)) { return false; @@ -84,7 +84,7 @@ bool getInfillLines(const std::string& filename, const AngleRadians& angle, Poly Infill infill_comp(pattern, zig_zagify, connect_polygons, shape, infill_line_width, line_distance, infill_overlap, infill_multiplier, AngleDegrees(angle), z, shift, max_resolution, max_deviation); Settings infill_settings; std::vector result_paths; - Polygons dummy_polys; + Shape dummy_polys; infill_comp.generate(result_paths, dummy_polys, output, infill_settings, 1, SectionType::INFILL, nullptr, nullptr); } return true; @@ -136,7 +136,7 @@ TEST_P(PathOrderMonotonicTest, SectionsTest) const auto params = GetParam(); const double angle_radians{ std::get<1>(params) }; const auto& filename = std::get<0>(params); - Polygons polylines; + Shape polylines; ASSERT_TRUE(getInfillLines(filename, angle_radians, polylines)) << "Input test-file could not be read, check setup."; const Point2LL& pt_r = polylines.begin()->at(0); diff --git a/tests/ReadTestPolygons.cpp b/tests/ReadTestPolygons.cpp index 6e0f196952..fdaef7d883 100644 --- a/tests/ReadTestPolygons.cpp +++ b/tests/ReadTestPolygons.cpp @@ -5,7 +5,7 @@ #include -#include "geometry/polygons.h" +#include "geometry/shape.h" #include "utils/Coord_t.h" // NOTE: See the documentation in the header-file for an explanation of this simple file format. @@ -14,7 +14,7 @@ namespace cura { // Read multiple files to the collection of polygons. // Returns boolean success/failure (read errors, not found, etc.). -bool readTestPolygons(const std::vector& filenames, std::vector& polygons_out) +bool readTestPolygons(const std::vector& filenames, std::vector& polygons_out) { for (const std::string& filename : filenames) { @@ -28,7 +28,7 @@ bool readTestPolygons(const std::vector& filenames, std::vector& polygons_out) +bool readTestPolygons(const std::string& filename, std::vector& polygons_out) { FILE* handle = std::fopen(filename.c_str(), "r"); if (! handle) @@ -37,7 +37,7 @@ bool readTestPolygons(const std::string& filename, std::vector& polygo } Polygon next_path; - Polygons next_shape; + Shape next_shape; char command = '_'; int read = 0; diff --git a/tests/ReadTestPolygons.h b/tests/ReadTestPolygons.h index 6dc8524fa9..9baaba4721 100644 --- a/tests/ReadTestPolygons.h +++ b/tests/ReadTestPolygons.h @@ -34,8 +34,8 @@ v 50000 50000 namespace cura { -bool readTestPolygons(const std::vector& filenames, std::vector& polygons_out); -bool readTestPolygons(const std::string& filename, std::vector& polygons_out); +bool readTestPolygons(const std::vector& filenames, std::vector& polygons_out); +bool readTestPolygons(const std::string& filename, std::vector& polygons_out); } // namespace cura #endif // READ_TEST_POLYGONS_H diff --git a/tests/WallsComputationTest.cpp b/tests/WallsComputationTest.cpp index fd89907b7e..424a3c9b66 100644 --- a/tests/WallsComputationTest.cpp +++ b/tests/WallsComputationTest.cpp @@ -41,12 +41,12 @@ class WallsComputationTest : public testing::Test /*! * Basic 10x10mm square shape to work with. */ - Polygons square_shape; + Shape square_shape; /*! * A rectangle enclosing two triangular holes; */ - Polygons ff_holes; + Shape ff_holes; WallsComputationTest() : walls_computation(settings, LayerIndex(100)) { diff --git a/tests/arcus/ArcusCommunicationTest.cpp b/tests/arcus/ArcusCommunicationTest.cpp index 2599a0b941..cf66883c36 100644 --- a/tests/arcus/ArcusCommunicationTest.cpp +++ b/tests/arcus/ArcusCommunicationTest.cpp @@ -33,7 +33,7 @@ class ArcusCommunicationTest : public testing::Test Polygon test_circle; Polygon test_convex_shape; - Polygons test_shapes; // all above polygons + Shape test_shapes; // all above polygons void SetUp() override { diff --git a/tests/integration/SlicePhaseTest.cpp b/tests/integration/SlicePhaseTest.cpp index 13ca9b8b2e..9c6a0f641b 100644 --- a/tests/integration/SlicePhaseTest.cpp +++ b/tests/integration/SlicePhaseTest.cpp @@ -157,7 +157,7 @@ TEST_F(SlicePhaseTest, Cylinder1000) const coord_t y = std::sin(std::numbers::pi * 2 / num_vertices * i) * radius; circle.emplace_back(x, y); } - Polygons circles; + Shape circles; circles.add(circle); for (size_t layer_nr = 0; layer_nr < num_layers; layer_nr++) diff --git a/tests/utils/AABBTest.cpp b/tests/utils/AABBTest.cpp index 48c620b3aa..95d115d7ad 100644 --- a/tests/utils/AABBTest.cpp +++ b/tests/utils/AABBTest.cpp @@ -34,12 +34,12 @@ TEST(AABBTest, TestConstructPoint) TEST(AABBTest, TestConstructPolygons) { - Polygons empty_polygon; + Shape empty_polygon; AABB polygons_box_a(empty_polygon); EXPECT_FALSE(polygons_box_a.contains(Point2LL(0, 0))) << "Box constructed from empty polygon shouldn't contain anything."; - Polygons polygons; + Shape polygons; polygons.add(Polygon(ClipperLib::Path({ ClipperLib::IntPoint{ -10, -10 }, ClipperLib::IntPoint{ 10, -10 }, ClipperLib::IntPoint{ -5, -5 }, ClipperLib::IntPoint{ -10, 10 } }))); polygons.add(Polygon(ClipperLib::Path({ ClipperLib::IntPoint{ 11, 11 }, ClipperLib::IntPoint{ -11, 11 }, ClipperLib::IntPoint{ 4, 4 }, ClipperLib::IntPoint{ 11, -11 } }))); polygons.add(Polygon(ClipperLib::Path({ ClipperLib::IntPoint{ 2, 2 }, ClipperLib::IntPoint{ 2, 3 }, ClipperLib::IntPoint{ 3, 3 }, ClipperLib::IntPoint{ 3, 2 } }))); diff --git a/tests/utils/PolygonConnectorTest.cpp b/tests/utils/PolygonConnectorTest.cpp index 61dc3de67d..c30fde412e 100644 --- a/tests/utils/PolygonConnectorTest.cpp +++ b/tests/utils/PolygonConnectorTest.cpp @@ -21,10 +21,10 @@ class PolygonConnectorTest : public testing::Test Polygon test_triangle; Polygon test_circle; Polygon test_convex_shape; - Polygons test_shapes; // All above polygons! As well as an inset of 100 microns of them. + Shape test_shapes; // All above polygons! As well as an inset of 100 microns of them. PolygonConnector* pc; - Polygons connected_polygons; + Shape connected_polygons; std::vector connected_paths; virtual void SetUp() override @@ -164,14 +164,14 @@ TEST_F(PolygonConnectorTest, getBridgeTooNarrow) */ TEST_F(PolygonConnectorTest, connectFourNested) { - Polygons connecting; + Shape connecting; connecting.add(test_square_around); // 1200-wide square. connecting.add(test_square); // 1000-wide square. connecting.add(test_square.offset(-100)); // 800-wide square. connecting.add(test_square.offset(-200)); // 600-wide square. pc->add(connecting); - Polygons output_polygons; + Shape output_polygons; std::vector output_paths; pc->connect(output_polygons, output_paths); diff --git a/tests/utils/PolygonTest.cpp b/tests/utils/PolygonTest.cpp index a63919fa3e..b2ef8d770b 100644 --- a/tests/utils/PolygonTest.cpp +++ b/tests/utils/PolygonTest.cpp @@ -26,7 +26,7 @@ class PolygonTest : public testing::Test Polygon clipper_bug; Polygon clockwise_large; Polygon clockwise_small; - Polygons clockwise_donut; + Shape clockwise_donut; Polygon line; Polygon small_area; @@ -68,8 +68,8 @@ class PolygonTest : public testing::Test clockwise_small.emplace_back(50, 50); clockwise_small.emplace_back(50, -50); - Polygons outer; - Polygons inner; + Shape outer; + Shape inner; outer.push_back(clockwise_large); inner.push_back(clockwise_small); clockwise_donut = outer.difference(inner); @@ -82,7 +82,7 @@ class PolygonTest : public testing::Test small_area.emplace_back(10, 10); small_area.emplace_back(0, 10); } - void twoPolygonsAreEqual(Polygons& polygon1, Polygons& polygon2) const + void twoPolygonsAreEqual(Shape& polygon1, Shape& polygon2) const { auto poly_cmp = [](const ClipperLib::Path& a, const ClipperLib::Path& b) { @@ -112,18 +112,18 @@ class PolygonTest : public testing::Test TEST_F(PolygonTest, polygonOffsetTest) { - Polygons test_squares; + Shape test_squares; test_squares.push_back(test_square); - const Polygons expanded = test_squares.offset(25); + const Shape expanded = test_squares.offset(25); const coord_t expanded_length = expanded.length(); - Polygons square_hole; + Shape square_hole; Polygon& square_inverted = square_hole.newLine(); for (int i = test_square.size() - 1; i >= 0; i--) { square_inverted.push_back(test_square[i]); } - const Polygons contracted = square_hole.offset(25); + const Shape contracted = square_hole.offset(25); const coord_t contracted_length = contracted.length(); ASSERT_NEAR(expanded_length, contracted_length, 5) << "Offset on outside poly is different from offset on inverted poly!"; @@ -131,9 +131,9 @@ TEST_F(PolygonTest, polygonOffsetTest) TEST_F(PolygonTest, polygonOffsetBugTest) { - Polygons polys; + Shape polys; polys.push_back(clipper_bug); - const Polygons offsetted = polys.offset(-20); + const Shape offsetted = polys.offset(-20); for (const Polygon& poly : offsetted) { @@ -146,7 +146,7 @@ TEST_F(PolygonTest, polygonOffsetBugTest) TEST_F(PolygonTest, isOutsideTest) { - Polygons test_triangle; + Shape test_triangle; test_triangle.push_back(triangle); EXPECT_FALSE(test_triangle.inside(Point2LL(0, 100))) << "Left point should be outside the triangle."; @@ -159,7 +159,7 @@ TEST_F(PolygonTest, isOutsideTest) TEST_F(PolygonTest, isInsideTest) { - Polygons test_polys; + Shape test_polys; Polygon& poly = test_polys.newLine(); poly.push_back(Point2LL(82124, 98235)); poly.push_back(Point2LL(83179, 98691)); @@ -179,7 +179,7 @@ TEST_F(PolygonTest, isInsideTest) TEST_F(PolygonTest, isOnBorderTest) { - Polygons test_triangle; + Shape test_triangle; test_triangle.push_back(triangle); EXPECT_FALSE(test_triangle.inside(Point2LL(200, 0), false)) << "Point is on the bottom edge of the triangle."; @@ -190,7 +190,7 @@ TEST_F(PolygonTest, isOnBorderTest) TEST_F(PolygonTest, DISABLED_isInsideLineTest) // Disabled because this fails due to a bug in Clipper. { - Polygons polys; + Shape polys; polys.push_back(line); EXPECT_FALSE(polys.inside(Point2LL(50, 0), false)) << "Should be outside since it is on the border and border is considered outside."; @@ -243,7 +243,7 @@ TEST_F(PolygonTest, differenceClockwiseTest) TEST_F(PolygonTest, getEmptyHolesTest) { - const Polygons holes = clockwise_donut.getEmptyHoles(); + const Shape holes = clockwise_donut.getEmptyHoles(); ASSERT_EQ(holes.size(), 1); ASSERT_EQ(holes[0].size(), clockwise_small.size()) << "Empty hole should have the same amount of vertices as the original polygon."; @@ -258,7 +258,7 @@ TEST_F(PolygonTest, getEmptyHolesTest) */ TEST_F(PolygonTest, convexTestCube) { - Polygons d_polygons; + Shape d_polygons; Polygon& d = d_polygons.newLine(); d.push_back(Point2LL(0, 0)); d.push_back(Point2LL(10, 0)); @@ -279,7 +279,7 @@ TEST_F(PolygonTest, convexTestCube) */ TEST_F(PolygonTest, convexHullStar) { - Polygons d_polygons; + Shape d_polygons; Polygon& d = d_polygons.newLine(); const int num_points = 10; @@ -315,7 +315,7 @@ TEST_F(PolygonTest, convexHullStar) */ TEST_F(PolygonTest, convexHullMultipleMinX) { - Polygons d_polygons; + Shape d_polygons; Polygon& d = d_polygons.newLine(); d.push_back(Point2LL(0, 0)); d.push_back(Point2LL(0, -10)); @@ -341,7 +341,7 @@ TEST_F(PolygonTest, convexHullMultipleMinX) */ TEST_F(PolygonTest, convexTestCubeColinear) { - Polygons d_polygons; + Shape d_polygons; Polygon& d = d_polygons.newLine(); d.push_back(Point2LL(0, 0)); d.push_back(Point2LL(5, 0)); @@ -366,7 +366,7 @@ TEST_F(PolygonTest, convexTestCubeColinear) */ TEST_F(PolygonTest, convexHullRemoveDuplicatePoints) { - Polygons d_polygons; + Shape d_polygons; Polygon& d = d_polygons.newLine(); d.push_back(Point2LL(0, 0)); d.push_back(Point2LL(0, 0)); @@ -395,7 +395,7 @@ TEST_F(PolygonTest, removeSmallAreas_simple) // basic set of polygons auto test_square_2 = test_square; test_square_2.translate(Point2LL(0, 500)); - auto d_polygons = Polygons{}; + auto d_polygons = Shape{}; d_polygons.push_back(test_square); d_polygons.push_back(test_square_2); d_polygons.push_back(triangle); @@ -426,14 +426,14 @@ TEST_F(PolygonTest, removeSmallAreas_small_area) triangle_1.translate(Point2LL(50, 0)); // add areas to polygons - auto d_polygons = Polygons{}; + auto d_polygons = Shape{}; d_polygons.push_back(small_area_1); d_polygons.push_back(small_area_2); d_polygons.push_back(test_square); // area = 10000 micron^2 = 1e-2 mm^2 d_polygons.push_back(triangle_1); - // make an expected Polygons - auto exp_polygons = Polygons{}; + // make an expected Shape + auto exp_polygons = Shape{}; exp_polygons.push_back(test_square); exp_polygons.push_back(triangle_1); @@ -460,7 +460,7 @@ TEST_F(PolygonTest, removeSmallAreas_hole) small_hole_1.translate(Point2LL(10, 10)); // add areas to polygons - auto d_polygons = Polygons{}; + auto d_polygons = Shape{}; d_polygons.push_back(test_square); // area = 10000 micron^2 = 1e-2 mm^2 d_polygons.push_back(small_hole_1); @@ -471,8 +471,8 @@ TEST_F(PolygonTest, removeSmallAreas_hole) twoPolygonsAreEqual(act_polygons, d_polygons); // for remove_holes == true there should be one less poly. - // make an expected Polygons - auto exp_polygons = Polygons{}; + // make an expected Shape + auto exp_polygons = Shape{}; exp_polygons.push_back(test_square); act_polygons = d_polygons; act_polygons.removeSmallAreas(1e-3, true); @@ -498,7 +498,7 @@ TEST_F(PolygonTest, removeSmallAreas_hole_2) med_square_1.translate(Point2LL(150, 150)); // add areas to polygons - auto d_polygons = Polygons{}; + auto d_polygons = Shape{}; d_polygons.push_back(test_square); // area = 10000 micron^2 = 1e-2 mm^2 d_polygons.push_back(small_hole_1); d_polygons.push_back(med_square_1); @@ -506,8 +506,8 @@ TEST_F(PolygonTest, removeSmallAreas_hole_2) // for remove_holes == false, two polygons removed. auto act_polygons = d_polygons; - // make an expected Polygons - auto exp_polygons = Polygons{}; + // make an expected Shape + auto exp_polygons = Shape{}; exp_polygons.push_back(test_square); exp_polygons.push_back(small_hole_1); act_polygons.removeSmallAreas(3e-3, false); @@ -516,7 +516,7 @@ TEST_F(PolygonTest, removeSmallAreas_hole_2) // for remove_holes == true, three polygons removed. act_polygons = d_polygons; // make an expected Polygons - exp_polygons = Polygons{}; + exp_polygons = Shape{}; exp_polygons.push_back(test_square); act_polygons.removeSmallAreas(3e-3, true); twoPolygonsAreEqual(act_polygons, exp_polygons); @@ -544,7 +544,7 @@ TEST_F(PolygonTest, removeSmallAreas_complex) triangle_1.translate(Point2LL(600, 0)); // add areas to polygons - auto d_polygons = Polygons{}; + auto d_polygons = Shape{}; d_polygons.push_back(small_area_1); d_polygons.push_back(small_area_2); d_polygons.push_back(test_square); // area = 10000 micron^2 = 1e-2 mm^2 @@ -554,8 +554,8 @@ TEST_F(PolygonTest, removeSmallAreas_complex) // for remove_holes == false there should be 2 small areas removed. auto act_polygons = d_polygons; - // make an expected Polygons - auto exp_polygons = Polygons{}; + // make an expected Shape + auto exp_polygons = Shape{}; exp_polygons.push_back(test_square); // area = 10000 micron^2 = 1e-2 mm^2 exp_polygons.push_back(small_hole_1); exp_polygons.push_back(small_hole_2); @@ -566,7 +566,7 @@ TEST_F(PolygonTest, removeSmallAreas_complex) // for remove_holes == true there should be 2 small areas and 2 small holes removed. act_polygons = d_polygons; // make an expected Polygons - exp_polygons = Polygons{}; + exp_polygons = Shape{}; exp_polygons.push_back(test_square); exp_polygons.push_back(triangle_1); // area = 10000 micron^2 = 1e-2 mm^2 act_polygons.removeSmallAreas(1e-3, true); diff --git a/tests/utils/PolygonUtilsTest.cpp b/tests/utils/PolygonUtilsTest.cpp index 7dbf07569f..1758d3b495 100644 --- a/tests/utils/PolygonUtilsTest.cpp +++ b/tests/utils/PolygonUtilsTest.cpp @@ -70,7 +70,7 @@ TEST_P(MoveInsideTest, MoveInside) TEST_P(MoveInsideTest, MoveInside2) { const MoveInsideParameters parameters = GetParam(); - Polygons polys; + Shape polys; polys.add(test_square); Point2LL result = parameters.close_to; PolygonUtils::moveInside2(polys, result, parameters.distance); @@ -164,7 +164,7 @@ TEST_F(MoveInsideTest, cornerEdgeTest2) const Point2LL supposed1(80, 80); // Allow two possible values here, since the behaviour for this edge case is not specified. const Point2LL supposed2(72, 100); constexpr coord_t distance = 28; - Polygons polys; + Shape polys; polys.add(test_square); Point2LL result = close_to; PolygonUtils::moveInside2(polys, result, distance); @@ -178,7 +178,7 @@ TEST_F(MoveInsideTest, pointyCorner) { const Point2LL from(55, 100); // Above pointy bit. Point2LL result(from); - Polygons inside; + Shape inside; inside.add(pointy_square); ClosestPoint cpp = PolygonUtils::ensureInsideOrOutside(inside, result, 10); @@ -192,7 +192,7 @@ TEST_F(MoveInsideTest, pointyCornerFail) // Should fail with normal moveInside2 (and the like). const Point2LL from(55, 170); // Above pointy bit. Point2LL result(from); - Polygons inside; + Shape inside; inside.add(pointy_square); ClosestPoint cpp = PolygonUtils::moveInside2(inside, result, 10); @@ -206,7 +206,7 @@ TEST_F(MoveInsideTest, outsidePointyCorner) const Point2LL from(60, 70); // Above pointy bit. Point2LL result(from); const Point2LL supposed(50, 70); // 10 below pointy bit. - Polygons inside; + Shape inside; inside.add(pointy_square); const ClosestPoint cpp = PolygonUtils::ensureInsideOrOutside(inside, result, -10); @@ -221,7 +221,7 @@ TEST_F(MoveInsideTest, outsidePointyCornerFail) const Point2LL from(60, 70); // Above pointy bit. Point2LL result(from); const Point2LL supposed(50, 70); // 10 below pointy bit. - Polygons inside; + Shape inside; inside.add(pointy_square); const ClosestPoint cpp = PolygonUtils::moveInside2(inside, result, -10); @@ -265,7 +265,7 @@ class FindCloseTest : public testing::TestWithParam TEST_P(FindCloseTest, FindClose) { const FindCloseParameters parameters = GetParam(); - Polygons polygons; + Shape polygons; polygons.add(test_square); auto loc_to_line = PolygonUtils::createLocToLineGrid(polygons, parameters.cell_size); @@ -312,9 +312,9 @@ INSTANTIATE_TEST_SUITE_P( class PolygonUtilsTest : public testing::Test { public: - Polygons test_squares; - Polygons test_line; - Polygons test_line_extra_vertices; // Line that has extra vertices along it that are technically unnecessary. + Shape test_squares; + Shape test_line; + Shape test_line_extra_vertices; // Line that has extra vertices along it that are technically unnecessary. PolygonUtilsTest() { @@ -399,7 +399,7 @@ struct GetNextParallelIntersectionParameters class GetNextParallelIntersectionTest : public testing::TestWithParam { public: - Polygons test_squares; + Shape test_squares; GetNextParallelIntersectionTest() { @@ -448,7 +448,7 @@ TEST_F(PolygonUtilsTest, RelativeHammingSquaresOverlap) TEST_F(PolygonUtilsTest, RelativeHammingDisjunct) { - Polygons shifted_polys = test_squares; // Make a copy. + Shape shifted_polys = test_squares; // Make a copy. shifted_polys[0].translate(Point2LL(200, 0)); ASSERT_EQ(PolygonUtils::relativeHammingDistance(test_squares, shifted_polys), 1.0); @@ -456,7 +456,7 @@ TEST_F(PolygonUtilsTest, RelativeHammingDisjunct) TEST_F(PolygonUtilsTest, RelativeHammingHalfOverlap) { - Polygons shifted_polys = test_squares; // Make a copy. + Shape shifted_polys = test_squares; // Make a copy. shifted_polys[0].translate(Point2LL(50, 0)); ASSERT_EQ(PolygonUtils::relativeHammingDistance(test_squares, shifted_polys), 0.5); @@ -469,7 +469,7 @@ TEST_F(PolygonUtilsTest, RelativeHammingHalfOverlap) */ TEST_F(PolygonUtilsTest, RelativeHammingQuarterOverlap) { - Polygons shifted_polys = test_squares; // Make a copy. + Shape shifted_polys = test_squares; // Make a copy. shifted_polys[0].translate(Point2LL(50, 50)); ASSERT_EQ(PolygonUtils::relativeHammingDistance(test_squares, shifted_polys), 0.75); @@ -506,7 +506,7 @@ TEST_F(PolygonUtilsTest, TEST_F(PolygonUtilsTest, RelativeHammingLineLineDisjunct) { - Polygons shifted_line = test_line; // Make a copy. + Shape shifted_line = test_line; // Make a copy. shifted_line[0].translate(Point2LL(0, 1)); ASSERT_EQ(PolygonUtils::relativeHammingDistance(test_line, test_line), 1.0); From b6c95854703dacecfa137dcfa17b3416674580d6 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 16 Feb 2024 15:12:00 +0100 Subject: [PATCH 007/135] Use references when possible/useful CURA-9830 --- include/geometry/generic_closed_polyline.h | 4 ++-- include/geometry/point3_matrix.h | 6 +++--- include/geometry/point_matrix.h | 6 +++--- include/geometry/polygon.h | 22 +++++++++++----------- src/geometry/polygon.cpp | 22 +++++++++++----------- src/geometry/shape.cpp | 4 ++-- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/include/geometry/generic_closed_polyline.h b/include/geometry/generic_closed_polyline.h index 55ff0fd5a4..f8ab8322f5 100644 --- a/include/geometry/generic_closed_polyline.h +++ b/include/geometry/generic_closed_polyline.h @@ -61,7 +61,7 @@ class GenericClosedPolyline : public Polyline * * http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/PointInPolygon.htm */ - bool inside(Point2LL p, bool border_result = false) const; + bool inside(const Point2LL& p, bool border_result = false) const; bool inside(const auto& polygon) const; }; @@ -70,7 +70,7 @@ class GenericClosedPolyline : public Polyline // Definitions of templated methods // ########################################################### template -bool GenericClosedPolyline::inside(Point2LL p, bool border_result) const +bool GenericClosedPolyline::inside(const Point2LL& p, bool border_result) const { int res = ClipperLib::PointInPolygon(p, *this); if (res == -1) diff --git a/include/geometry/point3_matrix.h b/include/geometry/point3_matrix.h index ce7447cd61..1d6ad31201 100644 --- a/include/geometry/point3_matrix.h +++ b/include/geometry/point3_matrix.h @@ -45,7 +45,7 @@ class Point3Matrix matrix[8] = 1; } - Point3LL apply(const Point3LL p) const + Point3LL apply(const Point3LL& p) const { const double x = static_cast(p.x_); const double y = static_cast(p.y_); @@ -59,13 +59,13 @@ class Point3Matrix /*! * Apply matrix to vector as homogeneous coordinates. */ - Point2LL apply(const Point2LL p) const + Point2LL apply(const Point2LL& p) const { Point3LL result = apply(Point3LL(p.X, p.Y, 1)); return Point2LL(result.x_ / result.z_, result.y_ / result.z_); } - static Point3Matrix translate(const Point2LL p) + static Point3Matrix translate(const Point2LL& p) { Point3Matrix ret; // uniform matrix ret.matrix[2] = static_cast(p.X); diff --git a/include/geometry/point_matrix.h b/include/geometry/point_matrix.h index 4f3c348414..381cda6264 100644 --- a/include/geometry/point_matrix.h +++ b/include/geometry/point_matrix.h @@ -32,7 +32,7 @@ class PointMatrix matrix[3] = matrix[0]; } - PointMatrix(const Point2LL p) + PointMatrix(const Point2LL& p) { matrix[0] = static_cast(p.X); matrix[1] = static_cast(p.Y); @@ -51,7 +51,7 @@ class PointMatrix return ret; } - Point2LL apply(const Point2LL p) const + Point2LL apply(const Point2LL& p) const { const double x = static_cast(p.X); const double y = static_cast(p.Y); @@ -61,7 +61,7 @@ class PointMatrix /*! * \warning only works on a rotation matrix! Output is incorrect for other types of matrix */ - Point2LL unapply(const Point2LL p) const + Point2LL unapply(const Point2LL& p) const { const double x = static_cast(p.X); const double y = static_cast(p.Y); diff --git a/include/geometry/polygon.h b/include/geometry/polygon.h index b06e286e12..7880959441 100644 --- a/include/geometry/polygon.h +++ b/include/geometry/polygon.h @@ -108,15 +108,15 @@ class Polygon : public GenericClosedPolyline * \param cos_angle The cosine on the angle in L 012 */ static void smooth_corner_simple( - const Point2LL p0, - const Point2LL p1, - const Point2LL p2, - const ListPolyIt p0_it, - const ListPolyIt p1_it, - const ListPolyIt p2_it, - const Point2LL v10, - const Point2LL v12, - const Point2LL v02, + const Point2LL& p0, + const Point2LL& p1, + const Point2LL& p2, + const ListPolyIt& p0_it, + const ListPolyIt& p1_it, + const ListPolyIt& p2_it, + const Point2LL& v10, + const Point2LL& v12, + const Point2LL& v02, const int64_t shortcut_length, double cos_angle); @@ -134,7 +134,7 @@ class Polygon : public GenericClosedPolyline * \param shortcut_length The desired length ofthe shortcutting line * \return Whether this whole polygon whould be removed by the smoothing */ - static bool smooth_corner_complex(const Point2LL p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length); + static bool smooth_corner_complex(const Point2LL& p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length); /*! * Try to take a step away from the corner point in order to take a bigger shortcut. @@ -153,7 +153,7 @@ class Polygon : public GenericClosedPolyline * \param[in,out] backward_is_too_far Whether trying another step backward is blocked by the shortcut length condition. Updated for the next iteration. */ static void smooth_outward_step( - const Point2LL p1, + const Point2LL& p1, const int64_t shortcut_length2, ListPolyIt& p0_it, ListPolyIt& p2_it, diff --git a/src/geometry/polygon.cpp b/src/geometry/polygon.cpp index 67e6db362b..d5211f4e99 100644 --- a/src/geometry/polygon.cpp +++ b/src/geometry/polygon.cpp @@ -230,15 +230,15 @@ void Polygon::smooth_outward(const AngleDegrees min_angle, int shortcut_length, } void Polygon::smooth_corner_simple( - const Point2LL p0, - const Point2LL p1, - const Point2LL p2, - const ListPolyIt p0_it, - const ListPolyIt p1_it, - const ListPolyIt p2_it, - const Point2LL v10, - const Point2LL v12, - const Point2LL v02, + const Point2LL& p0, + const Point2LL& p1, + const Point2LL& p2, + const ListPolyIt& p0_it, + const ListPolyIt& p1_it, + const ListPolyIt& p2_it, + const Point2LL& v10, + const Point2LL& v12, + const Point2LL& v02, const int64_t shortcut_length, double cos_angle) { @@ -331,7 +331,7 @@ void Polygon::smooth_corner_simple( } void Polygon::smooth_outward_step( - const Point2LL p1, + const Point2LL& p1, const int64_t shortcut_length2, ListPolyIt& p0_it, ListPolyIt& p2_it, @@ -395,7 +395,7 @@ void Polygon::smooth_outward_step( } } -bool Polygon::smooth_corner_complex(const Point2LL p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length) +bool Polygon::smooth_corner_complex(const Point2LL& p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length) { // walk away from the corner until the shortcut > shortcut_length or it would smooth a piece inward // - walk in both directions untill shortcut > shortcut_length diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index a1b7b86b68..e7e04746cd 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -147,7 +147,7 @@ void Shape::add(const Shape& other) std::copy(other.begin(), other.end(), std::back_inserter(*this)); } -bool Shape::inside(Point2LL p, bool border_result) const +bool Shape::inside(const Point2LL& p, bool border_result) const { int poly_count_inside = 0; for (const ClipperLib::Path& poly : *this) @@ -162,7 +162,7 @@ bool Shape::inside(Point2LL p, bool border_result) const return (poly_count_inside % 2) == 1; } -size_t Shape::findInside(Point2LL p, bool border_result) const +size_t Shape::findInside(const Point2LL& p, bool border_result) const { if (size() < 1) { From a0fa9ca06013582f19b1dac32993e6ca51d7f422 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Fri, 16 Feb 2024 14:12:34 +0000 Subject: [PATCH 008/135] Applied clang-format. --- include/InsetOrderOptimizer.h | 2 +- include/SupportInfillPart.h | 2 +- include/infill/LightningGenerator.h | 15 ++++++------ include/pathPlanning/Comb.h | 2 +- include/sliceDataStorage.h | 10 ++++---- include/support.h | 3 +-- include/utils/polygonUtils.h | 3 +-- src/FffGcodeWriter.cpp | 7 ++---- src/geometry/lines_set.cpp | 2 +- src/raft.cpp | 4 ++-- src/sliceDataStorage.cpp | 12 ++++++---- src/support.cpp | 36 +++++++++++++---------------- 12 files changed, 45 insertions(+), 53 deletions(-) diff --git a/include/InsetOrderOptimizer.h b/include/InsetOrderOptimizer.h index a7a08a63f9..b96852478d 100644 --- a/include/InsetOrderOptimizer.h +++ b/include/InsetOrderOptimizer.h @@ -109,7 +109,7 @@ class InsetOrderOptimizer std::vector> inset_polys_; // vector of vectors holding the inset polygons Shape retraction_region_; // After printing an outer wall, move into this region so that retractions do not leave visible blobs. Calculated lazily if needed (see - // retraction_region_calculated). + // retraction_region_calculated). /*! * Determine if the paths should be reversed diff --git a/include/SupportInfillPart.h b/include/SupportInfillPart.h index 74ca7a065d..ff73156d73 100644 --- a/include/SupportInfillPart.h +++ b/include/SupportInfillPart.h @@ -31,7 +31,7 @@ class SupportInfillPart coord_t support_line_width_; //!< The support line width int inset_count_to_generate_; //!< The number of insets need to be generated from the outline. This is not the actual insets that will be generated. std::vector> infill_area_per_combine_per_density_; //!< a list of separated sub-areas which requires different infill densities and combined thicknesses - // for infill_areas[x][n], x means the density level and n means the thickness + // for infill_areas[x][n], x means the density level and n means the thickness std::vector wall_toolpaths_; //!< Any walls go here, not in the areas, where they could be combined vertically (don't combine walls). Binned by inset_idx. coord_t custom_line_distance_; //!< The distance between support infill lines. 0 means use the default line distance instead. diff --git a/include/infill/LightningGenerator.h b/include/infill/LightningGenerator.h index 2cae273cbd..0d6ff88552 100644 --- a/include/infill/LightningGenerator.h +++ b/include/infill/LightningGenerator.h @@ -1,18 +1,17 @@ -//Copyright (c) 2021 Ultimaker B.V. -//CuraEngine is released under the terms of the AGPLv3 or higher. +// Copyright (c) 2021 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef LIGHTNING_GENERATOR_H #define LIGHTNING_GENERATOR_H -#include "LightningLayer.h" - -#include "../utils/polygonUtils.h" - #include #include #include -namespace cura +#include "../utils/polygonUtils.h" +#include "LightningLayer.h" + +namespace cura { class SliceMeshStorage; @@ -33,7 +32,7 @@ class SliceMeshStorage; * Printing of Hollowed Objects" by Tricard, Claux and Lefebvre: * https://www.researchgate.net/publication/333808588_Ribbed_Support_Vaults_for_3D_Printing_of_Hollowed_Objects */ -class LightningGenerator // "Just like Nicola used to make!" +class LightningGenerator // "Just like Nicola used to make!" { public: /*! diff --git a/include/pathPlanning/Comb.h b/include/pathPlanning/Comb.h index 0104d16f61..6d6802b10b 100644 --- a/include/pathPlanning/Comb.h +++ b/include/pathPlanning/Comb.h @@ -143,7 +143,7 @@ class Comb std::unique_ptr inside_loc_to_line_minimum_; //!< The SparsePointGridInclusive mapping locations to line segments of the inner boundary. std::unique_ptr inside_loc_to_line_optimal_; //!< The SparsePointGridInclusive mapping locations to line segments of the inner boundary. std::unordered_map boundary_outside_; //!< The boundary outside of which to stay to avoid collision with other layer parts. This is a pointer cause we only - //!< compute it when we move outside the boundary (so not when there is only a single part in the layer) + //!< compute it when we move outside the boundary (so not when there is only a single part in the layer) std::unordered_map model_boundary_; //!< The boundary of the model itself std::unordered_map> outside_loc_to_line_; //!< The SparsePointGridInclusive mapping locations to line segments of the outside boundary. std::unordered_map> diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 6b987c636a..2082f71234 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -65,7 +65,7 @@ class SliceLayerPart //!< a cross-section of the 3D model. The first polygon is the outer boundary polygon and the //!< rest are holes. Shape print_outline; //!< An approximation to the outline of what's actually printed, based on the outer wall. - //!< Too small parts will be omitted compared to the outline. + //!< Too small parts will be omitted compared to the outline. Shape spiral_wall; //!< The centerline of the wall used by spiralize mode. Only computed if spiralize mode is enabled. Shape inner_area; //!< The area of the outline, minus the walls. This will be filled with either skin or infill. std::vector skin_parts; //!< The skin parts which are filled for 100% with lines and/or insets. @@ -214,9 +214,9 @@ class SupportLayer std::vector support_infill_parts; //!< a list of support infill parts Shape support_bottom; //!< Piece of support below the support and above the model. This must not overlap with any of the support_infill_parts or support_roof. Shape support_roof; //!< Piece of support above the support and below the model. This must not overlap with any of the support_infill_parts or support_bottom. - // NOTE: This is _all_ of the support_roof, and as such, overlaps with support_fractional_roof! + // NOTE: This is _all_ of the support_roof, and as such, overlaps with support_fractional_roof! Shape support_fractional_roof; //!< If the support distance is not exactly a multiple of the layer height, - // the first part of support just underneath the model needs to be printed at a fracional layer height. + // the first part of support just underneath the model needs to be printed at a fracional layer height. Shape support_mesh_drop_down; //!< Areas from support meshes which should be supported by more support Shape support_mesh; //!< Areas from support meshes which should NOT be supported by more support Shape anti_overhang; //!< Areas where no overhang should be detected. @@ -286,9 +286,9 @@ class SliceMeshStorage std::vector skin_angles; //!< a list of angle values which is cycled through to determine the skin angle of each layer std::vector overhang_areas; //!< For each layer the areas that are classified as overhang on this mesh. std::vector full_overhang_areas; //!< For each layer the full overhang without the tangent of the overhang angle removed, such that the overhang area adjoins the - //!< areas of the next layers. + //!< areas of the next layers. std::vector> overhang_points; //!< For each layer a list of points where point-overhang is detected. This is overhang that hasn't got any surface area, - //!< such as a corner pointing downwards. + //!< such as a corner pointing downwards. AABB3D bounding_box; //!< the mesh's bounding box std::shared_ptr base_subdiv_cube; diff --git a/include/support.h b/include/support.h index 9d9eb71725..36412b4dcb 100644 --- a/include/support.h +++ b/include/support.h @@ -74,8 +74,7 @@ class AreaSupport * \param global_support_areas_per_layer the global support areas per layer * \param total_layer_count total number of layers */ - static void - splitGlobalSupportAreasIntoSupportInfillParts(SliceDataStorage& storage, const std::vector& global_support_areas_per_layer, unsigned int total_layer_count); + static void splitGlobalSupportAreasIntoSupportInfillParts(SliceDataStorage& storage, const std::vector& global_support_areas_per_layer, unsigned int total_layer_count); /*! * Generate gradual support on the already generated support areas. This must be called after generateSupportAreas(). diff --git a/include/utils/polygonUtils.h b/include/utils/polygonUtils.h index 2bf7431d6d..ce98eddfb6 100644 --- a/include/utils/polygonUtils.h +++ b/include/utils/polygonUtils.h @@ -597,8 +597,7 @@ class PolygonUtils * \return whether the line segment collides with the boundary of the * polygon(s) */ - static bool - polygonCollidesWithLineSegment(const Shape& polys, const Point2LL& transformed_startPoint, const Point2LL& transformed_endPoint, PointMatrix transformation_matrix); + static bool polygonCollidesWithLineSegment(const Shape& polys, const Point2LL& transformed_startPoint, const Point2LL& transformed_endPoint, PointMatrix transformation_matrix); /*! * Checks whether a given line segment collides with a given polygon(s). diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index fa97716b73..fe28ec5e74 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3539,11 +3539,8 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer } -bool FffGcodeWriter::addSupportRoofsToGCode( - const SliceDataStorage& storage, - const Shape& support_roof_outlines, - const GCodePathConfig& current_roof_config, - LayerPlan& gcode_layer) const +bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, const Shape& support_roof_outlines, const GCodePathConfig& current_roof_config, LayerPlan& gcode_layer) + const { const SupportLayer& support_layer = storage.support.supportLayers[std::max(LayerIndex{ 0 }, gcode_layer.getLayerNr())]; diff --git a/src/geometry/lines_set.cpp b/src/geometry/lines_set.cpp index 0291e9c305..8bd1ddac3f 100644 --- a/src/geometry/lines_set.cpp +++ b/src/geometry/lines_set.cpp @@ -7,8 +7,8 @@ #include "geometry/open_polyline.h" #include "geometry/polygon.h" -#include "geometry/shape.h" #include "geometry/polyline_type.h" +#include "geometry/shape.h" namespace cura { diff --git a/src/raft.cpp b/src/raft.cpp index 0266366ec2..e94e220125 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -50,8 +50,8 @@ void Raft::generate(SliceDataStorage& storage) { const Shape& ooze_shield = storage.oozeShield[0]; Shape ooze_shield_raft = ooze_shield - .offset(shield_line_width_layer0) // start half a line width outside shield - .difference(ooze_shield.offset(-max_raft_distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield + .offset(shield_line_width_layer0) // start half a line width outside shield + .difference(ooze_shield.offset(-max_raft_distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield storage.raftBaseOutline = storage.raftBaseOutline.unionPolygons(ooze_shield_raft); storage.raftSurfaceOutline = storage.raftSurfaceOutline.unionPolygons(ooze_shield_raft); storage.raftInterfaceOutline = storage.raftInterfaceOutline.unionPolygons(ooze_shield_raft); diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index fba4619210..8dca3ad05b 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -266,9 +266,12 @@ SliceDataStorage::SliceDataStorage() machine_size.include(machine_max); } -Shape - SliceDataStorage::getLayerOutlines(const LayerIndex layer_nr, const bool include_support, const bool include_prime_tower, const bool external_polys_only, const int extruder_nr) - const +Shape SliceDataStorage::getLayerOutlines( + const LayerIndex layer_nr, + const bool include_support, + const bool include_prime_tower, + const bool external_polys_only, + const int extruder_nr) const { const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; @@ -759,8 +762,7 @@ void SupportLayer::fillInfillParts( const coord_t custom_line_distance /*has default 0*/) { const Shape& support_this_layer = support_fill_per_layer[layer_nr]; - const Shape& support_layer_above - = (layer_nr + 1) >= support_fill_per_layer.size() || layer_nr <= 0 ? Shape() : support_fill_per_layer[layer_nr + 1].offset(grow_layer_above); + const Shape& support_layer_above = (layer_nr + 1) >= support_fill_per_layer.size() || layer_nr <= 0 ? Shape() : support_fill_per_layer[layer_nr + 1].offset(grow_layer_above); const auto all_support_areas_in_layer = { support_this_layer.difference(support_layer_above), support_this_layer.intersection(support_layer_above) }; bool use_fractional_config = true; for (auto& support_areas : all_support_areas_in_layer) diff --git a/src/support.cpp b/src/support.cpp index af3b41cc01..5b75e58f27 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -75,10 +75,7 @@ bool AreaSupport::handleSupportModifierMesh(SliceDataStorage& storage, const Set } -void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts( - SliceDataStorage& storage, - const std::vector& global_support_areas_per_layer, - unsigned int total_layer_count) +void AreaSupport::splitGlobalSupportAreasIntoSupportInfillParts(SliceDataStorage& storage, const std::vector& global_support_areas_per_layer, unsigned int total_layer_count) { if (total_layer_count == 0) { @@ -950,13 +947,13 @@ Shape AreaSupport::generateVaryingXYDisallowedArea(const SliceMeshStorage& stora const auto smooth_dist = xy_distance / 2.0; Shape varying_xy_disallowed_areas = layer_current - // offset using the varying offset distances we calculated previously - .offsetMulti(varying_offsets) - // close operation to smooth the x/y disallowed area boundary. With varying xy distances we see some jumps in the boundary. - // As the x/y disallowed areas "cut in" to support the xy-disallowed area may propagate through the support area. If the - // x/y disallowed area is not smoothed boost has trouble generating a voronoi diagram. - .offset(smooth_dist) - .offset(-smooth_dist); + // offset using the varying offset distances we calculated previously + .offsetMulti(varying_offsets) + // close operation to smooth the x/y disallowed area boundary. With varying xy distances we see some jumps in the boundary. + // As the x/y disallowed areas "cut in" to support the xy-disallowed area may propagate through the support area. If the + // x/y disallowed area is not smoothed boost has trouble generating a voronoi diagram. + .offset(smooth_dist) + .offset(-smooth_dist); scripta::log("support_varying_xy_disallowed_areas", varying_xy_disallowed_areas, SectionType::SUPPORT, layer_idx); return varying_xy_disallowed_areas; } @@ -1158,8 +1155,7 @@ void AreaSupport::generateSupportAreasForMesh( { // join with support from layer up const Shape empty; const Shape* layer_above = (layer_idx < support_areas.size()) ? &support_areas[layer_idx + 1] : ∅ - const Shape model_mesh_on_layer - = (layer_idx > 0) && ! is_support_mesh_nondrop_place_holder ? storage.getLayerOutlines(layer_idx, no_support, no_prime_tower) : empty; + const Shape model_mesh_on_layer = (layer_idx > 0) && ! is_support_mesh_nondrop_place_holder ? storage.getLayerOutlines(layer_idx, no_support, no_prime_tower) : empty; if (is_support_mesh_nondrop_place_holder) { layer_above = ∅ @@ -1469,8 +1465,8 @@ std::pair AreaSupport::computeBasicAndFullOverhang(const SliceData } Shape overhang_extended = basic_overhang - // +0.1mm for easier joining with support from layer above - .offset(max_dist_from_lower_layer * layers_below + MM2INT(0.1)); + // +0.1mm for easier joining with support from layer above + .offset(max_dist_from_lower_layer * layers_below + MM2INT(0.1)); Shape full_overhang = overhang_extended.intersection(outlines); return std::make_pair(basic_overhang, full_overhang); @@ -1572,11 +1568,11 @@ void AreaSupport::handleTowers( } for (Shape& tower_roof : tower_roofs - | ranges::views::filter( - [](const auto& poly) - { - return ! poly.empty(); - })) + | ranges::views::filter( + [](const auto& poly) + { + return ! poly.empty(); + })) { supportLayer_this = supportLayer_this.unionPolygons(tower_roof); From 98d12868ec1b1a6531f9bf8f3537bfc283530203 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 16 Feb 2024 15:23:28 +0100 Subject: [PATCH 009/135] Minor cleaning --- include/geometry/lines_set.h | 4 +--- include/geometry/points_set.h | 4 ++-- include/geometry/polyline.h | 6 ----- src/WallToolPaths.cpp | 4 ++-- src/WallsComputation.cpp | 2 +- src/geometry/lines_set.cpp | 6 ++--- src/geometry/shape.cpp | 43 ----------------------------------- src/slicer.cpp | 4 ++-- 8 files changed, 11 insertions(+), 62 deletions(-) diff --git a/include/geometry/lines_set.h b/include/geometry/lines_set.h index b9b2b67761..09157c7a75 100644 --- a/include/geometry/lines_set.h +++ b/include/geometry/lines_set.h @@ -117,11 +117,9 @@ class LinesSet : public std::vector * See \ref removeDegenerateVertsPolyline for a version that works on * polylines. */ -#warning rename this to removeDegenerateVerts - void removeDegenerateVertsForEveryone(); + void removeDegenerateVerts(); Shape offset(coord_t distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; - // Polygons offsetPolyLine(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, bool inputPolyIsClosed = false) const; /*! * Utility method for creating the tube (or 'donut') of a shape. diff --git a/include/geometry/points_set.h b/include/geometry/points_set.h index 7fd1e81caf..70214c088b 100644 --- a/include/geometry/points_set.h +++ b/include/geometry/points_set.h @@ -68,9 +68,9 @@ class PointsSet : public std::vector Point2LL closestPointTo(const Point2LL& p) const; /*! - * Translate the whole polygon in some direction. + * Translate all the points in some direction. * - * \param translation The direction in which to move the polygon + * \param translation The direction in which to move the points */ void translate(const Point2LL& translation); diff --git a/include/geometry/polyline.h b/include/geometry/polyline.h index bb2e9ea8ab..0ec9c65381 100644 --- a/include/geometry/polyline.h +++ b/include/geometry/polyline.h @@ -122,12 +122,6 @@ class Polyline : public PointsSet */ void simplify(const coord_t smallest_line_segment_squared = MM2INT(0.01) * MM2INT(0.01), const coord_t allowed_error_distance_squared = 25); - /*! - * See simplify(.) - */ -#warning This can probably be merge with simplify ? - void simplifyPolyline(const coord_t smallest_line_segment_squared = 100, const coord_t allowed_error_distance_squared = 25); - private: /*! * Private implementation for both simplify and simplifyPolygons. diff --git a/src/WallToolPaths.cpp b/src/WallToolPaths.cpp index 6b8f708366..da5d0f50ed 100644 --- a/src/WallToolPaths.cpp +++ b/src/WallToolPaths.cpp @@ -102,11 +102,11 @@ const std::vector& WallToolPaths::generate() } PolygonUtils::fixSelfIntersections(epsilon_offset, prepared_outline); - prepared_outline.removeDegenerateVertsForEveryone(); + prepared_outline.removeDegenerateVerts(); prepared_outline.removeColinearEdges(AngleRadians(0.005)); // Removing collinear edges may introduce self intersections, so we need to fix them again PolygonUtils::fixSelfIntersections(epsilon_offset, prepared_outline); - prepared_outline.removeDegenerateVertsForEveryone(); + prepared_outline.removeDegenerateVerts(); prepared_outline = prepared_outline.unionPolygons(); prepared_outline = Simplify(settings_).polygon(prepared_outline); diff --git a/src/WallsComputation.cpp b/src/WallsComputation.cpp index c6cde890b3..1d0b1380b9 100644 --- a/src/WallsComputation.cpp +++ b/src/WallsComputation.cpp @@ -127,7 +127,7 @@ void WallsComputation::generateSpiralInsets(SliceLayerPart* part, coord_t line_w // Optimize the wall. This prevents buffer underruns in the printer firmware, and reduces processing time in CuraEngine. const ExtruderTrain& train_wall = settings_.get("wall_0_extruder_nr"); part->spiral_wall = Simplify(train_wall.settings_).polygon(part->spiral_wall); - part->spiral_wall.removeDegenerateVertsForEveryone(); + part->spiral_wall.removeDegenerateVerts(); if (recompute_outline_based_on_outer_wall) { part->print_outline = part->spiral_wall.offset(line_width_0 / 2, ClipperLib::jtSquare); diff --git a/src/geometry/lines_set.cpp b/src/geometry/lines_set.cpp index 8bd1ddac3f..ace3190940 100644 --- a/src/geometry/lines_set.cpp +++ b/src/geometry/lines_set.cpp @@ -145,7 +145,7 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType } template -void LinesSet::removeDegenerateVertsForEveryone() +void LinesSet::removeDegenerateVerts() { constexpr bool for_polyline = LineType::type_ == PolylineType::Open; for (size_t poly_idx = 0; poly_idx < this->size(); poly_idx++) @@ -220,7 +220,7 @@ template LinesSet LinesSet::splitIntoSegments() cons template coord_t LinesSet::length() const; template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; template Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; -template void LinesSet::removeDegenerateVertsForEveryone(); +template void LinesSet::removeDegenerateVerts(); template void LinesSet::addIfNotEmpty(const OpenPolyline& line); template void LinesSet::addIfNotEmpty(OpenPolyline&& line); @@ -232,7 +232,7 @@ template LinesSet LinesSet::splitIntoSegments() const; template coord_t LinesSet::length() const; template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; template Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; -template void LinesSet::removeDegenerateVertsForEveryone(); +template void LinesSet::removeDegenerateVerts(); template void LinesSet::addIfNotEmpty(const Polygon& line); template void LinesSet::addIfNotEmpty(Polygon&& line); diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index e7e04746cd..058e0da8ff 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -467,49 +467,6 @@ void Shape::removeSmallAreas(const double min_area_size, const bool remove_holes resize(new_end - begin()); } -void Shape::removeSmallCircumference(const coord_t min_circumference_size, const bool remove_holes) -{ - removeSmallAreaCircumference(0.0, min_circumference_size, remove_holes); -} - -void Shape::removeSmallAreaCircumference(const double min_area_size, const coord_t min_circumference_size, const bool remove_holes) -{ - Shape new_polygon; - - bool outline_is_removed = false; - for (const Polygon& poly : (*this)) - { - double area = poly.area(); - auto circumference = poly.length(); - bool is_outline = area >= 0; - - if (is_outline) - { - if (circumference >= min_circumference_size && std::abs(area) >= min_area_size) - { - new_polygon.push_back(poly); - outline_is_removed = false; - } - else - { - outline_is_removed = true; - } - } - else if (outline_is_removed) - { - // containing parent outline is removed; hole should be removed as well - } - else if (! remove_holes || (circumference >= min_circumference_size && std::abs(area) >= min_area_size)) - { - // keep hole-polygon if we do not remove holes, or if its - // circumference is bigger then the minimum circumference size - new_polygon.push_back(poly); - } - } - - *this = new_polygon; -} - Shape Shape::removePolygon(const Shape& to_be_removed, int same_distance) const { Shape result; diff --git a/src/slicer.cpp b/src/slicer.cpp index f5ef5c3882..b0197d95e0 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -789,7 +789,7 @@ void SlicerLayer::makePolygons(const Mesh* mesh) mesh->settings_.get("meshfix_maximum_resolution"), mesh->settings_.get("meshfix_maximum_deviation"), static_cast(mesh->settings_.get("meshfix_maximum_extrusion_area_deviation"))); - polygons.removeDegenerateVertsForEveryone(); // remove verts connected to overlapping line segments + polygons.removeDegenerateVerts(); // remove verts connected to overlapping line segments // Clean up polylines for Surface Mode printing auto itPolylines = std::remove_if( @@ -801,7 +801,7 @@ void SlicerLayer::makePolygons(const Mesh* mesh) }); openPolylines.erase(itPolylines, openPolylines.end()); - openPolylines.removeDegenerateVertsForEveryone(); + openPolylines.removeDegenerateVerts(); } Slicer::Slicer(Mesh* i_mesh, const coord_t thickness, const size_t slice_layer_count, bool use_variable_layer_heights, std::vector* adaptive_layers) From fdba35a8ad244235a7b4d2c34421d57a09820933 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 16 Feb 2024 15:59:43 +0100 Subject: [PATCH 010/135] Prepare for explicit constructors --- src/bridge.cpp | 14 ++++++-------- src/multiVolumes.cpp | 3 ++- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/bridge.cpp b/src/bridge.cpp index 69b20a9280..dba4aeb043 100644 --- a/src/bridge.cpp +++ b/src/bridge.cpp @@ -127,7 +127,7 @@ double bridgeAngle( { if (! poly.empty()) { - skin_perimeter_lines.emplace_back(poly); + skin_perimeter_lines.push_back(poly.toType()); } } @@ -138,19 +138,17 @@ double bridgeAngle( // one or more edges of the skin region are unsupported, determine the longest coord_t max_dist2 = 0; double line_angle = -1; - for (const Polygon& air_line : skin_perimeter_lines_over_air) + for (const OpenPolyline& air_line : skin_perimeter_lines_over_air) { - Point2LL p0 = air_line[0]; - for (unsigned i = 1; i < air_line.size(); ++i) + for (auto iterator = air_line.beginSegments(); iterator != air_line.endSegments(); ++iterator) { - const Point2LL& p1(air_line[i]); - coord_t dist2 = vSize2(p0 - p1); + const Point2LL vector = (*iterator).start - (*iterator).end; + coord_t dist2 = vSize2(vector); if (dist2 > max_dist2) { max_dist2 = dist2; - line_angle = angle(p0 - p1); + line_angle = angle(vector); } - p0 = p1; } } return line_angle; diff --git a/src/multiVolumes.cpp b/src/multiVolumes.cpp index a43c7612e4..41291c34f6 100644 --- a/src/multiVolumes.cpp +++ b/src/multiVolumes.cpp @@ -135,8 +135,9 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: // they have to be polylines, because they might break up further when doing the cutting for (Polygon& poly : cutting_mesh_polygons) { +#warning this should not be required poly.push_back(poly[0]); - cutting_mesh_polylines.push_back(poly); + cutting_mesh_polylines.push_back(poly.toType()); } cutting_mesh_polygons.clear(); From 9c6c33336c0a09cb95842e7ec375e4bb7816e661 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 16 Feb 2024 16:25:50 +0100 Subject: [PATCH 011/135] Remove classes friendness. They are not supposed to like each other. CURA-9830 --- include/geometry/generic_closed_polyline.h | 2 -- include/geometry/polygon.h | 2 -- include/geometry/polyline.h | 2 -- 3 files changed, 6 deletions(-) diff --git a/include/geometry/generic_closed_polyline.h b/include/geometry/generic_closed_polyline.h index f8ab8322f5..bb1cc916a6 100644 --- a/include/geometry/generic_closed_polyline.h +++ b/include/geometry/generic_closed_polyline.h @@ -14,8 +14,6 @@ namespace cura template class GenericClosedPolyline : public Polyline { - friend class Polygons; - public: GenericClosedPolyline() = default; diff --git a/include/geometry/polygon.h b/include/geometry/polygon.h index 7880959441..ea8e1ebe09 100644 --- a/include/geometry/polygon.h +++ b/include/geometry/polygon.h @@ -15,8 +15,6 @@ class AngleDegrees; class Polygon : public GenericClosedPolyline { - friend class Shape; - public: Polygon() = default; diff --git a/include/geometry/polyline.h b/include/geometry/polyline.h index 0ec9c65381..6b750538e0 100644 --- a/include/geometry/polyline.h +++ b/include/geometry/polyline.h @@ -19,8 +19,6 @@ class AngleRadians; template class Polyline : public PointsSet { - friend class Polygons; - public: static constexpr PolylineType type_ = PolylineTypeVal; From f94e0125c375d82165ecab2416d307c25b64b04a Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 16 Feb 2024 16:56:14 +0100 Subject: [PATCH 012/135] Code documentation CURA-9830 --- include/geometry/lines_set.h | 19 ++++++++---- include/geometry/points_set.h | 11 +++++++ include/geometry/polyline.h | 19 ++++++++++++ include/utils/ExtrusionLine.h | 2 +- src/geometry/lines_set.cpp | 10 +++---- src/geometry/polygon.cpp | 4 +-- src/geometry/shape.cpp | 56 +++++++++++++++++------------------ src/utils/polygonUtils.cpp | 4 +-- 8 files changed, 81 insertions(+), 44 deletions(-) diff --git a/include/geometry/lines_set.h b/include/geometry/lines_set.h index 09157c7a75..eabdb9284f 100644 --- a/include/geometry/lines_set.h +++ b/include/geometry/lines_set.h @@ -16,6 +16,14 @@ class OpenPolyline; template class LinesSet; +/*! + * \brief Base class for all geometry containers representing a set of polylines. All the polylines + * have to be of the same type, e.g. open polylines. Due to the nature of the Polyline + * classes, it is possible to cast a LinesSet directly to a + * std::vector> so that we can call the Clipper functions + * which having to do an active data conversion. It is also possible to virtually change the + * inner type of lines without having to do a conversion. + */ template class LinesSet : public std::vector { @@ -56,20 +64,19 @@ class LinesSet : public std::vector template const LinesSet& toType() const { + // This does work as long as we don't add any attribute to the PointsSet class or any of its child return *reinterpret_cast*>(this); } - const std::vector>& getCallable() const + const std::vector>& asRawVector() const { - // This does work as long as we don't add any attribute to the Polygon class or any of its - // parent until std::vector + // This does work as long as we don't add any attribute to the PointsSet class or any of its child return *reinterpret_cast>*>(this); } - std::vector>& getCallable() + std::vector>& asRawVector() { - // This does work as long as we don't add any attribute to the Polygon class or any of its - // parent until std::vector + // This does work as long as we don't add any attribute to the PointsSet class or any of its child return *reinterpret_cast>*>(this); } diff --git a/include/geometry/points_set.h b/include/geometry/points_set.h index 70214c088b..78814e4382 100644 --- a/include/geometry/points_set.h +++ b/include/geometry/points_set.h @@ -34,6 +34,15 @@ bool shorterThan(const T& shape, const coord_t check_length) return true; } +/*! + * \brief Base class for all geometry containers representing a set of points. + * \warning This class and all its subclasses must not contain any attribute. This way the memory + * footprint of all the objects is the same whatever their type, which allows us to + * directly cast them between each other, and also most important, into + * std::vector which is the base type required by ClipperLib. This gives us the + * possibility to have nice container with transformation methods, and call the Clipper + * functions directly on them without having to make any active data conversion. + */ class PointsSet : public std::vector { public: @@ -53,11 +62,13 @@ class PointsSet : public std::vector const std::vector& asRawVector() const { + // This does work as long as we don't add any attribute to the PointsSet class or any of its child return *reinterpret_cast*>(this); } std::vector& asRawVector() { + // This does work as long as we don't add any attribute to the PointsSet class or any of its child return *reinterpret_cast*>(this); } diff --git a/include/geometry/polyline.h b/include/geometry/polyline.h index 6b750538e0..44bbbc48dc 100644 --- a/include/geometry/polyline.h +++ b/include/geometry/polyline.h @@ -16,6 +16,25 @@ template class LinesSet; class AngleRadians; +/*! + * \brief Base class for various types of polylines. A polyline is basically a set of points, but + * we geometrically interpret them forming a chain of segments between each other. + * + * * Open Polyline : this represents a line that does not closes, i.e. the last point is different + * from the initial point + * * Closed Polyline : a closed polyline as a final segment joining the last point and the + * initial one + * * Filled Polyline : this is a particular type of closed polyline, for which we consider that the + * "inside" part of the line forms a surface + * + * Due to the nature of the PointsSet class, it is possible to cast e.g. an open polyline to a + * closed polyline. This only changes whether the last point forms a segment with the initial one, + * but the list of points itself does not change. + * + * \note Historically, the open and closed polylines were not explicitely differenciated, so + * sometimes we would use an open polyline with an extra point at the end, which virtually + * closes the line. This behaviour is now deprecated and should be removed over time. + */ template class Polyline : public PointsSet { diff --git a/include/utils/ExtrusionLine.h b/include/utils/ExtrusionLine.h index d977ddc5d1..9c60558552 100644 --- a/include/utils/ExtrusionLine.h +++ b/include/utils/ExtrusionLine.h @@ -262,7 +262,7 @@ struct ExtrusionLine Shape paths; paths.emplace_back(poly); - ClipperLib::SimplifyPolygons(paths.getCallable(), ClipperLib::pftNonZero); + ClipperLib::SimplifyPolygons(paths.asRawVector(), ClipperLib::pftNonZero); return paths; } diff --git a/src/geometry/lines_set.cpp b/src/geometry/lines_set.cpp index ace3190940..480b123a65 100644 --- a/src/geometry/lines_set.cpp +++ b/src/geometry/lines_set.cpp @@ -112,17 +112,17 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType { if (distance == 0) { - return Shape(getCallable()); + return Shape(asRawVector()); } Shape temp; - const ClipperLib::Paths* actual_polygons = &getCallable(); + const ClipperLib::Paths* actual_polygons = &asRawVector(); Shape ret; ClipperLib::EndType end_type; if constexpr (LineType::type_ == PolylineType::Filled) { - temp = Shape(getCallable()).unionPolygons(); - actual_polygons = &temp.getCallable(); + temp = Shape(asRawVector()).unionPolygons(); + actual_polygons = &temp.asRawVector(); end_type = ClipperLib::etClosedPolygon; } else if constexpr (LineType::type_ == PolylineType::Closed) @@ -140,7 +140,7 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType ClipperLib::ClipperOffset clipper(miter_limit, 10.0); clipper.AddPaths(*actual_polygons, joinType, end_type); clipper.MiterLimit = miter_limit; - clipper.Execute(ret.getCallable(), distance); + clipper.Execute(ret.asRawVector(), distance); return ret; } diff --git a/src/geometry/polygon.cpp b/src/geometry/polygon.cpp index d5211f4e99..b0a01cb362 100644 --- a/src/geometry/polygon.cpp +++ b/src/geometry/polygon.cpp @@ -37,7 +37,7 @@ Shape Polygon::intersection(const Polygon& other) const ClipperLib::Clipper clipper(clipper_init); clipper.AddPath(*this, ClipperLib::ptSubject, true); clipper.AddPath(other, ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctIntersection, ret.getCallable()); + clipper.Execute(ClipperLib::ctIntersection, ret.asRawVector()); return ret; } @@ -624,7 +624,7 @@ Shape Polygon::offset(int distance, ClipperLib::JoinType join_type, double miter ClipperLib::ClipperOffset clipper(miter_limit, 10.0); clipper.AddPath(*this, join_type, ClipperLib::etClosedPolygon); clipper.MiterLimit = miter_limit; - clipper.Execute(ret.getCallable(), distance); + clipper.Execute(ret.asRawVector(), distance); return ret; } diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index 058e0da8ff..0058303627 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -40,7 +40,7 @@ Shape Shape::approxConvexHull(int extra_outset) const Shape offset_result; ClipperLib::ClipperOffset offsetter(1.2, 10.0); offsetter.AddPath(path, ClipperLib::jtRound, ClipperLib::etClosedPolygon); - offsetter.Execute(offset_result.getCallable(), overshoot); + offsetter.Execute(offset_result.asRawVector(), overshoot); convex_hull.add(offset_result); } @@ -104,9 +104,9 @@ Shape Shape::difference(const Shape& other) const { Shape ret; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); - clipper.AddPaths(other.getCallable(), ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctDifference, ret.getCallable()); + clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); + clipper.AddPaths(other.asRawVector(), ClipperLib::ptClip, true); + clipper.Execute(ClipperLib::ctDifference, ret.asRawVector()); return ret; } @@ -114,9 +114,9 @@ Shape Shape::unionPolygons(const Shape& other, ClipperLib::PolyFillType fill_typ { Shape ret; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); - clipper.AddPaths(other.getCallable(), ClipperLib::ptSubject, true); - clipper.Execute(ClipperLib::ctUnion, ret.getCallable(), fill_type, fill_type); + clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); + clipper.AddPaths(other.asRawVector(), ClipperLib::ptSubject, true); + clipper.Execute(ClipperLib::ctUnion, ret.asRawVector(), fill_type, fill_type); return ret; } @@ -124,9 +124,9 @@ Shape Shape::intersection(const Shape& other) const { Shape ret; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); - clipper.AddPaths(other.getCallable(), ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctIntersection, ret.getCallable()); + clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); + clipper.AddPaths(other.asRawVector(), ClipperLib::ptClip, true); + clipper.Execute(ClipperLib::ctIntersection, ret.asRawVector()); return ret; } @@ -233,11 +233,11 @@ LinesSet Shape::intersectionPolyLines(const LinesSet ClipperLib::PolyTree result; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(split_polylines.getCallable(), ClipperLib::ptSubject, false); - clipper.AddPaths(getCallable(), ClipperLib::ptClip, true); + clipper.AddPaths(split_polylines.asRawVector(), ClipperLib::ptSubject, false); + clipper.AddPaths(asRawVector(), ClipperLib::ptClip, true); clipper.Execute(ClipperLib::ctIntersection, result); LinesSet ret; - ClipperLib::OpenPathsFromPolyTree(result, ret.getCallable()); + ClipperLib::OpenPathsFromPolyTree(result, ret.asRawVector()); if (restitch) { @@ -263,9 +263,9 @@ Shape Shape::xorPolygons(const Shape& other, ClipperLib::PolyFillType pft) const { Shape ret; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); - clipper.AddPaths(other.getCallable(), ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctXor, ret.getCallable(), pft); + clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); + clipper.AddPaths(other.asRawVector(), ClipperLib::ptClip, true); + clipper.Execute(ClipperLib::ctXor, ret.asRawVector(), pft); return ret; } @@ -273,8 +273,8 @@ Shape Shape::execute(ClipperLib::PolyFillType pft) const { Shape ret; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); - clipper.Execute(ClipperLib::ctXor, ret.getCallable(), pft); + clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); + clipper.Execute(ClipperLib::ctXor, ret.asRawVector(), pft); return ret; } /* @@ -332,7 +332,7 @@ Shape Shape::offsetMulti(const std::vector& offset_dists) const ret.push_back(ret_poly_line); } - ClipperLib::SimplifyPolygons(ret.getCallable(), ClipperLib::PolyFillType::pftPositive); + ClipperLib::SimplifyPolygons(ret.asRawVector(), ClipperLib::PolyFillType::pftPositive); return ret; } @@ -343,7 +343,7 @@ Shape Shape::getOutsidePolygons() const ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree poly_tree; constexpr bool paths_are_closed_polys = true; - clipper.AddPaths(getCallable(), ClipperLib::ptSubject, paths_are_closed_polys); + clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, paths_are_closed_polys); clipper.Execute(ClipperLib::ctUnion, poly_tree); for (int outer_poly_idx = 0; outer_poly_idx < poly_tree.ChildCount(); outer_poly_idx++) @@ -360,7 +360,7 @@ Shape Shape::removeEmptyHoles() const ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree poly_tree; constexpr bool paths_are_closed_polys = true; - clipper.AddPaths(getCallable(), ClipperLib::ptSubject, paths_are_closed_polys); + clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, paths_are_closed_polys); clipper.Execute(ClipperLib::ctUnion, poly_tree); bool remove_holes = true; @@ -374,7 +374,7 @@ Shape Shape::getEmptyHoles() const ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree poly_tree; constexpr bool paths_are_closed_polys = true; - clipper.AddPaths(getCallable(), ClipperLib::ptSubject, paths_are_closed_polys); + clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, paths_are_closed_polys); clipper.Execute(ClipperLib::ctUnion, poly_tree); bool remove_holes = false; @@ -523,15 +523,15 @@ Shape Shape::processEvenOdd(ClipperLib::PolyFillType poly_fill_type) const { Shape ret; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); - clipper.Execute(ClipperLib::ctUnion, ret.getCallable(), poly_fill_type); + clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); + clipper.Execute(ClipperLib::ctUnion, ret.asRawVector(), poly_fill_type); return ret; } Shape Shape::toPolygons(ClipperLib::PolyTree& poly_tree) { Shape ret; - ClipperLib::PolyTreeToPaths(poly_tree, ret.getCallable()); + ClipperLib::PolyTreeToPaths(poly_tree, ret.asRawVector()); return ret; } @@ -725,7 +725,7 @@ std::vector Shape::splitIntoParts(bool unionAll) const std::vector ret; ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree resultPolyTree; - clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); + clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); if (unionAll) clipper.Execute(ClipperLib::ctUnion, resultPolyTree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); else @@ -756,7 +756,7 @@ std::vector Shape::sortByNesting() const std::vector ret; ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree resultPolyTree; - clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); + clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); clipper.Execute(ClipperLib::ctUnion, resultPolyTree); sortByNesting_processPolyTreeNode(&resultPolyTree, 0, ret); @@ -783,7 +783,7 @@ PartsView Shape::splitIntoPartsView(bool unionAll) PartsView partsView(*this); ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree resultPolyTree; - clipper.AddPaths(getCallable(), ClipperLib::ptSubject, true); + clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); if (unionAll) clipper.Execute(ClipperLib::ctUnion, resultPolyTree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); else diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index 1f667741e0..8d5dc52c70 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -1487,7 +1487,7 @@ void PolygonUtils::fixSelfIntersections(const coord_t epsilon, Shape& polygon) { if (epsilon < 1) { - ClipperLib::SimplifyPolygons(polygon.getCallable()); + ClipperLib::SimplifyPolygons(polygon.asRawVector()); return; } @@ -1531,7 +1531,7 @@ void PolygonUtils::fixSelfIntersections(const coord_t epsilon, Shape& polygon) } } - ClipperLib::SimplifyPolygons(polygon.getCallable()); + ClipperLib::SimplifyPolygons(polygon.asRawVector()); } Shape PolygonUtils::unionManySmall(const Shape& polygon) From 8cb4323eec59163bb3e8547e5f825456a56e6226 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 16 Feb 2024 16:56:33 +0100 Subject: [PATCH 013/135] Add missing file CURA-9830 --- include/geometry/shape.h | 300 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 include/geometry/shape.h diff --git a/include/geometry/shape.h b/include/geometry/shape.h new file mode 100644 index 0000000000..9af9a97e89 --- /dev/null +++ b/include/geometry/shape.h @@ -0,0 +1,300 @@ +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_SHAPE_H +#define GEOMETRY_SHAPE_H + +#include "geometry/lines_set.h" +#include "geometry/polygon.h" +#include "settings/types/Angle.h" + +namespace cura +{ + +class Polygon; +class Ratio; +class SingleShape; +class PartsView; + +class Shape : public LinesSet +{ +public: + Shape() = default; + + Shape(const Shape& other) = default; + + Shape(Shape&& other) = default; + + Shape(const std::initializer_list& initializer) + : LinesSet(initializer) + { + } + + Shape(const std::vector& paths) + : LinesSet(paths) + { + } + + Shape& operator=(const Shape& other); + + Shape& operator=(Shape&& other); + + void add(const Shape& other); + + /*! + * Convert ClipperLib::PolyTree to a Shape object, + * which uses ClipperLib::Paths instead of ClipperLib::PolyTree + */ + static Shape toPolygons(ClipperLib::PolyTree& poly_tree); + + Shape difference(const Shape& other) const; + + Shape unionPolygons(const Shape& other, ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero) const; + + /*! + * Union all polygons with each other (When polygons.add(polygon) has been called for overlapping polygons) + */ + Shape unionPolygons() const + { + return unionPolygons(Shape()); + } + + Shape intersection(const Shape& other) const; + + /*! + * Intersect polylines with this area Polygons object. + * + * \note Due to a clipper bug with polylines with nearly collinear segments, the polylines are cut up into separate polylines, and restitched back together at the end. + * + * \param polylines The (non-closed!) polylines to limit to the area of this Polygons object + * \param restitch Whether to stitch the resulting segments into longer polylines, or leave every segment as a single segment + * \param max_stitch_distance The maximum distance for two polylines to be stitched together with a segment + * \return The resulting polylines limited to the area of this Polygons object + */ + LinesSet intersectionPolyLines(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; + + /*! + * Add the front to each polygon so that the polygon is represented as a polyline + */ +#warning This could probably be removed + void toPolylines(); + + /*! + * Split this poly line object into several line segment objects + * and store them in the \p result + */ + void splitPolylinesIntoSegments(Shape& result) const; + Shape splitPolylinesIntoSegments() const; + + /*! + * Split this polygon object into several line segment objects + * and store them in the \p result + */ + void splitPolygonsIntoSegments(Shape& result) const; + Shape splitPolygonsIntoSegments() const; + + Shape xorPolygons(const Shape& other, ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const; + + Shape execute(ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const; + + /*! + * Check if we are inside the polygon. + * + * We do this by counting the number of polygons inside which this point lies. + * An odd number is inside, while an even number is outside. + * + * Returns false if outside, true if inside; if the point lies exactly on the border, will return \p border_result. + * + * \param p The point for which to check if it is inside this polygon + * \param border_result What to return when the point is exactly on the border + * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) + */ + bool inside(const Point2LL& p, bool border_result = false) const; + + /*! + * Find the polygon inside which point \p p resides. + * + * We do this by tracing from the point towards the positive X direction, + * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. + * We then find the polygon with an uneven number of crossings which is closest to \p p. + * + * If \p border_result, we return the first polygon which is exactly on \p p. + * + * \param p The point for which to check in which polygon it is. + * \param border_result Whether a point exactly on a polygon counts as inside + * \return The index of the polygon inside which the point \p p resides + */ + size_t findInside(const Point2LL& p, bool border_result = false) const; + + /*! + * Approximates the convex hull of the polygons. + * \p extra_outset Extra offset outward + * \return the convex hull (approximately) + * + */ + Shape approxConvexHull(int extra_outset = 0) const; + + /*! + * Make each of the polygons convex + */ + void makeConvex(); + + /*! + * Compute the area enclosed within the polygons (minus holes) + * + * \return The area in square micron + */ + double area() const; + + /*! + * Smooth out small perpendicular segments + * Smoothing is performed by removing the inner most vertex of a line segment smaller than \p remove_length + * which has an angle with the next and previous line segment smaller than roughly 150* + * + * Note that in its current implementation this function doesn't remove line segments with an angle smaller than 30* + * Such would be the case for an N shape. + * + * \param remove_length The length of the largest segment removed + * \return The smoothed polygon + */ + Shape smooth(int remove_length) const; + + /*! + * Smooth out sharp inner corners, by taking a shortcut which bypasses the corner + * + * \param angle The maximum angle of inner corners to be smoothed out + * \param shortcut_length The desired length of the shortcut line segment introduced (shorter shortcuts may be unavoidable) + * \return The resulting polygons + */ + Shape smooth_outward(const AngleDegrees angle, int shortcut_length) const; + + Shape smooth2(int remove_length, int min_area) const; //!< removes points connected to small lines + + void removeColinearEdges(const AngleRadians max_deviation_angle = AngleRadians(0.0005)); + + void scale(const Ratio& ratio); + + void translate(const Point2LL& delta); + + /*! + * Remove all but the polygons on the very outside. + * Exclude holes and parts within holes. + * \return the resulting polygons. + */ + Shape getOutsidePolygons() const; + + /*! + * Exclude holes which have no parts inside of them. + * \return the resulting polygons. + */ + Shape removeEmptyHoles() const; + + /*! + * Return hole polygons which have no parts inside of them. + * \return the resulting polygons. + */ + Shape getEmptyHoles() const; + + /*! + * Split up the polygons into groups according to the even-odd rule. + * Each SingleShape in the result has an outline as first polygon, whereas the rest are holes. + */ + std::vector splitIntoParts(bool unionAll = false) const; + + /*! + * Sort the polygons into bins where each bin has polygons which are contained within one of the polygons in the previous bin. + * + * \warning When polygons are crossing each other the result is undefined. + */ + std::vector sortByNesting() const; + + /*! + * Split up the polygons into groups according to the even-odd rule. + * Each vector in the result has the index to an outline as first index, whereas the rest are indices to holes. + * + * \warning Note that this function reorders the polygons! + */ + PartsView splitIntoPartsView(bool unionAll = false); + + /*! + * Removes polygons with area smaller than \p min_area_size (note that min_area_size is in mm^2, not in micron^2). + * Unless \p remove_holes is true, holes are not removed even if their area is below \p min_area_size. + * However, holes that are contained within outlines whose area is below the threshold are removed though. + */ + void removeSmallAreas(const double min_area_size, const bool remove_holes = false); + + /*! + * Removes the same polygons from this set (and also empty polygons). + * Shape are considered the same if all points lie within [same_distance] of their counterparts. + */ + Shape removePolygon(const Shape& to_be_removed, int same_distance = 0) const; + + Shape processEvenOdd(ClipperLib::PolyFillType poly_fill_type = ClipperLib::PolyFillType::pftEvenOdd) const; + + /*! + * Ensure the polygon is manifold, by removing small areas where the polygon touches itself. + * ____ ____ + * | | | | + * | |____ ==> | / ____ + * """"| | """ / | + * |____| |____| + * + */ + void ensureManifold(); + + Point2LL min() const; + + Point2LL max() const; + + void applyMatrix(const PointMatrix& matrix); + + void applyMatrix(const Point3Matrix& matrix); + + Shape offsetMulti(const std::vector& offset_dists) const; + + /*! + * @brief Export the polygon to a WKT string + * + * @param stream The stream to write to + */ + [[maybe_unused]] void writeWkt(std::ostream& stream) const; + + /*! + * @brief Import the polygon from a WKT string + * + * @param wkt The WKT string to read from + * @return Shape The polygons read from the stream + */ + [[maybe_unused]] static Shape fromWkt(const std::string& wkt); + +private: + /*! + * recursive part of \ref Polygons::removeEmptyHoles and \ref Polygons::getEmptyHoles + * \param node The node of the polygons part to process + * \param remove_holes Whether to remove empty holes or everything but the empty holes + * \param ret Where to store polygons which are not empty holes + */ + void removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Shape& ret) const; + void splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const; + void sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const; + void splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Shape& reordered, ClipperLib::PolyNode* node) const; +}; + +} // namespace cura + +namespace std +{ +#if 0 +template<> +struct hash +{ + size_t operator()(const cura::PolygonPointer& poly) const + { + const cura::ConstPolygonRef ref = *static_cast(poly); + return std::hash()(&*ref); + } +}; +#endif +} // namespace std + +#endif // GEOMETRY_SHAPE_H From ba6ebd66e4e864246b44004d89fd7b9918cf8ade Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 29 Mar 2024 14:06:28 +0100 Subject: [PATCH 014/135] Make prime tower only prime the used extruders CURA-11717 --- include/FffGcodeWriter.h | 4 ++- include/PrimeTower.h | 8 +++-- src/FffGcodeWriter.cpp | 13 ++++++--- src/FffPolygonGenerator.cpp | 2 ++ src/PrimeTower.cpp | 58 ++++++++++++++++++++----------------- 5 files changed, 50 insertions(+), 35 deletions(-) diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index 4c4061c37b..251712c8fc 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -295,9 +295,11 @@ class FffGcodeWriter : public NoCopy * * \param[in] storage where the slice data is stored. * \param current_extruder The current extruder with which we last printed + * \param global_extruders_used The extruders that are at some point used for the print job * \return The order of extruders for a layer beginning with \p current_extruder */ - std::vector getUsedExtrudersOnLayer(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const; + std::vector + getUsedExtrudersOnLayer(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr, const std::vector& global_extruders_used) const; /*! * Calculate in which order to plan the meshes of a specific extruder diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 61a0beb901..b11522643d 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -28,8 +28,8 @@ class LayerPlan; class PrimeTower { private: - using MovesByExtruder = std::vector; - using MovesByLayer = std::vector; + using MovesByExtruder = std::map; + using MovesByLayer = std::map>; size_t extruder_count_; //!< Number of extruders @@ -79,10 +79,12 @@ class PrimeTower */ PrimeTower(); + void initializeExtruders(const std::vector& used_extruders); + /*! * Check whether we actually use the prime tower. */ - void checkUsed(const SliceDataStorage& storage); + void checkUsed(); /*! * Generate the prime tower area to be used on each layer diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index c71c925ea0..74343ea99b 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1543,12 +1543,13 @@ void FffGcodeWriter::calculateExtruderOrderPerLayer(const SliceDataStorage& stor } size_t extruder_count = Application::getInstance().current_slice_->scene.extruders.size(); + const std::vector extruders_used = storage.getExtrudersUsed(); const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; PrimeTowerMethod prime_tower_mode = mesh_group_settings.get("prime_tower_mode"); for (LayerIndex layer_nr = -Raft::getTotalExtraLayers(); layer_nr < static_cast(storage.print_layer_count); layer_nr++) { std::vector>& extruder_order_per_layer_here = (layer_nr < 0) ? extruder_order_per_layer_negative_layers : extruder_order_per_layer; - std::vector extruder_order = getUsedExtrudersOnLayer(storage, last_extruder, layer_nr); + std::vector extruder_order = getUsedExtrudersOnLayer(storage, last_extruder, layer_nr, extruders_used); extruder_order_per_layer_here.push_back(extruder_order); if (! extruder_order.empty()) @@ -1573,10 +1574,14 @@ void FffGcodeWriter::calculatePrimeLayerPerExtruder(const SliceDataStorage& stor } } -std::vector FffGcodeWriter::getUsedExtrudersOnLayer(const SliceDataStorage& storage, const size_t start_extruder, const LayerIndex& layer_nr) const +std::vector FffGcodeWriter::getUsedExtrudersOnLayer( + const SliceDataStorage& storage, + const size_t start_extruder, + const LayerIndex& layer_nr, + const std::vector& global_extruders_used) const { const Settings& mesh_group_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; - size_t extruder_count = Application::getInstance().current_slice_->scene.extruders.size(); + size_t extruder_count = global_extruders_used.size(); assert(static_cast(extruder_count) > 0); std::vector ret; std::vector extruder_is_used_on_this_layer = storage.getExtrudersUsed(layer_nr); @@ -1601,7 +1606,7 @@ std::vector FffGcodeWriter::getUsedExtrudersOnLayer(const SliceData ordered_extruders.push_back(start_extruder); for (size_t extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) { - if (extruder_nr != start_extruder) + if (extruder_nr != start_extruder && global_extruders_used[extruder_nr]) { ordered_extruders.push_back(extruder_nr); } diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index b0d5ff5ff2..24e23b547a 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -404,6 +404,8 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper& Progress::messageProgressStage(Progress::Stage::SUPPORT, &time_keeper); + storage.primeTower.initializeExtruders(storage.getExtrudersUsed()); + AreaSupport::generateOverhangAreas(storage); AreaSupport::generateSupportAreas(storage); TreeSupport tree_support_generator(storage); diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 57dc4d9853..f9ebcb4f4c 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -52,35 +52,37 @@ PrimeTower::PrimeTower() && scene.current_mesh_group->settings.get("prime_tower_size") > 10; would_have_actual_tower_ = enabled_; // Assume so for now. +} - extruder_count_ = scene.extruders.size(); - extruder_order_.resize(extruder_count_); - for (unsigned int extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) +void PrimeTower::initializeExtruders(const std::vector& used_extruders) +{ + // Add used extruders in default order, then sort. + for (unsigned int extruder_nr = 0; extruder_nr < used_extruders.size(); extruder_nr++) { - extruder_order_[extruder_nr] = extruder_nr; // Start with default order, then sort. + if (used_extruders[extruder_nr]) + { + extruder_order_.push_back(extruder_nr); + } } + + extruder_count_ = extruder_order_.size(); + // Sort from high adhesion to low adhesion. - const Scene* scene_pointer = &scene; // Communicate to lambda via pointer to prevent copy. + const Scene& scene = Application::getInstance().current_slice_->scene; std::stable_sort( extruder_order_.begin(), extruder_order_.end(), - [scene_pointer](const unsigned int& extruder_nr_a, const unsigned int& extruder_nr_b) -> bool + [&scene](const unsigned int& extruder_nr_a, const unsigned int& extruder_nr_b) -> bool { - const Ratio adhesion_a = scene_pointer->extruders[extruder_nr_a].settings_.get("material_adhesion_tendency"); - const Ratio adhesion_b = scene_pointer->extruders[extruder_nr_b].settings_.get("material_adhesion_tendency"); + const Ratio adhesion_a = scene.extruders[extruder_nr_a].settings_.get("material_adhesion_tendency"); + const Ratio adhesion_b = scene.extruders[extruder_nr_b].settings_.get("material_adhesion_tendency"); return adhesion_a < adhesion_b; }); } -void PrimeTower::checkUsed(const SliceDataStorage& storage) +void PrimeTower::checkUsed() { - std::vector extruder_is_used = storage.getExtrudersUsed(); - size_t used_extruder_count = 0; - for (bool is_used : extruder_is_used) - { - used_extruder_count += is_used; - } - if (used_extruder_count <= 1) + if (extruder_count_ <= 1) { enabled_ = false; } @@ -108,7 +110,7 @@ void PrimeTower::generateGroundpoly() void PrimeTower::generatePaths(const SliceDataStorage& storage) { - checkUsed(storage); + checkUsed(); const int raft_total_extra_layers = Raft::getTotalExtraLayers(); would_have_actual_tower_ = storage.max_print_height_second_to_last_extruder @@ -138,9 +140,13 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse const coord_t base_height = std::max(scene.settings.get("prime_tower_base_height"), has_raft ? layer_height : 0); const double base_curve_magnitude = mesh_group_settings.get("prime_tower_base_curve_magnitude"); - prime_moves_.resize(extruder_count_); - base_extra_moves_.resize(extruder_count_); - inset_extra_moves_.resize(extruder_count_); + for (size_t extruder_nr : extruder_order_) + { + // By default, add empty moves for every extruder + prime_moves_[extruder_nr]; + base_extra_moves_[extruder_nr]; + inset_extra_moves_[extruder_nr]; + } coord_t cumulative_inset = 0; // Each tower shape is going to be printed inside the other. This is the inset we're doing for each extruder. for (size_t extruder_nr : extruder_order_) @@ -226,8 +232,6 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati if (method == PrimeTowerMethod::INTERLEAVED || method == PrimeTowerMethod::NORMAL) { - const size_t nb_extruders = scene.extruders.size(); - // Pre-compute radiuses of each extruder ring std::vector rings_radii; const coord_t tower_size = mesh_group_settings.get("prime_tower_size"); @@ -242,9 +246,9 @@ void PrimeTower::generatePaths_sparseInfill(const std::vector& cumulati // Generate all possible extruders combinations, e.g. if there are 4 extruders, we have combinations // 0 / 0-1 / 0-1-2 / 0-1-2-3 / 1 / 1-2 / 1-2-3 / 2 / 2-3 / 3 // A combination is represented by a bitmask - for (size_t first_extruder_idx = 0; first_extruder_idx < nb_extruders; ++first_extruder_idx) + for (size_t first_extruder_idx = 0; first_extruder_idx < extruder_count_; ++first_extruder_idx) { - size_t nb_extruders_sparse = method == PrimeTowerMethod::NORMAL ? first_extruder_idx + 1 : nb_extruders; + size_t nb_extruders_sparse = method == PrimeTowerMethod::NORMAL ? first_extruder_idx + 1 : extruder_count_; for (size_t last_extruder_idx = first_extruder_idx; last_extruder_idx < nb_extruders_sparse; ++last_extruder_idx) { @@ -444,7 +448,7 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext { // Actual prime pattern const GCodePathConfig& config = gcode_layer.configs_storage_.prime_tower_config_per_extruder[extruder_nr]; - const Polygons& pattern = prime_moves_[extruder_nr]; + const Polygons& pattern = prime_moves_.at(extruder_nr); gcode_layer.addPolygonsByOptimizer(pattern, config); } } @@ -454,7 +458,7 @@ bool PrimeTower::addToGcode_base(LayerPlan& gcode_layer, const size_t extruder_n const size_t raft_total_extra_layers = Raft::getTotalExtraLayers(); LayerIndex absolute_layer_number = gcode_layer.getLayerNr() + raft_total_extra_layers; - const std::vector& pattern_extra_brim = base_extra_moves_[extruder_nr]; + const std::vector& pattern_extra_brim = base_extra_moves_.at(extruder_nr); if (absolute_layer_number < pattern_extra_brim.size()) { // Extra rings for stronger base @@ -477,7 +481,7 @@ bool PrimeTower::addToGcode_inset(LayerPlan& gcode_layer, const size_t extruder_ if (absolute_layer_number == 0) // Extra-adhesion on very first layer only { - const Polygons& pattern_extra_inset = inset_extra_moves_[extruder_nr]; + const Polygons& pattern_extra_inset = inset_extra_moves_.at(extruder_nr); if (! pattern_extra_inset.empty()) { const GCodePathConfig& config = gcode_layer.configs_storage_.prime_tower_config_per_extruder[extruder_nr]; From 1ee8726e9a149ee1c52ed1ba81fa152f04dfe449 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 2 Apr 2024 10:12:02 +0200 Subject: [PATCH 015/135] Fix unit tests Possible crash when finializing a layer plan and prime tower not initialized. Although not possible in normal execution (prime tower is always initialized first), it is still a healthy fix. CURA-11717 --- src/sliceDataStorage.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index b369dbb082..cfc4d32c08 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -362,13 +362,9 @@ Polygons SliceDataStorage::getLayerOutlines( total.add(support_layer.support_roof); } } - int prime_tower_outer_extruder_nr = primeTower.extruder_order_[0]; - if (include_prime_tower && (extruder_nr == -1 || extruder_nr == prime_tower_outer_extruder_nr)) + if (include_prime_tower && primeTower.enabled_ && (extruder_nr == -1 || (! primeTower.extruder_order_.empty() && extruder_nr == primeTower.extruder_order_[0]))) { - if (primeTower.enabled_) - { - total.add(primeTower.getOuterPoly(layer_nr)); - } + total.add(primeTower.getOuterPoly(layer_nr)); } return total; } From 2efbdd2b11f208be0a1bc4a2a646f4c7f7236cf3 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 2 Apr 2024 14:23:40 +0200 Subject: [PATCH 016/135] Pin version 5.7.0 --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index a5527b0e01..e6c16b939b 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,4 +1,4 @@ -version: "5.7.0-beta.1" +version: "5.7.0" requirements: - "scripta/0.1.0@ultimaker/testing" requirements_arcus: From 928ebe1c3c3c85e0a65be94aa92626b68220622e Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 2 Apr 2024 15:58:41 +0200 Subject: [PATCH 017/135] Fix overlapping lines with gradual (support) infill. Separate out the areas, since overlapping lines will become a big problem when 'connect infill lines' or 'zig zag' is enabled. This does mean that lines are less well-connected when the pattern _isn't_ already connected in and of itself, like lines. However, such patterns aren't recommended anyway. Also some compensation for the extra density which we _may_ now lose in some cases might need to be done. It should still allow us to to the combine (though I can't see that this happens in practice, either before or after this fix, so we'll may have to look at that in more detail later). part of CURA-11597 --- src/skin.cpp | 6 ++++-- src/support.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/skin.cpp b/src/skin.cpp index 842a6e576f..797fc6b679 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -494,6 +494,7 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) continue; } Polygons less_dense_infill = infill_area; // one step less dense with each infill_step + Polygons sum_more_dense; for (size_t infill_step = 0; infill_step < max_infill_steps; infill_step++) { LayerIndex min_layer = layer_idx + infill_step * gradual_infill_step_layer_count + static_cast(layer_skip_count); @@ -526,11 +527,12 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) part.infill_area_per_combine_per_density.emplace_back(); std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); const Polygons more_dense_infill = infill_area.difference(less_dense_infill); - infill_area_per_combine_current_density.push_back(more_dense_infill); + infill_area_per_combine_current_density.push_back(more_dense_infill.difference(sum_more_dense)); + sum_more_dense = sum_more_dense.unionPolygons(more_dense_infill); } part.infill_area_per_combine_per_density.emplace_back(); std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); - infill_area_per_combine_current_density.push_back(infill_area); + infill_area_per_combine_current_density.push_back(infill_area.difference(sum_more_dense)); part.infill_area_own = std::nullopt; // clear infill_area_own, it's not needed any more. assert(! part.infill_area_per_combine_per_density.empty() && "infill_area_per_combine_per_density is now initialized"); } diff --git a/src/support.cpp b/src/support.cpp index 7488c6832f..82b9f22e06 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -234,6 +234,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) // calculate density areas for this island Polygons less_dense_support = infill_area; // one step less dense with each density_step + Polygons sum_more_dense; for (unsigned int density_step = 0; density_step < max_density_steps; ++density_step) { LayerIndex actual_min_layer{ layer_nr + density_step * gradual_support_step_layer_count + static_cast(layer_skip_count) }; @@ -292,12 +293,13 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) support_infill_part.infill_area_per_combine_per_density_.emplace_back(); std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); const Polygons more_dense_support = infill_area.difference(less_dense_support); - support_area_current_density.push_back(more_dense_support); + support_area_current_density.push_back(more_dense_support.difference(sum_more_dense)); + sum_more_dense = sum_more_dense.unionPolygons(more_dense_support); } support_infill_part.infill_area_per_combine_per_density_.emplace_back(); std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); - support_area_current_density.push_back(infill_area); + support_area_current_density.push_back(infill_area.difference(sum_more_dense)); assert(support_infill_part.infill_area_per_combine_per_density_.size() != 0 && "support_infill_part.infill_area_per_combine_per_density should now be initialized"); #ifdef DEBUG From 5ba7baf4124cd75f4be57d6154d263f7361f2968 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 3 Apr 2024 13:10:02 +0200 Subject: [PATCH 018/135] Fixed some brim issue CURA-9830 --- include/geometry/shape.h | 6 +++--- src/SkirtBrim.cpp | 5 +---- src/bridge.cpp | 2 +- src/geometry/shape.cpp | 8 +++++++- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/geometry/shape.h b/include/geometry/shape.h index d74bf7d873..b91ad296f6 100644 --- a/include/geometry/shape.h +++ b/include/geometry/shape.h @@ -62,7 +62,7 @@ class Shape : public LinesSet Shape intersection(const Shape& other) const; /*! - * Intersect polylines with this area Polygons object. + * Intersect polylines with the area covered by the shape. * * \note Due to a clipper bug with polylines with nearly collinear segments, the polylines are cut up into separate polylines, and restitched back together at the end. * @@ -71,8 +71,8 @@ class Shape : public LinesSet * \param max_stitch_distance The maximum distance for two polylines to be stitched together with a segment * \return The resulting polylines limited to the area of this Polygons object */ -#warning Rework this - LinesSet intersectionPolyLines(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; + template + LinesSet intersectionPolyLines(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; /*! * Add the front to each polygon so that the polygon is represented as a polyline diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 3497c3535c..4aee2fe1fa 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -256,10 +256,7 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std // limit brim lines to allowed areas, stitch them and store them in the result brim = Simplify(Application::getInstance().current_slice_->scene.extruders[offset.extruder_nr_].settings_).polygon(brim); -#warning Restore this somehow - // brim.toPolylines(); - - LinesSet brim_lines = allowed_areas_per_extruder[offset.extruder_nr_].intersectionPolyLines(brim.toType(), false); + LinesSet brim_lines = allowed_areas_per_extruder[offset.extruder_nr_].intersectionPolyLines(brim, false); length_added = brim_lines.length(); Shape newly_covered = brim_lines.offset(extruder_config.line_width_ / 2 + 10, ClipperLib::jtRound); diff --git a/src/bridge.cpp b/src/bridge.cpp index dba4aeb043..4c1b0bca31 100644 --- a/src/bridge.cpp +++ b/src/bridge.cpp @@ -122,7 +122,7 @@ double bridgeAngle( const coord_t bb_max_dim = std::max(boundary_box.max_.X - boundary_box.min_.X, boundary_box.max_.Y - boundary_box.min_.Y); const Shape air_below(bb_poly.offset(bb_max_dim).difference(prev_layer_outline).offset(-10)); - std::vector skin_perimeter_lines; + LinesSet skin_perimeter_lines; for (const Polygon& poly : skin_outline) { if (! poly.empty()) diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index 813cd7e58f..6832e833bc 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -19,6 +19,7 @@ #include #include +#include "geometry/closed_polyline.h" #include "geometry/parts_view.h" #include "geometry/single_shape.h" #include "settings/types/Ratio.h" @@ -228,7 +229,8 @@ size_t Shape::findInside(const Point2LL& p, bool border_result) const return ret; } -LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const +template +LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const { LinesSet split_polylines = polylines.splitIntoSegments(); @@ -944,4 +946,8 @@ void Shape::applyMatrix(const Point3Matrix& matrix) } } +template LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; +template LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; +template LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; + } // namespace cura From 51daa75a08b4bbed37ebec25137b49ed13d26466 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 3 Apr 2024 13:38:31 +0200 Subject: [PATCH 019/135] Only add zig-zag connector when not 'too close' to scanline. This can in some cases lead to (nearly) doubly printed extrusion-paths (or close enough), especially in support, where it might also present the biggest problems. part of CURA-11597 --- include/infill/NoZigZagConnectorProcessor.h | 2 +- include/infill/ZigzagConnectorProcessor.h | 13 +------------ src/infill.cpp | 6 +++--- src/infill/NoZigZagConnectorProcessor.cpp | 2 +- src/infill/ZigzagConnectorProcessor.cpp | 15 ++++++++++++--- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/include/infill/NoZigZagConnectorProcessor.h b/include/infill/NoZigZagConnectorProcessor.h index 002fb0fb7b..6e59dcdaa5 100644 --- a/include/infill/NoZigZagConnectorProcessor.h +++ b/include/infill/NoZigZagConnectorProcessor.h @@ -29,7 +29,7 @@ class NoZigZagConnectorProcessor : public ZigzagConnectorProcessor } void registerVertex(const Point2LL& vertex); - void registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index); + void registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index, coord_t min_distance_to_scanline); void registerPolyFinished(); }; diff --git a/include/infill/ZigzagConnectorProcessor.h b/include/infill/ZigzagConnectorProcessor.h index 513ad9d8f1..9adb751430 100644 --- a/include/infill/ZigzagConnectorProcessor.h +++ b/include/infill/ZigzagConnectorProcessor.h @@ -137,7 +137,7 @@ class ZigzagConnectorProcessor * \param intersection The intersection * \param scanline_index Index of the current scanline */ - virtual void registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index); + virtual void registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index, coord_t min_distance_to_scanline); /*! * Handle the end of a polygon and prepare for the next. @@ -166,17 +166,6 @@ class ZigzagConnectorProcessor */ bool shouldAddCurrentConnector(int start_scanline_idx, int end_scanline_idx) const; - /*! - * Checks whether two points are separated at least by "threshold" microns. - * If they are far away from each other enough, the line represented by the two points - * will be added; In case they are close, the second point will be set to be the same - * as the first and this line won't be added. - * - * \param first_point The first of the points - * \param second_point The second of the points - */ - void checkAndAddZagConnectorLine(Point2LL* first_point, Point2LL* second_point); - /*! * Adds a Zag connector represented by the given points. The last line of the connector will not be * added if the given connector is an end piece and "connected_endpieces" is not enabled. diff --git a/src/infill.cpp b/src/infill.cpp index c085307622..ff51356267 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -746,12 +746,12 @@ void Infill::generateLinearBasedInfill( for (int scanline_idx = scanline_idx0; scanline_idx != scanline_idx1 + direction; scanline_idx += direction) { - int x = scanline_idx * line_distance + shift; - int y = p1.Y + (p0.Y - p1.Y) * (x - p1.X) / (p0.X - p1.X); + const int x = scanline_idx * line_distance + shift; + const int y = p1.Y + (p0.Y - p1.Y) * (x - p1.X) / (p0.X - p1.X); assert(scanline_idx - scanline_min_idx >= 0 && scanline_idx - scanline_min_idx < int(cut_list.size()) && "reading infill cutlist index out of bounds!"); cut_list[scanline_idx - scanline_min_idx].push_back(y); Point2LL scanline_linesegment_intersection(x, y); - zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx); + zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, infill_line_width_); crossings_per_scanline[scanline_idx - min_scanline_index].emplace_back(scanline_linesegment_intersection, poly_idx, point_idx); } zigzag_connector_processor.registerVertex(p1); diff --git a/src/infill/NoZigZagConnectorProcessor.cpp b/src/infill/NoZigZagConnectorProcessor.cpp index 1ffa6532f4..25cb0fa48e 100644 --- a/src/infill/NoZigZagConnectorProcessor.cpp +++ b/src/infill/NoZigZagConnectorProcessor.cpp @@ -14,7 +14,7 @@ void NoZigZagConnectorProcessor::registerVertex(const Point2LL&) // No need to add anything. } -void NoZigZagConnectorProcessor::registerScanlineSegmentIntersection(const Point2LL&, int) +void NoZigZagConnectorProcessor::registerScanlineSegmentIntersection(const Point2LL&, int, coord_t) { // No need to add anything. } diff --git a/src/infill/ZigzagConnectorProcessor.cpp b/src/infill/ZigzagConnectorProcessor.cpp index 7f75b608ff..bb7c1bbbac 100644 --- a/src/infill/ZigzagConnectorProcessor.cpp +++ b/src/infill/ZigzagConnectorProcessor.cpp @@ -84,7 +84,7 @@ bool ZigzagConnectorProcessor::shouldAddCurrentConnector(int start_scanline_idx, } -void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index) +void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index, coord_t min_distance_to_scanline) { if (is_first_connector_) { @@ -100,8 +100,17 @@ void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2L if (shouldAddCurrentConnector(last_connector_index_, scanline_index)) { const bool is_this_endpiece = scanline_index == last_connector_index_; - current_connector_.push_back(intersection); - addZagConnector(current_connector_, is_this_endpiece); + bool close_to_line_except_intersect = false; + const coord_t min_dist2 = min_distance_to_scanline * min_distance_to_scanline; + for (const auto& point : current_connector_) + { + close_to_line_except_intersect |= (std::abs(point.X - intersection.X) < min_distance_to_scanline) && (vSize2(point - intersection) > min_dist2); + } + if (! close_to_line_except_intersect) + { + current_connector_.push_back(intersection); + addZagConnector(current_connector_, is_this_endpiece); + } } } From 042745ed7055446f493482c65d58c0b75582df4e Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 3 Apr 2024 14:28:20 +0200 Subject: [PATCH 020/135] Remove narrow areas from --and simplify-- gradual infill areas. Narrow or small areas can lead to double printing of lines, as a polygon is filled out that can be narrower than the line-width. Also observed what might be micro-segments in the connecting zags (if there are any), so simplify those out as well. part of CURA-11597 --- src/skin.cpp | 7 +++++-- src/support.cpp | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/skin.cpp b/src/skin.cpp index 797fc6b679..7dc2993a82 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -16,6 +16,7 @@ #include "sliceDataStorage.h" #include "utils/math.h" #include "utils/polygonUtils.h" +#include "utils/Simplify.h" #define MIN_AREA_SIZE (0.4 * 0.4) @@ -465,6 +466,8 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) const LayerIndex mesh_min_layer = mesh.settings.get("initial_bottom_layers"); const LayerIndex mesh_max_layer = mesh.layers.size() - 1 - mesh.settings.get("top_layers"); + const Simplify simplifier(mesh.settings.get("infill_extruder_nr").settings_); + const auto infill_wall_count = mesh.settings.get("infill_wall_line_count"); const auto infill_wall_width = mesh.settings.get("infill_line_width"); const auto infill_overlap = mesh.settings.get("infill_overlap_mm"); @@ -527,12 +530,12 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) part.infill_area_per_combine_per_density.emplace_back(); std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); const Polygons more_dense_infill = infill_area.difference(less_dense_infill); - infill_area_per_combine_current_density.push_back(more_dense_infill.difference(sum_more_dense)); + infill_area_per_combine_current_density.push_back(simplifier.polygon(more_dense_infill.difference(sum_more_dense).offset(-infill_wall_width).offset(infill_wall_width))); sum_more_dense = sum_more_dense.unionPolygons(more_dense_infill); } part.infill_area_per_combine_per_density.emplace_back(); std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); - infill_area_per_combine_current_density.push_back(infill_area.difference(sum_more_dense)); + infill_area_per_combine_current_density.push_back(simplifier.polygon(infill_area.difference(sum_more_dense).offset(-infill_wall_width).offset(infill_wall_width))); part.infill_area_own = std::nullopt; // clear infill_area_own, it's not needed any more. assert(! part.infill_area_per_combine_per_density.empty() && "infill_area_per_combine_per_density is now initialized"); } diff --git a/src/support.cpp b/src/support.cpp index 82b9f22e06..e8546c55f0 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -187,6 +187,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) const size_t max_density_steps = infill_extruder.settings_.get("gradual_support_infill_steps"); const coord_t wall_width = infill_extruder.settings_.get("support_line_width"); + const Simplify simplifier(infill_extruder.settings_); // no early-out for this function; it needs to initialize the [infill_area_per_combine_per_density] double layer_skip_count{ 8.0 }; // skip every so many layers as to ignore small gaps in the model making computation more easy @@ -293,13 +294,13 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) support_infill_part.infill_area_per_combine_per_density_.emplace_back(); std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); const Polygons more_dense_support = infill_area.difference(less_dense_support); - support_area_current_density.push_back(more_dense_support.difference(sum_more_dense)); + support_area_current_density.push_back(simplifier.polygon(more_dense_support.difference(sum_more_dense).offset(-wall_width).offset(wall_width))); sum_more_dense = sum_more_dense.unionPolygons(more_dense_support); } support_infill_part.infill_area_per_combine_per_density_.emplace_back(); std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); - support_area_current_density.push_back(infill_area.difference(sum_more_dense)); + support_area_current_density.push_back(simplifier.polygon(infill_area.difference(sum_more_dense).offset(-wall_width).offset(wall_width))); assert(support_infill_part.infill_area_per_combine_per_density_.size() != 0 && "support_infill_part.infill_area_per_combine_per_density should now be initialized"); #ifdef DEBUG From 659aa52b08b1b611ad53c87b4946c82ffeb53615 Mon Sep 17 00:00:00 2001 From: rburema Date: Wed, 3 Apr 2024 19:15:52 +0000 Subject: [PATCH 021/135] Applied clang-format. --- src/skin.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/skin.cpp b/src/skin.cpp index 7dc2993a82..e342b58554 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -14,9 +14,9 @@ #include "settings/types/Angle.h" //For the infill support angle. #include "settings/types/Ratio.h" #include "sliceDataStorage.h" +#include "utils/Simplify.h" #include "utils/math.h" #include "utils/polygonUtils.h" -#include "utils/Simplify.h" #define MIN_AREA_SIZE (0.4 * 0.4) @@ -530,7 +530,8 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) part.infill_area_per_combine_per_density.emplace_back(); std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); const Polygons more_dense_infill = infill_area.difference(less_dense_infill); - infill_area_per_combine_current_density.push_back(simplifier.polygon(more_dense_infill.difference(sum_more_dense).offset(-infill_wall_width).offset(infill_wall_width))); + infill_area_per_combine_current_density.push_back( + simplifier.polygon(more_dense_infill.difference(sum_more_dense).offset(-infill_wall_width).offset(infill_wall_width))); sum_more_dense = sum_more_dense.unionPolygons(more_dense_infill); } part.infill_area_per_combine_per_density.emplace_back(); From 6085288cd66e3924c6a395fda2fa41760a934cf5 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 4 Apr 2024 12:58:33 +0200 Subject: [PATCH 022/135] Checkpoint before trying different architecture --- CMakeLists.txt | 3 +- include/LayerPlan.h | 27 +++- include/PathOrder.h | 2 +- include/PathOrderMonotonic.h | 2 +- include/PathOrderOptimizer.h | 2 +- include/SkirtBrim.h | 2 +- include/geometry/lines_set.h | 1 + include/geometry/mixed_lines_set.h | 128 +++++++++++++++++++ include/geometry/polyline.h | 10 +- include/{PathOrdering.h => path_ordering.h} | 1 - include/sliceDataStorage.h | 12 +- include/utils/mixed_polyline_stitcher.h | 25 ++++ src/FffPolygonGenerator.cpp | 5 +- src/LayerPlan.cpp | 58 ++++++++- src/SkirtBrim.cpp | 55 ++++---- src/geometry/mixed_lines_set.cpp | 16 +++ src/{PathOrderPath.cpp => path_ordering.cpp} | 3 +- src/utils/PolylineStitcher.cpp | 26 ++++ src/utils/Simplify.cpp | 2 + 19 files changed, 329 insertions(+), 51 deletions(-) create mode 100644 include/geometry/mixed_lines_set.h rename include/{PathOrdering.h => path_ordering.h} (99%) create mode 100644 include/utils/mixed_polyline_stitcher.h create mode 100644 src/geometry/mixed_lines_set.cpp rename src/{PathOrderPath.cpp => path_ordering.cpp} (94%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5037ea3521..c4b25be417 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ set(engine_SRCS # Except main.cpp. src/MeshGroup.cpp src/Mold.cpp src/multiVolumes.cpp - src/PathOrderPath.cpp + src/path_ordering.cpp src/Preheat.cpp src/PrimeTower.cpp src/raft.cpp @@ -160,6 +160,7 @@ set(engine_SRCS # Except main.cpp. src/geometry/parts_view.cpp src/geometry/lines_set.cpp src/geometry/polyline.cpp + src/geometry/mixed_lines_set.cpp ) add_library(_CuraEngine STATIC ${engine_SRCS} ${engine_PB_SRCS}) diff --git a/include/LayerPlan.h b/include/LayerPlan.h index fedd1a192b..52b5bfd617 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -563,7 +563,32 @@ class LayerPlan : public NoCopy * \param order_requirements Pairs where first needs to be printed before second. Pointers are pointing to elements of \p lines */ void addLinesByOptimizer( - const std::vector& lines, + const LinesSet& lines, + const GCodePathConfig& config, + const SpaceFillType space_fill_type, + const bool enable_travel_optimization = false, + const coord_t wipe_dist = 0, + const Ratio flow_ratio = 1.0, + const std::optional near_start_location = std::optional(), + const double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT, + const bool reverse_print_direction = false, + const std::unordered_multimap& order_requirements = PathOrderOptimizer::no_order_requirements_); + + /*! + * Add lines to the gcode with optimized order. + * \param lines The lines + * \param config The config of the lines + * \param space_fill_type The type of space filling used to generate the line segments (should be either Lines or PolyLines!) + * \param enable_travel_optimization Whether to enable some potentially time consuming optimization of order the lines are printed to reduce the travel time required. + * \param wipe_dist (optional) the distance wiped without extruding after laying down a line. + * \param flow_ratio The ratio with which to multiply the extrusion amount + * \param near_start_location Optional: Location near where to add the first line. If not provided the last position is used. + * \param fan_speed optional fan speed override for this path + * \param reverse_print_direction Whether to reverse the optimized order and their printing direction. + * \param order_requirements Pairs where first needs to be printed before second. Pointers are pointing to elements of \p lines + */ + void addLinesByOptimizer( + const MixedLinesSet& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const bool enable_travel_optimization = false, diff --git a/include/PathOrder.h b/include/PathOrder.h index 7fd338fbfc..d1c826990f 100644 --- a/include/PathOrder.h +++ b/include/PathOrder.h @@ -4,7 +4,7 @@ #ifndef PATHORDER_H #define PATHORDER_H -#include "PathOrdering.h" +#include "path_ordering.h" #include "settings/ZSeamConfig.h" //To get the seam settings. #include "utils/polygonUtils.h" diff --git a/include/PathOrderMonotonic.h b/include/PathOrderMonotonic.h index 9ecf3e8713..b2334e7a9e 100644 --- a/include/PathOrderMonotonic.h +++ b/include/PathOrderMonotonic.h @@ -9,7 +9,7 @@ #include //To track starting points of monotonic sequences. #include "PathOrder.h" -#include "PathOrdering.h" +#include "path_ordering.h" namespace cura { diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index b8ecb9dfb1..1a84fc2952 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -16,7 +16,7 @@ #include #include "InsetOrderOptimizer.h" // for makeOrderIncludeTransitive -#include "PathOrdering.h" +#include "path_ordering.h" #include "pathPlanning/CombPath.h" //To calculate the combing distance if we want to use combing. #include "pathPlanning/LinePolygonsCrossings.h" //To prevent calculating combing distances if we don't cross the combing borders. #include "settings/EnumSettings.h" //To get the seam settings. diff --git a/include/SkirtBrim.h b/include/SkirtBrim.h index ea42724819..696ecf94aa 100644 --- a/include/SkirtBrim.h +++ b/include/SkirtBrim.h @@ -183,7 +183,7 @@ class SkirtBrim * \param[out] result Where to store the resulting brim line * \return The length of the added lines */ - coord_t generateOffset(const Offset& offset, Shape& covered_area, std::vector& allowed_areas_per_extruder, SkirtBrimLine& result); + coord_t generateOffset(const Offset& offset, Shape& covered_area, std::vector& allowed_areas_per_extruder, MixedLinesSet& result); /*! * Generate a skirt of extruders which don't yet comply with the minimum length requirement. diff --git a/include/geometry/lines_set.h b/include/geometry/lines_set.h index eabdb9284f..3b5555c414 100644 --- a/include/geometry/lines_set.h +++ b/include/geometry/lines_set.h @@ -61,6 +61,7 @@ class LinesSet : public std::vector return *this; } +#warning rename this to asType template const LinesSet& toType() const { diff --git a/include/geometry/mixed_lines_set.h b/include/geometry/mixed_lines_set.h new file mode 100644 index 0000000000..372af32323 --- /dev/null +++ b/include/geometry/mixed_lines_set.h @@ -0,0 +1,128 @@ +// Copyright (c) 2023 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_MIXED_LINES_SET_H +#define GEOMETRY_MIXED_LINES_SET_H + +#include "geometry/closed_polyline.h" +#include "geometry/lines_set.h" +#include "geometry/open_polyline.h" + +namespace cura +{ + +/*! + * \brief Container that can hold either open or closed polylines. We often have to handle "a bunch + * of lines" which are either open or closed without taking care of what they actually are. + */ +class MixedLinesSet +{ +private: + LinesSet open_lines_; + LinesSet closed_lines_; + +public: + MixedLinesSet() = default; + + MixedLinesSet(const MixedLinesSet& other) = default; + + MixedLinesSet(MixedLinesSet&& other) = default; + + MixedLinesSet(const LinesSet& open_lines) + : open_lines_(open_lines) + { + } + + MixedLinesSet(LinesSet&& open_lines) + : open_lines_(std::move(open_lines)) + { + } + + MixedLinesSet(const LinesSet& closed_lines) + : closed_lines_(closed_lines) + { + } + + MixedLinesSet(LinesSet&& closed_lines) + : closed_lines_(std::move(closed_lines)) + { + } + + const LinesSet& getOpenLines() const + { + return open_lines_; + } + + LinesSet& getOpenLines() + { + return open_lines_; + } + + void setOpenLines(const LinesSet& open_lines) + { + open_lines_ = open_lines; + } + + void setOpenLines(LinesSet&& open_lines) + { + open_lines_ = std::move(open_lines); + } + + const LinesSet& getClosedLines() const + { + return closed_lines_; + } + + LinesSet& getClosedLines() + { + return closed_lines_; + } + + void setClosedLines(const LinesSet& closed_lines) + { + closed_lines_ = closed_lines; + } + + void setClosedLines(LinesSet&& closed_lines) + { + closed_lines_ = std::move(closed_lines); + } + + ClosedPolyline& push_back(const ClosedPolyline& line) + { + closed_lines_.push_back(line); + return closed_lines_.back(); + } + + void push_back(const LinesSet& lines) + { + closed_lines_.add(lines); + } + + OpenPolyline& push_back(const OpenPolyline& line) + { + open_lines_.push_back(line); + return open_lines_.back(); + } + + void push_back(const LinesSet& lines) + { + open_lines_.add(lines); + } + + void push_back(const MixedLinesSet& lines); + + coord_t length() const + { + return open_lines_.length() + closed_lines_.length(); + } + + size_t size() const + { + return open_lines_.size() + closed_lines_.size(); + } +}; + +} // namespace cura + +#endif // GEOMETRY_MIXED_LINES_SET_H diff --git a/include/geometry/polyline.h b/include/geometry/polyline.h index 44bbbc48dc..a487062bf5 100644 --- a/include/geometry/polyline.h +++ b/include/geometry/polyline.h @@ -22,7 +22,7 @@ class AngleRadians; * * * Open Polyline : this represents a line that does not closes, i.e. the last point is different * from the initial point - * * Closed Polyline : a closed polyline as a final segment joining the last point and the + * * Closed Polyline : a closed polyline has a final segment joining the last point and the * initial one * * Filled Polyline : this is a particular type of closed polyline, for which we consider that the * "inside" part of the line forms a surface @@ -139,6 +139,14 @@ class Polyline : public PointsSet */ void simplify(const coord_t smallest_line_segment_squared = MM2INT(0.01) * MM2INT(0.01), const coord_t allowed_error_distance_squared = 25); + void pseudoClose() + { + if (size() >= 2) + { + push_back(front()); + } + } + private: /*! * Private implementation for both simplify and simplifyPolygons. diff --git a/include/PathOrdering.h b/include/path_ordering.h similarity index 99% rename from include/PathOrdering.h rename to include/path_ordering.h index a143d7d165..9126cc81d8 100644 --- a/include/PathOrdering.h +++ b/include/path_ordering.h @@ -76,7 +76,6 @@ struct PathOrdering */ bool backwards_; - /*! * Get vertex data from the custom path type. * diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index f3e9f73abe..4b1c30f924 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -13,6 +13,7 @@ #include "SupportInfillPart.h" #include "TopSurface.h" #include "WipeScriptConfig.h" +#include "geometry/mixed_lines_set.h" #include "geometry/open_polyline.h" #include "geometry/point2ll.h" #include "geometry/polygon.h" @@ -361,15 +362,6 @@ class SliceMeshStorage Point2LL getZSeamHint() const; }; -/*! - * Class to store all open polylines or closed polygons related to one outset index of brim/skirt. - */ -struct SkirtBrimLine -{ - LinesSet open_polylines; - Shape closed_polygons; -}; - class SliceDataStorage : public NoCopy { public: @@ -383,7 +375,7 @@ class SliceDataStorage : public NoCopy SupportStorage support; - std::vector skirt_brim[MAX_EXTRUDERS]; //!< Skirt/brim polygons per extruder, ordered from inner to outer polygons. + std::vector skirt_brim[MAX_EXTRUDERS]; //!< Skirt/brim polygons per extruder, ordered from inner to outer polygons. LinesSet support_brim; //!< brim lines for support, going from the edge of the support inward. \note Not ordered by inset. // Storage for the outline of the raft-parts. Will be filled with lines when the GCode is generated. diff --git a/include/utils/mixed_polyline_stitcher.h b/include/utils/mixed_polyline_stitcher.h new file mode 100644 index 0000000000..00e2633df4 --- /dev/null +++ b/include/utils/mixed_polyline_stitcher.h @@ -0,0 +1,25 @@ +// Copyright (c) 2024 Ultimaker B.V. +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#ifndef UTILS_OPEN_POLYLINE_STITCHER_H +#define UTILS_OPEN_POLYLINE_STITCHER_H + +#include "PolylineStitcher.h" +#include "geometry/closed_polyline.h" +#include "geometry/mixed_lines_set.h" +#include "geometry/open_polyline.h" + +namespace cura +{ + +class MixedPolylineStitcher : public PolylineStitcher, LinesSet, OpenPolyline, Point2LL> +{ +public: + static void stitch(const LinesSet& lines, MixedLinesSet& result, coord_t max_stitch_distance = MM2INT(0.1), coord_t snap_distance = 10) + { + PolylineStitcher::stitch(lines, result.getOpenLines(), result.getClosedLines(), max_stitch_distance, snap_distance); + } +}; + +} // namespace cura +#endif // UTILS_OPEN_POLYLINE_STITCHER_H diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 6ef5e8716a..55d1a49b32 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -1075,12 +1075,13 @@ void FffPolygonGenerator::processPlatformAdhesion(SliceDataStorage& storage) for (const auto& extruder : Application::getInstance().current_slice_->scene.extruders) { - Simplify simplifier(extruder.settings_); +#warning Using auto here apparently makes a copy and then the loop is useless -> double-check + /*Simplify simplifier(extruder.settings_); for (auto skirt_brim_line : storage.skirt_brim[extruder.extruder_nr_]) { skirt_brim_line.closed_polygons = simplifier.polygon(skirt_brim_line.closed_polygons); skirt_brim_line.open_polylines = simplifier.polyline(skirt_brim_line.open_polylines); - } + }*/ } } diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index c9e296e355..98a69cf0d3 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -1289,7 +1289,7 @@ void LayerPlan::addWalls( void LayerPlan::addLinesByOptimizer( - const std::vector& lines, + const LinesSet& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const bool enable_travel_optimization, @@ -1339,6 +1339,60 @@ void LayerPlan::addLinesByOptimizer( addLinesInGivenOrder(order_optimizer.paths_, config, space_fill_type, wipe_dist, flow_ratio, fan_speed); } +void LayerPlan::addLinesByOptimizer( + const MixedLinesSet& lines, + const GCodePathConfig& config, + const SpaceFillType space_fill_type, + const bool enable_travel_optimization, + const coord_t wipe_dist, + const Ratio flow_ratio, + const std::optional near_start_location, + const double fan_speed, + const bool reverse_print_direction, + const std::unordered_multimap& order_requirements) +{ + Shape boundary; + if (enable_travel_optimization && ! comb_boundary_minimum_.empty()) + { + // use the combing boundary inflated so that all infill lines are inside the boundary + int dist = 0; + if (layer_nr_ >= 0) + { + // determine how much the skin/infill lines overlap the combing boundary + for (const std::shared_ptr& mesh : storage_.meshes) + { + const coord_t overlap = std::max(mesh->settings.get("skin_overlap_mm"), mesh->settings.get("infill_overlap_mm")); + if (overlap > dist) + { + dist = overlap; + } + } + dist += 100; // ensure boundary is slightly outside all skin/infill lines + } + boundary.add(comb_boundary_minimum_.offset(dist)); + // simplify boundary to cut down processing time + boundary = Simplify(MM2INT(0.1), MM2INT(0.1), 0).polygon(boundary); + } + constexpr bool detect_loops = false; // We already know which lines are closed + PathOrderOptimizer order_optimizer( + near_start_location.value_or(getLastPlannedPositionOrStartingPosition()), + ZSeamConfig(), + detect_loops, + &boundary, + reverse_print_direction, + order_requirements); + for (const OpenPolyline& open_polyline : lines.getOpenLines()) + { + order_optimizer.addPolyline(&open_polyline); + } + for (const ClosedPolyline& closed_polyline : lines.getClosedLines()) + { + order_optimizer.addPolygon(&closed_polyline.toType()); + } + order_optimizer.optimize(); + + addLinesInGivenOrder(order_optimizer.paths_, config, space_fill_type, wipe_dist, flow_ratio, fan_speed); +} void LayerPlan::addLinesInGivenOrder( const std::vector>& lines, @@ -1474,7 +1528,7 @@ void LayerPlan::addLinesMonotonic( // Order monotonically, except for line-segments which stay in the excluded areas (read: close to the walls) consecutively. PathOrderMonotonic order(monotonic_direction, max_adjacent_distance, last_position); - std::vector left_over; + LinesSet left_over; bool last_would_have_been_excluded = false; for (size_t line_idx = 0; line_idx < line_order.paths_.size(); ++line_idx) { diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 4aee2fe1fa..6884e33f34 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -13,8 +13,9 @@ #include "settings/types/Ratio.h" #include "sliceDataStorage.h" #include "support.h" -#include "utils/OpenPolylineStitcher.h" +//#include "utils/OpenPolylineStitcher.h" #include "utils/Simplify.h" +#include "utils/mixed_polyline_stitcher.h" namespace cura { @@ -161,11 +162,11 @@ void SkirtBrim::generate() const coord_t maximum_deviation = global_settings.get("meshfix_maximum_deviation"); for (int extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) { - for (SkirtBrimLine& line : storage_.skirt_brim[extruder_nr]) + for (MixedLinesSet& line : storage_.skirt_brim[extruder_nr]) { constexpr coord_t max_area_dev = 0u; // No area deviation applied - line.open_polylines = Simplify(maximum_resolution, maximum_deviation, max_area_dev).polyline(line.open_polylines); - line.closed_polygons = Simplify(maximum_resolution, maximum_deviation, max_area_dev).polygon(line.closed_polygons); + line.setOpenLines(Simplify(maximum_resolution, maximum_deviation, max_area_dev).polyline(line.getOpenLines())); + line.setClosedLines(Simplify(maximum_resolution, maximum_deviation, max_area_dev).polyline(line.getClosedLines())); } } } @@ -181,7 +182,7 @@ std::vector SkirtBrim::generatePrimaryBrim(std::vector& all_bri { storage_.skirt_brim[offset.extruder_nr_].resize(offset.inset_idx_ + 1); } - SkirtBrimLine& output_location = storage_.skirt_brim[offset.extruder_nr_][offset.inset_idx_]; + MixedLinesSet& output_location = storage_.skirt_brim[offset.extruder_nr_][offset.inset_idx_]; const coord_t added_length = generateOffset(offset, covered_area, allowed_areas_per_extruder, output_location); if (added_length == 0) @@ -214,7 +215,7 @@ std::vector SkirtBrim::generatePrimaryBrim(std::vector& all_bri return total_length; } -coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std::vector& allowed_areas_per_extruder, SkirtBrimLine& result) +coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std::vector& allowed_areas_per_extruder, MixedLinesSet& result) { coord_t length_added; Shape brim; @@ -242,11 +243,12 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std const int reference_idx = std::get(offset.reference_outline_or_index_); const coord_t offset_dist = extruder_config.line_width_; +#warning Do it all in one go ? Shape local_brim; - auto closed_polygons_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].closed_polygons.toType().offset(offset_dist, ClipperLib::jtRound); + auto closed_polygons_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].getClosedLines().offset(offset_dist, ClipperLib::jtRound); local_brim.add(closed_polygons_brim); - auto open_polylines_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].open_polylines.offset(offset_dist, ClipperLib::jtRound); + auto open_polylines_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].getOpenLines().offset(offset_dist, ClipperLib::jtRound); local_brim.add(open_polylines_brim); local_brim.unionPolygons(); @@ -262,21 +264,19 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std Shape newly_covered = brim_lines.offset(extruder_config.line_width_ / 2 + 10, ClipperLib::jtRound); const coord_t max_stitch_distance = extruder_config.line_width_; - OpenPolylineStitcher::stitch(brim_lines, result.open_polylines, result.closed_polygons, max_stitch_distance); + MixedPolylineStitcher::stitch(brim_lines, result, max_stitch_distance); // clean up too small lines - for (size_t line_idx = 0; line_idx < result.open_polylines.size();) - { - const OpenPolyline& line = result.open_polylines[line_idx]; - if (line.shorterThan(min_brim_line_length)) - { - result.open_polylines.removeAt(line_idx); - } - else - { - line_idx++; - } - } + LinesSet& open_polylines = result.getOpenLines(); + open_polylines.erase( + std::remove_if( + open_polylines.begin(), + open_polylines.end(), + [](const OpenPolyline& line) + { + return line.shorterThan(min_brim_line_length); + }), + open_polylines.end()); // update allowed_areas_per_extruder covered_area = covered_area.unionPolygons(newly_covered.unionPolygons()); @@ -466,12 +466,12 @@ void SkirtBrim::generateShieldBrim(Shape& brim_covered_area, std::vector& // generate brim within shield_brim storage_.skirt_brim[extruder_nr].emplace_back(); - storage_.skirt_brim[extruder_nr].back().closed_polygons.add(shield_brim); + storage_.skirt_brim[extruder_nr].back().push_back(shield_brim.toType()); while (shield_brim.size() > 0) { shield_brim = shield_brim.offset(-primary_extruder_skirt_brim_line_width); - storage_.skirt_brim[extruder_nr].back().closed_polygons.add( - shield_brim); // throw all polygons for the shileds onto one heap; because the brim lines are generated from both sides the order will not be important + storage_.skirt_brim[extruder_nr].back().push_back(shield_brim.toType()); // throw all polygons for the shileds onto one heap; because the brim lines are + // generated from both sides the order will not be important } } @@ -528,7 +528,7 @@ void SkirtBrim::generateSecondarySkirtBrim(Shape& covered_area, std::vector, LinesSet, OpenPolyline, Point2LL>::stitch( + const LinesSet& lines, + LinesSet& result_lines, + LinesSet& result_polygons, + coord_t max_stitch_distance, + coord_t snap_distance); + template<> bool OpenPolylineStitcher::canReverse(const PathsPointIndex>&) { return true; } +template<> +bool PolylineStitcher, LinesSet, OpenPolyline, Point2LL>::canReverse(const PathsPointIndex>&) +{ + return true; +} + template<> bool ExtrusionLineStitcher::canConnect(const ExtrusionLine& a, const ExtrusionLine& b) { @@ -241,6 +255,12 @@ bool OpenPolylineStitcher::canConnect(const OpenPolyline&, const OpenPolyline&) return true; } +template<> +bool PolylineStitcher, LinesSet, OpenPolyline, Point2LL>::canConnect(const OpenPolyline&, const OpenPolyline&) +{ + return true; +} + template<> bool ExtrusionLineStitcher::isOdd(const ExtrusionLine& line) { @@ -253,4 +273,10 @@ bool OpenPolylineStitcher::isOdd(const OpenPolyline&) return false; } +template<> +bool PolylineStitcher, LinesSet, OpenPolyline, Point2LL>::isOdd(const OpenPolyline&) +{ + return false; +} + } // namespace cura diff --git a/src/utils/Simplify.cpp b/src/utils/Simplify.cpp index 44699bc4b1..56b39f195a 100644 --- a/src/utils/Simplify.cpp +++ b/src/utils/Simplify.cpp @@ -6,6 +6,7 @@ #include #include //Priority queue to prioritise removing unimportant vertices. +#include "geometry/closed_polyline.h" #include "geometry/open_polyline.h" namespace cura @@ -59,6 +60,7 @@ LinesSet Simplify::polyline(const LinesSet& polylines) const } template LinesSet Simplify::polyline(const LinesSet& polylines) const; +template LinesSet Simplify::polyline(const LinesSet& polylines) const; template<> Polyline Simplify::polyline(const Polyline& polyline) const From a13afa895d3dcb1ee8ca7c8e19d70f2afe4e5d5c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 8 Apr 2024 10:44:16 +0200 Subject: [PATCH 023/135] Checkpoint before changing architecture (again) --- include/geometry/closed_polyline.h | 2 +- include/geometry/generic_closed_polyline.h | 61 +----- include/geometry/lines_set.h | 135 +++++++++--- include/geometry/mixed_lines_set.h | 14 +- include/geometry/open_polyline.h | 19 +- include/geometry/points_set.h | 107 +++++++-- include/geometry/polygon.h | 30 ++- include/geometry/polyline.h | 123 +++++++++-- include/geometry/polyline_type.h | 5 +- include/geometry/shape.h | 18 +- include/sliceDataStorage.h | 4 +- include/slicer.h | 18 +- include/utils/ExtrusionLine.h | 40 ---- include/utils/OpenPolylineStitcher.h | 7 +- include/utils/Simplify.h | 10 +- include/utils/mixed_polyline_stitcher.h | 20 +- src/geometry/lines_set.cpp | 241 ++++++++++++++------- src/geometry/mixed_lines_set.cpp | 4 +- src/geometry/points_set.cpp | 36 +-- src/geometry/polygon.cpp | 40 ++-- src/geometry/polyline.cpp | 106 +++++---- src/geometry/shape.cpp | 232 ++++++++++---------- src/slicer.cpp | 22 +- src/utils/Simplify.cpp | 32 +-- 24 files changed, 778 insertions(+), 548 deletions(-) diff --git a/include/geometry/closed_polyline.h b/include/geometry/closed_polyline.h index 49ca7af908..e923714053 100644 --- a/include/geometry/closed_polyline.h +++ b/include/geometry/closed_polyline.h @@ -9,7 +9,7 @@ namespace cura { -using ClosedPolyline = GenericClosedPolyline; +// using ClosedPolyline = GenericClosedPolyline; } // namespace cura diff --git a/include/geometry/generic_closed_polyline.h b/include/geometry/generic_closed_polyline.h index bb1cc916a6..70c741024b 100644 --- a/include/geometry/generic_closed_polyline.h +++ b/include/geometry/generic_closed_polyline.h @@ -10,7 +10,7 @@ namespace cura { - +/* template class GenericClosedPolyline : public Polyline { @@ -32,65 +32,8 @@ class GenericClosedPolyline : public Polyline Polyline::operator=(other); return *this; } - - /*! - * Check if we are inside the polygon. We do this by tracing from the point towards the positive X direction, - * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. - * Care needs to be taken, if p.Y exactly matches a vertex to the right of p, then we need to count 1 intersect if the - * outline passes vertically past; and 0 (or 2) intersections if that point on the outline is a 'top' or 'bottom' vertex. - * The easiest way to do this is to break out two cases for increasing and decreasing Y ( from p0 to p1 ). - * A segment is tested if pa.Y <= p.Y < pb.Y, where pa and pb are the points (from p0,p1) with smallest & largest Y. - * When both have the same Y, no intersections are counted but there is a special test to see if the point falls - * exactly on the line. - * - * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. - * - * \deprecated This function is no longer used, since the Clipper function is used by the function PolygonRef::inside(.) - * - * \param p The point for which to check if it is inside this polygon - * \param border_result What to return when the point is exactly on the border - * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) - */ - // bool _inside(Point2LL p, bool border_result = false) const; - - /*! - * Clipper function. - * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. - * - * http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/PointInPolygon.htm - */ - bool inside(const Point2LL& p, bool border_result = false) const; - - bool inside(const auto& polygon) const; }; - -// ########################################################### -// Definitions of templated methods -// ########################################################### -template -bool GenericClosedPolyline::inside(const Point2LL& p, bool border_result) const -{ - int res = ClipperLib::PointInPolygon(p, *this); - if (res == -1) - { - return border_result; - } - return res == 1; -} - -template -bool GenericClosedPolyline::inside(const auto& polygon) const -{ - for (const auto& point : *this) - { - if (! ClipperLib::PointInPolygon(point, polygon)) - { - return false; - } - } - return true; -} - +*/ } // namespace cura #endif // GEOMETRY_GENERIC_CLOSED_POLYLINE_H diff --git a/include/geometry/lines_set.h b/include/geometry/lines_set.h index 3b5555c414..a35f0497a5 100644 --- a/include/geometry/lines_set.h +++ b/include/geometry/lines_set.h @@ -7,26 +7,23 @@ #include #include "geometry/point2ll.h" +#include "geometry/polyline_type.h" namespace cura { class Shape; -class OpenPolyline; -template -class LinesSet; +class Polyline; /*! - * \brief Base class for all geometry containers representing a set of polylines. All the polylines - * have to be of the same type, e.g. open polylines. Due to the nature of the Polyline - * classes, it is possible to cast a LinesSet directly to a - * std::vector> so that we can call the Clipper functions - * which having to do an active data conversion. It is also possible to virtually change the - * inner type of lines without having to do a conversion. + * \brief Base class for all geometry containers representing a set of polylines. */ template -class LinesSet : public std::vector +class LinesSet { +private: + std::vector lines_; + public: LinesSet() = default; @@ -35,34 +32,112 @@ class LinesSet : public std::vector LinesSet(LinesSet&& other) = default; LinesSet(const std::vector& lines) - : std::vector(lines) + : lines_(lines) { } LinesSet(std::vector&& lines) - : std::vector(std::move(lines)) + : lines_(std::move(lines)) { } - LinesSet(const std::vector>& paths) + /*LinesSet(const std::vector>& paths) : std::vector(*reinterpret_cast*>(&paths)) { + }*/ + + LinesSet(PolylineType type, std::vector>&& paths); + + const std::vector& getLines() const + { + return lines_; + } + + std::vector& getLines() + { + return lines_; + } + + std::vector::const_iterator begin() const + { + return lines_.begin(); + } + + std::vector::iterator begin() + { + return lines_.begin(); + } + + std::vector::const_iterator end() const + { + return lines_.end(); + } + + std::vector::iterator end() + { + return lines_.end(); + } + + const LineType& back() const + { + return lines_.back(); + } + + LineType& back() + { + return lines_.back(); } - LinesSet& operator=(const LinesSet& other) + void push_back(const LineType& line, bool checkNonEmpty = false); + + void push_back(LineType&& line, bool checkNonEmpty = false); + + void push_back(PolylineType type, ClipperLib::Paths&& paths); + + void push_back(LinesSet&& lines_set); + + size_t size() const + { + return lines_.size(); + } + + bool empty() const + { + return lines_.empty(); + } + + void reserve(size_t size) + { + lines_.reserve(size); + } + + void resize(size_t size) { - std::vector::operator=(other); - return *this; + lines_.resize(size); } - LinesSet& operator=(LinesSet&& other) + template + void emplace_back(Args&&... args) { - std::vector::operator=(other); - return *this; + lines_.emplace_back(args...); + } + + LinesSet& operator=(const LinesSet& other) = default; + + LinesSet& operator=(LinesSet&& other) = default; + + LineType& operator[](size_t index) + { + return lines_[index]; + } + + const LineType& operator[](size_t index) const + { + return lines_[index]; } #warning rename this to asType - template + /*template const LinesSet& toType() const { // This does work as long as we don't add any attribute to the PointsSet class or any of its child @@ -79,21 +154,17 @@ class LinesSet : public std::vector { // This does work as long as we don't add any attribute to the PointsSet class or any of its child return *reinterpret_cast>*>(this); - } + }*/ void add(const LinesSet& other) { - this->insert(this->end(), other.begin(), other.end()); + lines_->insert(other.lines_.end(), other.lines_.begin(), other.lines_.end()); } - void addIfNotEmpty(const LineType& line); - - void addIfNotEmpty(LineType&& line); - LineType& newLine() { - this->emplace_back(); - return this->back(); + lines_.emplace_back(); + return lines_.back(); } //!< Return the amount of points in all lines @@ -109,12 +180,13 @@ class LinesSet : public std::vector /*! * Add a simple line consisting of two points */ +#warning rename to addSegment and move to mixed void addLine(const Point2LL& from, const Point2LL& to); coord_t length() const; - void splitIntoSegments(LinesSet& result) const; - LinesSet splitIntoSegments() const; + void splitIntoSegments(LinesSet& result) const; + LinesSet splitIntoSegments() const; /*! * Removes overlapping consecutive line segments which don't delimit a @@ -136,6 +208,9 @@ class LinesSet : public std::vector * polygons. */ Shape tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; + +protected: + void addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; }; } // namespace cura diff --git a/include/geometry/mixed_lines_set.h b/include/geometry/mixed_lines_set.h index 372af32323..8f1ec679ff 100644 --- a/include/geometry/mixed_lines_set.h +++ b/include/geometry/mixed_lines_set.h @@ -4,23 +4,21 @@ #ifndef GEOMETRY_MIXED_LINES_SET_H #define GEOMETRY_MIXED_LINES_SET_H -#include "geometry/closed_polyline.h" #include "geometry/lines_set.h" -#include "geometry/open_polyline.h" +#include "geometry/polyline.h" namespace cura { +using MixedLinesSet = LinesSet; + +#if 0 /*! * \brief Container that can hold either open or closed polylines. We often have to handle "a bunch * of lines" which are either open or closed without taking care of what they actually are. */ -class MixedLinesSet +class MixedLinesSet : public LinesSet { -private: - LinesSet open_lines_; - LinesSet closed_lines_; - public: MixedLinesSet() = default; @@ -122,7 +120,7 @@ class MixedLinesSet return open_lines_.size() + closed_lines_.size(); } }; - +#endif } // namespace cura #endif // GEOMETRY_MIXED_LINES_SET_H diff --git a/include/geometry/open_polyline.h b/include/geometry/open_polyline.h index b6d8008509..23531227ba 100644 --- a/include/geometry/open_polyline.h +++ b/include/geometry/open_polyline.h @@ -9,42 +9,45 @@ namespace cura { -class OpenPolyline : public Polyline +/*class OpenPolyline : public Polyline { public: - OpenPolyline() = default; + OpenPolyline() + : Polyline{ PolylineType::Open } + { + } OpenPolyline(const OpenPolyline& other) = default; OpenPolyline(OpenPolyline&& other) = default; OpenPolyline(const std::initializer_list& initializer) - : Polyline(initializer) + : Polyline(PolylineType::Open, initializer) { } OpenPolyline(const std::vector& points) - : Polyline(points) + : Polyline(PolylineType::Open, points) { } OpenPolyline(std::vector&& points) - : Polyline(points) + : Polyline(PolylineType::Open, points) { } OpenPolyline& operator=(const OpenPolyline& other) { - Polyline::operator=(other); + Polyline::operator=(other); return *this; } OpenPolyline& operator=(OpenPolyline&& other) { - Polyline::operator=(other); + Polyline::operator=(other); return *this; } -}; +};*/ } // namespace cura diff --git a/include/geometry/points_set.h b/include/geometry/points_set.h index 78814e4382..54c6160936 100644 --- a/include/geometry/points_set.h +++ b/include/geometry/points_set.h @@ -36,18 +36,19 @@ bool shorterThan(const T& shape, const coord_t check_length) /*! * \brief Base class for all geometry containers representing a set of points. - * \warning This class and all its subclasses must not contain any attribute. This way the memory - * footprint of all the objects is the same whatever their type, which allows us to - * directly cast them between each other, and also most important, into - * std::vector which is the base type required by ClipperLib. This gives us the - * possibility to have nice container with transformation methods, and call the Clipper - * functions directly on them without having to make any active data conversion. */ -class PointsSet : public std::vector +class PointsSet { +private: + std::vector points_; + public: PointsSet() = default; + PointsSet(const PointsSet& other) = default; + + PointsSet(PointsSet&& other) = default; + PointsSet(const std::initializer_list& initializer); PointsSet(const std::vector& points); @@ -60,22 +61,102 @@ class PointsSet : public std::vector return *this; }*/ - const std::vector& asRawVector() const + const std::vector& getPoints() const + { + return points_; + } + + std::vector& getPoints() + { + return points_; + } + + size_t size() const + { + return points_.size(); + } + + void push_back(const Point2LL& point) + { + points_.push_back(point); + } + + void pop_back() + { + points_.pop_back(); + } + + std::vector::const_iterator begin() const + { + return points_.begin(); + } + + std::vector::iterator begin() + { + return points_.begin(); + } + + std::vector::const_iterator end() const + { + return points_.end(); + } + + std::vector::iterator end() { - // This does work as long as we don't add any attribute to the PointsSet class or any of its child - return *reinterpret_cast*>(this); + return points_.end(); } - std::vector& asRawVector() + const Point2LL& front() const { - // This does work as long as we don't add any attribute to the PointsSet class or any of its child - return *reinterpret_cast*>(this); + return points_.front(); } + Point2LL& front() + { + return points_.front(); + } + + const Point2LL& back() const + { + return points_.back(); + } + + Point2LL& back() + { + return points_.back(); + } + + bool empty() const + { + return points_.empty(); + } + + void resize(size_t size) + { + points_.resize(size); + } + + Point2LL& operator[](size_t index) + { + return points_[index]; + } + + const Point2LL& operator[](size_t index) const + { + return points_[index]; + } + + PointsSet& operator=(const PointsSet& other) = default; + + PointsSet& operator=(PointsSet&& other) = default; + +#warning seems to be unused Point2LL min() const; +#warning seems to be unused Point2LL max() const; +#warning seems to be unused Point2LL closestPointTo(const Point2LL& p) const; /*! diff --git a/include/geometry/polygon.h b/include/geometry/polygon.h index ea8e1ebe09..706dc061a0 100644 --- a/include/geometry/polygon.h +++ b/include/geometry/polygon.h @@ -4,7 +4,7 @@ #ifndef GEOMETRY_POLYGON_H #define GEOMETRY_POLYGON_H -#include "generic_closed_polyline.h" +#include "polyline.h" namespace cura { @@ -13,28 +13,42 @@ class Shape; class ListPolyIt; class AngleDegrees; -class Polygon : public GenericClosedPolyline +class Polygon : public Polyline { public: - Polygon() = default; + Polygon() + : Polyline{ PolylineType::Filled } + { + } Polygon(const Polygon& other) = default; Polygon(Polygon&& other) = default; Polygon(const std::initializer_list& initializer) - : GenericClosedPolyline(initializer) + : Polyline(PolylineType::Filled, initializer) + { + } + + explicit Polygon(const ClipperLib::Path& points) + : Polyline(PolylineType::Filled, points) { } - Polygon(const std::vector& points) - : GenericClosedPolyline(points) + explicit Polygon(ClipperLib::Path&& points) + : Polyline(PolylineType::Filled, points) { } Polygon& operator=(const Polygon& other) { - GenericClosedPolyline::operator=(other); + Polyline::operator=(other); + return *this; + } + + Polygon& operator=(Polygon&& other) + { + Polyline::operator=(other); return *this; } @@ -50,7 +64,7 @@ class Polygon : public GenericClosedPolyline double area() const { - return ClipperLib::Area(*this); + return ClipperLib::Area(getPoints()); } Point2LL centerOfMass() const; diff --git a/include/geometry/polyline.h b/include/geometry/polyline.h index a487062bf5..afb6d04c49 100644 --- a/include/geometry/polyline.h +++ b/include/geometry/polyline.h @@ -11,7 +11,6 @@ namespace cura { -class OpenPolyline; template class LinesSet; class AngleRadians; @@ -27,42 +26,96 @@ class AngleRadians; * * Filled Polyline : this is a particular type of closed polyline, for which we consider that the * "inside" part of the line forms a surface * - * Due to the nature of the PointsSet class, it is possible to cast e.g. an open polyline to a - * closed polyline. This only changes whether the last point forms a segment with the initial one, - * but the list of points itself does not change. - * * \note Historically, the open and closed polylines were not explicitely differenciated, so * sometimes we would use an open polyline with an extra point at the end, which virtually * closes the line. This behaviour is now deprecated and should be removed over time. */ -template class Polyline : public PointsSet { -public: - static constexpr PolylineType type_ = PolylineTypeVal; +private: +#warning possibly remove the enum and just use a "closed" boolean + PolylineType type_; public: using segments_iterator = SegmentIterator; using const_segments_iterator = SegmentIterator; - Polyline() = default; + Polyline(PolylineType type = PolylineType::Open) + : PointsSet() + , type_(type) + { + } + + Polyline(const Polyline& other) = default; + + Polyline(Polyline&& other) = default; - Polyline(const std::initializer_list& initializer) + Polyline(PolylineType type, const std::initializer_list& initializer) : PointsSet(initializer) + , type_(type) { } - Polyline(const std::vector& points) + Polyline(PolylineType type, const std::vector& points) : PointsSet(points) + , type_(type) { } - Polyline(std::vector&& points) + Polyline(PolylineType type, std::vector&& points) : PointsSet(points) + , type_(type) { } - template + virtual ~Polyline() = default; // This is required to tag the class as polymorphic + + Polyline& operator=(const Polyline& other) + { + PointsSet::operator=(other); + type_ = other.type_; + return *this; + } + + Polyline& operator=(Polyline&& other) + { + PointsSet::operator=(other); + type_ = other.type_; + return *this; + } + + PolylineType getType() const + { + return type_; + } + + /*! + * \brief Force setting the polyline type + * \param type The new type to be set + * \warning Forcibly setting the type changes the meaning of the vertices list. Use this method + * only if you are doing something specific, otherwise use convertToType() + */ + void setType(PolylineType type) + { + type_ = type; + } + + void convertToType(PolylineType type) + { +#warning implement me + } + + bool isClosed() const + { + return type_ != PolylineType::Open; + } + + bool isOpen() const + { + return type_ == PolylineType::Open; + } + + /*template OtherType& toType() { return *reinterpret_cast(this); @@ -72,7 +125,7 @@ class Polyline : public PointsSet const OtherType& toType() const { return *reinterpret_cast(this); - } + }*/ /*Polyline& operator=(const Polyline& other) { @@ -92,8 +145,8 @@ class Polyline : public PointsSet * Split these poly line objects into several line segment objects consisting of only two verts * and store them in the \p result */ - void splitIntoSegments(LinesSet& result) const; - LinesSet splitIntoSegments() const; + void splitIntoSegments(LinesSet& result) const; + LinesSet splitIntoSegments() const; /*! * On Y-axis positive upward displays, Orientation will return true if the polygon's orientation is counter-clockwise. @@ -102,7 +155,7 @@ class Polyline : public PointsSet */ bool orientation() const { - return ClipperLib::Orientation(*this); + return ClipperLib::Orientation(getPoints()); } coord_t length() const; @@ -111,7 +164,7 @@ class Polyline : public PointsSet void reverse() { - ClipperLib::ReversePath(*this); + ClipperLib::ReversePath(getPoints()); } void removeColinearEdges(const AngleRadians max_deviation_angle); @@ -139,13 +192,43 @@ class Polyline : public PointsSet */ void simplify(const coord_t smallest_line_segment_squared = MM2INT(0.01) * MM2INT(0.01), const coord_t allowed_error_distance_squared = 25); - void pseudoClose() + /*void pseudoClose() { if (size() >= 2) { push_back(front()); } - } + }*/ + + /*! + * Check if we are inside the polygon. We do this by tracing from the point towards the positive X direction, + * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. + * Care needs to be taken, if p.Y exactly matches a vertex to the right of p, then we need to count 1 intersect if the + * outline passes vertically past; and 0 (or 2) intersections if that point on the outline is a 'top' or 'bottom' vertex. + * The easiest way to do this is to break out two cases for increasing and decreasing Y ( from p0 to p1 ). + * A segment is tested if pa.Y <= p.Y < pb.Y, where pa and pb are the points (from p0,p1) with smallest & largest Y. + * When both have the same Y, no intersections are counted but there is a special test to see if the point falls + * exactly on the line. + * + * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. + * + * \deprecated This function is no longer used, since the Clipper function is used by the function PolygonRef::inside(.) + * + * \param p The point for which to check if it is inside this polygon + * \param border_result What to return when the point is exactly on the border + * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) + */ + // bool _inside(Point2LL p, bool border_result = false) const; + + /*! + * Clipper function. + * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. + * + * http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/PointInPolygon.htm + */ + bool inside(const Point2LL& p, bool border_result = false) const; + + bool inside(const auto& polygon) const; private: /*! diff --git a/include/geometry/polyline_type.h b/include/geometry/polyline_type.h index 0042b5d943..f203722086 100644 --- a/include/geometry/polyline_type.h +++ b/include/geometry/polyline_type.h @@ -9,8 +9,9 @@ namespace cura enum class PolylineType { - Open, - Closed, + Open, // Line is open and has no wise + ImplicitelyClosed, // Line is closed by having a virtual additional segment between last and first vertices + ExplicitelyClosed, // Line is closed by having the same point twice at beginning and end of list Filled }; diff --git a/include/geometry/shape.h b/include/geometry/shape.h index b91ad296f6..effe7ac464 100644 --- a/include/geometry/shape.h +++ b/include/geometry/shape.h @@ -4,7 +4,7 @@ #ifndef GEOMETRY_SHAPE_H #define GEOMETRY_SHAPE_H -#include "geometry/lines_set.h" +#include "geometry/mixed_lines_set.h" #include "geometry/polygon.h" #include "settings/types/Angle.h" @@ -30,17 +30,12 @@ class Shape : public LinesSet { } - Shape(const std::vector& paths) - : LinesSet(paths) - { - } + explicit Shape(ClipperLib::Paths&& paths); Shape& operator=(const Shape& other); Shape& operator=(Shape&& other); - void add(const Shape& other); - /*! * Convert ClipperLib::PolyTree to a Shape object, * which uses ClipperLib::Paths instead of ClipperLib::PolyTree @@ -49,6 +44,7 @@ class Shape : public LinesSet Shape difference(const Shape& other) const; +#warning rename this to union Shape unionPolygons(const Shape& other, ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero) const; /*! @@ -66,13 +62,13 @@ class Shape : public LinesSet * * \note Due to a clipper bug with polylines with nearly collinear segments, the polylines are cut up into separate polylines, and restitched back together at the end. * - * \param polylines The (non-closed!) polylines to limit to the area of this Polygons object + * \param polylines The polylines to limit to the area of this Polygons object * \param restitch Whether to stitch the resulting segments into longer polylines, or leave every segment as a single segment * \param max_stitch_distance The maximum distance for two polylines to be stitched together with a segment * \return The resulting polylines limited to the area of this Polygons object */ template - LinesSet intersectionPolyLines(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; + MixedLinesSet intersection(const MixedLinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; /*! * Add the front to each polygon so that the polygon is represented as a polyline @@ -258,7 +254,7 @@ class Shape : public LinesSet * * @param stream The stream to write to */ - [[maybe_unused]] void writeWkt(std::ostream& stream) const; + //[[maybe_unused]] void writeWkt(std::ostream& stream) const; /*! * @brief Import the polygon from a WKT string @@ -266,7 +262,7 @@ class Shape : public LinesSet * @param wkt The WKT string to read from * @return Shape The polygons read from the stream */ - [[maybe_unused]] static Shape fromWkt(const std::string& wkt); + //[[maybe_unused]] static Shape fromWkt(const std::string& wkt); /*! * @brief Remove self-intersections from the polygons diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 4b1c30f924..0ece72efee 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -169,7 +169,7 @@ class SliceLayer coord_t printZ; //!< The height at which this layer needs to be printed. Can differ from sliceZ due to the raft. coord_t thickness; //!< The thickness of this layer. Can be different when using variable layer heights. std::vector parts; //!< An array of LayerParts which contain the actual data. The parts are printed one at a time to minimize travel outside of the 3D model. - LinesSet openPolyLines; //!< A list of lines which were never hooked up into a 2D polygon. (Currently unused in normal operation) + LinesSet openPolyLines; //!< A list of lines which were never hooked up into a 2D polygon. (Currently unused in normal operation) /*! * \brief The parts of the model that are exposed at the very top of the @@ -376,7 +376,7 @@ class SliceDataStorage : public NoCopy SupportStorage support; std::vector skirt_brim[MAX_EXTRUDERS]; //!< Skirt/brim polygons per extruder, ordered from inner to outer polygons. - LinesSet support_brim; //!< brim lines for support, going from the edge of the support inward. \note Not ordered by inset. + LinesSet support_brim; //!< brim lines for support, going from the edge of the support inward. \note Not ordered by inset. // Storage for the outline of the raft-parts. Will be filled with lines when the GCode is generated. Shape raftBaseOutline; diff --git a/include/slicer.h b/include/slicer.h index 83d648f608..b5116688c8 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -62,7 +62,7 @@ class SlicerLayer int z = -1; Shape polygons; - LinesSet openPolylines; + LinesSet openPolylines; /*! * \brief Connect the segments into polygons for this layer of this \p mesh. @@ -77,7 +77,7 @@ class SlicerLayer * * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop */ - void makeBasicPolygonLoops(std::vector& open_polylines); + void makeBasicPolygonLoops(LinesSet& open_polylines); /*! * Connect the segments into a loop, starting from the segment with index \p start_segment_idx @@ -85,7 +85,7 @@ class SlicerLayer * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop * \param[in] start_segment_idx The index into SlicerLayer::segments for the first segment from which to start the polygon loop */ - void makeBasicPolygonLoop(std::vector& open_polylines, const size_t start_segment_idx); + void makeBasicPolygonLoop(LinesSet& open_polylines, const size_t start_segment_idx); /*! * Get the next segment connected to the end of \p segment. @@ -105,7 +105,7 @@ class SlicerLayer * * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop */ - void connectOpenPolylines(std::vector& open_polylines); + void connectOpenPolylines(LinesSet& open_polylines); /*! * Link up all the missing ends, closing up the smallest gaps first. This is an inefficient implementation which can run in O(n*n*n) time. @@ -114,7 +114,7 @@ class SlicerLayer * * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop yet */ - void stitch(std::vector& open_polylines); + void stitch(LinesSet& open_polylines); std::optional findPolygonGapCloser(Point2LL ip0, Point2LL ip1); @@ -127,7 +127,7 @@ class SlicerLayer * * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop yet */ - void stitch_extensive(std::vector& open_polylines); + void stitch_extensive(LinesSet& open_polylines); private: /*! @@ -436,7 +436,7 @@ class SlicerLayer * \param[in,out] terminus_1 the Terminus on polyline_1 to join at. * \param[out] reverse Whether the polylines need to be reversed. */ - void planPolylineStitch(const std::vector& open_polylines, Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const; + void planPolylineStitch(const LinesSet& open_polylines, Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const; /*! Joins polyline_1 onto polyline_0. * @@ -454,7 +454,7 @@ class SlicerLayer * polyline_0 and reverse[1] indicates whether to reverse * polyline_1 */ - static void joinPolylines(OpenPolyline& polyline_0, OpenPolyline& polyline_1, const bool reverse[2]); + static void joinPolylines(Polyline& polyline_0, Polyline& polyline_1, const bool reverse[2]); /*! * Connecting polylines that are not closed yet. @@ -474,7 +474,7 @@ class SlicerLayer * \param[in] allow_reverse If true, then this function is allowed * to reverse edge directions to merge polylines. */ - void connectOpenPolylinesImpl(std::vector& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse); + void connectOpenPolylinesImpl(LinesSet& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse); }; class Slicer diff --git a/include/utils/ExtrusionLine.h b/include/utils/ExtrusionLine.h index 9c60558552..cce89c9274 100644 --- a/include/utils/ExtrusionLine.h +++ b/include/utils/ExtrusionLine.h @@ -226,46 +226,6 @@ struct ExtrusionLine return ret; } - /*! - * Create a true-extrusion area shape for the path; this means that each junction follows the bead-width - * set for that junction. - */ - [[maybe_unused]] Shape toExtrusionPolygons() const - { - Polygon poly; - - const auto add_line_direction = [&poly](const auto iterator) - { - for (const auto& element : iterator | ranges::views::sliding(2)) - { - const ExtrusionJunction& j1 = element[0]; - const ExtrusionJunction& j2 = element[1]; - - const auto dir = j2.p_ - j1.p_; - const auto normal = turn90CCW(dir); - const auto mag = vSize(normal); - - if (mag <= 5) - { - continue; - } - - poly.emplace_back(j1.p_ + normal * j1.w_ / mag / 2); - poly.emplace_back(j2.p_ + normal * j2.w_ / mag / 2); - } - }; - - // forward pass - add_line_direction(junctions_); - // backward pass - add_line_direction(junctions_ | ranges::views::reverse); - - Shape paths; - paths.emplace_back(poly); - ClipperLib::SimplifyPolygons(paths.asRawVector(), ClipperLib::pftNonZero); - return paths; - } - /*! * Get the minimal width of this path */ diff --git a/include/utils/OpenPolylineStitcher.h b/include/utils/OpenPolylineStitcher.h index fd189fa818..25580da160 100644 --- a/include/utils/OpenPolylineStitcher.h +++ b/include/utils/OpenPolylineStitcher.h @@ -5,14 +5,13 @@ #define UTILS_OPEN_POLYLINE_STITCHER_H #include "PolylineStitcher.h" -#include "geometry/open_polyline.h" -#include "geometry/polygon.h" -#include "geometry/shape.h" +#include "geometry/lines_set.h" +#include "geometry/polyline.h" namespace cura { -using OpenPolylineStitcher = PolylineStitcher, Shape, OpenPolyline, Point2LL>; +using OpenPolylineStitcher = PolylineStitcher, LinesSet, OpenPolyline, Point2LL>; } // namespace cura #endif // UTILS_OPEN_POLYLINE_STITCHER_H diff --git a/include/utils/Simplify.h b/include/utils/Simplify.h index 9f40986d9e..d3db96a6dc 100644 --- a/include/utils/Simplify.h +++ b/include/utils/Simplify.h @@ -5,13 +5,15 @@ #define UTILS_SIMPLIFY_H #include "../settings/Settings.h" //To load the parameters from a Settings object. -#include "ExtrusionLine.h" #include "geometry/polygon.h" #include "linearAlg2D.h" //To calculate line deviations and intersecting lines. namespace cura { +struct ExtrusionLine; +struct ExtrusionJunction; + /*! * Utility class to reduce the resolution of polygons and polylines, under * certain constraints. @@ -115,8 +117,7 @@ class Simplify * \param polyline The polyline to simplify. * \return The simplified polyline. */ - template - Polyline polyline(const Polyline& polyline) const; + Polyline polyline(const Polyline& polyline) const; /*! * Simplify a variable-line-width polyline. @@ -418,8 +419,7 @@ class Simplify * \param polygon The polygon to add to. * \param vertex The vertex to add. */ - template - void appendVertex(Polyline& polygon, const Point2LL& vertex) const; + void appendVertex(Polyline& polygon, const Point2LL& vertex) const; /*! * Append a vertex to this extrusion line. diff --git a/include/utils/mixed_polyline_stitcher.h b/include/utils/mixed_polyline_stitcher.h index 00e2633df4..10bc3d9863 100644 --- a/include/utils/mixed_polyline_stitcher.h +++ b/include/utils/mixed_polyline_stitcher.h @@ -12,12 +12,26 @@ namespace cura { -class MixedPolylineStitcher : public PolylineStitcher, LinesSet, OpenPolyline, Point2LL> +class MixedPolylineStitcher : public PolylineStitcher, LinesSet, Polyline, Point2LL> { public: - static void stitch(const LinesSet& lines, MixedLinesSet& result, coord_t max_stitch_distance = MM2INT(0.1), coord_t snap_distance = 10) + static void stitch(const LinesSet& lines, MixedLinesSet& result, coord_t max_stitch_distance = MM2INT(0.1), coord_t snap_distance = 10) { - PolylineStitcher::stitch(lines, result.getOpenLines(), result.getClosedLines(), max_stitch_distance, snap_distance); + LinesSet open_lines; + LinesSet closed_lines; + + PolylineStitcher::stitch(lines, open_lines, closed_lines, max_stitch_distance, snap_distance); + + result.push_back(std::move(open_lines)); + + for (Polyline& closed_line : closed_lines) + { + // Base stitch method will create explicitely closed polylines, but won't tag them as such + // because it is a generic algporitm. Tag them now. + closed_line.setType(PolylineType::ExplicitelyClosed); + } + + result.push_back(std::move(closed_lines)); } }; diff --git a/src/geometry/lines_set.cpp b/src/geometry/lines_set.cpp index d1405150f6..fdede10b3d 100644 --- a/src/geometry/lines_set.cpp +++ b/src/geometry/lines_set.cpp @@ -5,32 +5,78 @@ #include -#include "geometry/closed_polyline.h" -#include "geometry/open_polyline.h" #include "geometry/polygon.h" -#include "geometry/polyline_type.h" +#include "geometry/polyline.h" #include "geometry/shape.h" namespace cura { +template +LinesSet::LinesSet(PolylineType type, std::vector>&& paths) +{ + reserve(paths.size()); + for (std::vector& path : paths) + { + push_back(type, std::move(path)); + } +} + +template +void LinesSet::push_back(const LineType& line, bool checkNonEmpty) +{ + if (! checkNonEmpty || ! line.empty()) + { + lines_.push_back(line); + } +} + +template +void LinesSet::push_back(LineType&& line, bool checkNonEmpty) +{ + if (! checkNonEmpty || ! line.empty()) + { + lines_.push_back(line); + } +} + +template +void LinesSet::push_back(PolylineType type, ClipperLib::Paths&& paths) +{ + reserve(size() + paths.size()); + for (ClipperLib::Path& path : paths) + { + lines_.emplace_back(type, std::move(path)); + } +} + +template +void LinesSet::push_back(LinesSet&& lines_set) +{ + reserve(size() + lines_set.size()); + for (LineType& line : lines_set) + { + push_back(std::move(line)); + } +} + template size_t LinesSet::pointCount() const { return std::accumulate( - this->begin(), - this->end(), + lines_.begin(), + lines_.end(), size_t(0), - [](size_t total, const Polygon& polygon) + [](size_t total, const LineType& line) { - return total + polygon.size(); + return total + line.size(); }); } template void LinesSet::addLine(const Point2LL& from, const Point2LL& to) { - this->emplace_back(std::initializer_list{ from, to }); + lines_.emplace_back(PolylineType::Open, std::initializer_list{ from, to }); } template @@ -38,7 +84,7 @@ void LinesSet::addIfNotEmpty(const LineType& line) { if (! line.empty()) { - this->push_back(line); + lines_.push_back(line); } } @@ -47,42 +93,42 @@ void LinesSet::addIfNotEmpty(LineType&& line) { if (! line.empty()) { - this->emplace_back(std::move(line)); + lines_.emplace_back(std::move(line)); } } template void LinesSet::removeAt(size_t index) { - if (this->size() == 1) + if (lines_.size() == 1) { - this->clear(); + lines_.clear(); } - else if (this->size() > 1) + else if (lines_.size() > 1) { - assert(index < this->size()); - if (index < this->size() - 1) + assert(index < lines_.size()); + if (index < lines_.size() - 1) { - (*this)[index] = std::move(this->back()); + lines_[index] = std::move(lines_.back()); } - this->resize(this->size() - 1); + lines_.resize(lines_.size() - 1); } } template -void LinesSet::splitIntoSegments(LinesSet& result) const +void LinesSet::splitIntoSegments(LinesSet& result) const { - for (const LineType& line : (*this)) + for (const LineType& line : lines_) { line.splitIntoSegments(result); } } template -LinesSet LinesSet::splitIntoSegments() const +LinesSet LinesSet::splitIntoSegments() const { - LinesSet result; - for (const LineType& line : (*this)) + LinesSet result; + for (const LineType& line : lines_) { line.splitIntoSegments(result); } @@ -93,8 +139,8 @@ template coord_t LinesSet::length() const { return std::accumulate( - this->begin(), - this->end(), + lines_.begin(), + lines_.end(), 0, [](coord_t total, const LineType& line) { @@ -113,45 +159,81 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType { if (distance == 0) { - return Shape(asRawVector()); - } + // Return a shape that contains only actual polygons + Shape result; - Shape temp; - const ClipperLib::Paths* actual_polygons = &asRawVector(); - Shape ret; - ClipperLib::EndType end_type; - if constexpr (LineType::type_ == PolylineType::Filled) - { - temp = Shape(asRawVector()).unionPolygons(); - actual_polygons = &temp.asRawVector(); - end_type = ClipperLib::etClosedPolygon; - } - else if constexpr (LineType::type_ == PolylineType::Closed) - { - end_type = ClipperLib::etClosedLine; - } - else if (joinType == ClipperLib::jtMiter) - { - end_type = ClipperLib::etOpenSquare; + for (const LineType& line : lines_) + { + if (const Polygon* polygon = dynamic_cast(&line)) + { + result.push_back(*polygon); + } + } + + return result; } else { - end_type = ClipperLib::etOpenRound; + Shape polygons; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + + for (const LineType& line : lines_) + { + if (const Polygon* polygon = dynamic_cast(&line)) + { + // Union all polygons first and add them later + polygons.push_back(*polygon); + + /*temp = Shape(asRawVector()).unionPolygons(); + actual_polygons = &temp.asRawVector(); + end_type = ClipperLib::etClosedPolygon;*/ + } + else + { + ClipperLib::EndType end_type; + + if (line.isClosed()) + { + end_type = ClipperLib::etClosedLine; + } + else if (joinType == ClipperLib::jtMiter) + { + end_type = ClipperLib::etOpenSquare; + } + else + { + end_type = ClipperLib::etOpenRound; + } + + clipper.AddPath(line.getPoints(), joinType, end_type); + } + } + + if (! polygons.empty()) + { + polygons = polygons.unionPolygons(); + + for (const Polygon& polygon : polygons) + { + clipper.AddPath(polygon.getPoints(), joinType, ClipperLib::etClosedPolygon); + } + } + + clipper.MiterLimit = miter_limit; + + ClipperLib::Paths result; + clipper.Execute(result, static_cast(distance)); + return Shape(std::move(result)); } - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - clipper.AddPaths(*actual_polygons, joinType, end_type); - clipper.MiterLimit = miter_limit; - clipper.Execute(ret.asRawVector(), distance); - return ret; } template void LinesSet::removeDegenerateVerts() { - constexpr bool for_polyline = LineType::type_ == PolylineType::Open; - for (size_t poly_idx = 0; poly_idx < this->size(); poly_idx++) + for (size_t poly_idx = 0; poly_idx < lines_.size(); poly_idx++) { - LineType& poly = (*this)[poly_idx]; + LineType& poly = lines_[poly_idx]; + bool for_polyline = ! poly.isClosed(); Polygon result; auto isDegenerate = [](const Point2LL& last, const Point2LL& now, const Point2LL& next) @@ -202,7 +284,7 @@ void LinesSet::removeDegenerateVerts() { if (for_polyline || result.size() > 2) { - poly = result; + poly = std::move(result); } else { @@ -213,40 +295,41 @@ void LinesSet::removeDegenerateVerts() } } -template size_t LinesSet::pointCount() const; -template void LinesSet::addLine(const Point2LL& from, const Point2LL& to); -template void LinesSet::removeAt(size_t index); -template void LinesSet::splitIntoSegments(LinesSet& result) const; -template LinesSet LinesSet::splitIntoSegments() const; -template coord_t LinesSet::length() const; -template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; -template Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; -template void LinesSet::removeDegenerateVerts(); -template void LinesSet::addIfNotEmpty(const OpenPolyline& line); -template void LinesSet::addIfNotEmpty(OpenPolyline&& line); +template +void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const +{ + for (const LineType& line : getLines()) + { + // In this context, the "Closed" argument means "Is a surface" so it should be only + // true for actual filled polygons. Closed polylines are to be treated as lines here. + clipper.AddPath(line.getPoints(), PolyTyp, line.getType() == PolylineType::Filled); + } +} + + +template size_t LinesSet::pointCount() const; +template void LinesSet::addLine(const Point2LL& from, const Point2LL& to); +template void LinesSet::removeAt(size_t index); +template void LinesSet::splitIntoSegments(LinesSet& result) const; +template LinesSet LinesSet::splitIntoSegments() const; +template coord_t LinesSet::length() const; +template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; +template void LinesSet::removeDegenerateVerts(); +template void LinesSet::addIfNotEmpty(const Polyline& line); +template void LinesSet::addIfNotEmpty(Polyline&& line); +template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; template size_t LinesSet::pointCount() const; -template void LinesSet::addLine(const Point2LL& from, const Point2LL& to); template void LinesSet::removeAt(size_t index); -template void LinesSet::splitIntoSegments(LinesSet& result) const; -template LinesSet LinesSet::splitIntoSegments() const; +template void LinesSet::splitIntoSegments(LinesSet& result) const; +template LinesSet LinesSet::splitIntoSegments() const; template coord_t LinesSet::length() const; template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; template Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; template void LinesSet::removeDegenerateVerts(); template void LinesSet::addIfNotEmpty(const Polygon& line); template void LinesSet::addIfNotEmpty(Polygon&& line); - -template size_t LinesSet::pointCount() const; -template void LinesSet::addLine(const Point2LL& from, const Point2LL& to); -template void LinesSet::removeAt(size_t index); -template void LinesSet::splitIntoSegments(LinesSet& result) const; -template LinesSet LinesSet::splitIntoSegments() const; -template coord_t LinesSet::length() const; -template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; -template Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; -template void LinesSet::removeDegenerateVerts(); -template void LinesSet::addIfNotEmpty(const ClosedPolyline& line); -template void LinesSet::addIfNotEmpty(ClosedPolyline&& line); +template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; } // namespace cura diff --git a/src/geometry/mixed_lines_set.cpp b/src/geometry/mixed_lines_set.cpp index 9413f1a730..a509b883e8 100644 --- a/src/geometry/mixed_lines_set.cpp +++ b/src/geometry/mixed_lines_set.cpp @@ -7,10 +7,10 @@ namespace cura { -void MixedLinesSet::push_back(const MixedLinesSet& lines) +/*void MixedLinesSet::push_back(const MixedLinesSet& lines) { push_back(lines.getOpenLines()); push_back(lines.getClosedLines()); -} +}*/ } // namespace cura diff --git a/src/geometry/points_set.cpp b/src/geometry/points_set.cpp index 707e1c01bb..ae210ffa2f 100644 --- a/src/geometry/points_set.cpp +++ b/src/geometry/points_set.cpp @@ -11,23 +11,23 @@ namespace cura { PointsSet::PointsSet(const std::initializer_list& initializer) - : std::vector(initializer) + : points_(initializer) { } PointsSet::PointsSet(const std::vector& points) - : std::vector(points) + : points_(points) { } PointsSet::PointsSet(std::vector&& points) - : std::vector(std::move(points)) + : points_(std::move(points)) { } void PointsSet::applyMatrix(const PointMatrix& matrix) { - for (Point2LL& point : (*this)) + for (Point2LL& point : points_) { point = matrix.apply(point); } @@ -35,7 +35,7 @@ void PointsSet::applyMatrix(const PointMatrix& matrix) void PointsSet::applyMatrix(const Point3Matrix& matrix) { - for (Point2LL& point : (*this)) + for (Point2LL& point : points_) { point = matrix.apply(point); } @@ -44,10 +44,10 @@ void PointsSet::applyMatrix(const Point3Matrix& matrix) Point2LL PointsSet::min() const { Point2LL ret = Point2LL(POINT_MAX, POINT_MAX); - for (Point2LL p : *this) + for (Point2LL point : points_) { - ret.X = std::min(ret.X, p.X); - ret.Y = std::min(ret.Y, p.Y); + ret.X = std::min(ret.X, point.X); + ret.Y = std::min(ret.Y, point.Y); } return ret; } @@ -55,35 +55,35 @@ Point2LL PointsSet::min() const Point2LL PointsSet::max() const { Point2LL ret = Point2LL(POINT_MIN, POINT_MIN); - for (Point2LL p : *this) + for (Point2LL point : points_) { - ret.X = std::max(ret.X, p.X); - ret.Y = std::max(ret.Y, p.Y); + ret.X = std::max(ret.X, point.X); + ret.Y = std::max(ret.Y, point.Y); } return ret; } Point2LL PointsSet::closestPointTo(const Point2LL& p) const { - Point2LL ret = p; + const Point2LL* ret = &p; double bestDist = std::numeric_limits::max(); - for (size_t n = 0; n < size(); n++) + for (const Point2LL& point : points_) { - double dist = vSize2f(p - (*this)[n]); + double dist = vSize2f(p - point); if (dist < bestDist) { - ret = (*this)[n]; + ret = &point; bestDist = dist; } } - return ret; + return *ret; } void PointsSet::translate(const Point2LL& translation) { - for (Point2LL& p : *this) + for (Point2LL& point : points_) { - p += translation; + point += translation; } } diff --git a/src/geometry/polygon.cpp b/src/geometry/polygon.cpp index b0a01cb362..82f796dc4b 100644 --- a/src/geometry/polygon.cpp +++ b/src/geometry/polygon.cpp @@ -33,12 +33,12 @@ namespace cura Shape Polygon::intersection(const Polygon& other) const { - Shape ret; + ClipperLib::Paths ret_paths; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPath(*this, ClipperLib::ptSubject, true); - clipper.AddPath(other, ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctIntersection, ret.asRawVector()); - return ret; + clipper.AddPath(getPoints(), ClipperLib::ptSubject, true); + clipper.AddPath(other.getPoints(), ClipperLib::ptClip, true); + clipper.Execute(ClipperLib::ctIntersection, ret_paths); + return Shape(std::move(ret_paths)); } void Polygon::smooth2(int remove_length, Polygon& result) const @@ -50,20 +50,20 @@ void Polygon::smooth2(int remove_length, Polygon& result) const for (unsigned int poly_idx = 1; poly_idx < size(); poly_idx++) { - const Point2LL& last = (*this)[poly_idx - 1]; - const Point2LL& now = (*this)[poly_idx]; - const Point2LL& next = (*this)[(poly_idx + 1) % size()]; + const Point2LL& last = getPoints()[poly_idx - 1]; + const Point2LL& now = getPoints()[poly_idx]; + const Point2LL& next = getPoints()[(poly_idx + 1) % size()]; if (shorterThen(last - now, remove_length) && shorterThen(now - next, remove_length)) { poly_idx++; // skip the next line piece (dont escalate the removal of edges) if (poly_idx < size()) { - result.push_back((*this)[poly_idx]); + result.push_back(getPoints()[poly_idx]); } } else { - result.push_back((*this)[poly_idx]); + result.push_back(getPoints()[poly_idx]); } } } @@ -113,15 +113,15 @@ void Polygon::smooth(int remove_length, Polygon& result) const } return true; }; - Point2LL v02 = (*this)[2] - (*this)[0]; + Point2LL v02 = getPoints()[2] - getPoints()[0]; Point2LL v02T = turn90CCW(v02); int64_t v02_size = vSize(v02); bool force_push = false; for (unsigned int poly_idx = 1; poly_idx < size(); poly_idx++) { - const Point2LL& p1 = (*this)[poly_idx]; - const Point2LL& p2 = (*this)[(poly_idx + 1) % size()]; - const Point2LL& p3 = (*this)[(poly_idx + 2) % size()]; + const Point2LL& p1 = getPoints()[poly_idx]; + const Point2LL& p2 = getPoints()[(poly_idx + 1) % size()]; + const Point2LL& p3 = getPoints()[(poly_idx + 2) % size()]; // v02 computed in last iteration // v02_size as well const Point2LL v12 = p2 - p1; @@ -582,13 +582,13 @@ Point2LL Polygon::centerOfMass() const { if (size() > 0) { - Point2LL p0 = (*this)[0]; + Point2LL p0 = getPoints()[0]; if (size() > 1) { double x = 0, y = 0; for (size_t n = 1; n <= size(); n++) { - Point2LL p1 = (*this)[n % size()]; + Point2LL p1 = getPoints()[n % size()]; double second_factor = static_cast((p0.X * p1.Y) - (p1.X * p0.Y)); x += double(p0.X + p1.X) * second_factor; @@ -620,12 +620,12 @@ Shape Polygon::offset(int distance, ClipperLib::JoinType join_type, double miter { return Shape({ *this }); } - Shape ret; + ClipperLib::Paths ret; ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - clipper.AddPath(*this, join_type, ClipperLib::etClosedPolygon); + clipper.AddPath(getPoints(), join_type, ClipperLib::etClosedPolygon); clipper.MiterLimit = miter_limit; - clipper.Execute(ret.asRawVector(), distance); - return ret; + clipper.Execute(ret, distance); + return Shape(std::move(ret)); } } // namespace cura diff --git a/src/geometry/polyline.cpp b/src/geometry/polyline.cpp index 40fdb074c2..135a165b12 100644 --- a/src/geometry/polyline.cpp +++ b/src/geometry/polyline.cpp @@ -13,8 +13,7 @@ namespace cura { -template -void Polyline::removeColinearEdges(const AngleRadians max_deviation_angle) +void Polyline::removeColinearEdges(const AngleRadians max_deviation_angle) { // TODO: Can be made more efficient (for example, use pointer-types for process-/skip-indices, so we can swap them without copy). @@ -30,7 +29,7 @@ void Polyline::removeColinearEdges(const AngleRadians max_devia { go = false; - const ClipperLib::Path& rpath = *this; + const ClipperLib::Path& rpath = getPoints(); const size_t pathlen = rpath.size(); if (pathlen <= 3) { @@ -39,7 +38,7 @@ void Polyline::removeColinearEdges(const AngleRadians max_devia std::vector skip_indices(size(), false); - Polyline new_path; + Polyline new_path(type_); for (size_t point_idx = 0; point_idx < pathlen; ++point_idx) { // Don't iterate directly over process-indices, but do it this way, because there are points _in_ process-indices that should nonetheless be skipped: @@ -83,7 +82,7 @@ void Polyline::removeColinearEdges(const AngleRadians max_devia ++point_idx; } } - (*this) = new_path; + (*this) = std::move(new_path); num_removed_in_iteration += pathlen - size(); process_indices.clear(); @@ -92,16 +91,14 @@ void Polyline::removeColinearEdges(const AngleRadians max_devia } while (num_removed_in_iteration > 0); } -template -Polyline::const_segments_iterator Polyline::beginSegments() const +Polyline::const_segments_iterator Polyline::beginSegments() const { return const_segments_iterator(begin(), begin(), end()); } -template -Polyline::const_segments_iterator Polyline::endSegments() const +Polyline::const_segments_iterator Polyline::endSegments() const { - if constexpr (type_ == PolylineType::Closed || type_ == PolylineType::Filled) + if (type_ == PolylineType::ImplicitelyClosed) { return const_segments_iterator(end(), begin(), end()); } @@ -111,16 +108,14 @@ Polyline::const_segments_iterator Polyline::en } } -template -Polyline::segments_iterator Polyline::beginSegments() +Polyline::segments_iterator Polyline::beginSegments() { return segments_iterator(begin(), begin(), end()); } -template -Polyline::segments_iterator Polyline::endSegments() +Polyline::segments_iterator Polyline::endSegments() { - if constexpr (type_ == PolylineType::Closed || type_ == PolylineType::Filled) + if (type_ == PolylineType::ImplicitelyClosed) { return segments_iterator(end(), begin(), end()); } @@ -130,8 +125,7 @@ Polyline::segments_iterator Polyline::endSegme } } -template -coord_t Polyline::length() const +coord_t Polyline::length() const { return std::accumulate( beginSegments(), @@ -143,8 +137,7 @@ coord_t Polyline::length() const }); } -template -bool Polyline::shorterThan(const coord_t check_length) const +bool Polyline::shorterThan(const coord_t check_length) const { coord_t length = 0; auto iterator_segment = std::find_if( @@ -158,51 +151,56 @@ bool Polyline::shorterThan(const coord_t check_length) const return iterator_segment == endSegments(); } -template -void Polyline::splitIntoSegments(LinesSet& result) const +void Polyline::splitIntoSegments(LinesSet& result) const { +#warning reserve space before adding all the segments for (auto it = beginSegments(); it != endSegments(); ++it) { - result.emplace_back(std::initializer_list{ (*it).start, (*it).end }); + result.emplace_back(PolylineType::Open, std::initializer_list{ (*it).start, (*it).end }); } } -template -LinesSet Polyline::splitIntoSegments() const +LinesSet Polyline::splitIntoSegments() const { - LinesSet result; + LinesSet result; splitIntoSegments(result); return result; } -template void Polyline::removeColinearEdges(const AngleRadians max_deviation_angle); -template Polyline::const_segments_iterator Polyline::beginSegments() const; -template Polyline::const_segments_iterator Polyline::endSegments() const; -template Polyline::segments_iterator Polyline::beginSegments(); -template Polyline::segments_iterator Polyline::endSegments(); -template coord_t Polyline::length() const; -template bool Polyline::shorterThan(const coord_t check_length) const; -template void Polyline::splitIntoSegments(LinesSet& result) const; -template LinesSet Polyline::splitIntoSegments() const; - -template void Polyline::removeColinearEdges(const AngleRadians max_deviation_angle); -template Polyline::const_segments_iterator Polyline::beginSegments() const; -template Polyline::const_segments_iterator Polyline::endSegments() const; -template Polyline::segments_iterator Polyline::beginSegments(); -template Polyline::segments_iterator Polyline::endSegments(); -template coord_t Polyline::length() const; -template bool Polyline::shorterThan(const coord_t check_length) const; -template void Polyline::splitIntoSegments(LinesSet& result) const; -template LinesSet Polyline::splitIntoSegments() const; - -template void Polyline::removeColinearEdges(const AngleRadians max_deviation_angle); -template Polyline::const_segments_iterator Polyline::beginSegments() const; -template Polyline::const_segments_iterator Polyline::endSegments() const; -template Polyline::segments_iterator Polyline::beginSegments(); -template Polyline::segments_iterator Polyline::endSegments(); -template coord_t Polyline::length() const; -template bool Polyline::shorterThan(const coord_t check_length) const; -template void Polyline::splitIntoSegments(LinesSet& result) const; -template LinesSet Polyline::splitIntoSegments() const; +bool Polyline::inside(const Point2LL& p, bool border_result) const +{ + if (isClosed()) + { + int res = ClipperLib::PointInPolygon(p, getPoints()); + if (res == -1) + { + return border_result; + } + return res == 1; + } + else + { + return false; + } +} + +bool Polyline::inside(const auto& polygon) const +{ + if (isClosed()) + { + for (const auto& point : *this) + { + if (! ClipperLib::PointInPolygon(point, polygon)) + { + return false; + } + } + return true; + } + else + { + return false; + } +} } // namespace cura diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index 6832e833bc..bab398273a 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -20,15 +20,37 @@ #include #include "geometry/closed_polyline.h" +#include "geometry/mixed_lines_set.h" #include "geometry/parts_view.h" #include "geometry/single_shape.h" #include "settings/types/Ratio.h" -#include "utils/OpenPolylineStitcher.h" #include "utils/linearAlg2D.h" +#include "utils/mixed_polyline_stitcher.h" namespace cura { +Shape::Shape(ClipperLib::Paths&& paths) +{ + reserve(paths.size()); + for (const ClipperLib::Path& path : paths) + { + emplace_back(std::move(path)); + } +} + +Shape& Shape::operator=(const Shape& other) +{ + LinesSet::operator=(other); + return *this; +} + +Shape& Shape::operator=(Shape&& other) +{ + LinesSet::operator=(other); + return *this; +} + Shape Shape::approxConvexHull(int extra_outset) const { constexpr int overshoot = MM2INT(100); // 10cm (hard-coded value). @@ -37,13 +59,13 @@ Shape Shape::approxConvexHull(int extra_outset) const // Perform the offset for each polygon one at a time. // This is necessary because the polygons may overlap, in which case the offset could end up in an infinite loop. // See http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperOffset/_Body.htm - for (const ClipperLib::Path& path : (*this)) + for (const Polygon& polygon : (*this)) { - Shape offset_result; + ClipperLib::Paths offset_result; ClipperLib::ClipperOffset offsetter(1.2, 10.0); - offsetter.AddPath(path, ClipperLib::jtRound, ClipperLib::etClosedPolygon); - offsetter.Execute(offset_result.asRawVector(), overshoot); - convex_hull.add(offset_result); + offsetter.AddPath(polygon.getPoints(), ClipperLib::jtRound, ClipperLib::etClosedPolygon); + offsetter.Execute(offset_result, overshoot); + convex_hull.push_back(PolylineType::ImplicitelyClosed, std::move(offset_result)); } return convex_hull.unionPolygons().offset(-overshoot + extra_outset, ClipperLib::jtRound); @@ -59,7 +81,7 @@ void Shape::makeConvex() // Andrew’s Monotone Chain Convex Hull Algorithm std::vector points; - for (const std::vector& poly : (*this)) + for (const Polygon& poly : getLines()) { points.insert(points.end(), poly.begin(), poly.end()); } @@ -104,57 +126,40 @@ void Shape::makeConvex() Shape Shape::difference(const Shape& other) const { - Shape ret; + ClipperLib::Paths ret; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); - clipper.AddPaths(other.asRawVector(), ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctDifference, ret.asRawVector()); - return ret; + addPaths(clipper, ClipperLib::ptSubject); + other.addPaths(clipper, ClipperLib::ptClip); + clipper.Execute(ClipperLib::ctDifference, ret); + return Shape(std::move(ret)); } Shape Shape::unionPolygons(const Shape& other, ClipperLib::PolyFillType fill_type) const { - Shape ret; + ClipperLib::Paths ret; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); - clipper.AddPaths(other.asRawVector(), ClipperLib::ptSubject, true); - clipper.Execute(ClipperLib::ctUnion, ret.asRawVector(), fill_type, fill_type); - return ret; + addPaths(clipper, ClipperLib::ptSubject); + other.addPaths(clipper, ClipperLib::ptSubject); + clipper.Execute(ClipperLib::ctUnion, ret, fill_type, fill_type); + return Shape(std::move(ret)); } Shape Shape::intersection(const Shape& other) const { - Shape ret; + ClipperLib::Paths ret; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); - clipper.AddPaths(other.asRawVector(), ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctIntersection, ret.asRawVector()); - return ret; -} - -Shape& Shape::operator=(const Shape& other) -{ - LinesSet::operator=(other); - return *this; -} - -Shape& Shape::operator=(Shape&& other) -{ - LinesSet::operator=(other); - return *this; -} - -void Shape::add(const Shape& other) -{ - std::copy(other.begin(), other.end(), std::back_inserter(*this)); + addPaths(clipper, ClipperLib::ptSubject); + other.addPaths(clipper, ClipperLib::ptClip); + clipper.Execute(ClipperLib::ctIntersection, ret); + return Shape(std::move(ret)); } bool Shape::inside(const Point2LL& p, bool border_result) const { int poly_count_inside = 0; - for (const ClipperLib::Path& poly : *this) + for (const Polygon& poly : *this) { - const int is_inside_this_poly = ClipperLib::PointInPolygon(p, poly); + const int is_inside_this_poly = ClipperLib::PointInPolygon(p, poly.getPoints()); if (is_inside_this_poly == -1) { return border_result; @@ -177,7 +182,7 @@ size_t Shape::findInside(const Point2LL& p, bool border_result) const for (size_t poly_idx = 0; poly_idx < size(); poly_idx++) { - const Polygon poly = (*this)[poly_idx]; + const Polygon& poly = (*this)[poly_idx]; Point2LL p0 = poly.back(); for (const Point2LL& p1 : poly) { @@ -230,55 +235,51 @@ size_t Shape::findInside(const Point2LL& p, bool border_result) const } template -LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const +MixedLinesSet Shape::intersection(const MixedLinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const { - LinesSet split_polylines = polylines.splitIntoSegments(); + LinesSet split_polylines = polylines.splitIntoSegments(); ClipperLib::PolyTree result; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(split_polylines.asRawVector(), ClipperLib::ptSubject, false); - clipper.AddPaths(asRawVector(), ClipperLib::ptClip, true); + split_polylines.addPaths(clipper, ClipperLib::ptSubject); + addPaths(clipper, ClipperLib::ptClip); clipper.Execute(ClipperLib::ctIntersection, result); - LinesSet ret; - ClipperLib::OpenPathsFromPolyTree(result, ret.asRawVector()); + ClipperLib::Paths result_paths; + ClipperLib::OpenPathsFromPolyTree(result, result_paths); if (restitch) { - LinesSet result_lines; - Shape result_polygons; + MixedLinesSet input_lines; + input_lines.push_back(PolylineType::Open, std::move(result_paths)); + + MixedLinesSet result_lines; const coord_t snap_distance = 10_mu; - OpenPolylineStitcher::stitch(ret, result_lines, result_polygons, max_stitch_distance, snap_distance); - ret = std::move(result_lines); - // if polylines got stitched into polygons, split them back up into a polyline again, because the result only admits polylines - for (const Polygon& poly : result_polygons) - { - if (! poly.empty()) - { - ret.push_back(poly); - } - } + MixedPolylineStitcher::stitch(input_lines, result_lines, max_stitch_distance, snap_distance); + return result_lines; + } + else + { + return MixedLinesSet(PolylineType::Open, std::move(result_paths)); } - - return ret; } Shape Shape::xorPolygons(const Shape& other, ClipperLib::PolyFillType pft) const { - Shape ret; + ClipperLib::Paths ret; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); - clipper.AddPaths(other.asRawVector(), ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctXor, ret.asRawVector(), pft); - return ret; + addPaths(clipper, ClipperLib::ptSubject); + other.addPaths(clipper, ClipperLib::ptClip); + clipper.Execute(ClipperLib::ctXor, ret, pft); + return Shape(std::move(ret)); } Shape Shape::execute(ClipperLib::PolyFillType pft) const { - Shape ret; + ClipperLib::Paths ret; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); - clipper.Execute(ClipperLib::ctXor, ret.asRawVector(), pft); - return ret; + addPaths(clipper, ClipperLib::ptSubject); + clipper.Execute(ClipperLib::ctXor, ret, pft); + return Shape(std::move(ret)); } /* void Polygons::toPolylines() @@ -297,14 +298,14 @@ Shape Shape::offsetMulti(const std::vector& offset_dists) const // we need as many offset-dists as points assert(pointCount() == offset_dists.size()); - Shape ret; + ClipperLib::Paths ret; size_t i = 0; - for (const ClipperLib::Path& poly_line : (*this) - | ranges::views::filter( - [](const ClipperLib::Path& path) - { - return ! path.empty(); - })) + for (const Polygon& poly_line : (*this) + | ranges::views::filter( + [](const Polygon& path) + { + return ! path.empty(); + })) { Polygon ret_poly_line; @@ -323,8 +324,8 @@ Shape Shape::offsetMulti(const std::vector& offset_dists) const auto offset_p1 = turn90CCW(normal(vec_dir, prev_dist)); auto offset_p2 = turn90CCW(normal(vec_dir, offset_dist)); - ret_poly_line.emplace_back(prev_p + offset_p1); - ret_poly_line.emplace_back(p + offset_p2); + ret_poly_line.push_back(prev_p + offset_p1); + ret_poly_line.push_back(p + offset_p2); } prev_p = p; @@ -332,12 +333,12 @@ Shape Shape::offsetMulti(const std::vector& offset_dists) const i++; } - ret.push_back(ret_poly_line); + ret.push_back(std::move(ret_poly_line.getPoints())); } - ClipperLib::SimplifyPolygons(ret.asRawVector(), ClipperLib::PolyFillType::pftPositive); + ClipperLib::SimplifyPolygons(ret, ClipperLib::PolyFillType::pftPositive); - return ret; + return Shape(std::move(ret)); } Shape Shape::getOutsidePolygons() const @@ -345,14 +346,13 @@ Shape Shape::getOutsidePolygons() const Shape ret; ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree poly_tree; - constexpr bool paths_are_closed_polys = true; - clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, paths_are_closed_polys); + addPaths(clipper, ClipperLib::ptSubject); clipper.Execute(ClipperLib::ctUnion, poly_tree); - for (int outer_poly_idx = 0; outer_poly_idx < poly_tree.ChildCount(); outer_poly_idx++) + for (size_t outer_poly_idx = 0; outer_poly_idx < static_cast(poly_tree.ChildCount()); outer_poly_idx++) { ClipperLib::PolyNode* child = poly_tree.Childs[outer_poly_idx]; - ret.emplace_back(child->Contour); + ret.emplace_back(std::move(child->Contour)); } return ret; } @@ -362,8 +362,7 @@ Shape Shape::removeEmptyHoles() const Shape ret; ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree poly_tree; - constexpr bool paths_are_closed_polys = true; - clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, paths_are_closed_polys); + addPaths(clipper, ClipperLib::ptSubject); clipper.Execute(ClipperLib::ctUnion, poly_tree); bool remove_holes = true; @@ -376,8 +375,7 @@ Shape Shape::getEmptyHoles() const Shape ret; ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree poly_tree; - constexpr bool paths_are_closed_polys = true; - clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, paths_are_closed_polys); + addPaths(clipper, ClipperLib::ptSubject); clipper.Execute(ClipperLib::ctUnion, poly_tree); bool remove_holes = false; @@ -387,19 +385,19 @@ Shape Shape::getEmptyHoles() const void Shape::removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Shape& ret) const { - for (int outer_poly_idx = 0; outer_poly_idx < node.ChildCount(); outer_poly_idx++) + for (size_t outer_poly_idx = 0; outer_poly_idx < static_cast(node.ChildCount()); outer_poly_idx++) { ClipperLib::PolyNode* child = node.Childs[outer_poly_idx]; if (remove_holes) { - ret.emplace_back(child->Contour); + ret.emplace_back(std::move(child->Contour)); } - for (int hole_node_idx = 0; hole_node_idx < child->ChildCount(); hole_node_idx++) + for (size_t hole_node_idx = 0; hole_node_idx < static_cast(child->ChildCount()); hole_node_idx++) { ClipperLib::PolyNode& hole_node = *child->Childs[hole_node_idx]; if ((hole_node.ChildCount() > 0) == remove_holes) { - ret.emplace_back(hole_node.Contour); + ret.emplace_back(std::move(hole_node.Contour)); removeEmptyHoles_processPolyTreeNode(hole_node, remove_holes, ret); } } @@ -414,7 +412,7 @@ void Shape::removeSmallAreas(const double min_area_size, const bool remove_holes for (auto it = begin(); it < new_end;) { // All polygons smaller than target are removed by replacing them with a polygon from the back of the vector - if (std::abs(INT2MM2(ClipperLib::Area(*it))) < min_area_size) + if (std::abs(INT2MM2(it->area())) < min_area_size) { *it = std::move(*--new_end); continue; @@ -428,7 +426,7 @@ void Shape::removeSmallAreas(const double min_area_size, const bool remove_holes std::vector small_holes; for (auto it = begin(); it < new_end;) { - double area = INT2MM2(ClipperLib::Area(*it)); + double area = INT2MM2(it->area()); if (std::abs(area) < min_area_size) { if (area >= 0) @@ -524,20 +522,20 @@ Shape Shape::removePolygon(const Shape& to_be_removed, int same_distance) const Shape Shape::processEvenOdd(ClipperLib::PolyFillType poly_fill_type) const { - Shape ret; + ClipperLib::Paths ret; ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); - clipper.Execute(ClipperLib::ctUnion, ret.asRawVector(), poly_fill_type); - return ret; + addPaths(clipper, ClipperLib::ptSubject); + clipper.Execute(ClipperLib::ctUnion, ret, poly_fill_type); + return Shape(std::move(ret)); } Shape Shape::toPolygons(ClipperLib::PolyTree& poly_tree) { - Shape ret; - ClipperLib::PolyTreeToPaths(poly_tree, ret.asRawVector()); - return ret; + ClipperLib::Paths ret; + ClipperLib::PolyTreeToPaths(poly_tree, ret); + return Shape(std::move(ret)); } - +/* [[maybe_unused]] Shape Shape::fromWkt(const std::string& wkt) { typedef boost::geometry::model::d2::point_xy point_type; @@ -588,7 +586,7 @@ Shape Shape::toPolygons(ClipperLib::PolyTree& poly_tree) stream << paths_str; stream << ")"; } - +*/ Shape Shape::smooth_outward(const AngleDegrees max_angle, int shortcut_length) const { Shape ret; @@ -728,7 +726,7 @@ std::vector Shape::splitIntoParts(bool unionAll) const std::vector ret; ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree resultPolyTree; - clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); + addPaths(clipper, ClipperLib::ptSubject); if (unionAll) clipper.Execute(ClipperLib::ctUnion, resultPolyTree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); else @@ -740,12 +738,12 @@ std::vector Shape::splitIntoParts(bool unionAll) const void Shape::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const { - for (int n = 0; n < node->ChildCount(); n++) + for (size_t n = 0; n < static_cast(node->ChildCount()); n++) { ClipperLib::PolyNode* child = node->Childs[n]; SingleShape part; part.emplace_back(child->Contour); - for (int i = 0; i < child->ChildCount(); i++) + for (size_t i = 0; i < static_cast(child->ChildCount()); i++) { part.emplace_back(child->Childs[i]->Contour); splitIntoParts_processPolyTreeNode(child->Childs[i], ret); @@ -759,7 +757,7 @@ std::vector Shape::sortByNesting() const std::vector ret; ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree resultPolyTree; - clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); + addPaths(clipper, ClipperLib::ptSubject); clipper.Execute(ClipperLib::ctUnion, resultPolyTree); sortByNesting_processPolyTreeNode(&resultPolyTree, 0, ret); @@ -768,7 +766,7 @@ std::vector Shape::sortByNesting() const void Shape::sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const { - for (int n = 0; n < node->ChildCount(); n++) + for (size_t n = 0; n < static_cast(node->ChildCount()); n++) { ClipperLib::PolyNode* child = node->Childs[n]; if (nesting_idx >= ret.size()) @@ -786,7 +784,7 @@ PartsView Shape::splitIntoPartsView(bool unionAll) PartsView partsView(*this); ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree resultPolyTree; - clipper.AddPaths(asRawVector(), ClipperLib::ptSubject, true); + addPaths(clipper, ClipperLib::ptSubject); if (unionAll) clipper.Execute(ClipperLib::ctUnion, resultPolyTree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); else @@ -800,14 +798,14 @@ PartsView Shape::splitIntoPartsView(bool unionAll) void Shape::splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Shape& reordered, ClipperLib::PolyNode* node) const { - for (int n = 0; n < node->ChildCount(); n++) + for (size_t n = 0; n < static_cast(node->ChildCount()); n++) { ClipperLib::PolyNode* child = node->Childs[n]; partsView.emplace_back(); size_t pos = partsView.size() - 1; partsView[pos].push_back(reordered.size()); reordered.emplace_back(child->Contour); // TODO: should this steal the internal representation for speed? - for (int i = 0; i < child->ChildCount(); i++) + for (size_t i = 0; i < static_cast(child->ChildCount()); i++) { partsView[pos].push_back(reordered.size()); reordered.emplace_back(child->Childs[i]->Contour); @@ -859,7 +857,7 @@ Shape Shape::removeNearSelfIntersections() const point.x *= 4; point.y *= 4; } - polys.push_back(*reinterpret_cast*>(&ring)); // NOTE: 'add' already moves the vector + polys.emplace_back(std::move(*reinterpret_cast(&ring))); } } polys = polys.unionPolygons(); @@ -946,8 +944,8 @@ void Shape::applyMatrix(const Point3Matrix& matrix) } } -template LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; +/*template LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; template LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; -template LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; +template LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const;*/ } // namespace cura diff --git a/src/slicer.cpp b/src/slicer.cpp index bb61cb57c5..fe993b9d57 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -30,7 +30,7 @@ constexpr int largest_neglected_gap_first_phase = MM2INT(0.01); //!< distance be constexpr int largest_neglected_gap_second_phase = MM2INT(0.02); //!< distance between two line segments regarded as connected constexpr int max_stitch1 = MM2INT(10.0); //!< maximal distance stitched between open polylines to form polygons -void SlicerLayer::makeBasicPolygonLoops(std::vector& open_polylines) +void SlicerLayer::makeBasicPolygonLoops(LinesSet& open_polylines) { for (size_t start_segment_idx = 0; start_segment_idx < segments.size(); start_segment_idx++) { @@ -43,9 +43,9 @@ void SlicerLayer::makeBasicPolygonLoops(std::vector& open_polyline segments.clear(); } -void SlicerLayer::makeBasicPolygonLoop(std::vector& open_polylines, const size_t start_segment_idx) +void SlicerLayer::makeBasicPolygonLoop(LinesSet& open_polylines, const size_t start_segment_idx) { - OpenPolyline poly; + Polyline poly; poly.push_back(segments[start_segment_idx].start); for (int segment_idx = start_segment_idx; segment_idx != -1;) @@ -56,7 +56,7 @@ void SlicerLayer::makeBasicPolygonLoop(std::vector& open_polylines segment_idx = getNextSegmentIdx(segment, start_segment_idx); if (segment_idx == static_cast(start_segment_idx)) { // polyon is closed - polygons.push_back(poly); + polygons.push_back(Polygon(std::move(poly.getPoints()))); return; } } @@ -128,7 +128,7 @@ int SlicerLayer::getNextSegmentIdx(const SlicerSegment& segment, const size_t st return next_segment_idx; } -void SlicerLayer::connectOpenPolylines(std::vector& open_polylines) +void SlicerLayer::connectOpenPolylines(LinesSet& open_polylines) { constexpr bool allow_reverse = false; // Search a bit fewer cells but at cost of covering more area. @@ -137,7 +137,7 @@ void SlicerLayer::connectOpenPolylines(std::vector& open_polylines connectOpenPolylinesImpl(open_polylines, largest_neglected_gap_second_phase, cell_size, allow_reverse); } -void SlicerLayer::stitch(std::vector& open_polylines) +void SlicerLayer::stitch(LinesSet& open_polylines) { bool allow_reverse = true; connectOpenPolylinesImpl(open_polylines, max_stitch1, max_stitch1, allow_reverse); @@ -190,7 +190,7 @@ bool SlicerLayer::PossibleStitch::operator<(const PossibleStitch& other) const } std::priority_queue - SlicerLayer::findPossibleStitches(const std::vector& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) const + SlicerLayer::findPossibleStitches(const LinesSet& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) const { std::priority_queue stitch_queue; @@ -336,7 +336,7 @@ std::priority_queue return stitch_queue; } -void SlicerLayer::planPolylineStitch(const std::vector& open_polylines, Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const +void SlicerLayer::planPolylineStitch(const LinesSet& open_polylines, Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const { size_t polyline_0_idx = terminus_0.getPolylineIdx(); size_t polyline_1_idx = terminus_1.getPolylineIdx(); @@ -385,7 +385,7 @@ void SlicerLayer::planPolylineStitch(const std::vector& open_polyl } } -void SlicerLayer::joinPolylines(OpenPolyline& polyline_0, OpenPolyline& polyline_1, const bool reverse[2]) +void SlicerLayer::joinPolylines(Polyline& polyline_0, Polyline& polyline_1, const bool reverse[2]) { if (reverse[0]) { @@ -452,7 +452,7 @@ void SlicerLayer::TerminusTrackingMap::updateMap( } } -void SlicerLayer::connectOpenPolylinesImpl(std::vector& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) +void SlicerLayer::connectOpenPolylinesImpl(LinesSet& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) { // below code closes smallest gaps first @@ -534,7 +534,7 @@ void SlicerLayer::connectOpenPolylinesImpl(std::vector& open_polyl } } -void SlicerLayer::stitch_extensive(std::vector& open_polylines) +void SlicerLayer::stitch_extensive(LinesSet& open_polylines) { // For extensive stitching find 2 open polygons that are touching 2 closed polygons. // Then find the shortest path over this polygon that can be used to connect the open polygons, diff --git a/src/utils/Simplify.cpp b/src/utils/Simplify.cpp index 56b39f195a..179611b915 100644 --- a/src/utils/Simplify.cpp +++ b/src/utils/Simplify.cpp @@ -6,8 +6,8 @@ #include #include //Priority queue to prioritise removing unimportant vertices. -#include "geometry/closed_polyline.h" -#include "geometry/open_polyline.h" +#include "geometry/polyline.h" +#include "utils/ExtrusionLine.h" namespace cura { @@ -31,7 +31,7 @@ Shape Simplify::polygon(const Shape& polygons) const Shape result; for (size_t i = 0; i < polygons.size(); ++i) { - result.addIfNotEmpty(polygon(polygons[i])); + result.push_back(polygon(polygons[i]), true); } return result; } @@ -54,30 +54,15 @@ LinesSet Simplify::polyline(const LinesSet& polylines) const LinesSet result; for (size_t i = 0; i < polylines.size(); ++i) { - result.addIfNotEmpty(polyline(polylines[i])); + result.push_back(polyline(polylines[i]), true); } return result; } -template LinesSet Simplify::polyline(const LinesSet& polylines) const; -template LinesSet Simplify::polyline(const LinesSet& polylines) const; - -template<> -Polyline Simplify::polyline(const Polyline& polyline) const -{ - return simplify(polyline, false); -} - -template<> -Polyline Simplify::polyline(const Polyline& polyline) const -{ - return simplify(polyline, true); -} - -template<> -Polyline Simplify::polyline(const Polyline& polyline) const +Polyline Simplify::polyline(const Polyline& polyline) const { - return simplify(polyline, true); + assert(polyline.getType() != PolylineType::ExplicitelyClosed && "Simplify algorithm doesn't expect explicitely closed polylines"); + return simplify(polyline, polyline.isClosed()); } ExtrusionLine Simplify::polyline(const ExtrusionLine& polyline) const @@ -114,8 +99,7 @@ ExtrusionLine Simplify::createEmpty(const ExtrusionLine& original) const return result; } -template -void Simplify::appendVertex(Polyline& polygon, const Point2LL& vertex) const +void Simplify::appendVertex(Polyline& polygon, const Point2LL& vertex) const { polygon.push_back(vertex); } From ead0ddeb135b271d6d58ec0dbd4923ae96119fc8 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 10 Apr 2024 09:08:14 +0200 Subject: [PATCH 024/135] Better metric for when a connection is too close to the scanline. Instead of one point within a very small distance, all points need to be within a slightly larger distance to be ignored. part of CURA-11597 --- src/infill.cpp | 2 +- src/infill/ZigzagConnectorProcessor.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/infill.cpp b/src/infill.cpp index ff51356267..ce5189973e 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -751,7 +751,7 @@ void Infill::generateLinearBasedInfill( assert(scanline_idx - scanline_min_idx >= 0 && scanline_idx - scanline_min_idx < int(cut_list.size()) && "reading infill cutlist index out of bounds!"); cut_list[scanline_idx - scanline_min_idx].push_back(y); Point2LL scanline_linesegment_intersection(x, y); - zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, infill_line_width_); + zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, infill_line_width_ * 2); crossings_per_scanline[scanline_idx - min_scanline_index].emplace_back(scanline_linesegment_intersection, poly_idx, point_idx); } zigzag_connector_processor.registerVertex(p1); diff --git a/src/infill/ZigzagConnectorProcessor.cpp b/src/infill/ZigzagConnectorProcessor.cpp index bb7c1bbbac..315735bb9a 100644 --- a/src/infill/ZigzagConnectorProcessor.cpp +++ b/src/infill/ZigzagConnectorProcessor.cpp @@ -100,13 +100,13 @@ void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2L if (shouldAddCurrentConnector(last_connector_index_, scanline_index)) { const bool is_this_endpiece = scanline_index == last_connector_index_; - bool close_to_line_except_intersect = false; + bool close_to_line_except_intersect = true; const coord_t min_dist2 = min_distance_to_scanline * min_distance_to_scanline; for (const auto& point : current_connector_) { - close_to_line_except_intersect |= (std::abs(point.X - intersection.X) < min_distance_to_scanline) && (vSize2(point - intersection) > min_dist2); + close_to_line_except_intersect &= std::abs(point.X - intersection.X) < min_distance_to_scanline; } - if (! close_to_line_except_intersect) + if (current_connector_.empty() || ! close_to_line_except_intersect) { current_connector_.push_back(intersection); addZagConnector(current_connector_, is_this_endpiece); From dc4c4e18b747c3f8dda21d4000ef9818f61cca79 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 10 Apr 2024 21:19:19 +0200 Subject: [PATCH 025/135] Fully building engine with new(newnew) architecture --- CMakeLists.txt | 2 + include/LayerPlan.h | 45 +++-- include/PathOrderOptimizer.h | 4 +- include/TreeSupportUtils.h | 9 +- include/geometry/closed_lines_set.h | 26 +++ include/geometry/closed_polyline.h | 123 +++++++++++++- include/geometry/lines_set.h | 92 ++++++----- include/geometry/mixed_lines_set.h | 146 +++++----------- include/geometry/open_lines_set.h | 32 ++++ include/geometry/open_polyline.h | 35 ++-- include/geometry/points_set.h | 61 ++++++- include/geometry/polygon.h | 21 +-- include/geometry/polyline.h | 114 ++----------- include/geometry/shape.h | 26 ++- include/infill/ZigzagConnectorProcessor.h | 2 +- include/path_ordering.h | 6 +- include/sliceDataStorage.h | 6 +- include/slicer.h | 22 +-- include/utils/OpenPolylineStitcher.h | 6 +- include/utils/PolylineStitcher.h | 3 + include/utils/Simplify.h | 39 +++-- include/utils/mixed_polyline_stitcher.h | 34 +--- include/utils/polygonUtils.h | 27 +-- src/FffGcodeWriter.cpp | 63 ++++--- src/FffPolygonGenerator.cpp | 7 +- src/InterlockingGenerator.cpp | 4 +- src/LayerPlan.cpp | 108 ++++++++---- src/Mold.cpp | 2 +- src/PrimeTower.cpp | 4 +- src/SkirtBrim.cpp | 65 ++++---- src/TopSurface.cpp | 2 +- src/TreeModelVolumes.cpp | 16 +- src/TreeSupport.cpp | 32 ++-- src/TreeSupportTipGenerator.cpp | 26 +-- src/WallToolPaths.cpp | 2 +- src/bridge.cpp | 20 +-- src/communication/ArcusCommunication.cpp | 2 +- src/geometry/closed_polyline.cpp | 43 +++++ src/geometry/lines_set.cpp | 193 ++++++++++++++-------- src/geometry/mixed_lines_set.cpp | 158 +++++++++++++++++- src/geometry/points_set.cpp | 4 +- src/geometry/polyline.cpp | 55 +----- src/geometry/shape.cpp | 94 +++++++---- src/infill.cpp | 35 ++-- src/infill/GyroidInfill.cpp | 4 +- src/infill/LightningGenerator.cpp | 4 +- src/infill/LightningLayer.cpp | 2 +- src/infill/LightningTreeNode.cpp | 2 +- src/infill/SubDivCube.cpp | 2 +- src/infill/ZigzagConnectorProcessor.cpp | 4 +- src/multiVolumes.cpp | 11 +- src/pathPlanning/Comb.cpp | 2 +- src/path_ordering.cpp | 32 ++-- src/plugins/converters.cpp | 10 +- src/raft.cpp | 2 +- src/skin.cpp | 10 +- src/sliceDataStorage.cpp | 12 +- src/slicer.cpp | 43 +++-- src/support.cpp | 24 +-- src/utils/AABB.cpp | 2 +- src/utils/PolylineStitcher.cpp | 46 ++++-- src/utils/Simplify.cpp | 53 ++++-- src/utils/ToolpathVisualizer.cpp | 2 +- src/utils/mixed_polyline_stitcher.cpp | 33 ++++ src/utils/polygonUtils.cpp | 28 ++-- 65 files changed, 1333 insertions(+), 811 deletions(-) create mode 100644 include/geometry/closed_lines_set.h create mode 100644 include/geometry/open_lines_set.h create mode 100644 src/geometry/closed_polyline.cpp create mode 100644 src/utils/mixed_polyline_stitcher.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c4b25be417..32f0cdafa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,6 +152,7 @@ set(engine_SRCS # Except main.cpp. src/utils/ToolpathVisualizer.cpp src/utils/VoronoiUtils.cpp src/utils/VoxelUtils.cpp + src/utils/mixed_polyline_stitcher.cpp src/geometry/polygon.cpp src/geometry/shape.cpp @@ -160,6 +161,7 @@ set(engine_SRCS # Except main.cpp. src/geometry/parts_view.cpp src/geometry/lines_set.cpp src/geometry/polyline.cpp + src/geometry/closed_polyline.cpp src/geometry/mixed_lines_set.cpp ) diff --git a/include/LayerPlan.h b/include/LayerPlan.h index 52b5bfd617..205779c088 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -562,8 +562,9 @@ class LayerPlan : public NoCopy * \param reverse_print_direction Whether to reverse the optimized order and their printing direction. * \param order_requirements Pairs where first needs to be printed before second. Pointers are pointing to elements of \p lines */ + template void addLinesByOptimizer( - const LinesSet& lines, + const LinesSet& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const bool enable_travel_optimization = false, @@ -572,7 +573,7 @@ class LayerPlan : public NoCopy const std::optional near_start_location = std::optional(), const double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT, const bool reverse_print_direction = false, - const std::unordered_multimap& order_requirements = PathOrderOptimizer::no_order_requirements_); + const std::unordered_multimap& order_requirements = PathOrderOptimizer::no_order_requirements_); /*! * Add lines to the gcode with optimized order. @@ -597,7 +598,7 @@ class LayerPlan : public NoCopy const std::optional near_start_location = std::optional(), const double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT, const bool reverse_print_direction = false, - const std::unordered_multimap& order_requirements = PathOrderOptimizer::no_order_requirements_); + const std::unordered_multimap& order_requirements = PathOrderOptimizer::no_order_requirements_); /*! * Add lines to the g-code with monotonic order. @@ -622,7 +623,7 @@ class LayerPlan : public NoCopy */ void addLinesMonotonic( const Shape& area, - const std::vector& lines, + const OpenLinesSet& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const AngleRadians monotonic_direction, @@ -632,25 +633,6 @@ class LayerPlan : public NoCopy const Ratio flow_ratio = 1.0_r, const double fan_speed = GCodePathConfig::FAN_SPEED_DEFAULT); -protected: - /*! - * Add order optimized lines to the gcode. - * \param lines The lines in order - * \param config The config of the lines - * \param space_fill_type The type of space filling used to generate the line segments (should be either Lines or PolyLines!) - * \param wipe_dist (optional) the distance wiped without extruding after laying down a line. - * \param flow_ratio The ratio with which to multiply the extrusion amount - * \param fan_speed optional fan speed override for this path - */ - void addLinesInGivenOrder( - const std::vector>& lines, - const GCodePathConfig& config, - const SpaceFillType space_fill_type, - const coord_t wipe_dist, - const Ratio flow_ratio, - const double fan_speed); - -public: /*! * Add a spiralized slice of wall that is interpolated in X/Y between \p last_wall and \p wall. * @@ -805,6 +787,23 @@ class LayerPlan : public NoCopy * \return the combing boundary or an empty Shape if no combing is required */ Shape computeCombBoundary(const CombBoundary boundary_type); + + /*! + * Add order optimized lines to the gcode. + * \param lines The lines in order + * \param config The config of the lines + * \param space_fill_type The type of space filling used to generate the line segments (should be either Lines or PolyLines!) + * \param wipe_dist (optional) the distance wiped without extruding after laying down a line. + * \param flow_ratio The ratio with which to multiply the extrusion amount + * \param fan_speed optional fan speed override for this path + */ + void addLinesInGivenOrder( + const std::vector>& lines, + const GCodePathConfig& config, + const SpaceFillType space_fill_type, + const coord_t wipe_dist, + const Ratio flow_ratio, + const double fan_speed); }; } // namespace cura diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 1a84fc2952..fcdd21eec1 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -16,9 +16,9 @@ #include #include "InsetOrderOptimizer.h" // for makeOrderIncludeTransitive -#include "path_ordering.h" #include "pathPlanning/CombPath.h" //To calculate the combing distance if we want to use combing. #include "pathPlanning/LinePolygonsCrossings.h" //To prevent calculating combing distances if we don't cross the combing borders. +#include "path_ordering.h" #include "settings/EnumSettings.h" //To get the seam settings. #include "settings/ZSeamConfig.h" //To read the seam configuration. #include "utils/linearAlg2D.h" //To find the angle of corners to hide seams. @@ -884,7 +884,7 @@ class PathOrderOptimizer * \param polygon A polygon to get a random vertex of. * \return A random index in that polygon. */ - size_t getRandomPointInPolygon(const Polygon& polygon) const + size_t getRandomPointInPolygon(const PointsSet& polygon) const { return rand() % polygon.size(); } diff --git a/include/TreeSupportUtils.h b/include/TreeSupportUtils.h index cae1d02c38..bc09302e34 100644 --- a/include/TreeSupportUtils.h +++ b/include/TreeSupportUtils.h @@ -33,13 +33,10 @@ class TreeSupportUtils */ static LinesSet toPolylines(const Shape& poly) { -#warning We should just cast it to a LineSet instead, but that's running for trouble yet LinesSet result; for (const auto& path : poly) { - Polygon part(path); - part.push_back(path[0]); - result.push_back(part); + result.push_back(path.toPseudoOpenPolyline()); } return result; } @@ -159,8 +156,8 @@ class TreeSupportUtils Shape areas; LinesSet lines; roof_computation.generate(toolpaths, areas, lines, config.settings, layer_idx, SectionType::SUPPORT, cross_fill_provider); - lines.add(toPolylines(areas)); - lines.add(toPolylines(toolpaths)); + lines.push_back(toPolylines(areas)); + lines.push_back(toPolylines(toolpaths)); return lines; } diff --git a/include/geometry/closed_lines_set.h b/include/geometry/closed_lines_set.h new file mode 100644 index 0000000000..114fab92d6 --- /dev/null +++ b/include/geometry/closed_lines_set.h @@ -0,0 +1,26 @@ +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_CLOSED_LINES_SET_H +#define GEOMETRY_CLOSED_LINES_SET_H + +#include "geometry/closed_polyline.h" +#include "geometry/lines_set.h" + +namespace cura +{ + +/*! + * \brief Convenience definition for a container that can hold only closed polylines. This makes it + * explicit what the lines actually represent. + */ +#warning Try with a using instead +class ClosedLinesSet : public LinesSet +{ +public: + ClosedLinesSet() = default; +}; + +} // namespace cura + +#endif // GEOMETRY_CLOSED_LINES_SET_H diff --git a/include/geometry/closed_polyline.h b/include/geometry/closed_polyline.h index e923714053..3d65f0b216 100644 --- a/include/geometry/closed_polyline.h +++ b/include/geometry/closed_polyline.h @@ -4,12 +4,131 @@ #ifndef GEOMETRY_CLOSED_POLYLINE_H #define GEOMETRY_CLOSED_POLYLINE_H -#include "geometry/generic_closed_polyline.h" +#include "geometry/polyline.h" namespace cura { -// using ClosedPolyline = GenericClosedPolyline; +class OpenPolyline; + +class ClosedPolyline : public Polyline +{ +private: + /*! If true, that means the last point in the list is at the same position as the start point, + * making it explicitely closed. + * If false, you have to add an additional segment between the end point and the start point to + * actually have the line closed. */ + bool explicitely_closed_{ false }; + +public: +#warning try to set bool explicitely_closed as argument + ClosedPolyline() = default; + + ClosedPolyline(const ClosedPolyline& other) = default; + + ClosedPolyline(ClosedPolyline&& other) = default; + + ClosedPolyline(const std::initializer_list& initializer, bool explicitely_closed) + : Polyline(initializer) + , explicitely_closed_(explicitely_closed) + { + } + + explicit ClosedPolyline(const ClipperLib::Path& points, bool explicitely_closed) + : Polyline(points) + , explicitely_closed_(explicitely_closed) + { + } + + explicit ClosedPolyline(ClipperLib::Path&& points, bool explicitely_closed) + : Polyline(points) + , explicitely_closed_(explicitely_closed) + { + } + + virtual bool addClosingSegment() const + { + return ! explicitely_closed_; + } + + virtual size_t segmentsCount() const override + { + if (explicitely_closed_) + { + return size() >= 3 ? size() - 1 : 0; + } + else + { + return size() >= 2 ? size() : 0; + } + } + + ClosedPolyline& operator=(const ClosedPolyline& other) + { + Polyline::operator=(other); + return *this; + } + + ClosedPolyline& operator=(ClosedPolyline&& other) + { + Polyline::operator=(other); + return *this; + } + + bool isExplicitelyClosed() const + { + return explicitely_closed_; + } + + /*! + * \brief Sets whether the points set is to be treated as explicitely or implicitely closed + * \warning This does not actually changes the points set, only the interpretation of it will + * change. So use this method only if you really know what you are doing. + */ + void setExplicitelyClosed(bool explicitely_closed) + { + explicitely_closed_ = explicitely_closed; + } + + /*! + * Check if we are inside the polygon. We do this by tracing from the point towards the positive X direction, + * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. + * Care needs to be taken, if p.Y exactly matches a vertex to the right of p, then we need to count 1 intersect if the + * outline passes vertically past; and 0 (or 2) intersections if that point on the outline is a 'top' or 'bottom' vertex. + * The easiest way to do this is to break out two cases for increasing and decreasing Y ( from p0 to p1 ). + * A segment is tested if pa.Y <= p.Y < pb.Y, where pa and pb are the points (from p0,p1) with smallest & largest Y. + * When both have the same Y, no intersections are counted but there is a special test to see if the point falls + * exactly on the line. + * + * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. + * + * \deprecated This function is no longer used, since the Clipper function is used by the function PolygonRef::inside(.) + * + * \param p The point for which to check if it is inside this polygon + * \param border_result What to return when the point is exactly on the border + * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) + */ + // bool _inside(Point2LL p, bool border_result = false) const; + + /*! + * Clipper function. + * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. + * + * http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/PointInPolygon.htm + */ + bool inside(const Point2LL& p, bool border_result = false) const; + + bool inside(const ClipperLib::Path& polygon) const; + + /*! + * \brief Converts the closed polyline to an open polyline which happens to have its end and start points at the same + * position, making it a pseudo-closed polyline. Although this should never be required in practice, there + * are many places in the code where this is done because historically we wouldn't make a clear difference + * between open and closed polylines + * \return An open polyline instance, with the end point at the same position of the start point + */ + OpenPolyline toPseudoOpenPolyline() const; +}; } // namespace cura diff --git a/include/geometry/lines_set.h b/include/geometry/lines_set.h index a35f0497a5..fe528465b1 100644 --- a/include/geometry/lines_set.h +++ b/include/geometry/lines_set.h @@ -7,13 +7,14 @@ #include #include "geometry/point2ll.h" -#include "geometry/polyline_type.h" namespace cura { class Shape; -class Polyline; +template +class LinesSet; +class OpenPolyline; /*! * \brief Base class for all geometry containers representing a set of polylines. @@ -41,12 +42,7 @@ class LinesSet { } - /*LinesSet(const std::vector>& paths) - : std::vector(*reinterpret_cast*>(&paths)) - { - }*/ - - LinesSet(PolylineType type, std::vector>&& paths); + LinesSet(ClipperLib::Paths&& paths); const std::vector& getLines() const { @@ -58,6 +54,11 @@ class LinesSet return lines_; } + void setLines(std::vector&& lines) + { + lines_ = lines; + } + std::vector::const_iterator begin() const { return lines_.begin(); @@ -88,13 +89,34 @@ class LinesSet return lines_.back(); } + const LineType& front() const + { + return lines_.front(); + } + + LineType& front() + { + return lines_.front(); + } + void push_back(const LineType& line, bool checkNonEmpty = false); void push_back(LineType&& line, bool checkNonEmpty = false); - void push_back(PolylineType type, ClipperLib::Paths&& paths); + void push_back(ClipperLib::Paths&& paths); + + template + void push_back(LinesSet&& lines_set); - void push_back(LinesSet&& lines_set); + void push_back(const LinesSet& other) + { + lines_.insert(other.lines_.end(), other.lines_.begin(), other.lines_.end()); + } + + void pop_back() + { + lines_.pop_back(); + } size_t size() const { @@ -116,49 +138,42 @@ class LinesSet lines_.resize(size); } + void clear() + { + lines_.clear(); + } + template void emplace_back(Args&&... args) { lines_.emplace_back(args...); } - LinesSet& operator=(const LinesSet& other) = default; - - LinesSet& operator=(LinesSet&& other) = default; - - LineType& operator[](size_t index) + std::vector::iterator erase(std::vector::const_iterator first, std::vector::const_iterator last) { - return lines_[index]; + lines_.erase(first, last); } - const LineType& operator[](size_t index) const + LinesSet& operator=(LinesSet&& other) { - return lines_[index]; + lines_ = std::move(other.lines_); + return *this; } -#warning rename this to asType - /*template - const LinesSet& toType() const + LinesSet& operator=(const LinesSet& other) { - // This does work as long as we don't add any attribute to the PointsSet class or any of its child - return *reinterpret_cast*>(this); + lines_ = other.lines_; + return *this; } - const std::vector>& asRawVector() const + LineType& operator[](size_t index) { - // This does work as long as we don't add any attribute to the PointsSet class or any of its child - return *reinterpret_cast>*>(this); + return lines_[index]; } - std::vector>& asRawVector() - { - // This does work as long as we don't add any attribute to the PointsSet class or any of its child - return *reinterpret_cast>*>(this); - }*/ - - void add(const LinesSet& other) + const LineType& operator[](size_t index) const { - lines_->insert(other.lines_.end(), other.lines_.begin(), other.lines_.end()); + return lines_[index]; } LineType& newLine() @@ -185,8 +200,8 @@ class LinesSet coord_t length() const; - void splitIntoSegments(LinesSet& result) const; - LinesSet splitIntoSegments() const; + void splitIntoSegments(LinesSet& result) const; + LinesSet splitIntoSegments() const; /*! * Removes overlapping consecutive line segments which don't delimit a @@ -199,7 +214,7 @@ class LinesSet */ void removeDegenerateVerts(); - Shape offset(coord_t distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; + Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; /*! * Utility method for creating the tube (or 'donut') of a shape. @@ -209,8 +224,9 @@ class LinesSet */ Shape tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; -protected: void addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; + + void addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; }; } // namespace cura diff --git a/include/geometry/mixed_lines_set.h b/include/geometry/mixed_lines_set.h index 8f1ec679ff..a6d17bafb9 100644 --- a/include/geometry/mixed_lines_set.h +++ b/include/geometry/mixed_lines_set.h @@ -4,123 +4,55 @@ #ifndef GEOMETRY_MIXED_LINES_SET_H #define GEOMETRY_MIXED_LINES_SET_H -#include "geometry/lines_set.h" -#include "geometry/polyline.h" +#include + +#include "utils/Coord_t.h" namespace cura { -using MixedLinesSet = LinesSet; +class Polyline; +class OpenPolyline; +class ClosedPolyline; +class Polygon; +class Shape; +template +class LinesSet; + -#if 0 /*! - * \brief Container that can hold either open or closed polylines. We often have to handle "a bunch - * of lines" which are either open or closed without taking care of what they actually are. + * \brief Convenience definition for a container that can hold either open or closed polylines. */ -class MixedLinesSet : public LinesSet +class MixedLinesSet : public std::vector> { public: - MixedLinesSet() = default; - - MixedLinesSet(const MixedLinesSet& other) = default; - - MixedLinesSet(MixedLinesSet&& other) = default; - - MixedLinesSet(const LinesSet& open_lines) - : open_lines_(open_lines) - { - } - - MixedLinesSet(LinesSet&& open_lines) - : open_lines_(std::move(open_lines)) - { - } - - MixedLinesSet(const LinesSet& closed_lines) - : closed_lines_(closed_lines) - { - } - - MixedLinesSet(LinesSet&& closed_lines) - : closed_lines_(std::move(closed_lines)) - { - } - - const LinesSet& getOpenLines() const - { - return open_lines_; - } - - LinesSet& getOpenLines() - { - return open_lines_; - } - - void setOpenLines(const LinesSet& open_lines) - { - open_lines_ = open_lines; - } - - void setOpenLines(LinesSet&& open_lines) - { - open_lines_ = std::move(open_lines); - } - - const LinesSet& getClosedLines() const - { - return closed_lines_; - } - - LinesSet& getClosedLines() - { - return closed_lines_; - } - - void setClosedLines(const LinesSet& closed_lines) - { - closed_lines_ = closed_lines; - } - - void setClosedLines(LinesSet&& closed_lines) - { - closed_lines_ = std::move(closed_lines); - } - - ClosedPolyline& push_back(const ClosedPolyline& line) - { - closed_lines_.push_back(line); - return closed_lines_.back(); - } - - void push_back(const LinesSet& lines) - { - closed_lines_.add(lines); - } - - OpenPolyline& push_back(const OpenPolyline& line) - { - open_lines_.push_back(line); - return open_lines_.back(); - } - - void push_back(const LinesSet& lines) - { - open_lines_.add(lines); - } - - void push_back(const MixedLinesSet& lines); - - coord_t length() const - { - return open_lines_.length() + closed_lines_.length(); - } - - size_t size() const - { - return open_lines_.size() + closed_lines_.size(); - } + Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; + + void push_back(const OpenPolyline& line); + + void push_back(OpenPolyline&& line); + + void push_back(ClosedPolyline&& line); + + void push_back(const Polygon& line); + + void push_back(const std::shared_ptr& line); + + void push_back(const std::shared_ptr& line); + + void push_back(LinesSet&& lines_set); + + void push_back(const LinesSet& lines_set); + + void push_back(LinesSet&& lines_set); + + void push_back(const LinesSet& lines_set); + + void push_back(const Shape& shape); + + coord_t length() const; }; -#endif + } // namespace cura #endif // GEOMETRY_MIXED_LINES_SET_H diff --git a/include/geometry/open_lines_set.h b/include/geometry/open_lines_set.h new file mode 100644 index 0000000000..ea8cfcb9f4 --- /dev/null +++ b/include/geometry/open_lines_set.h @@ -0,0 +1,32 @@ +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher + +#ifndef GEOMETRY_OPEN_LINES_SET_H +#define GEOMETRY_OPEN_LINES_SET_H + +#include "geometry/lines_set.h" +#include "geometry/open_polyline.h" + +namespace cura +{ + +/*! + * \brief Convenience definition for a container that can hold only open polylines. This makes it + * explicit what the lines actually represent. + */ +using OpenLinesSet = LinesSet; +#warning Try with a using instead +/*class OpenLinesSet : public LinesSet +{ +public: + OpenLinesSet() = default; + + OpenLinesSet(const LinesSet& other) + : LinesSet(other) + { + } +};*/ + +} // namespace cura + +#endif // GEOMETRY_OPEN_LINES_SET_H diff --git a/include/geometry/open_polyline.h b/include/geometry/open_polyline.h index 23531227ba..9b1dff3aa3 100644 --- a/include/geometry/open_polyline.h +++ b/include/geometry/open_polyline.h @@ -9,45 +9,52 @@ namespace cura { -/*class OpenPolyline : public Polyline +class OpenPolyline : public Polyline { public: - OpenPolyline() - : Polyline{ PolylineType::Open } - { - } + OpenPolyline() = default; OpenPolyline(const OpenPolyline& other) = default; OpenPolyline(OpenPolyline&& other) = default; OpenPolyline(const std::initializer_list& initializer) - : Polyline(PolylineType::Open, initializer) + : Polyline(initializer) { } - OpenPolyline(const std::vector& points) - : Polyline(PolylineType::Open, points) + OpenPolyline(const ClipperLib::Path& points) + : Polyline(points) { } - OpenPolyline(std::vector&& points) - : Polyline(PolylineType::Open, points) + OpenPolyline(ClipperLib::Path&& points) + : Polyline(std::move(points)) { } - OpenPolyline& operator=(const OpenPolyline& other) + virtual bool addClosingSegment() const override { - Polyline::operator=(other); - return *this; + return false; // Definitely not + } + + virtual size_t segmentsCount() const override + { + return size() > 1 ? size() - 1 : 0; } OpenPolyline& operator=(OpenPolyline&& other) + { + Polyline::operator=(std::move(other)); + return *this; + } + + OpenPolyline& operator=(const OpenPolyline& other) { Polyline::operator=(other); return *this; } -};*/ +}; } // namespace cura diff --git a/include/geometry/points_set.h b/include/geometry/points_set.h index 54c6160936..d8b2a7797a 100644 --- a/include/geometry/points_set.h +++ b/include/geometry/points_set.h @@ -51,9 +51,9 @@ class PointsSet PointsSet(const std::initializer_list& initializer); - PointsSet(const std::vector& points); + PointsSet(const ClipperLib::Path& points); - PointsSet(std::vector&& points); + PointsSet(ClipperLib::Path&& points); /*PointsSet& operator=(const PointsSet& other) { @@ -71,6 +71,11 @@ class PointsSet return points_; } + void setPoints(std::vector&& points) + { + points_ = points; + } + size_t size() const { return points_.size(); @@ -81,11 +86,23 @@ class PointsSet points_.push_back(point); } + template + void emplace_back(Args&&... args) + { + points_.emplace_back(args...); + } + void pop_back() { points_.pop_back(); } + template + void insert(Args&&... args) + { + points_.insert(args...); + } + std::vector::const_iterator begin() const { return points_.begin(); @@ -106,6 +123,26 @@ class PointsSet return points_.end(); } + std::vector::const_reverse_iterator rbegin() const + { + return points_.rbegin(); + } + + std::vector::reverse_iterator rbegin() + { + return points_.rbegin(); + } + + std::vector::const_reverse_iterator rend() const + { + return points_.rend(); + } + + std::vector::reverse_iterator rend() + { + return points_.rend(); + } + const Point2LL& front() const { return points_.front(); @@ -126,6 +163,16 @@ class PointsSet return points_.back(); } + const Point2LL& at(size_t pos) const + { + return points_.at(pos); + } + + Point2LL& at(size_t pos) + { + return points_.at(pos); + } + bool empty() const { return points_.empty(); @@ -136,6 +183,16 @@ class PointsSet points_.resize(size); } + void reserve(size_t size) + { + points_.reserve(size); + } + + void clear() + { + points_.clear(); + } + Point2LL& operator[](size_t index) { return points_[index]; diff --git a/include/geometry/polygon.h b/include/geometry/polygon.h index 706dc061a0..652b28997c 100644 --- a/include/geometry/polygon.h +++ b/include/geometry/polygon.h @@ -4,7 +4,7 @@ #ifndef GEOMETRY_POLYGON_H #define GEOMETRY_POLYGON_H -#include "polyline.h" +#include "closed_polyline.h" namespace cura { @@ -13,30 +13,27 @@ class Shape; class ListPolyIt; class AngleDegrees; -class Polygon : public Polyline +class Polygon : public ClosedPolyline { public: - Polygon() - : Polyline{ PolylineType::Filled } - { - } + Polygon() = default; Polygon(const Polygon& other) = default; Polygon(Polygon&& other) = default; - Polygon(const std::initializer_list& initializer) - : Polyline(PolylineType::Filled, initializer) + Polygon(const std::initializer_list& initializer, bool explicitely_closed) + : ClosedPolyline(initializer, explicitely_closed) { } - explicit Polygon(const ClipperLib::Path& points) - : Polyline(PolylineType::Filled, points) + explicit Polygon(const ClipperLib::Path& points, bool explicitely_closed) + : ClosedPolyline(points, explicitely_closed) { } - explicit Polygon(ClipperLib::Path&& points) - : Polyline(PolylineType::Filled, points) + explicit Polygon(ClipperLib::Path&& points, bool explicitely_closed) + : ClosedPolyline(points, explicitely_closed) { } diff --git a/include/geometry/polyline.h b/include/geometry/polyline.h index afb6d04c49..8f7a162f35 100644 --- a/include/geometry/polyline.h +++ b/include/geometry/polyline.h @@ -5,15 +5,15 @@ #define GEOMETRY_POLYLINE_H #include "geometry/points_set.h" -#include "geometry/polyline_type.h" #include "geometry/segment_iterator.h" namespace cura { -template +template class LinesSet; class AngleRadians; +class OpenPolyline; /*! * \brief Base class for various types of polylines. A polyline is basically a set of points, but @@ -32,107 +32,49 @@ class AngleRadians; */ class Polyline : public PointsSet { -private: -#warning possibly remove the enum and just use a "closed" boolean - PolylineType type_; - public: using segments_iterator = SegmentIterator; using const_segments_iterator = SegmentIterator; - Polyline(PolylineType type = PolylineType::Open) - : PointsSet() - , type_(type) - { - } + Polyline() = default; Polyline(const Polyline& other) = default; Polyline(Polyline&& other) = default; - Polyline(PolylineType type, const std::initializer_list& initializer) + Polyline(const std::initializer_list& initializer) : PointsSet(initializer) - , type_(type) { } - Polyline(PolylineType type, const std::vector& points) + Polyline(const std::vector& points) : PointsSet(points) - , type_(type) { } - Polyline(PolylineType type, std::vector&& points) + Polyline(ClipperLib::Path&& points) : PointsSet(points) - , type_(type) { } - virtual ~Polyline() = default; // This is required to tag the class as polymorphic + virtual ~Polyline() = default; + + virtual bool addClosingSegment() const = 0; + + virtual size_t segmentsCount() const = 0; Polyline& operator=(const Polyline& other) { PointsSet::operator=(other); - type_ = other.type_; return *this; } Polyline& operator=(Polyline&& other) { PointsSet::operator=(other); - type_ = other.type_; return *this; } - PolylineType getType() const - { - return type_; - } - - /*! - * \brief Force setting the polyline type - * \param type The new type to be set - * \warning Forcibly setting the type changes the meaning of the vertices list. Use this method - * only if you are doing something specific, otherwise use convertToType() - */ - void setType(PolylineType type) - { - type_ = type; - } - - void convertToType(PolylineType type) - { -#warning implement me - } - - bool isClosed() const - { - return type_ != PolylineType::Open; - } - - bool isOpen() const - { - return type_ == PolylineType::Open; - } - - /*template - OtherType& toType() - { - return *reinterpret_cast(this); - } - - template - const OtherType& toType() const - { - return *reinterpret_cast(this); - }*/ - - /*Polyline& operator=(const Polyline& other) - { - std::vector::operator=(other); - return *this; - }*/ - const_segments_iterator beginSegments() const; const_segments_iterator endSegments() const; @@ -145,8 +87,8 @@ class Polyline : public PointsSet * Split these poly line objects into several line segment objects consisting of only two verts * and store them in the \p result */ - void splitIntoSegments(LinesSet& result) const; - LinesSet splitIntoSegments() const; + void splitIntoSegments(LinesSet& result) const; + LinesSet splitIntoSegments() const; /*! * On Y-axis positive upward displays, Orientation will return true if the polygon's orientation is counter-clockwise. @@ -200,36 +142,6 @@ class Polyline : public PointsSet } }*/ - /*! - * Check if we are inside the polygon. We do this by tracing from the point towards the positive X direction, - * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. - * Care needs to be taken, if p.Y exactly matches a vertex to the right of p, then we need to count 1 intersect if the - * outline passes vertically past; and 0 (or 2) intersections if that point on the outline is a 'top' or 'bottom' vertex. - * The easiest way to do this is to break out two cases for increasing and decreasing Y ( from p0 to p1 ). - * A segment is tested if pa.Y <= p.Y < pb.Y, where pa and pb are the points (from p0,p1) with smallest & largest Y. - * When both have the same Y, no intersections are counted but there is a special test to see if the point falls - * exactly on the line. - * - * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. - * - * \deprecated This function is no longer used, since the Clipper function is used by the function PolygonRef::inside(.) - * - * \param p The point for which to check if it is inside this polygon - * \param border_result What to return when the point is exactly on the border - * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) - */ - // bool _inside(Point2LL p, bool border_result = false) const; - - /*! - * Clipper function. - * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. - * - * http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/PointInPolygon.htm - */ - bool inside(const Point2LL& p, bool border_result = false) const; - - bool inside(const auto& polygon) const; - private: /*! * Private implementation for both simplify and simplifyPolygons. diff --git a/include/geometry/shape.h b/include/geometry/shape.h index effe7ac464..0545f5ff1e 100644 --- a/include/geometry/shape.h +++ b/include/geometry/shape.h @@ -4,7 +4,7 @@ #ifndef GEOMETRY_SHAPE_H #define GEOMETRY_SHAPE_H -#include "geometry/mixed_lines_set.h" +#include "geometry/lines_set.h" #include "geometry/polygon.h" #include "settings/types/Angle.h" @@ -18,6 +18,10 @@ class PartsView; class Shape : public LinesSet { +public: + // Clipper returns implicitely closed polygons + static constexpr bool clipper_explicitely_closed_ = false; + public: Shape() = default; @@ -30,12 +34,22 @@ class Shape : public LinesSet { } - explicit Shape(ClipperLib::Paths&& paths); + explicit Shape(ClipperLib::Paths&& paths, bool explicitely_closed = clipper_explicitely_closed_); Shape& operator=(const Shape& other); Shape& operator=(Shape&& other); + void emplace_back(ClipperLib::Paths&& paths, bool explicitely_closed = clipper_explicitely_closed_); + + void emplace_back(ClipperLib::Path&& path, bool explicitely_closed = clipper_explicitely_closed_); + + template + void emplace_back(Args&&... args) + { + LinesSet::emplace_back(args...); + } + /*! * Convert ClipperLib::PolyTree to a Shape object, * which uses ClipperLib::Paths instead of ClipperLib::PolyTree @@ -68,7 +82,8 @@ class Shape : public LinesSet * \return The resulting polylines limited to the area of this Polygons object */ template - MixedLinesSet intersection(const MixedLinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; +#warning Technically this should return a MixedLinesSet + LinesSet intersection(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; /*! * Add the front to each polygon so that the polygon is represented as a polyline @@ -275,6 +290,11 @@ class Shape : public LinesSet */ Shape removeNearSelfIntersections() const; + /*! + * \brief Simplify the polygon lines using ClipperLib::SimplifyPolygons + */ + void simplify(ClipperLib::PolyFillType fill_type = ClipperLib::pftEvenOdd); + private: /*! * recursive part of \ref Polygons::removeEmptyHoles and \ref Polygons::getEmptyHoles diff --git a/include/infill/ZigzagConnectorProcessor.h b/include/infill/ZigzagConnectorProcessor.h index e0f349c429..5e869fc5fc 100644 --- a/include/infill/ZigzagConnectorProcessor.h +++ b/include/infill/ZigzagConnectorProcessor.h @@ -171,7 +171,7 @@ class ZigzagConnectorProcessor * * \param polyline The polyline to add */ - void addPolyline(const Polygon& polyline); + void addPolyline(const OpenPolyline& polyline); /*! * Checks whether the current connector should be added or not. diff --git a/include/path_ordering.h b/include/path_ordering.h index 9126cc81d8..5a5de96e17 100644 --- a/include/path_ordering.h +++ b/include/path_ordering.h @@ -50,7 +50,7 @@ struct PathOrdering * Vertex data, converted into a Polygon so that the orderer knows how * to deal with this data. */ - const Polygon* converted_{ nullptr }; + const PointsSet* converted_{ nullptr }; /*! * Which vertex along the path to start printing with. @@ -88,7 +88,7 @@ struct PathOrdering * for each different type that this class is used with. See the .cpp file * for examples and where to add a new specialization. */ - const Polygon& getVertexData(); + const PointsSet& getVertexData(); protected: /*! @@ -99,7 +99,7 @@ struct PathOrdering * For example, if the ``PathType`` is a list of ``ExtrusionJunction``s, * this will store the coordinates of those junctions. */ - std::optional cached_vertices_; + std::optional cached_vertices_; }; } // namespace cura diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 0ece72efee..5f732e12df 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -14,7 +14,7 @@ #include "TopSurface.h" #include "WipeScriptConfig.h" #include "geometry/mixed_lines_set.h" -#include "geometry/open_polyline.h" +#include "geometry/open_lines_set.h" #include "geometry/point2ll.h" #include "geometry/polygon.h" #include "geometry/single_shape.h" @@ -169,7 +169,7 @@ class SliceLayer coord_t printZ; //!< The height at which this layer needs to be printed. Can differ from sliceZ due to the raft. coord_t thickness; //!< The thickness of this layer. Can be different when using variable layer heights. std::vector parts; //!< An array of LayerParts which contain the actual data. The parts are printed one at a time to minimize travel outside of the 3D model. - LinesSet openPolyLines; //!< A list of lines which were never hooked up into a 2D polygon. (Currently unused in normal operation) + OpenLinesSet openPolyLines; //!< A list of lines which were never hooked up into a 2D polygon. (Currently unused in normal operation) /*! * \brief The parts of the model that are exposed at the very top of the @@ -376,7 +376,7 @@ class SliceDataStorage : public NoCopy SupportStorage support; std::vector skirt_brim[MAX_EXTRUDERS]; //!< Skirt/brim polygons per extruder, ordered from inner to outer polygons. - LinesSet support_brim; //!< brim lines for support, going from the edge of the support inward. \note Not ordered by inset. + LinesSet support_brim; //!< brim lines for support, going from the edge of the support inward. \note Not ordered by inset. // Storage for the outline of the raft-parts. Will be filled with lines when the GCode is generated. Shape raftBaseOutline; diff --git a/include/slicer.h b/include/slicer.h index b5116688c8..7204edfd99 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -8,7 +8,7 @@ #include #include -#include "geometry/polygon.h" +#include "geometry/open_lines_set.h" #include "geometry/shape.h" #include "settings/EnumSettings.h" @@ -62,7 +62,7 @@ class SlicerLayer int z = -1; Shape polygons; - LinesSet openPolylines; + OpenLinesSet openPolylines; /*! * \brief Connect the segments into polygons for this layer of this \p mesh. @@ -77,7 +77,7 @@ class SlicerLayer * * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop */ - void makeBasicPolygonLoops(LinesSet& open_polylines); + void makeBasicPolygonLoops(OpenLinesSet& open_polylines); /*! * Connect the segments into a loop, starting from the segment with index \p start_segment_idx @@ -85,7 +85,7 @@ class SlicerLayer * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop * \param[in] start_segment_idx The index into SlicerLayer::segments for the first segment from which to start the polygon loop */ - void makeBasicPolygonLoop(LinesSet& open_polylines, const size_t start_segment_idx); + void makeBasicPolygonLoop(OpenLinesSet& open_polylines, const size_t start_segment_idx); /*! * Get the next segment connected to the end of \p segment. @@ -105,7 +105,7 @@ class SlicerLayer * * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop */ - void connectOpenPolylines(LinesSet& open_polylines); + void connectOpenPolylines(OpenLinesSet& open_polylines); /*! * Link up all the missing ends, closing up the smallest gaps first. This is an inefficient implementation which can run in O(n*n*n) time. @@ -114,7 +114,7 @@ class SlicerLayer * * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop yet */ - void stitch(LinesSet& open_polylines); + void stitch(OpenLinesSet& open_polylines); std::optional findPolygonGapCloser(Point2LL ip0, Point2LL ip1); @@ -127,7 +127,7 @@ class SlicerLayer * * \param[in,out] open_polylines The polylines which are stiched, but couldn't be closed into a loop yet */ - void stitch_extensive(LinesSet& open_polylines); + void stitch_extensive(OpenLinesSet& open_polylines); private: /*! @@ -418,7 +418,7 @@ class SlicerLayer * the order of a polyline. * \return The stitches that are allowed in order from best to worst. */ - std::priority_queue findPossibleStitches(const std::vector& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) const; + std::priority_queue findPossibleStitches(const OpenLinesSet& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) const; /*! Plans the best way to perform a stitch. * @@ -436,7 +436,7 @@ class SlicerLayer * \param[in,out] terminus_1 the Terminus on polyline_1 to join at. * \param[out] reverse Whether the polylines need to be reversed. */ - void planPolylineStitch(const LinesSet& open_polylines, Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const; + void planPolylineStitch(const OpenLinesSet& open_polylines, Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const; /*! Joins polyline_1 onto polyline_0. * @@ -454,7 +454,7 @@ class SlicerLayer * polyline_0 and reverse[1] indicates whether to reverse * polyline_1 */ - static void joinPolylines(Polyline& polyline_0, Polyline& polyline_1, const bool reverse[2]); + static void joinPolylines(OpenPolyline& polyline_0, OpenPolyline& polyline_1, const bool reverse[2]); /*! * Connecting polylines that are not closed yet. @@ -474,7 +474,7 @@ class SlicerLayer * \param[in] allow_reverse If true, then this function is allowed * to reverse edge directions to merge polylines. */ - void connectOpenPolylinesImpl(LinesSet& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse); + void connectOpenPolylinesImpl(OpenLinesSet& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse); }; class Slicer diff --git a/include/utils/OpenPolylineStitcher.h b/include/utils/OpenPolylineStitcher.h index 25580da160..bca7c2442e 100644 --- a/include/utils/OpenPolylineStitcher.h +++ b/include/utils/OpenPolylineStitcher.h @@ -5,13 +5,13 @@ #define UTILS_OPEN_POLYLINE_STITCHER_H #include "PolylineStitcher.h" -#include "geometry/lines_set.h" -#include "geometry/polyline.h" +#include "geometry/open_lines_set.h" +#include "geometry/shape.h" namespace cura { -using OpenPolylineStitcher = PolylineStitcher, LinesSet, OpenPolyline, Point2LL>; +using OpenPolylineStitcher = PolylineStitcher; } // namespace cura #endif // UTILS_OPEN_POLYLINE_STITCHER_H diff --git a/include/utils/PolylineStitcher.h b/include/utils/PolylineStitcher.h index 6c9b51dcff..cddfb0effa 100644 --- a/include/utils/PolylineStitcher.h +++ b/include/utils/PolylineStitcher.h @@ -65,6 +65,9 @@ class PolylineStitcher static bool canConnect(const Path& a, const Path& b); static bool isOdd(const Path& line); + +private: + static void pushToClosedResult(OutputPaths& result_polygons, const Path& polyline); }; } // namespace cura diff --git a/include/utils/Simplify.h b/include/utils/Simplify.h index d3db96a6dc..5e5ac0b5fd 100644 --- a/include/utils/Simplify.h +++ b/include/utils/Simplify.h @@ -5,12 +5,15 @@ #define UTILS_SIMPLIFY_H #include "../settings/Settings.h" //To load the parameters from a Settings object. +#include "geometry/mixed_lines_set.h" #include "geometry/polygon.h" #include "linearAlg2D.h" //To calculate line deviations and intersecting lines. namespace cura { +template +class LinesSet; struct ExtrusionLine; struct ExtrusionJunction; @@ -110,6 +113,15 @@ class Simplify template LinesSet polyline(const LinesSet& polylines) const; + /*! + * Simplify a batch of polylines. + * + * The endpoints of each polyline cannot be altered. + * \param polylines The polylines to simplify. + * \return The simplified polylines. + */ + MixedLinesSet polyline(const MixedLinesSet& polylines) const; + /*! * Simplify a polyline. * @@ -117,7 +129,15 @@ class Simplify * \param polyline The polyline to simplify. * \return The simplified polyline. */ - Polyline polyline(const Polyline& polyline) const; + OpenPolyline polyline(const OpenPolyline& polyline) const; + + /*! + * Simplify a polyline. + * + * \param polyline The polyline to simplify. + * \return The simplified polyline. + */ + ClosedPolyline polyline(const ClosedPolyline& polyline) const; /*! * Simplify a variable-line-width polyline. @@ -397,20 +417,13 @@ class Simplify size_t previousNotDeleted(size_t index, const std::vector& to_delete) const; /*! - * Create an empty polygon with the same properties as an original polygon, + * Create an empty polygonal with the same properties as an original polygon, * but without the vertex data. - * \param original The polygon to copy the properties from. - * \return An empty polygon. + * \param original The polygonal to copy the properties from. + * \return An empty polygonal. */ - Polygon createEmpty(const Polygon& original) const; - - /*! - * Create an empty extrusion line with the same properties as an original - * extrusion line, but without the vertex data. - * \param original The extrusion line to copy the properties from. - * \return An empty extrusion line. - */ - ExtrusionLine createEmpty(const ExtrusionLine& original) const; + template + Polygonal createEmpty(const Polygonal& original) const; /*! * Append a vertex to this polygon. diff --git a/include/utils/mixed_polyline_stitcher.h b/include/utils/mixed_polyline_stitcher.h index 10bc3d9863..d6ad13a453 100644 --- a/include/utils/mixed_polyline_stitcher.h +++ b/include/utils/mixed_polyline_stitcher.h @@ -1,39 +1,23 @@ // Copyright (c) 2024 Ultimaker B.V. // CuraEngine is released under the terms of the AGPLv3 or higher. -#ifndef UTILS_OPEN_POLYLINE_STITCHER_H -#define UTILS_OPEN_POLYLINE_STITCHER_H +#ifndef UTILS_MIXED_POLYLINE_STITCHER_H +#define UTILS_MIXED_POLYLINE_STITCHER_H #include "PolylineStitcher.h" -#include "geometry/closed_polyline.h" -#include "geometry/mixed_lines_set.h" -#include "geometry/open_polyline.h" +#include "geometry/closed_lines_set.h" +#include "geometry/open_lines_set.h" namespace cura { -class MixedPolylineStitcher : public PolylineStitcher, LinesSet, Polyline, Point2LL> +class MixedLinesSet; + +class MixedPolylineStitcher : public PolylineStitcher { public: - static void stitch(const LinesSet& lines, MixedLinesSet& result, coord_t max_stitch_distance = MM2INT(0.1), coord_t snap_distance = 10) - { - LinesSet open_lines; - LinesSet closed_lines; - - PolylineStitcher::stitch(lines, open_lines, closed_lines, max_stitch_distance, snap_distance); - - result.push_back(std::move(open_lines)); - - for (Polyline& closed_line : closed_lines) - { - // Base stitch method will create explicitely closed polylines, but won't tag them as such - // because it is a generic algporitm. Tag them now. - closed_line.setType(PolylineType::ExplicitelyClosed); - } - - result.push_back(std::move(closed_lines)); - } + static void stitch(const LinesSet& lines, MixedLinesSet& result, coord_t max_stitch_distance = MM2INT(0.1), coord_t snap_distance = 10); }; } // namespace cura -#endif // UTILS_OPEN_POLYLINE_STITCHER_H +#endif // UTILS_MIXED_POLYLINE_STITCHER_H diff --git a/include/utils/polygonUtils.h b/include/utils/polygonUtils.h index eb51837670..0355da4fa2 100644 --- a/include/utils/polygonUtils.h +++ b/include/utils/polygonUtils.h @@ -20,14 +20,16 @@ namespace cura /*! * Result of finding the closest point to a given within a set of polygons, with extra information on where the point is. */ -struct ClosestPoint +#warning Rename to ClosedPoint, and ClosedPoint to ClosedPointPolygon +template +struct GenericClosestPoint { Point2LL location_; //!< Result location - const PointsSet* poly_{ nullptr }; //!< Line in which the result was found (or nullptr if no result was found) + const LineType* poly_{ nullptr }; //!< Line in which the result was found (or nullptr if no result was found) size_t poly_idx_; //!< The index of the polygon in some Polygons where ClosestPoint::poly can be found size_t point_idx_; //!< Index to the first point in the polygon of the line segment on which the result was found - ClosestPoint(Point2LL p, size_t pos, const PointsSet* poly) + GenericClosestPoint(Point2LL p, size_t pos, const LineType* poly) : location_(p) , poly_(poly) , poly_idx_(NO_INDEX) @@ -35,7 +37,7 @@ struct ClosestPoint { } - ClosestPoint(Point2LL p, size_t pos, const PointsSet* poly, size_t poly_idx) + GenericClosestPoint(Point2LL p, size_t pos, const LineType* poly, size_t poly_idx) : location_(p) , poly_(poly) , poly_idx_(poly_idx) @@ -43,14 +45,14 @@ struct ClosestPoint { } - ClosestPoint(const PointsSet* poly) + GenericClosestPoint(const LineType* poly) : poly_(poly) , poly_idx_(NO_INDEX) , point_idx_(NO_INDEX) { } - ClosestPoint() + GenericClosestPoint() : poly_idx_(NO_INDEX) , point_idx_(NO_INDEX) { @@ -66,7 +68,7 @@ struct ClosestPoint return point_idx_ != NO_INDEX; } - bool operator==(const ClosestPoint& rhs) const + bool operator==(const GenericClosestPoint& rhs) const { // no need to compare on poy_idx // it's sometimes unused while poly is always initialized @@ -74,6 +76,8 @@ struct ClosestPoint } }; +using ClosestPoint = GenericClosestPoint; + } // namespace cura namespace std @@ -175,7 +179,7 @@ class PolygonUtils * \param poly The polygon. * \param point_idx The index of the point in the polygon. */ - static Point2LL getVertexInwardNormal(const Polygon& poly, unsigned int point_idx); + static Point2LL getVertexInwardNormal(const Polyline& poly, unsigned int point_idx); /*! * Get a point from the \p poly with a given \p offset. @@ -185,7 +189,7 @@ class PolygonUtils * \param offset The distance the point has to be moved outward from the polygon. * \return A point at the given distance inward from the point on the boundary polygon. */ - static Point2LL getBoundaryPointWithOffset(const Polygon& poly, unsigned int point_idx, int64_t offset); + static Point2LL getBoundaryPointWithOffset(const Polyline& poly, unsigned int point_idx, int64_t offset); /*! * Move a point away from the boundary by looking at the boundary normal of the nearest vert. @@ -517,12 +521,13 @@ class PolygonUtils * \param start_idx the index of the prev poly point on the poly. * \param poly_start_idx The index of the point in the polygon which is to be handled as the start of the polygon. No point further than this point will be the result. */ - static bool getNextPointWithDistance(Point2LL from, int64_t dist, const Polygon& poly, int start_idx, int poly_start_idx, GivenDistPoint& result); + static bool getNextPointWithDistance(Point2LL from, int64_t dist, const OpenPolyline& poly, int start_idx, int poly_start_idx, GivenDistPoint& result); /*! * Walk a given \p distance along the polygon from a given point \p from on the polygon */ - static ClosestPoint walk(const ClosestPoint& from, coord_t distance); + template + static GenericClosestPoint walk(const GenericClosestPoint& from, coord_t distance); /*! * Get the point on a polygon which intersects a line parallel to a line going through the starting point and through another point. diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index baa0cded30..73b5c0b853 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1340,14 +1340,13 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan struct BrimLineReference { const size_t inset_idx; - const OpenPolyline* poly; + const Polyline* poly; }; size_t total_line_count = 0; - for (const SkirtBrimLine& line : storage.skirt_brim[extruder_nr]) + for (const MixedLinesSet& lines : storage.skirt_brim[extruder_nr]) { - total_line_count += line.closed_polygons.size(); - total_line_count += line.open_polylines.size(); + total_line_count += lines.size(); // For layer_nr != 0 add only the innermost brim line (which is only the case if skirt_height > 1) if (layer_nr != 0) @@ -1355,9 +1354,8 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan break; } } - LinesSet all_brim_lines; - + MixedLinesSet all_brim_lines; all_brim_lines.reserve(total_line_count); const coord_t line_w = train.settings_.get("skirt_brim_line_width") * train.settings_.get("initial_layer_line_width_factor"); @@ -1367,7 +1365,8 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan for (size_t inset_idx = 0; inset_idx < storage.skirt_brim[extruder_nr].size(); inset_idx++) { - const SkirtBrimLine& offset = storage.skirt_brim[extruder_nr][inset_idx]; + const MixedLinesSet& offset = storage.skirt_brim[extruder_nr][inset_idx]; + /* auto push_lines = [&all_brim_lines, &grid, &inset_idx](const LinesSet& lines) { for (const LineType& line : lines) @@ -1392,6 +1391,20 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan push_lines(offset.closed_polygons); push_lines(offset.open_polylines); + */ + + for (const std::shared_ptr& line : offset) + { + if (line->segmentsCount() > 0) + { + all_brim_lines.push_back(line); + for (const Point2LL& p : *line) + { + grid.insert(p, BrimLineReference{ inset_idx, line.get() }); + } + } + } + // For layer_nr != 0 add only the innermost brim line (which is only the case if skirt_height > 1) if (layer_nr != 0) @@ -1401,7 +1414,7 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan } const auto smart_brim_ordering = train.settings_.get("brim_smart_ordering") && train.settings_.get("adhesion_type") == EPlatformAdhesion::BRIM; - std::unordered_multimap order_requirements; + std::unordered_multimap order_requirements; for (const std::pair>& p : grid) { const BrimLineReference& here = p.second.val; @@ -1467,7 +1480,7 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan start_close_to, fan_speed, reverse_print_direction, - layer_nr == 0 ? order_requirements : PathOrderOptimizer::no_order_requirements_); + layer_nr == 0 ? order_requirements : PathOrderOptimizer::no_order_requirements_); } @@ -1478,11 +1491,11 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan if ((layer_nr == 0) && (extruder_nr == mesh_group_settings.get("support_extruder_nr_layer_0").extruder_nr_)) { total_line_count += storage.support_brim.size(); - LinesSet support_brim_lines = storage.support_brim; + // LinesSet support_brim_lines = storage.support_brim; #warning Check for bugs !! // support_brim_lines.toPolylines(); gcode_layer.addLinesByOptimizer( - support_brim_lines, + storage.support_brim, gcode_layer.configs_storage_.skirt_brim_config_per_extruder[extruder_nr], SpaceFillType::PolyLines, enable_travel_optimization, @@ -1715,7 +1728,7 @@ void FffGcodeWriter::addMeshLayerToGCode_meshSurfaceMode(const SliceMeshStorage& { if (! part.outline.empty()) { - polygons.add(part.outline); + polygons.push_back(part.outline); } } @@ -2171,9 +2184,9 @@ bool FffGcodeWriter::processSingleLayerInfill( { const coord_t cut_offset = get_cut_offset(zig_zaggify_infill, infill_line_width, min_skin_below_wall_count); Shape tool = infill_below_skin.offset(static_cast(cut_offset)); - infill_lines_here = tool.intersectionPolyLines(infill_lines_here); + infill_lines_here = tool.intersection(infill_lines_here); } - infill_lines.add(infill_lines_here); + infill_lines.push_back(infill_lines_here); // normal processing for the infill that isn't below skin in_outline = infill_not_below_skin; if (density_idx == last_idx) @@ -2236,10 +2249,10 @@ bool FffGcodeWriter::processSingleLayerInfill( { const coord_t cut_offset = get_cut_offset(zig_zaggify_infill, infill_line_width, wall_line_count); Shape tool = sparse_in_outline.offset(static_cast(cut_offset)); - infill_lines_here = tool.intersectionPolyLines(infill_lines_here); + infill_lines_here = tool.intersection(infill_lines_here); } - infill_lines.add(infill_lines_here); - infill_polygons.add(infill_polygons_here); + infill_lines.push_back(infill_lines_here); + infill_polygons.push_back(infill_polygons_here); } wall_tool_paths.emplace_back(part.infill_wall_toolpaths); // The extra infill walls were generated separately. Add these too. @@ -2407,9 +2420,9 @@ bool FffGcodeWriter::partitionInfillBySkinAbove( // subtract the expanded overlap region from the regions accumulated from higher layers skin_above_combined = skin_above_combined.difference(overlap_expanded); // subtract the expanded overlap region from this skin part and add the remainder to the overlap region - skin_above_combined.add(relevant_outline.difference(overlap_expanded)); + skin_above_combined.push_back(relevant_outline.difference(overlap_expanded)); // and add the overlap area as well - skin_above_combined.add(overlap); + skin_above_combined.push_back(overlap); } else // this layer is the 1st layer above the layer whose infill we're printing { @@ -2429,17 +2442,17 @@ bool FffGcodeWriter::partitionInfillBySkinAbove( // ------- ------------------------------------- skin_above_combined = skin_above_combined.difference(relevant_outline.offset(tiny_infill_offset)); - skin_above_combined.add(relevant_outline); + skin_above_combined.push_back(relevant_outline); } } else // no overlap { - skin_above_combined.add(relevant_outline); + skin_above_combined.push_back(relevant_outline); } } else // this is the first skin region we have looked at { - skin_above_combined.add(relevant_outline); + skin_above_combined.push_back(relevant_outline); } } } @@ -2614,7 +2627,7 @@ bool FffGcodeWriter::processInsets( { if (boundaryBox.hit(prevLayerPart.boundaryBox)) { - outlines_below.add(prevLayerPart.outline); + outlines_below.push_back(prevLayerPart.outline); } } } @@ -2640,7 +2653,7 @@ bool FffGcodeWriter::processInsets( AABB support_roof_bb(support_layer.support_roof); if (boundaryBox.hit(support_roof_bb)) { - outlines_below.add(support_layer.support_roof); + outlines_below.push_back(support_layer.support_roof); } } else @@ -2650,7 +2663,7 @@ bool FffGcodeWriter::processInsets( AABB support_part_bb(support_part.getInfillArea()); if (boundaryBox.hit(support_part_bb)) { - outlines_below.add(support_part.getInfillArea()); + outlines_below.push_back(support_part.getInfillArea()); } } } diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 55d1a49b32..2266b344bc 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -569,8 +569,7 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz { for (const Polygon& poly : part.outline) { - layer.openPolyLines.push_back(OpenPolyline(poly)); - layer.openPolyLines.back().push_back(layer.openPolyLines.back()[0]); // add the segment which closes the polygon + layer.openPolyLines.push_back(poly.toPseudoOpenPolyline()); } } layer.parts.clear(); @@ -627,8 +626,8 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz if (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { const Shape& own_infill_area = other_part.getOwnInfillArea(); - std::vector cut_lines = own_infill_area.intersectionPolyLines(layer.openPolyLines); - new_polylines.add(cut_lines); + OpenLinesSet cut_lines = own_infill_area.intersection(layer.openPolyLines); + new_polylines.push_back(cut_lines); // NOTE: closed polygons will be represented as polylines, which will be closed automatically in the PathOrderOptimizer if (! own_infill_area.empty()) { diff --git a/src/InterlockingGenerator.cpp b/src/InterlockingGenerator.cpp index b730c73669..263171ff45 100644 --- a/src/InterlockingGenerator.cpp +++ b/src/InterlockingGenerator.cpp @@ -235,7 +235,7 @@ std::vector InterlockingGenerator::computeUnionedVolumeRegions() const break; } const SlicerLayer& layer = mesh->layers[static_cast(layer_nr)]; - layer_region.add(layer.polygons); + layer_region.push_back(layer.polygons); } layer_region = layer_region.offset(ignored_gap_).offset(-ignored_gap_); // Morphological close to merge meshes into single volume layer_region.applyMatrix(rotation_); @@ -302,7 +302,7 @@ void InterlockingGenerator::applyMicrostructureToOutlines(const std::unordered_s { Shape areas_here = cell_area_per_mesh_per_layer[static_cast(layer_nr / beam_layer_count_) % cell_area_per_mesh_per_layer.size()][mesh_idx]; areas_here.translate(Point2LL(bottom_corner.x_, bottom_corner.y_)); - structure_per_layer[mesh_idx][static_cast(layer_nr / beam_layer_count_)].add(areas_here); + structure_per_layer[mesh_idx][static_cast(layer_nr / beam_layer_count_)].push_back(areas_here); } } } diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 98a69cf0d3..57ac191456 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -207,11 +207,11 @@ Shape LayerPlan::computeCombBoundary(const CombBoundary boundary_type) { if (combing_mode == CombingMode::ALL) // Add the increased outline offset (skin, infill and part of the inner walls) { - comb_boundary.add(part.outline.offset(offset)); + comb_boundary.push_back(part.outline.offset(offset)); } else if (combing_mode == CombingMode::NO_SKIN) // Add the increased outline offset, subtract skin (infill and part of the inner walls) { - comb_boundary.add(part.outline.offset(offset).difference(part.inner_area.difference(part.infill_area))); + comb_boundary.push_back(part.outline.offset(offset).difference(part.inner_area.difference(part.infill_area))); } else if (combing_mode == CombingMode::NO_OUTER_SURFACES) { @@ -220,15 +220,15 @@ Shape LayerPlan::computeCombBoundary(const CombBoundary boundary_type) { for (const SkinPart& skin_part : outer_surface_part.skin_parts) { - top_and_bottom_most_fill.add(skin_part.top_most_surface_fill); - top_and_bottom_most_fill.add(skin_part.bottom_most_surface_fill); + top_and_bottom_most_fill.push_back(skin_part.top_most_surface_fill); + top_and_bottom_most_fill.push_back(skin_part.bottom_most_surface_fill); } } - comb_boundary.add(part.outline.offset(offset).difference(top_and_bottom_most_fill)); + comb_boundary.push_back(part.outline.offset(offset).difference(top_and_bottom_most_fill)); } else if (combing_mode == CombingMode::INFILL) // Add the infill (infill only) { - comb_boundary.add(part.infill_area); + comb_boundary.push_back(part.infill_area); } } } @@ -807,7 +807,7 @@ void LayerPlan::addWallLine( LinesSet line_polys; line_polys.addLine(p0, p1); constexpr bool restitch = false; // only a single line doesn't need stitching - auto roofing_line_segments = roofing_mask_.intersectionPolyLines(line_polys, restitch); + auto roofing_line_segments = roofing_mask_.intersection(line_polys, restitch); if (roofing_line_segments.empty()) { @@ -880,7 +880,7 @@ void LayerPlan::addWallLine( LinesSet line_polys; line_polys.addLine(p0, p1); constexpr bool restitch = false; // only a single line doesn't need stitching - line_polys = bridge_wall_mask_.intersectionPolyLines(line_polys, restitch); + line_polys = bridge_wall_mask_.intersection(line_polys, restitch); // line_polys now contains the wall lines that need to be printed using bridge_config @@ -898,7 +898,7 @@ void LayerPlan::addWallLine( smallest_dist2 = dist2; } } - const Polygon& bridge = line_polys[nearest]; + const OpenPolyline& bridge = line_polys[nearest]; // set b0 to the nearest vertex and b1 the furthest Point2LL b0 = bridge[0]; @@ -1052,7 +1052,7 @@ void LayerPlan::addWall( LinesSet line_polys; line_polys.addLine(p0.p_, p1.p_); constexpr bool restitch = false; // only a single line doesn't need stitching - line_polys = bridge_wall_mask_.intersectionPolyLines(line_polys, restitch); + line_polys = bridge_wall_mask_.intersection(line_polys, restitch); while (line_polys.size() > 0) { @@ -1068,7 +1068,7 @@ void LayerPlan::addWall( smallest_dist2 = dist2; } } - const Polygon& bridge = line_polys[nearest]; + const OpenPolyline& bridge = line_polys[nearest]; // set b0 to the nearest vertex and b1 the furthest Point2LL b0 = bridge[0]; @@ -1287,9 +1287,9 @@ void LayerPlan::addWalls( } } - +template void LayerPlan::addLinesByOptimizer( - const LinesSet& lines, + const LinesSet& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const bool enable_travel_optimization, @@ -1298,7 +1298,7 @@ void LayerPlan::addLinesByOptimizer( const std::optional near_start_location, const double fan_speed, const bool reverse_print_direction, - const std::unordered_multimap& order_requirements) + const std::unordered_multimap& order_requirements) { Shape boundary; if (enable_travel_optimization && ! comb_boundary_minimum_.empty()) @@ -1318,21 +1318,31 @@ void LayerPlan::addLinesByOptimizer( } dist += 100; // ensure boundary is slightly outside all skin/infill lines } - boundary.add(comb_boundary_minimum_.offset(dist)); + boundary.push_back(comb_boundary_minimum_.offset(dist)); // simplify boundary to cut down processing time boundary = Simplify(MM2INT(0.1), MM2INT(0.1), 0).polygon(boundary); } constexpr bool detect_loops = true; - PathOrderOptimizer order_optimizer( + PathOrderOptimizer order_optimizer( near_start_location.value_or(getLastPlannedPositionOrStartingPosition()), ZSeamConfig(), detect_loops, &boundary, reverse_print_direction, order_requirements); - for (const OpenPolyline& polyline : lines) + if constexpr (std::is_same::value) { - order_optimizer.addPolyline(&polyline); + for (const OpenPolyline& polyline : lines) + { + order_optimizer.addPolyline(&polyline); + } + } + if constexpr (std::is_same::value) + { + for (const ClosedPolyline& polyline : lines) + { + order_optimizer.addPolygon(&polyline); + } } order_optimizer.optimize(); @@ -1349,7 +1359,7 @@ void LayerPlan::addLinesByOptimizer( const std::optional near_start_location, const double fan_speed, const bool reverse_print_direction, - const std::unordered_multimap& order_requirements) + const std::unordered_multimap& order_requirements) { Shape boundary; if (enable_travel_optimization && ! comb_boundary_minimum_.empty()) @@ -1369,33 +1379,37 @@ void LayerPlan::addLinesByOptimizer( } dist += 100; // ensure boundary is slightly outside all skin/infill lines } - boundary.add(comb_boundary_minimum_.offset(dist)); + boundary.push_back(comb_boundary_minimum_.offset(dist)); // simplify boundary to cut down processing time boundary = Simplify(MM2INT(0.1), MM2INT(0.1), 0).polygon(boundary); } constexpr bool detect_loops = false; // We already know which lines are closed - PathOrderOptimizer order_optimizer( + PathOrderOptimizer order_optimizer( near_start_location.value_or(getLastPlannedPositionOrStartingPosition()), ZSeamConfig(), detect_loops, &boundary, reverse_print_direction, order_requirements); - for (const OpenPolyline& open_polyline : lines.getOpenLines()) + for (const std::shared_ptr& line : lines) { - order_optimizer.addPolyline(&open_polyline); - } - for (const ClosedPolyline& closed_polyline : lines.getClosedLines()) - { - order_optimizer.addPolygon(&closed_polyline.toType()); + if (const std::shared_ptr open_line = dynamic_pointer_cast(line)) + { + order_optimizer.addPolyline(open_line.get()); + } + else if (const std::shared_ptr closed_line = dynamic_pointer_cast(line)) + { + order_optimizer.addPolygon(closed_line.get()); + } } + order_optimizer.optimize(); addLinesInGivenOrder(order_optimizer.paths_, config, space_fill_type, wipe_dist, flow_ratio, fan_speed); } void LayerPlan::addLinesInGivenOrder( - const std::vector>& lines, + const std::vector>& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const coord_t wipe_dist, @@ -1406,8 +1420,8 @@ void LayerPlan::addLinesInGivenOrder( coord_t line_width_2 = half_line_width * half_line_width; for (size_t order_idx = 0; order_idx < lines.size(); order_idx++) { - const PathOrdering& path = lines[order_idx]; - const OpenPolyline& polyline = *path.vertices_; + const PathOrdering& path = lines[order_idx]; + const Polyline& polyline = *path.vertices_; const size_t start_idx = path.start_vertex_; assert(start_idx == 0 || start_idx == polyline.size() - 1 || path.is_closed_); const Point2LL start = polyline[start_idx]; @@ -1475,8 +1489,8 @@ void LayerPlan::addLinesInGivenOrder( // Don't wipe if next starting point is very near if (wipe && (order_idx < lines.size() - 1)) { - const PathOrdering& next_path = lines[order_idx + 1]; - const Polygon& next_polygon = *next_path.vertices_; + const PathOrdering& next_path = lines[order_idx + 1]; + const Polyline& next_polygon = *next_path.vertices_; const size_t next_start = next_path.start_vertex_; const Point2LL& next_p0 = next_polygon[next_start]; if (vSize2(next_p0 - p1) <= line_width * line_width * 4) @@ -1499,7 +1513,7 @@ void LayerPlan::addLinesInGivenOrder( void LayerPlan::addLinesMonotonic( const Shape& area, - const std::vector& lines, + const OpenLinesSet& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const AngleRadians monotonic_direction, @@ -1521,13 +1535,13 @@ void LayerPlan::addLinesMonotonic( } line_order.optimize(); - const auto is_inside_exclusion = [&exclude_areas, &exclude_dist2](const Polygon& path) + const auto is_inside_exclusion = [&exclude_areas, &exclude_dist2](const OpenPolyline& path) { return vSize2(path[1] - path[0]) < exclude_dist2 && exclude_areas.inside((path[0] + path[1]) / 2); }; // Order monotonically, except for line-segments which stay in the excluded areas (read: close to the walls) consecutively. - PathOrderMonotonic order(monotonic_direction, max_adjacent_distance, last_position); + PathOrderMonotonic order(monotonic_direction, max_adjacent_distance, last_position); LinesSet left_over; bool last_would_have_been_excluded = false; for (size_t line_idx = 0; line_idx < line_order.paths_.size(); ++line_idx) @@ -2662,4 +2676,28 @@ void LayerPlan::setRoofingMask(const Shape& polys) roofing_mask_ = polys; } +template void LayerPlan::addLinesByOptimizer( + const LinesSet& lines, + const GCodePathConfig& config, + const SpaceFillType space_fill_type, + const bool enable_travel_optimization, + const coord_t wipe_dist, + const Ratio flow_ratio, + const std::optional near_start_location, + const double fan_speed, + const bool reverse_print_direction, + const std::unordered_multimap& order_requirements); + +template void LayerPlan::addLinesByOptimizer( + const LinesSet& lines, + const GCodePathConfig& config, + const SpaceFillType space_fill_type, + const bool enable_travel_optimization, + const coord_t wipe_dist, + const Ratio flow_ratio, + const std::optional near_start_location, + const double fan_speed, + const bool reverse_print_direction, + const std::unordered_multimap& order_requirements); + } // namespace cura diff --git a/src/Mold.cpp b/src/Mold.cpp index 1399c20a35..2813b3bb31 100644 --- a/src/Mold.cpp +++ b/src/Mold.cpp @@ -79,7 +79,7 @@ void Mold::process(std::vector& slicer_list) SlicerLayer& layer = slicer.layers[layer_nr]; Shape model_outlines = layer.polygons.unionPolygons(layer.openPolylines.offset(open_polyline_width / 2)); layer.openPolylines.clear(); - all_original_mold_outlines.add(model_outlines); + all_original_mold_outlines.push_back(model_outlines); if (angle >= 90) { diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 259e47f6f5..9dc4da4ef8 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -157,7 +157,7 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse { // Create a new polygon with an offset from the outer polygon. Shape polygons = outer_poly_.offset(-cumulative_inset - wall_nr * line_width - line_width / 2); - prime_moves.add(polygons); + prime_moves.push_back(polygons); current_volume += polygons.length() * line_width * layer_height * flow; if (polygons.empty()) // Don't continue. We won't ever reach the required volume because it doesn't fit. { @@ -198,7 +198,7 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse Shape pattern = PolygonUtils::generateInset(outer_poly_, line_width, cumulative_inset); if (! pattern.empty()) { - inset_extra_moves_[extruder_nr].add(pattern); + inset_extra_moves_[extruder_nr].push_back(pattern); } } } diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 6884e33f34..13f691c178 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -8,7 +8,7 @@ #include "Application.h" #include "ExtruderTrain.h" #include "Slice.h" -#include "geometry/closed_polyline.h" +#include "geometry/shape.h" #include "settings/EnumSettings.h" #include "settings/types/Ratio.h" #include "sliceDataStorage.h" @@ -160,13 +160,12 @@ void SkirtBrim::generate() const Settings& global_settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings; const coord_t maximum_resolution = global_settings.get("meshfix_maximum_resolution"); const coord_t maximum_deviation = global_settings.get("meshfix_maximum_deviation"); + constexpr coord_t max_area_dev = 0u; // No area deviation applied for (int extruder_nr = 0; extruder_nr < extruder_count_; extruder_nr++) { - for (MixedLinesSet& line : storage_.skirt_brim[extruder_nr]) + for (MixedLinesSet& lines : storage_.skirt_brim[extruder_nr]) { - constexpr coord_t max_area_dev = 0u; // No area deviation applied - line.setOpenLines(Simplify(maximum_resolution, maximum_deviation, max_area_dev).polyline(line.getOpenLines())); - line.setClosedLines(Simplify(maximum_resolution, maximum_deviation, max_area_dev).polyline(line.getClosedLines())); + lines = Simplify(maximum_resolution, maximum_deviation, max_area_dev).polyline(lines); } } } @@ -230,11 +229,11 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std const double area = polygon.area(); if (area > 0 && offset.outside_) { - brim.add(polygon.offset(offset_value, ClipperLib::jtRound)); + brim.push_back(polygon.offset(offset_value, ClipperLib::jtRound)); } else if (area < 0 && offset.inside_) { - brim.add(polygon.offset(-offset_value, ClipperLib::jtRound)); + brim.push_back(polygon.offset(-offset_value, ClipperLib::jtRound)); } } } @@ -243,22 +242,18 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std const int reference_idx = std::get(offset.reference_outline_or_index_); const coord_t offset_dist = extruder_config.line_width_; -#warning Do it all in one go ? - Shape local_brim; - auto closed_polygons_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].getClosedLines().offset(offset_dist, ClipperLib::jtRound); - local_brim.add(closed_polygons_brim); + Shape local_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].offset(offset_dist, ClipperLib::jtRound); - auto open_polylines_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].getOpenLines().offset(offset_dist, ClipperLib::jtRound); - local_brim.add(open_polylines_brim); +#warning Is this required now we do all the offsetting in one pass ? local_brim.unionPolygons(); - brim.add(local_brim); + brim.push_back(local_brim); } // limit brim lines to allowed areas, stitch them and store them in the result brim = Simplify(Application::getInstance().current_slice_->scene.extruders[offset.extruder_nr_].settings_).polygon(brim); - LinesSet brim_lines = allowed_areas_per_extruder[offset.extruder_nr_].intersectionPolyLines(brim, false); + LinesSet brim_lines = allowed_areas_per_extruder[offset.extruder_nr_].intersection(brim, false); length_added = brim_lines.length(); Shape newly_covered = brim_lines.offset(extruder_config.line_width_ / 2 + 10, ClipperLib::jtRound); @@ -266,17 +261,20 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std const coord_t max_stitch_distance = extruder_config.line_width_; MixedPolylineStitcher::stitch(brim_lines, result, max_stitch_distance); - // clean up too small lines - LinesSet& open_polylines = result.getOpenLines(); - open_polylines.erase( + // clean up too small lines (only open ones, which was done historically but may be a mistake) + result.erase( std::remove_if( - open_polylines.begin(), - open_polylines.end(), - [](const OpenPolyline& line) + result.begin(), + result.end(), + [](const std::shared_ptr& line) { - return line.shorterThan(min_brim_line_length); + if (const std::shared_ptr open_line = dynamic_pointer_cast(line)) + { + return open_line->shorterThan(min_brim_line_length); + } + return false; }), - open_polylines.end()); + result.end()); // update allowed_areas_per_extruder covered_area = covered_area.unionPolygons(newly_covered.unionPolygons()); @@ -401,10 +399,10 @@ Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) for (const SupportInfillPart& support_infill_part : support_layer.support_infill_parts) { - first_layer_outline.add(support_infill_part.outline_); + first_layer_outline.push_back(support_infill_part.outline_); } - first_layer_outline.add(support_layer.support_bottom); - first_layer_outline.add(support_layer.support_roof); + first_layer_outline.push_back(support_layer.support_bottom); + first_layer_outline.push_back(support_layer.support_roof); } } constexpr coord_t join_distance = 20; @@ -466,12 +464,12 @@ void SkirtBrim::generateShieldBrim(Shape& brim_covered_area, std::vector& // generate brim within shield_brim storage_.skirt_brim[extruder_nr].emplace_back(); - storage_.skirt_brim[extruder_nr].back().push_back(shield_brim.toType()); + storage_.skirt_brim[extruder_nr].back().push_back(shield_brim); while (shield_brim.size() > 0) { shield_brim = shield_brim.offset(-primary_extruder_skirt_brim_line_width); - storage_.skirt_brim[extruder_nr].back().push_back(shield_brim.toType()); // throw all polygons for the shileds onto one heap; because the brim lines are - // generated from both sides the order will not be important + storage_.skirt_brim[extruder_nr].back().push_back(shield_brim); // throw all polygons for the shileds onto one heap; because the brim lines are + // generated from both sides the order will not be important } } @@ -628,7 +626,7 @@ std::vector SkirtBrim::generateAllowedAreas(const std::vector& sta if (covered_area < 0) { // Invert offset to make holes grow inside - allowed_areas.add(covered_surface.offset(-offset, ClipperLib::jtRound)); + allowed_areas.push_back(covered_surface.offset(-offset, ClipperLib::jtRound)); } else { @@ -681,7 +679,7 @@ void SkirtBrim::generateSupportBrim() Shape support_outline; for (SupportInfillPart& part : support_layer.support_infill_parts) { - support_outline.add(part.outline_); + support_outline.push_back(part.outline_); } const Shape brim_area = support_outline.difference(support_outline.offset(-brim_width)); support_layer.excludeAreasFromSupportInfillAreas(brim_area, AABB(brim_area)); @@ -703,14 +701,15 @@ void SkirtBrim::generateSupportBrim() } } - storage_.support_brim.add(brim_line.toType()); + const bool brim_line_empty = brim_line.empty(); // Store before moving + storage_.support_brim.push_back(std::move(brim_line)); // In case of adhesion::NONE length of support brim is only the length of the brims formed for the support const coord_t length = (adhesion_type_ == EPlatformAdhesion::NONE) ? skirt_brim_length : skirt_brim_length + storage_.support_brim.length(); if (skirt_brim_number + 1 >= line_count && length > 0 && length < minimal_length) // Make brim or skirt have more lines when total length is too small. { line_count++; } - if (brim_line.empty()) + if (brim_line_empty) { // the fist layer of support is fully filled with brim break; } diff --git a/src/TopSurface.cpp b/src/TopSurface.cpp index 5d6eb35b0d..2bb57ce274 100644 --- a/src/TopSurface.cpp +++ b/src/TopSurface.cpp @@ -108,7 +108,7 @@ bool TopSurface::ironing(const SliceDataStorage& storage, const SliceMeshStorage skip_line_stitching); std::vector ironing_paths; Shape ironing_polygons; - LinesSet ironing_lines; + OpenLinesSet ironing_lines; infill_generator.generate(ironing_paths, ironing_polygons, ironing_lines, mesh.settings, layer.getLayerNr(), SectionType::IRONING); if (ironing_polygons.empty() && ironing_lines.empty() && ironing_paths.empty()) diff --git a/src/TreeModelVolumes.cpp b/src/TreeModelVolumes.cpp index c30df3707a..8b9e0aa9bc 100644 --- a/src/TreeModelVolumes.cpp +++ b/src/TreeModelVolumes.cpp @@ -117,7 +117,7 @@ TreeModelVolumes::TreeModelVolumes( return; // Can't break as parallel_for wont allow it, this is equivalent to a continue. } Shape outline = extractOutlineFromMesh(mesh_l, layer_idx); - layer_outlines_[mesh_to_layeroutline_idx[mesh_idx_l]].second[layer_idx].add(outline); + layer_outlines_[mesh_to_layeroutline_idx[mesh_idx_l]].second[layer_idx].push_back(outline); }); } // Merge all the layer outlines together. @@ -140,17 +140,17 @@ TreeModelVolumes::TreeModelVolumes( { if (layer_idx < coord_t(additional_excluded_areas.size())) { - anti_overhang_[layer_idx].add(additional_excluded_areas[layer_idx]); + anti_overhang_[layer_idx].push_back(additional_excluded_areas[layer_idx]); } if (SUPPORT_TREE_AVOID_SUPPORT_BLOCKER) { - anti_overhang_[layer_idx].add(storage.support.supportLayers[layer_idx].anti_overhang); + anti_overhang_[layer_idx].push_back(storage.support.supportLayers[layer_idx].anti_overhang); } if (storage.primeTower.enabled_) { - anti_overhang_[layer_idx].add(storage.primeTower.getGroundPoly()); + anti_overhang_[layer_idx].push_back(storage.primeTower.getGroundPoly()); } anti_overhang_[layer_idx] = anti_overhang_[layer_idx].unionPolygons(); }); @@ -655,12 +655,12 @@ void TreeModelVolumes::calculateCollision(const std::deque& key Shape collision_areas = machine_border_; if (size_t(layer_idx) < layer_outlines_[outline_idx].second.size()) { - collision_areas.add(layer_outlines_[outline_idx].second[layer_idx]); + collision_areas.push_back(layer_outlines_[outline_idx].second[layer_idx]); } collision_areas = collision_areas.offset( radius + xy_distance); // jtRound is not needed here, as the overshoot can not cause errors in the algorithm, because no assumptions are made about the model. - data[key].add(collision_areas); // if a key does not exist when it is accessed it is added! + data[key].push_back(collision_areas); // if a key does not exist when it is accessed it is added! } // Add layers below, to ensure correct support_bottom_distance. Also save placeable areas of radius 0, if required for this mesh. @@ -669,7 +669,7 @@ void TreeModelVolumes::calculateCollision(const std::deque& key key.second = layer_idx; for (size_t layer_offset = 1; layer_offset <= z_distance_bottom_layers && layer_idx - coord_t(layer_offset) > min_layer_bottom; layer_offset++) { - data[key].add(data[RadiusLayerPair(radius, layer_idx - layer_offset)]); + data[key].push_back(data[RadiusLayerPair(radius, layer_idx - layer_offset)]); } // Placeable areas also have to be calculated when a collision has to be calculated if called outside of precalculate to prevent an infinite loop when they are // invalidly requested... @@ -719,7 +719,7 @@ void TreeModelVolumes::calculateCollision(const std::deque& key const coord_t required_range_x = coord_t(xy_distance - ((layer_offset - (z_distance_top_layers == 1 ? 0.5 : 0)) * xy_distance / z_distance_top_layers)); // ^^^ The conditional -0.5 ensures that plastic can never touch on the diagonal downward when the z_distance_top_layers = 1. // It is assumed to be better to not support an overhang<90� than to risk fusing to it. - data[key].add(layer_outlines_[outline_idx].second[layer_idx + layer_offset].offset(radius + required_range_x)); + data[key].push_back(layer_outlines_[outline_idx].second[layer_idx + layer_offset].offset(radius + required_range_x)); } data[key] = data[key].unionPolygons(max_anti_overhang_layer >= layer_idx ? anti_overhang_[layer_idx].offset(radius) : Shape()); } diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 441eb80c23..9358693b16 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -131,11 +131,11 @@ void TreeSupport::generateSupportAreas(SliceDataStorage& storage) [&](const LayerIndex layer_idx) { Shape exlude_at_layer; - exlude_at_layer.add(storage.support.supportLayers[layer_idx].support_bottom); - exlude_at_layer.add(storage.support.supportLayers[layer_idx].support_roof); + exlude_at_layer.push_back(storage.support.supportLayers[layer_idx].support_bottom); + exlude_at_layer.push_back(storage.support.supportLayers[layer_idx].support_roof); for (auto part : storage.support.supportLayers[layer_idx].support_infill_parts) { - exlude_at_layer.add(part.outline_); + exlude_at_layer.push_back(part.outline_); } exclude[layer_idx] = exlude_at_layer.unionPolygons(); scripta::log("tree_support_exclude", exclude[layer_idx], SectionType::SUPPORT, layer_idx); @@ -1724,7 +1724,7 @@ void TreeSupport::generateBranchAreas( vertex = Point2LL(matrix[0] * vertex.X + matrix[1] * vertex.Y, matrix[2] * vertex.X + matrix[3] * vertex.Y); circle.push_back(center_position + vertex); } - poly.add(circle.offset(0)); + poly.push_back(circle.offset(0)); } poly = poly.unionPolygons() @@ -1891,7 +1891,7 @@ void TreeSupport::smoothBranchAreas(std::vector& support_layer_storage) { Shape area = parts[idx]; reversePolygon(area); - holes_original.add(area); + holes_original.push_back(area); } support_holes[layer_idx] = holes_original; }); @@ -2031,7 +2031,7 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_storage) for (auto poly : holeparts[layer_idx - 1]) { - holes_below.add(poly); + holes_below.push_back(poly); } for (auto [idx, hole] : holeparts[layer_idx] | ranges::views::enumerate) @@ -2092,7 +2092,7 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_storage) } else { - valid_holes[layer_idx].add(hole); + valid_holes[layer_idx].push_back(hole); holeparts[layer_idx][idx] = Shape(); // all remaining holes will have to be removed later, so removing the hole means it is confirmed valid! } } @@ -2114,7 +2114,7 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_storage) support_layer_storage[layer_idx] = support_layer_storage[layer_idx].getOutsidePolygons(); reversePolygon(valid_holes[layer_idx]); - support_layer_storage[layer_idx].add(valid_holes[layer_idx]); + support_layer_storage[layer_idx].push_back(valid_holes[layer_idx]); }); @@ -2155,7 +2155,7 @@ void TreeSupport::finalizeInterfaceAndSupportAreas( for (FakeRoofArea& f_roof : fake_roof_areas[layer_idx]) { - fake_roof_lines.add( + fake_roof_lines.push_back( TreeSupportUtils::generateSupportInfillLines(f_roof.area_, config, false, layer_idx, f_roof.line_distance_, storage.support.cross_fill_provider, false) .offset(config.support_line_width / 2)); } @@ -2228,7 +2228,7 @@ void TreeSupport::finalizeInterfaceAndSupportAreas( = static_cast(std::max(0, (static_cast(layer_idx) - static_cast(layers_below)) - static_cast(config.z_distance_bottom_layers))); constexpr bool no_support = false; constexpr bool no_prime_tower = false; - floor_layer.add(layer_outset.intersection(storage.getLayerOutlines(sample_layer, no_support, no_prime_tower))); + floor_layer.push_back(layer_outset.intersection(storage.getLayerOutlines(sample_layer, no_support, no_prime_tower))); if (layers_below < config.support_bottom_layers) { layers_below = std::min(layers_below + 1UL, config.support_bottom_layers); @@ -2353,7 +2353,7 @@ void TreeSupport::drawAreas(std::vector>& move_bou { for (std::pair pair : dropped_down_areas[i]) { - support_layer_storage[pair.first].add(pair.second); + support_layer_storage[pair.first].push_back(pair.second); } } @@ -2399,15 +2399,15 @@ void TreeSupport::drawAreas(std::vector>& move_bou { if (data_pair.first->missing_roof_layers_ > data_pair.first->distance_to_top_) { - support_roof_storage_fractional[layer_idx + 1].add(data_pair.second); + support_roof_storage_fractional[layer_idx + 1].push_back(data_pair.second); } else { - support_layer_storage_fractional[layer_idx + 1].add(data_pair.second); + support_layer_storage_fractional[layer_idx + 1].push_back(data_pair.second); } } - ((data_pair.first->missing_roof_layers_ > data_pair.first->distance_to_top_) ? support_roof_storage : support_layer_storage)[layer_idx].add(data_pair.second); + ((data_pair.first->missing_roof_layers_ > data_pair.first->distance_to_top_) ? support_roof_storage : support_layer_storage)[layer_idx].push_back(data_pair.second); } if (layer_idx + 1 < support_roof_storage_fractional.size()) { @@ -2420,7 +2420,7 @@ void TreeSupport::drawAreas(std::vector>& move_bou { if (support_layer_storage.size() > layer_idx) { - support_layer_storage[layer_idx].add(additional_required_support_area[layer_idx]); + support_layer_storage[layer_idx].push_back(additional_required_support_area[layer_idx]); } scripta::log("tree_support_layer_storage", support_layer_storage[layer_idx], SectionType::SUPPORT, layer_idx); } diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 1791336c95..5453444934 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -266,7 +266,7 @@ LinesSet TreeSupportTipGenerator::ensureMaximumDistancePolyline(co coord_t current_distance = std::max(distance, coord_t(FUDGE_LENGTH * 2)); if (length < 2 * distance && min_points <= 1) { - ClosestPoint middle_point(part[0], 0, &part); + GenericClosestPoint middle_point(part[0], 0, &part); middle_point = PolygonUtils::walk(middle_point, coord_t(length / 2)); line.push_back(middle_point.location_); } @@ -447,7 +447,7 @@ void TreeSupportTipGenerator::dropOverhangAreas(const SliceMeshStorage& mesh, st { { std::lock_guard critical_section_storage(critical); - result[layer_idx - lag_ctr].add(remaining_overhang); + result[layer_idx - lag_ctr].push_back(remaining_overhang); } Shape relevant_forbidden_below = volumes_.getCollision(roof ? 0 : config_.getRadius(0), layer_idx - lag_ctr, ! xy_overrides_).offset(EPSILON); @@ -530,10 +530,10 @@ void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& m if (full_overhang_area.area() > EPSILON) { std::lock_guard critical_section_potential_support_roofs(critical_potential_support_roofs); - potential_support_roofs[layer_idx - dtt_roof].add((full_overhang_area)); + potential_support_roofs[layer_idx - dtt_roof].push_back((full_overhang_area)); if (dtt_roof == 0) { - support_roof_drawn_fractional_[layer_idx].add(full_overhang_area); + support_roof_drawn_fractional_[layer_idx].push_back(full_overhang_area); } } else @@ -590,8 +590,8 @@ void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& m -LayerIndex{ std::min(layer_idx, LayerIndex{ support_roof_layers_ }) }, LayerIndex{ std::min(LayerIndex{ potential_support_roofs.size() - layer_idx }, LayerIndex{ support_roof_layers_ + 1 }) })) { - fuzzy_area.add(support_roof_drawn_[layer_idx + layer_offset]); - fuzzy_area.add(potential_support_roofs[layer_idx + layer_offset]); + fuzzy_area.push_back(support_roof_drawn_[layer_idx + layer_offset]); + fuzzy_area.push_back(potential_support_roofs[layer_idx + layer_offset]); } fuzzy_area = fuzzy_area.unionPolygons(); fuzzy_area.removeSmallAreas(std::max(minimum_roof_area_, tip_roof_size_)); @@ -600,7 +600,7 @@ void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& m { if (! potential_roof.intersection(fuzzy_area).empty()) { - additional_support_roofs[layer_idx].add(potential_roof); + additional_support_roofs[layer_idx].push_back(potential_roof); } } } @@ -608,7 +608,7 @@ void TreeSupportTipGenerator::calculateRoofAreas(const cura::SliceMeshStorage& m { Shape valid_roof = potential_support_roofs[layer_idx].difference(forbidden_here); valid_roof.removeSmallAreas(std::max(minimum_roof_area_, tip_roof_size_)); - additional_support_roofs[layer_idx].add(valid_roof); + additional_support_roofs[layer_idx].push_back(valid_roof); } } }); @@ -749,11 +749,11 @@ void TreeSupportTipGenerator::addLinesAsInfluenceAreas( added_roofs = added_roofs.unionPolygons(); { std::lock_guard critical_section_roof(critical_roof_tips_); - roof_tips_drawn_[insert_layer_idx - dtt_roof_tip].add(added_roofs); + roof_tips_drawn_[insert_layer_idx - dtt_roof_tip].push_back(added_roofs); if (dtt_roof_tip == 0) { - support_roof_drawn_fractional_[insert_layer_idx].add(added_roofs); + support_roof_drawn_fractional_[insert_layer_idx].push_back(added_roofs); } } } @@ -1157,11 +1157,11 @@ void TreeSupportTipGenerator::generateTips( if (layer_idx < additional_support_areas.size() && TreeSupportUtils::generateSupportInfillLines(roof_area, config_, true, layer_idx, support_roof_line_distance_, cross_fill_provider_, false).empty()) { - additional_support_areas[layer_idx].add(roof_area); + additional_support_areas[layer_idx].push_back(roof_area); } else { - storage.support.supportLayers[layer_idx].support_roof.add(roof_area); + storage.support.supportLayers[layer_idx].support_roof.push_back(roof_area); } } @@ -1192,7 +1192,7 @@ void TreeSupportTipGenerator::generateTips( // Fractional roof is a modifier applied to a roof area, which means if only the fractional roof area is set, there will be nothing as there is no roof to // modify. Because of that the fractional roof has ALSO to be added to the roof. - storage.support.supportLayers[layer_idx].support_roof.add(all_roof_fractional); + storage.support.supportLayers[layer_idx].support_roof.push_back(all_roof_fractional); } Shape all_roof = support_roof_drawn_[layer_idx].unionPolygons(roof_tips_drawn_[layer_idx]); diff --git a/src/WallToolPaths.cpp b/src/WallToolPaths.cpp index b7e1861463..b747493cf7 100644 --- a/src/WallToolPaths.cpp +++ b/src/WallToolPaths.cpp @@ -97,7 +97,7 @@ const std::vector& WallToolPaths::generate() auto smoother = actions::smooth(settings_); for (Polygon& polygon : prepared_outline) { - polygon = smoother(polygon.asRawVector()); + polygon.setPoints(smoother(polygon.getPoints())); } } diff --git a/src/bridge.cpp b/src/bridge.cpp index 4c1b0bca31..ebf281c247 100644 --- a/src/bridge.cpp +++ b/src/bridge.cpp @@ -3,7 +3,7 @@ #include "bridge.h" -#include "geometry/open_polyline.h" +#include "geometry/open_lines_set.h" #include "geometry/polygon.h" #include "settings/types/Ratio.h" #include "sliceDataStorage.h" @@ -50,12 +50,12 @@ double bridgeAngle( { solid_below = solid_below.difference(prev_layer_part.getOwnInfillArea()); } - prev_layer_outline.add(solid_below); // not intersected with skin + prev_layer_outline.push_back(solid_below); // not intersected with skin if (! boundary_box.hit(prev_layer_part.boundaryBox)) continue; - islands.add(skin_outline.intersection(solid_below)); + islands.push_back(skin_outline.intersection(solid_below)); } } } @@ -74,12 +74,12 @@ double bridgeAngle( AABB support_roof_bb(support_layer->support_roof); if (boundary_box.hit(support_roof_bb)) { - prev_layer_outline.add(support_layer->support_roof); // not intersected with skin + prev_layer_outline.push_back(support_layer->support_roof); // not intersected with skin Shape supported_skin(skin_outline.intersection(support_layer->support_roof)); if (! supported_skin.empty()) { - supported_regions.add(supported_skin); + supported_regions.push_back(supported_skin); } } } @@ -90,12 +90,12 @@ double bridgeAngle( AABB support_part_bb(support_part.getInfillArea()); if (boundary_box.hit(support_part_bb)) { - prev_layer_outline.add(support_part.getInfillArea()); // not intersected with skin + prev_layer_outline.push_back(support_part.getInfillArea()); // not intersected with skin Shape supported_skin(skin_outline.intersection(support_part.getInfillArea())); if (! supported_skin.empty()) { - supported_regions.add(supported_skin); + supported_regions.push_back(supported_skin); } } } @@ -122,16 +122,16 @@ double bridgeAngle( const coord_t bb_max_dim = std::max(boundary_box.max_.X - boundary_box.min_.X, boundary_box.max_.Y - boundary_box.min_.Y); const Shape air_below(bb_poly.offset(bb_max_dim).difference(prev_layer_outline).offset(-10)); - LinesSet skin_perimeter_lines; + OpenLinesSet skin_perimeter_lines; for (const Polygon& poly : skin_outline) { if (! poly.empty()) { - skin_perimeter_lines.push_back(poly.toType()); + skin_perimeter_lines.emplace_back(poly.toPseudoOpenPolyline()); } } - LinesSet skin_perimeter_lines_over_air(air_below.intersectionPolyLines(skin_perimeter_lines)); + OpenLinesSet skin_perimeter_lines_over_air(air_below.intersection(skin_perimeter_lines)); if (skin_perimeter_lines_over_air.size()) { diff --git a/src/communication/ArcusCommunication.cpp b/src/communication/ArcusCommunication.cpp index 29d7dc0872..fb321aeb8b 100644 --- a/src/communication/ArcusCommunication.cpp +++ b/src/communication/ArcusCommunication.cpp @@ -451,7 +451,7 @@ void ArcusCommunication::sendPolygon(const PrintFeatureType& type, const Polygon void ArcusCommunication::sendPolygons(const PrintFeatureType& type, const Shape& polygons, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity) { - for (const std::vector& polygon : polygons) + for (const Polygon& polygon : polygons) { path_compiler->sendPolygon(type, polygon, line_width, line_thickness, velocity); } diff --git a/src/geometry/closed_polyline.cpp b/src/geometry/closed_polyline.cpp new file mode 100644 index 0000000000..cdd3689551 --- /dev/null +++ b/src/geometry/closed_polyline.cpp @@ -0,0 +1,43 @@ +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#include "geometry/closed_polyline.h" + +#include "geometry/open_polyline.h" + +namespace cura +{ + +bool ClosedPolyline::inside(const Point2LL& p, bool border_result) const +{ + int res = ClipperLib::PointInPolygon(p, getPoints()); + if (res == -1) + { + return border_result; + } + return res == 1; +} + +bool ClosedPolyline::inside(const ClipperLib::Path& polygon) const +{ + for (const auto& point : *this) + { + if (! ClipperLib::PointInPolygon(point, polygon)) + { + return false; + } + } + return true; +} + +OpenPolyline ClosedPolyline::toPseudoOpenPolyline() const +{ + OpenPolyline open_polyline(getPoints()); + if (addClosingSegment()) + { + open_polyline.push_back(open_polyline.getPoints().front()); + } + return open_polyline; +} + +} // namespace cura diff --git a/src/geometry/lines_set.cpp b/src/geometry/lines_set.cpp index fdede10b3d..8451ba0a3d 100644 --- a/src/geometry/lines_set.cpp +++ b/src/geometry/lines_set.cpp @@ -5,20 +5,20 @@ #include +#include "geometry/open_lines_set.h" #include "geometry/polygon.h" -#include "geometry/polyline.h" #include "geometry/shape.h" namespace cura { template -LinesSet::LinesSet(PolylineType type, std::vector>&& paths) +LinesSet::LinesSet(ClipperLib::Paths&& paths) { reserve(paths.size()); - for (std::vector& path : paths) + for (ClipperLib::Path& path : paths) { - push_back(type, std::move(path)); + lines_.emplace_back(std::move(path)); } } @@ -41,22 +41,23 @@ void LinesSet::push_back(LineType&& line, bool checkNonEmpty) } template -void LinesSet::push_back(PolylineType type, ClipperLib::Paths&& paths) +void LinesSet::push_back(ClipperLib::Paths&& paths) { reserve(size() + paths.size()); for (ClipperLib::Path& path : paths) { - lines_.emplace_back(type, std::move(path)); + lines_.emplace_back(std::move(path)); } } template -void LinesSet::push_back(LinesSet&& lines_set) +template +void LinesSet::push_back(LinesSet&& lines_set) { reserve(size() + lines_set.size()); - for (LineType& line : lines_set) + for (OtherLineType& line : lines_set) { - push_back(std::move(line)); + emplace_back(std::move(line)); } } @@ -73,28 +74,10 @@ size_t LinesSet::pointCount() const }); } -template -void LinesSet::addLine(const Point2LL& from, const Point2LL& to) -{ - lines_.emplace_back(PolylineType::Open, std::initializer_list{ from, to }); -} - -template -void LinesSet::addIfNotEmpty(const LineType& line) -{ - if (! line.empty()) - { - lines_.push_back(line); - } -} - -template -void LinesSet::addIfNotEmpty(LineType&& line) +template<> +void LinesSet::addLine(const Point2LL& from, const Point2LL& to) { - if (! line.empty()) - { - lines_.emplace_back(std::move(line)); - } + lines_.emplace_back(std::initializer_list{ from, to }); } template @@ -116,7 +99,7 @@ void LinesSet::removeAt(size_t index) } template -void LinesSet::splitIntoSegments(LinesSet& result) const +void LinesSet::splitIntoSegments(OpenLinesSet& result) const { for (const LineType& line : lines_) { @@ -125,9 +108,9 @@ void LinesSet::splitIntoSegments(LinesSet& result) const } template -LinesSet LinesSet::splitIntoSegments() const +OpenLinesSet LinesSet::splitIntoSegments() const { - LinesSet result; + OpenLinesSet result; for (const LineType& line : lines_) { line.splitIntoSegments(result); @@ -154,25 +137,80 @@ Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t ou return offset(outer_offset).difference(offset(-inner_offset)); } -template -Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const +template<> +Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const { if (distance == 0) { - // Return a shape that contains only actual polygons Shape result; - - for (const LineType& line : lines_) + for (const ClosedPolyline& line : getLines()) { - if (const Polygon* polygon = dynamic_cast(&line)) - { - result.push_back(*polygon); - } + result.emplace_back(line.getPoints(), line.isExplicitelyClosed()); } + return result; + } + ClipperLib::Paths ret; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + addPaths(clipper, join_type, ClipperLib::etClosedPolygon); + clipper.MiterLimit = miter_limit; + clipper.Execute(ret, static_cast(distance)); + return Shape(std::move(ret)); +} +template<> +Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const +{ + if (distance == 0) + { + Shape result; + result.push_back(getLines()); return result; } - else + ClipperLib::Paths ret; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + addPaths(clipper, join_type, ClipperLib::etClosedPolygon); + clipper.MiterLimit = miter_limit; + clipper.Execute(ret, static_cast(distance)); + return Shape(std::move(ret)); +} + +template<> +Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const +{ + Shape result; + + if (distance != 0) + { + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + ClipperLib::EndType end_type; + if (join_type == ClipperLib::jtMiter) + { + end_type = ClipperLib::etOpenSquare; + } + else + { + end_type = ClipperLib::etOpenRound; + } + + addPaths(clipper, join_type, end_type); + + clipper.MiterLimit = miter_limit; + ClipperLib::Paths result_paths; + clipper.Execute(result_paths, static_cast(distance)); + result = Shape(std::move(result_paths)); + } + + return result; +} + +#if 0 +template<> +Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const +{ +#error Implement me if required + Shape result; + + if (distance != 0) { Shape polygons; ClipperLib::ClipperOffset clipper(miter_limit, 10.0); @@ -192,7 +230,7 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType { ClipperLib::EndType end_type; - if (line.isClosed()) + if (line.addClosingSegment()) { end_type = ClipperLib::etClosedLine; } @@ -225,7 +263,10 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType clipper.Execute(result, static_cast(distance)); return Shape(std::move(result)); } + + return result; } +#endif template void LinesSet::removeDegenerateVerts() @@ -233,8 +274,8 @@ void LinesSet::removeDegenerateVerts() for (size_t poly_idx = 0; poly_idx < lines_.size(); poly_idx++) { LineType& poly = lines_[poly_idx]; - bool for_polyline = ! poly.isClosed(); - Polygon result; + const bool for_polyline = (dynamic_cast(&poly) != nullptr); + ClipperLib::Path result; auto isDegenerate = [](const Point2LL& last, const Point2LL& now, const Point2LL& next) { @@ -284,7 +325,7 @@ void LinesSet::removeDegenerateVerts() { if (for_polyline || result.size() > 2) { - poly = std::move(result); + poly.setPoints(std::move(result)); } else { @@ -300,36 +341,58 @@ void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::Poly { for (const LineType& line : getLines()) { +#warning No dynamic cast is required here... // In this context, the "Closed" argument means "Is a surface" so it should be only // true for actual filled polygons. Closed polylines are to be treated as lines here. - clipper.AddPath(line.getPoints(), PolyTyp, line.getType() == PolylineType::Filled); + clipper.AddPath(line.getPoints(), PolyTyp, dynamic_cast(&line) != nullptr); } } +template +void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const +{ + for (const LineType& line : getLines()) + { + clipper.AddPath(line.getPoints(), jointType, endType); + } +} -template size_t LinesSet::pointCount() const; -template void LinesSet::addLine(const Point2LL& from, const Point2LL& to); -template void LinesSet::removeAt(size_t index); -template void LinesSet::splitIntoSegments(LinesSet& result) const; -template LinesSet LinesSet::splitIntoSegments() const; -template coord_t LinesSet::length() const; -template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; -template Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; -template void LinesSet::removeDegenerateVerts(); -template void LinesSet::addIfNotEmpty(const Polyline& line); -template void LinesSet::addIfNotEmpty(Polyline&& line); -template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; +template LinesSet::LinesSet(ClipperLib::Paths&& paths); +template size_t LinesSet::pointCount() const; +template void LinesSet::removeAt(size_t index); +template void LinesSet::splitIntoSegments(OpenLinesSet& result) const; +template OpenLinesSet LinesSet::splitIntoSegments() const; +template coord_t LinesSet::length() const; +template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template void LinesSet::removeDegenerateVerts(); +template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; +template void LinesSet::push_back(const OpenPolyline& line, bool checkNonEmpty); +template void LinesSet::push_back(OpenPolyline&& line, bool checkNonEmpty); +template void LinesSet::push_back(LinesSet&& lines_set); + +template size_t LinesSet::pointCount() const; +template void LinesSet::removeAt(size_t index); +template void LinesSet::splitIntoSegments(OpenLinesSet& result) const; +template OpenLinesSet LinesSet::splitIntoSegments() const; +template coord_t LinesSet::length() const; +template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template void LinesSet::removeDegenerateVerts(); +template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; +template void LinesSet::push_back(const ClosedPolyline& line, bool checkNonEmpty); +template void LinesSet::push_back(ClosedPolyline&& line, bool checkNonEmpty); +template void LinesSet::push_back(LinesSet&& lines_set); +template void LinesSet::push_back(LinesSet&& lines_set); template size_t LinesSet::pointCount() const; template void LinesSet::removeAt(size_t index); -template void LinesSet::splitIntoSegments(LinesSet& result) const; -template LinesSet LinesSet::splitIntoSegments() const; +template void LinesSet::splitIntoSegments(OpenLinesSet& result) const; +template OpenLinesSet LinesSet::splitIntoSegments() const; template coord_t LinesSet::length() const; template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; -template Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const; template void LinesSet::removeDegenerateVerts(); -template void LinesSet::addIfNotEmpty(const Polygon& line); -template void LinesSet::addIfNotEmpty(Polygon&& line); template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; +template void LinesSet::push_back(const Polygon& line, bool checkNonEmpty); +template void LinesSet::push_back(Polygon&& line, bool checkNonEmpty); +template void LinesSet::push_back(LinesSet&& lines_set); } // namespace cura diff --git a/src/geometry/mixed_lines_set.cpp b/src/geometry/mixed_lines_set.cpp index a509b883e8..2ad346e598 100644 --- a/src/geometry/mixed_lines_set.cpp +++ b/src/geometry/mixed_lines_set.cpp @@ -3,14 +3,164 @@ #include "geometry/mixed_lines_set.h" +#include + +#include "geometry/open_polyline.h" +#include "geometry/shape.h" + namespace cura { -/*void MixedLinesSet::push_back(const MixedLinesSet& lines) +Shape MixedLinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const +{ + if (distance == 0) + { + // Return a shape that contains only actual polygons + Shape result; + + for (const std::shared_ptr& line : (*this)) + { + if (const std::shared_ptr polygon = dynamic_pointer_cast(line)) + { + result.push_back(*polygon); + } + } + + return result; + } + else + { + Shape polygons; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + + for (const std::shared_ptr& line : (*this)) + { + if (const std::shared_ptr polygon = dynamic_pointer_cast(line)) + { + // Union all polygons first and add them later + polygons.push_back(*polygon); + } + else + { + ClipperLib::EndType end_type; + + if (line->addClosingSegment()) + { + end_type = ClipperLib::etClosedLine; + } + else if (join_type == ClipperLib::jtMiter) + { + end_type = ClipperLib::etOpenSquare; + } + else + { + end_type = ClipperLib::etOpenRound; + } + + clipper.AddPath(line->getPoints(), join_type, end_type); + } + } + + if (! polygons.empty()) + { + polygons = polygons.unionPolygons(); + + for (const Polygon& polygon : polygons) + { + clipper.AddPath(polygon.getPoints(), join_type, ClipperLib::etClosedPolygon); + } + } + + clipper.MiterLimit = miter_limit; + + ClipperLib::Paths result; + clipper.Execute(result, static_cast(distance)); + return Shape(std::move(result)); + } +} + +void MixedLinesSet::push_back(const OpenPolyline& line) +{ + std::vector>::push_back(std::make_shared(line)); +} + +void MixedLinesSet::push_back(OpenPolyline&& line) +{ + std::vector>::push_back(std::make_shared(std::move(line))); +} + +void MixedLinesSet::push_back(ClosedPolyline&& line) +{ + std::vector>::push_back(std::make_shared(std::move(line))); +} + +void MixedLinesSet::push_back(const Polygon& line) +{ + std::vector>::push_back(std::make_shared(std::move(line))); +} + +void MixedLinesSet::push_back(const std::shared_ptr& line) +{ + std::vector>::push_back(line); +} + +void MixedLinesSet::push_back(const std::shared_ptr& line) +{ + std::vector>::push_back(line); +} + +void MixedLinesSet::push_back(LinesSet&& lines_set) +{ + reserve(size() + lines_set.size()); + for (OpenPolyline& line : lines_set) + { + push_back(std::move(line)); + } +} + +void MixedLinesSet::push_back(const LinesSet& lines_set) +{ + reserve(size() + lines_set.size()); + for (const OpenPolyline& line : lines_set) + { + push_back(line); + } +} + +void MixedLinesSet::push_back(LinesSet&& lines_set) +{ + reserve(size() + lines_set.size()); + for (ClosedPolyline& line : lines_set) + { + push_back(std::move(line)); + } +} + +void MixedLinesSet::push_back(const LinesSet& lines_set) +{ + reserve(size() + lines_set.size()); + for (const Polygon& line : lines_set) + { + push_back(line); + } +} + +void MixedLinesSet::push_back(const Shape& shape) +{ + push_back(static_cast&>(shape)); +} + +coord_t MixedLinesSet::length() const { - push_back(lines.getOpenLines()); - push_back(lines.getClosedLines()); -}*/ + return std::accumulate( + begin(), + end(), + coord_t(0), + [](coord_t value, const std::shared_ptr& line) + { + return value + line->length(); + }); +} } // namespace cura diff --git a/src/geometry/points_set.cpp b/src/geometry/points_set.cpp index ae210ffa2f..b22105a839 100644 --- a/src/geometry/points_set.cpp +++ b/src/geometry/points_set.cpp @@ -15,12 +15,12 @@ PointsSet::PointsSet(const std::initializer_list& initializer) { } -PointsSet::PointsSet(const std::vector& points) +PointsSet::PointsSet(const ClipperLib::Path& points) : points_(points) { } -PointsSet::PointsSet(std::vector&& points) +PointsSet::PointsSet(ClipperLib::Path&& points) : points_(std::move(points)) { } diff --git a/src/geometry/polyline.cpp b/src/geometry/polyline.cpp index 135a165b12..fb75fd9a7e 100644 --- a/src/geometry/polyline.cpp +++ b/src/geometry/polyline.cpp @@ -5,8 +5,7 @@ #include -#include "geometry/lines_set.h" -#include "geometry/open_polyline.h" +#include "geometry/open_lines_set.h" #include "settings/types/Angle.h" #include "utils/linearAlg2D.h" @@ -38,7 +37,7 @@ void Polyline::removeColinearEdges(const AngleRadians max_deviation_angle) std::vector skip_indices(size(), false); - Polyline new_path(type_); + std::vector new_path; for (size_t point_idx = 0; point_idx < pathlen; ++point_idx) { // Don't iterate directly over process-indices, but do it this way, because there are points _in_ process-indices that should nonetheless be skipped: @@ -82,7 +81,7 @@ void Polyline::removeColinearEdges(const AngleRadians max_deviation_angle) ++point_idx; } } - (*this) = std::move(new_path); + setPoints(std::move(new_path)); num_removed_in_iteration += pathlen - size(); process_indices.clear(); @@ -98,7 +97,7 @@ Polyline::const_segments_iterator Polyline::beginSegments() const Polyline::const_segments_iterator Polyline::endSegments() const { - if (type_ == PolylineType::ImplicitelyClosed) + if (addClosingSegment()) { return const_segments_iterator(end(), begin(), end()); } @@ -115,7 +114,7 @@ Polyline::segments_iterator Polyline::beginSegments() Polyline::segments_iterator Polyline::endSegments() { - if (type_ == PolylineType::ImplicitelyClosed) + if (addClosingSegment()) { return segments_iterator(end(), begin(), end()); } @@ -151,56 +150,20 @@ bool Polyline::shorterThan(const coord_t check_length) const return iterator_segment == endSegments(); } -void Polyline::splitIntoSegments(LinesSet& result) const +void Polyline::splitIntoSegments(OpenLinesSet& result) const { #warning reserve space before adding all the segments for (auto it = beginSegments(); it != endSegments(); ++it) { - result.emplace_back(PolylineType::Open, std::initializer_list{ (*it).start, (*it).end }); + result.emplace_back(std::initializer_list{ (*it).start, (*it).end }); } } -LinesSet Polyline::splitIntoSegments() const +OpenLinesSet Polyline::splitIntoSegments() const { - LinesSet result; + OpenLinesSet result; splitIntoSegments(result); return result; } -bool Polyline::inside(const Point2LL& p, bool border_result) const -{ - if (isClosed()) - { - int res = ClipperLib::PointInPolygon(p, getPoints()); - if (res == -1) - { - return border_result; - } - return res == 1; - } - else - { - return false; - } -} - -bool Polyline::inside(const auto& polygon) const -{ - if (isClosed()) - { - for (const auto& point : *this) - { - if (! ClipperLib::PointInPolygon(point, polygon)) - { - return false; - } - } - return true; - } - else - { - return false; - } -} - } // namespace cura diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index bab398273a..6763521d57 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -24,21 +24,31 @@ #include "geometry/parts_view.h" #include "geometry/single_shape.h" #include "settings/types/Ratio.h" +#include "utils/OpenPolylineStitcher.h" #include "utils/linearAlg2D.h" -#include "utils/mixed_polyline_stitcher.h" namespace cura { -Shape::Shape(ClipperLib::Paths&& paths) +Shape::Shape(ClipperLib::Paths&& paths, bool explicitely_closed) { - reserve(paths.size()); - for (const ClipperLib::Path& path : paths) + emplace_back(std::move(paths), explicitely_closed); +} + +void Shape::emplace_back(ClipperLib::Paths&& paths, bool explicitely_closed) +{ + reserve(size() + paths.size()); + for (ClipperLib::Path& path : paths) { - emplace_back(std::move(path)); + emplace_back(std::move(path), explicitely_closed); } } +void Shape::emplace_back(ClipperLib::Path&& path, bool explicitely_closed) +{ + static_cast*>(this)->emplace_back(std::move(path), explicitely_closed); +} + Shape& Shape::operator=(const Shape& other) { LinesSet::operator=(other); @@ -47,7 +57,7 @@ Shape& Shape::operator=(const Shape& other) Shape& Shape::operator=(Shape&& other) { - LinesSet::operator=(other); + LinesSet::operator=(std::move(other)); return *this; } @@ -65,7 +75,7 @@ Shape Shape::approxConvexHull(int extra_outset) const ClipperLib::ClipperOffset offsetter(1.2, 10.0); offsetter.AddPath(polygon.getPoints(), ClipperLib::jtRound, ClipperLib::etClosedPolygon); offsetter.Execute(offset_result, overshoot); - convex_hull.push_back(PolylineType::ImplicitelyClosed, std::move(offset_result)); + convex_hull.emplace_back(std::move(offset_result)); } return convex_hull.unionPolygons().offset(-overshoot + extra_outset, ClipperLib::jtRound); @@ -121,7 +131,7 @@ void Shape::makeConvex() std::reverse(points.begin(), points.end()); make_sorted_poly_convex(points); - *this = { convexified }; + setLines({ std::move(convexified) }); } Shape Shape::difference(const Shape& other) const @@ -235,9 +245,9 @@ size_t Shape::findInside(const Point2LL& p, bool border_result) const } template -MixedLinesSet Shape::intersection(const MixedLinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const +OpenLinesSet Shape::intersection(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const { - LinesSet split_polylines = polylines.splitIntoSegments(); + LinesSet split_polylines = polylines.splitIntoSegments(); ClipperLib::PolyTree result; ClipperLib::Clipper clipper(clipper_init); @@ -247,20 +257,32 @@ MixedLinesSet Shape::intersection(const MixedLinesSet& polylines, bool restitch, ClipperLib::Paths result_paths; ClipperLib::OpenPathsFromPolyTree(result, result_paths); + OpenLinesSet result_lines(std::move(result_paths)); + if (restitch) { - MixedLinesSet input_lines; - input_lines.push_back(PolylineType::Open, std::move(result_paths)); + OpenLinesSet result_open_lines; + Shape result_closed_lines; - MixedLinesSet result_lines; const coord_t snap_distance = 10_mu; - MixedPolylineStitcher::stitch(input_lines, result_lines, max_stitch_distance, snap_distance); - return result_lines; - } - else - { - return MixedLinesSet(PolylineType::Open, std::move(result_paths)); + OpenPolylineStitcher::stitch(result_lines, result_open_lines, result_closed_lines, max_stitch_distance, snap_distance); + + result_lines = std::move(result_open_lines); + // if open polylines got stitched into closed polylines, split them back up into open polylines again, because the result only admits open polylines + for (ClosedPolyline& closed_line : result_closed_lines) + { + if (! closed_line.empty()) + { + if (closed_line.size() > 2) + { + closed_line.push_back(closed_line.front()); + } + result_lines.emplace_back(std::move(closed_line.getPoints())); + } + } } + + return result_lines; } Shape Shape::xorPolygons(const Shape& other, ClipperLib::PolyFillType pft) const @@ -742,10 +764,10 @@ void Shape::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std:: { ClipperLib::PolyNode* child = node->Childs[n]; SingleShape part; - part.emplace_back(child->Contour); + part.emplace_back(std::move(child->Contour)); for (size_t i = 0; i < static_cast(child->ChildCount()); i++) { - part.emplace_back(child->Childs[i]->Contour); + part.emplace_back(std::move(child->Childs[i]->Contour)); splitIntoParts_processPolyTreeNode(child->Childs[i], ret); } ret.push_back(part); @@ -773,7 +795,7 @@ void Shape::sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const { ret.resize(nesting_idx + 1); } - ret[nesting_idx].emplace_back(child->Contour); + ret[nesting_idx].emplace_back(std::move(child->Contour)); sortByNesting_processPolyTreeNode(child, nesting_idx + 1, ret); } } @@ -792,7 +814,7 @@ PartsView Shape::splitIntoPartsView(bool unionAll) splitIntoPartsView_processPolyTreeNode(partsView, reordered, &resultPolyTree); - (*this) = reordered; + (*this) = std::move(reordered); return partsView; } @@ -804,11 +826,11 @@ void Shape::splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Shape& partsView.emplace_back(); size_t pos = partsView.size() - 1; partsView[pos].push_back(reordered.size()); - reordered.emplace_back(child->Contour); // TODO: should this steal the internal representation for speed? + reordered.emplace_back(std::move(child->Contour)); for (size_t i = 0; i < static_cast(child->ChildCount()); i++) { partsView[pos].push_back(reordered.size()); - reordered.emplace_back(child->Childs[i]->Contour); + reordered.emplace_back(std::move(child->Childs[i]->Contour)); splitIntoPartsView_processPolyTreeNode(partsView, reordered, child->Childs[i]); } } @@ -866,6 +888,22 @@ Shape Shape::removeNearSelfIntersections() const return polys; } +void Shape::simplify(ClipperLib::PolyFillType fill_type) +{ + // This is the actual content from clipper.cpp::SimplifyPolygons, but rewritten here in order + // to avoid a list copy + ClipperLib::Clipper clipper; + ClipperLib::Paths ret; + clipper.StrictlySimple(true); + addPaths(clipper, ClipperLib::ptSubject); + clipper.Execute(ClipperLib::ctUnion, ret, fill_type, fill_type); + + for (size_t i = 0; i < size(); ++i) + { + getLines()[i].setPoints(std::move(ret[i])); + } +} + void Shape::ensureManifold() { std::vector duplicate_locations; @@ -944,8 +982,8 @@ void Shape::applyMatrix(const Point3Matrix& matrix) } } -/*template LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; -template LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; -template LinesSet Shape::intersectionPolyLines(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const;*/ +template LinesSet Shape::intersection(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; +template LinesSet Shape::intersection(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; +template LinesSet Shape::intersection(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; } // namespace cura diff --git a/src/infill.cpp b/src/infill.cpp index ef075b1cd2..4edb595819 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -126,12 +126,12 @@ void Infill::generate( if (small_infill_part.offset(-infill_line_width_ / 2).offset(infill_line_width_ / 2).area() < infill_line_width_ * infill_line_width_ * 10 && ! inner_contour_.intersection(small_infill_part.offset(infill_line_width_ / 4)).empty()) { - inner_contour_.add(small_infill_part); + inner_contour_.push_back(small_infill_part); } else { // the part must still be printed, so re-add it - small_infill.add(small_infill_part); + small_infill.push_back(small_infill_part); } } inner_contour_.unionPolygons(); @@ -186,8 +186,8 @@ void Infill::generate( zig_zaggify_ = zig_zaggify_real; multiplyInfill(generated_result_polygons, generated_result_lines); - result_polygons.add(generated_result_polygons); - result_lines.add(generated_result_lines); + result_polygons.push_back(generated_result_polygons); + result_lines.push_back(generated_result_lines); } else { @@ -198,8 +198,8 @@ void Infill::generate( _generate(toolpaths, generated_result_polygons, generated_result_lines, settings, cross_fill_provider, lightning_trees, mesh); - result_polygons.add(generated_result_polygons); - result_lines.add(generated_result_lines); + result_polygons.push_back(generated_result_polygons); + result_lines.push_back(generated_result_lines); } scripta::log("infill_result_polygons_0", result_polygons, section_type, layer_idx); scripta::log("infill_result_lines_0", result_lines, section_type, layer_idx); @@ -324,8 +324,8 @@ void Infill::_generate( mesh ? mesh->settings.get("infill_pattern") : settings.get("infill_pattern"), mesh ? mesh->settings : settings); toolpaths.insert(toolpaths.end(), toolpaths_.begin(), toolpaths_.end()); - result_polygons.add(generated_result_polygons_); - result_lines.add(generated_result_lines_); + result_polygons.push_back(generated_result_polygons_); + result_lines.push_back(generated_result_lines_); #endif break; } @@ -381,7 +381,7 @@ void Infill::multiplyInfill(Shape& result_polygons, LinesSet& resu first_offset = inner_contour_.difference(first_offset); } } - result.add(first_offset); + result.push_back(first_offset); // Create the additional offsets from the first offsets, generated earlier, the direction of these offsets is // depended on whether these lines should be connected or not. @@ -394,7 +394,7 @@ void Infill::multiplyInfill(Shape& result_polygons, LinesSet& resu for (size_t infill_line = 1; infill_line < multiplier; ++infill_line) { Shape extra_polys = reference_polygons.offset(extra_offset); - result.add(extra_polys); + result.push_back(extra_polys); reference_polygons = std::move(extra_polys); } } @@ -409,10 +409,10 @@ void Infill::multiplyInfill(Shape& result_polygons, LinesSet& resu result_polygons.clear(); result_lines.clear(); } - result_polygons.add(result); + result_polygons.push_back(result); if (! zig_zaggify_) { - LinesSet polylines = inner_contour_.intersectionPolyLines(*reinterpret_cast*>(&result_polygons)); + LinesSet polylines = inner_contour_.intersection(static_cast>(result_polygons)); result_polygons.clear(); OpenPolylineStitcher::stitch(polylines, result_lines, result_polygons, infill_line_width_); } @@ -432,7 +432,7 @@ void Infill::generateLightningInfill(const std::shared_ptr& tree { return; } - result_lines.add(trees->convertToLines(inner_contour_, infill_line_width_)); + result_lines.push_back(trees->convertToLines(inner_contour_, infill_line_width_)); } void Infill::generateConcentricInfill(std::vector& toolpaths, const Settings& settings) @@ -519,7 +519,7 @@ void Infill::generateCubicSubDivInfill(LinesSet& result, const Sli LinesSet uncropped; mesh.base_subdiv_cube->generateSubdivisionLines(z_, uncropped); constexpr bool restitch = false; // cubic subdivision lines are always single line segments - not polylines consisting of multiple segments. - result = outer_contour_.offset(infill_overlap_).intersectionPolyLines(uncropped, restitch); + result = outer_contour_.offset(infill_overlap_).intersection(uncropped, restitch); } void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provider, Shape& result_polygons, LinesSet& result_lines) @@ -535,7 +535,7 @@ void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provid { Shape cross_pattern_polygons; cross_pattern_polygons.push_back(cross_pattern_polygon); - result_polygons.add(inner_contour_.intersection(cross_pattern_polygons)); + result_polygons.push_back(inner_contour_.intersection(cross_pattern_polygons)); } else { @@ -543,8 +543,9 @@ void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provid cross_pattern_polygon.push_back(cross_pattern_polygon[0]); LinesSet cross_pattern_polylines; - cross_pattern_polylines.push_back(cross_pattern_polygon); - LinesSet poly_lines = inner_contour_.intersectionPolyLines(cross_pattern_polylines); +#warning No sure we should add the last point in this case + cross_pattern_polylines.push_back(cross_pattern_polygon.toPseudoOpenPolyline()); + LinesSet poly_lines = inner_contour_.intersection(cross_pattern_polylines); OpenPolylineStitcher::stitch(poly_lines, result_lines, result_polygons, infill_line_width_); } } diff --git a/src/infill/GyroidInfill.cpp b/src/infill/GyroidInfill.cpp index fcb87d562a..12159e1b0f 100644 --- a/src/infill/GyroidInfill.cpp +++ b/src/infill/GyroidInfill.cpp @@ -90,7 +90,7 @@ void GyroidInfill::generateTotalGyroidInfill(LinesSet& result_line LinesSet line; line.addLine(last, current); constexpr bool restitch = false; // only a single line doesn't need stitching - line = in_outline.intersectionPolyLines(line, restitch); + line = in_outline.intersection(line, restitch); if (line.size() > 0) { // some of the line is inside the boundary @@ -182,7 +182,7 @@ void GyroidInfill::generateTotalGyroidInfill(LinesSet& result_line LinesSet line; line.addLine(last, current); constexpr bool restitch = false; // only a single line doesn't need stitching - line = in_outline.intersectionPolyLines(line, restitch); + line = in_outline.intersection(line, restitch); if (line.size() > 0) { // some of the line is inside the boundary diff --git a/src/infill/LightningGenerator.cpp b/src/infill/LightningGenerator.cpp index 574a2625bf..bf952de1d0 100644 --- a/src/infill/LightningGenerator.cpp +++ b/src/infill/LightningGenerator.cpp @@ -56,7 +56,7 @@ void LightningGenerator::generateInitialInternalOverhangs(const SliceMeshStorage Shape infill_area_here; for (auto& part : current_layer.parts) { - infill_area_here.add(part.getOwnInfillArea().offset(infill_wall_offset)); + infill_area_here.push_back(part.getOwnInfillArea().offset(infill_wall_offset)); } // Remove the part of the infill area that is already supported by the walls. @@ -88,7 +88,7 @@ void LightningGenerator::generateTrees(const SliceMeshStorage& mesh) { for (const auto& part : mesh.layers[layer_id].parts) { - infill_outlines[layer_id].add(part.getOwnInfillArea().offset(infill_wall_offset)); + infill_outlines[layer_id].push_back(part.getOwnInfillArea().offset(infill_wall_offset)); } } diff --git a/src/infill/LightningLayer.cpp b/src/infill/LightningLayer.cpp index 2383549d38..ae97013241 100644 --- a/src/infill/LightningLayer.cpp +++ b/src/infill/LightningLayer.cpp @@ -229,7 +229,7 @@ LinesSet LightningLayer::convertToLines(const Shape& limit_to_outl { tree->convertToPolylines(result_lines, line_width); } - result_lines = limit_to_outline.intersectionPolyLines(result_lines); + result_lines = limit_to_outline.intersection(result_lines); return result_lines; } diff --git a/src/infill/LightningTreeNode.cpp b/src/infill/LightningTreeNode.cpp index 1d61c082df..8873030320 100644 --- a/src/infill/LightningTreeNode.cpp +++ b/src/infill/LightningTreeNode.cpp @@ -361,7 +361,7 @@ void LightningTreeNode::convertToPolylines(LinesSet& output, const result.emplace_back(); convertToPolylines(0, result); removeJunctionOverlap(result, line_width); - output.add(result); + output.push_back(result); } void LightningTreeNode::convertToPolylines(size_t long_line_idx, LinesSet& output) const diff --git a/src/infill/SubDivCube.cpp b/src/infill/SubDivCube.cpp index f528d56a21..1f68d77609 100644 --- a/src/infill/SubDivCube.cpp +++ b/src/infill/SubDivCube.cpp @@ -233,7 +233,7 @@ coord_t SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, const LayerI Shape collide; for (const SliceLayerPart& part : mesh.layers[layer_nr].parts) { - collide.add(part.infill_area); + collide.push_back(part.infill_area); } Point2LL centerpoint = location; diff --git a/src/infill/ZigzagConnectorProcessor.cpp b/src/infill/ZigzagConnectorProcessor.cpp index ac97deaa0e..ffe86771d0 100644 --- a/src/infill/ZigzagConnectorProcessor.cpp +++ b/src/infill/ZigzagConnectorProcessor.cpp @@ -147,7 +147,7 @@ void ZigzagConnectorProcessor::addZagConnector(std::vector& points, bo { return; } - Polygon polyline(points); + OpenPolyline polyline(points); if (is_endpiece && ! connected_endpieces_) { polyline.pop_back(); @@ -164,7 +164,7 @@ void cura::ZigzagConnectorProcessor::reset() current_connector_.clear(); } -void cura::ZigzagConnectorProcessor::addPolyline(const Polygon& polyline) +void cura::ZigzagConnectorProcessor::addPolyline(const OpenPolyline& polyline) { result_.emplace_back(polyline); for (Point2LL& p : result_.back()) diff --git a/src/multiVolumes.cpp b/src/multiVolumes.cpp index 41291c34f6..e89e2a3d19 100644 --- a/src/multiVolumes.cpp +++ b/src/multiVolumes.cpp @@ -119,7 +119,7 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: for (LayerIndex layer_nr = 0; layer_nr < cutting_mesh_volume.layers.size(); layer_nr++) { Shape& cutting_mesh_polygons = cutting_mesh_volume.layers[layer_nr].polygons; - LinesSet& cutting_mesh_polylines = cutting_mesh_volume.layers[layer_nr].openPolylines; + OpenLinesSet& cutting_mesh_polylines = cutting_mesh_volume.layers[layer_nr].openPolylines; Shape cutting_mesh_area_recomputed; Shape* cutting_mesh_area; coord_t surface_line_width = cutting_mesh.settings_.get("wall_line_width_0"); @@ -135,9 +135,8 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: // they have to be polylines, because they might break up further when doing the cutting for (Polygon& poly : cutting_mesh_polygons) { -#warning this should not be required - poly.push_back(poly[0]); - cutting_mesh_polylines.push_back(poly.toType()); + poly.push_back(poly.front()); + cutting_mesh_polylines.emplace_back(poly.getPoints()); } cutting_mesh_polygons.clear(); @@ -164,10 +163,10 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: Shape& carved_mesh_layer = carved_volume.layers[layer_nr].polygons; Shape intersection = cutting_mesh_polygons.intersection(carved_mesh_layer); - new_outlines.add(intersection); + new_outlines.push_back(intersection); if (cutting_mesh.settings_.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) // niet te geleuven { - new_polylines.add(carved_mesh_layer.intersectionPolyLines(cutting_mesh_polylines)); + new_polylines.push_back(carved_mesh_layer.intersection(cutting_mesh_polylines)); } carved_mesh_layer = carved_mesh_layer.difference(*cutting_mesh_area); diff --git a/src/pathPlanning/Comb.cpp b/src/pathPlanning/Comb.cpp index f5410d4e16..f1fbf8e475 100644 --- a/src/pathPlanning/Comb.cpp +++ b/src/pathPlanning/Comb.cpp @@ -499,7 +499,7 @@ void Comb::Crossing::findCrossingInOrMid(const PartsView& partsView_inside, cons close_towards_start_penalty_function); if (crossing_1_in_cp.isValid()) { - dest_crossing_poly_ = reinterpret_cast(crossing_1_in_cp.poly_); + dest_crossing_poly_ = crossing_1_in_cp.poly_; in_or_mid_ = result; } else diff --git a/src/path_ordering.cpp b/src/path_ordering.cpp index 26e1d95b15..cbdf514467 100644 --- a/src/path_ordering.cpp +++ b/src/path_ordering.cpp @@ -10,48 +10,60 @@ namespace cura { template<> -const Polygon& PathOrdering::getVertexData() +const PointsSet& PathOrdering::getVertexData() { return *vertices_; } template<> -const Polygon& PathOrdering::getVertexData() +const PointsSet& PathOrdering::getVertexData() { return *vertices_; } template<> -const Polygon& PathOrdering::getVertexData() +const PointsSet& PathOrdering::getVertexData() { - return *reinterpret_cast(vertices_); + return *vertices_; +} + +template<> +const PointsSet& PathOrdering::getVertexData() +{ + return *vertices_; } template<> -const Polygon& PathOrdering::getVertexData() +const PointsSet& PathOrdering::getVertexData() { - return *reinterpret_cast(vertices_); + return *vertices_; +} + +template<> +const PointsSet& PathOrdering::getVertexData() +{ + return *vertices_; } template<> -const Polygon& PathOrdering::getVertexData() +const PointsSet& PathOrdering::getVertexData() { return vertices_->outline.outerPolygon(); } template<> -const Polygon& PathOrdering::getVertexData() +const PointsSet& PathOrdering::getVertexData() { return vertices_->outline.outerPolygon(); } template<> -const Polygon& PathOrdering::getVertexData() +const PointsSet& PathOrdering::getVertexData() { return vertices_->outline_.outerPolygon(); } template<> -const Polygon& PathOrdering::getVertexData() +const PointsSet& PathOrdering::getVertexData() { if (! cached_vertices_) { diff --git a/src/plugins/converters.cpp b/src/plugins/converters.cpp index 27c685385f..d106d0d038 100644 --- a/src/plugins/converters.cpp +++ b/src/plugins/converters.cpp @@ -247,20 +247,20 @@ infill_generate_response::native_value_type infill_generate_response::operator() Polygon hole{}; for (auto& path_msg : hole_msg.path()) { - hole.push_back(Point2LL{ path_msg.x(), path_msg.y() }); + hole.emplace_back(path_msg.x(), path_msg.y()); } polygon.push_back(hole); } - result_polygons.add(polygon); + result_polygons.push_back(polygon); } for (auto& polygon : message.poly_lines().paths()) { - Polygon poly_line; + OpenPolyline poly_line; for (auto& p : polygon.path()) { - poly_line.emplace_back(Point2LL{ p.x(), p.y() }); + poly_line.emplace_back(p.x(), p.y()); } result_lines.emplace_back(poly_line); } @@ -486,4 +486,4 @@ gcode_paths_modify_response::native_value_type } } // namespace cura::plugins -#endif // ENABLE_PLUGINS \ No newline at end of file +#endif // ENABLE_PLUGINS diff --git a/src/raft.cpp b/src/raft.cpp index e94e220125..4eb329964f 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -80,7 +80,7 @@ void Raft::generate(SliceDataStorage& storage) for (auto& part : outline_parts) { part.makeConvex(); - outline.add(part); + outline.push_back(part); } outline = outline.unionPolygons(); diff --git a/src/skin.cpp b/src/skin.cpp index 560d2977ba..c00096412f 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -67,7 +67,7 @@ Shape SkinInfillAreaComputation::getOutlineOnLayer(const SliceLayerPart& part_he { if (part_here.boundaryBox.hit(part2.boundaryBox)) { - result.add(part2.outline); + result.push_back(part2.outline); } } return result; @@ -421,8 +421,8 @@ void SkinInfillAreaComputation::generateInfillSupport(SliceMeshStorage& mesh) Shape infill_above; for (SliceLayerPart& part_above : layer_above.parts) { - inside_above.add(part_above.infill_area); - infill_above.add(part_above.getOwnInfillArea()); + inside_above.push_back(part_above.infill_area); + infill_above.push_back(part_above.getOwnInfillArea()); } for (SliceLayerPart& part : layer.parts) @@ -514,7 +514,7 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) { continue; } - relevent_upper_polygons.add(upper_layer_part.getOwnInfillArea()); + relevent_upper_polygons.push_back(upper_layer_part.getOwnInfillArea()); } less_dense_infill = less_dense_infill.intersection(relevent_upper_polygons); } @@ -592,7 +592,7 @@ void SkinInfillAreaComputation::combineInfillLayers(SliceMeshStorage& mesh) if (part.boundaryBox.hit(lower_layer_part.boundaryBox)) { Shape intersection = infill_area_per_combine[combine_count_here - 1].intersection(lower_layer_part.infill_area).offset(-200).offset(200); - result.add(intersection); // add area to be thickened + result.push_back(intersection); // add area to be thickened infill_area_per_combine[combine_count_here - 1] = infill_area_per_combine[combine_count_here - 1].difference(intersection); // remove thickened area from less thick layer here unsigned int max_lower_density_idx = density_idx; diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index cf1075dd8e..636f6ca0f7 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -85,7 +85,7 @@ void SliceLayer::getOutlines(Shape& result, bool external_polys_only) const } else { - result.add(part.print_outline); + result.push_back(part.print_outline); } } } @@ -356,10 +356,10 @@ Shape SliceDataStorage::getLayerOutlines( { for (const SupportInfillPart& support_infill_part : support_layer.support_infill_parts) { - total.add(support_infill_part.outline_); + total.push_back(support_infill_part.outline_); } - total.add(support_layer.support_bottom); - total.add(support_layer.support_roof); + total.push_back(support_layer.support_bottom); + total.push_back(support_layer.support_roof); } } int prime_tower_outer_extruder_nr = primeTower.extruder_order_[0]; @@ -367,7 +367,7 @@ Shape SliceDataStorage::getLayerOutlines( { if (primeTower.enabled_) { - total.add(primeTower.getOuterPoly(layer_nr)); + total.push_back(primeTower.getOuterPoly(layer_nr)); } } return total; @@ -775,7 +775,7 @@ void SupportLayer::fillInfillParts( const size_t overhang_layer_nr = layer_nr + (mesh_z_distance_top / infill_layer_height) + 1; if (overhang_layer_nr < mesh->overhang_areas.size()) { - overhang_z_dist_above.add(mesh->overhang_areas[overhang_layer_nr]); + overhang_z_dist_above.push_back(mesh->overhang_areas[overhang_layer_nr]); } } overhang_z_dist_above = overhang_z_dist_above.unionPolygons(); diff --git a/src/slicer.cpp b/src/slicer.cpp index fe993b9d57..ba257594bf 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -30,7 +30,7 @@ constexpr int largest_neglected_gap_first_phase = MM2INT(0.01); //!< distance be constexpr int largest_neglected_gap_second_phase = MM2INT(0.02); //!< distance between two line segments regarded as connected constexpr int max_stitch1 = MM2INT(10.0); //!< maximal distance stitched between open polylines to form polygons -void SlicerLayer::makeBasicPolygonLoops(LinesSet& open_polylines) +void SlicerLayer::makeBasicPolygonLoops(OpenLinesSet& open_polylines) { for (size_t start_segment_idx = 0; start_segment_idx < segments.size(); start_segment_idx++) { @@ -43,9 +43,9 @@ void SlicerLayer::makeBasicPolygonLoops(LinesSet& open_polylines) segments.clear(); } -void SlicerLayer::makeBasicPolygonLoop(LinesSet& open_polylines, const size_t start_segment_idx) +void SlicerLayer::makeBasicPolygonLoop(OpenLinesSet& open_polylines, const size_t start_segment_idx) { - Polyline poly; + OpenPolyline poly; poly.push_back(segments[start_segment_idx].start); for (int segment_idx = start_segment_idx; segment_idx != -1;) @@ -56,7 +56,7 @@ void SlicerLayer::makeBasicPolygonLoop(LinesSet& open_polylines, const segment_idx = getNextSegmentIdx(segment, start_segment_idx); if (segment_idx == static_cast(start_segment_idx)) { // polyon is closed - polygons.push_back(Polygon(std::move(poly.getPoints()))); + polygons.push_back(Polygon(std::move(poly.getPoints()), true)); return; } } @@ -128,7 +128,7 @@ int SlicerLayer::getNextSegmentIdx(const SlicerSegment& segment, const size_t st return next_segment_idx; } -void SlicerLayer::connectOpenPolylines(LinesSet& open_polylines) +void SlicerLayer::connectOpenPolylines(OpenLinesSet& open_polylines) { constexpr bool allow_reverse = false; // Search a bit fewer cells but at cost of covering more area. @@ -137,7 +137,7 @@ void SlicerLayer::connectOpenPolylines(LinesSet& open_polylines) connectOpenPolylinesImpl(open_polylines, largest_neglected_gap_second_phase, cell_size, allow_reverse); } -void SlicerLayer::stitch(LinesSet& open_polylines) +void SlicerLayer::stitch(OpenLinesSet& open_polylines) { bool allow_reverse = true; connectOpenPolylinesImpl(open_polylines, max_stitch1, max_stitch1, allow_reverse); @@ -190,7 +190,7 @@ bool SlicerLayer::PossibleStitch::operator<(const PossibleStitch& other) const } std::priority_queue - SlicerLayer::findPossibleStitches(const LinesSet& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) const + SlicerLayer::findPossibleStitches(const OpenLinesSet& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) const { std::priority_queue stitch_queue; @@ -336,7 +336,7 @@ std::priority_queue return stitch_queue; } -void SlicerLayer::planPolylineStitch(const LinesSet& open_polylines, Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const +void SlicerLayer::planPolylineStitch(const OpenLinesSet& open_polylines, Terminus& terminus_0, Terminus& terminus_1, bool reverse[2]) const { size_t polyline_0_idx = terminus_0.getPolylineIdx(); size_t polyline_1_idx = terminus_1.getPolylineIdx(); @@ -385,7 +385,7 @@ void SlicerLayer::planPolylineStitch(const LinesSet& open_polylines, T } } -void SlicerLayer::joinPolylines(Polyline& polyline_0, Polyline& polyline_1, const bool reverse[2]) +void SlicerLayer::joinPolylines(OpenPolyline& polyline_0, OpenPolyline& polyline_1, const bool reverse[2]) { if (reverse[0]) { @@ -452,7 +452,7 @@ void SlicerLayer::TerminusTrackingMap::updateMap( } } -void SlicerLayer::connectOpenPolylinesImpl(LinesSet& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) +void SlicerLayer::connectOpenPolylinesImpl(OpenLinesSet& open_polylines, coord_t max_dist, coord_t cell_size, bool allow_reverse) { // below code closes smallest gaps first @@ -493,7 +493,7 @@ void SlicerLayer::connectOpenPolylinesImpl(LinesSet& open_polylines, c { // finished polygon OpenPolyline& polyline_0 = open_polylines[best_polyline_0_idx]; - polygons.push_back(std::move(polyline_0)); // Will also clear the polyline + polygons.push_back(Polygon(std::move(polyline_0.getPoints()), true)); // Will also clear the polyline Terminus cur_terms[2] = { { best_polyline_0_idx, false }, { best_polyline_0_idx, true } }; for (size_t idx = 0U; idx != 2U; ++idx) { @@ -534,7 +534,7 @@ void SlicerLayer::connectOpenPolylinesImpl(LinesSet& open_polylines, c } } -void SlicerLayer::stitch_extensive(LinesSet& open_polylines) +void SlicerLayer::stitch_extensive(OpenLinesSet& open_polylines) { // For extensive stitching find 2 open polygons that are touching 2 closed polygons. // Then find the shortest path over this polygon that can be used to connect the open polygons, @@ -585,7 +585,7 @@ void SlicerLayer::stitch_extensive(LinesSet& open_polylines) { if (best_result->pointIdxA == best_result->pointIdxB) { - polygons.push_back(open_polylines[best_polyline_1_idx]); + polygons.push_back(Polygon(open_polylines[best_polyline_1_idx].getPoints(), true)); open_polylines[best_polyline_1_idx].clear(); } else if (best_result->AtoB) @@ -600,7 +600,7 @@ void SlicerLayer::stitch_extensive(LinesSet& open_polylines) else { unsigned int n = polygons.size(); - polygons.push_back(open_polylines[best_polyline_1_idx]); + polygons.push_back(Polygon(open_polylines[best_polyline_1_idx].getPoints(), true)); for (unsigned int j = best_result->pointIdxB; j != best_result->pointIdxA; j = (j + 1) % polygons[best_result->polygonIdx].size()) polygons[n].push_back(polygons[best_result->polygonIdx][j]); open_polylines[best_polyline_1_idx].clear(); @@ -735,7 +735,7 @@ std::optional SlicerLayer::findPolygonPointClosestTo(Point2L void SlicerLayer::makePolygons(const Mesh* mesh) { - std::vector open_polylines; + OpenLinesSet open_polylines; makeBasicPolygonLoops(open_polylines); @@ -759,16 +759,13 @@ void SlicerLayer::makePolygons(const Mesh* mesh) { for (const OpenPolyline& polyline : open_polylines) { - polygons.addIfNotEmpty(polyline); + polygons.push_back(Polygon(polyline.getPoints(), false), true); } } for (const OpenPolyline& polyline : open_polylines) { - if (! polyline.empty()) - { - openPolylines.push_back(std::move(polyline)); - } + openPolylines.push_back(std::move(polyline), true); } // Remove all the tiny polygons, or polygons that are not closed. As they do not contribute to the actual print. @@ -1079,12 +1076,12 @@ void Slicer::makePolygons(Mesh& mesh, SlicingTolerance slicing_tolerance, std::v { if (hole_offset_max_diameter == 0) { - holes.add(poly.offset(xy_offset_hole)); + holes.push_back(poly.offset(xy_offset_hole)); } else if (abs_area < max_hole_area) { const auto distance = static_cast(std::lerp(xy_offset_hole, 0, abs_area / max_hole_area)); - holes.add(poly.offset(distance)); + holes.push_back(poly.offset(distance)); } else { @@ -1097,7 +1094,7 @@ void Slicer::makePolygons(Mesh& mesh, SlicingTolerance slicing_tolerance, std::v } } - layers[layer_nr].polygons.add(outline.difference(holes.unionPolygons())); + layers[layer_nr].polygons.push_back(outline.difference(holes.unionPolygons())); } } }); diff --git a/src/support.cpp b/src/support.cpp index 2ce0ced1ef..9a960ac8ac 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -61,13 +61,13 @@ bool AreaSupport::handleSupportModifierMesh(SliceDataStorage& storage, const Set switch (modifier_type) { case ANTI_OVERHANG: - support_layer.anti_overhang.add(slicer_layer.polygons); + support_layer.anti_overhang.push_back(slicer_layer.polygons); break; case SUPPORT_DROP_DOWN: - support_layer.support_mesh_drop_down.add(slicer_layer.polygons); + support_layer.support_mesh_drop_down.push_back(slicer_layer.polygons); break; case SUPPORT_VANILLA: - support_layer.support_mesh.add(slicer_layer.polygons); + support_layer.support_mesh.push_back(slicer_layer.polygons); break; } } @@ -274,7 +274,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) // if (upper_part_boundary_box.hit(this_part_boundary_box)) { - relevant_upper_polygons.add(upper_infill_parts[upper_part_idx].outline_); + relevant_upper_polygons.push_back(upper_infill_parts[upper_part_idx].outline_); } } @@ -377,7 +377,7 @@ void AreaSupport::combineSupportInfillLayers(SliceDataStorage& storage) continue; } - result.add(intersection); // add area to be thickened + result.push_back(intersection); // add area to be thickened infill_area_per_combine[combine_count_here - 1] = infill_area_per_combine[combine_count_here - 1].difference(intersection); // remove thickened area from less thick layer here @@ -669,7 +669,7 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage) generateSupportAreasForMesh(storage, *infill_settings, *roof_settings, *bottom_settings, mesh_idx, storage.print_layer_count, mesh_support_areas_per_layer); for (size_t layer_idx = 0; layer_idx < storage.print_layer_count; layer_idx++) { - global_support_areas_per_layer[layer_idx].add(mesh_support_areas_per_layer[layer_idx]); + global_support_areas_per_layer[layer_idx].push_back(mesh_support_areas_per_layer[layer_idx]); } } @@ -1183,7 +1183,7 @@ void AreaSupport::generateSupportAreasForMesh( if (layer_idx < layer_count - tower_top_layer_count && layer_idx >= tower_top_layer_count + bottom_empty_layer_count) { Shape tiny_tower_here; - tiny_tower_here.add(polygon_part); + tiny_tower_here.push_back(polygon_part); tower_roofs.emplace_back(tiny_tower_here); } } @@ -1687,11 +1687,11 @@ void AreaSupport::generateSupportBottom(SliceDataStorage& storage, const SliceMe Shape mesh_outlines; for (auto layer_idx_below = bottom_layer_idx_below; layer_idx_below < layer_idx - z_distance_bottom + 1; layer_idx_below += 1) { - mesh_outlines.add(mesh.layers[layer_idx_below].getOutlines()); + mesh_outlines.push_back(mesh.layers[layer_idx_below].getOutlines()); } Shape bottoms; generateSupportInterfaceLayer(global_support_areas_per_layer[layer_idx], mesh_outlines, bottom_line_width, bottom_outline_offset, minimum_bottom_area, bottoms); - support_layers[layer_idx].support_bottom.add(bottoms); + support_layers[layer_idx].support_bottom.push_back(bottoms); scripta::log("support_interface_bottoms", bottoms, SectionType::SUPPORT, layer_idx); } } @@ -1720,14 +1720,14 @@ void AreaSupport::generateSupportRoof(SliceDataStorage& storage, const SliceMesh Shape mesh_outlines; for (auto layer_idx_above = top_layer_idx_above; layer_idx_above > layer_idx + z_distance_top - 1; layer_idx_above -= 1) { - mesh_outlines.add(mesh.layers[layer_idx_above].getOutlines()); + mesh_outlines.push_back(mesh.layers[layer_idx_above].getOutlines()); } Shape roofs; generateSupportInterfaceLayer(global_support_areas_per_layer[layer_idx], mesh_outlines, roof_line_width, roof_outline_offset, minimum_roof_area, roofs); - support_layers[layer_idx].support_roof.add(roofs); + support_layers[layer_idx].support_roof.push_back(roofs); if (layer_idx > 0 && layer_idx < support_layers.size() - 1) { - support_layers[layer_idx].support_fractional_roof.add(roofs.difference(support_layers[layer_idx + 1].support_roof)); + support_layers[layer_idx].support_fractional_roof.push_back(roofs.difference(support_layers[layer_idx + 1].support_roof)); } scripta::log("support_interface_roofs", roofs, SectionType::SUPPORT, layer_idx); } diff --git a/src/utils/AABB.cpp b/src/utils/AABB.cpp index 0a8cf58d57..7f04f79ad6 100644 --- a/src/utils/AABB.cpp +++ b/src/utils/AABB.cpp @@ -171,7 +171,7 @@ void AABB::expand(int dist) Polygon AABB::toPolygon() const { - return Polygon({ min_, Point2LL(max_.X, min_.Y), max_, Point2LL(min_.X, max_.Y) }); + return Polygon({ min_, Point2LL(max_.X, min_.Y), max_, Point2LL(min_.X, max_.Y) }, false); } } // namespace cura diff --git a/src/utils/PolylineStitcher.cpp b/src/utils/PolylineStitcher.cpp index 4ffd9a29eb..efc78b15c9 100644 --- a/src/utils/PolylineStitcher.cpp +++ b/src/utils/PolylineStitcher.cpp @@ -3,7 +3,8 @@ #include "utils/PolylineStitcher.h" -#include "geometry/closed_polyline.h" +#include "geometry/closed_lines_set.h" +#include "geometry/open_lines_set.h" #include "utils/ExtrusionLineStitcher.h" #include "utils/OpenPolylineStitcher.h" #include "utils/PolygonsPointIndex.h" @@ -195,7 +196,7 @@ void PolylineStitcher::stitch( } if (closest_is_closing_polygon) { - result_polygons.emplace_back(chain); + pushToClosedResult(result_polygons, chain); } else { @@ -210,12 +211,7 @@ void PolylineStitcher::stitch( } } -template void OpenPolylineStitcher::stitch( - const LinesSet& lines, - LinesSet& result_lines, - Shape& result_polygons, - coord_t max_stitch_distance, - coord_t snap_distance); +template void OpenPolylineStitcher::stitch(const OpenLinesSet& lines, OpenLinesSet& result_lines, Shape& result_polygons, coord_t max_stitch_distance, coord_t snap_distance); template void ExtrusionLineStitcher::stitch( const VariableWidthLines& lines, @@ -224,10 +220,10 @@ template void ExtrusionLineStitcher::stitch( coord_t max_stitch_distance, coord_t snap_distance); -template void PolylineStitcher, LinesSet, OpenPolyline, Point2LL>::stitch( - const LinesSet& lines, - LinesSet& result_lines, - LinesSet& result_polygons, +template void PolylineStitcher::stitch( + const OpenLinesSet& lines, + OpenLinesSet& result_lines, + ClosedLinesSet& result_polygons, coord_t max_stitch_distance, coord_t snap_distance); @@ -238,7 +234,7 @@ bool OpenPolylineStitcher::canReverse(const PathsPointIndex -bool PolylineStitcher, LinesSet, OpenPolyline, Point2LL>::canReverse(const PathsPointIndex>&) +bool PolylineStitcher::canReverse(const PathsPointIndex>&) { return true; } @@ -256,7 +252,7 @@ bool OpenPolylineStitcher::canConnect(const OpenPolyline&, const OpenPolyline&) } template<> -bool PolylineStitcher, LinesSet, OpenPolyline, Point2LL>::canConnect(const OpenPolyline&, const OpenPolyline&) +bool PolylineStitcher::canConnect(const OpenPolyline&, const OpenPolyline&) { return true; } @@ -274,9 +270,29 @@ bool OpenPolylineStitcher::isOdd(const OpenPolyline&) } template<> -bool PolylineStitcher, LinesSet, OpenPolyline, Point2LL>::isOdd(const OpenPolyline&) +bool PolylineStitcher::isOdd(const OpenPolyline&) { return false; } +template<> +void ExtrusionLineStitcher::pushToClosedResult(VariableWidthLines& result_polygons, const ExtrusionLine& polyline) +{ + result_polygons.push_back(polyline); +} + +template<> +void OpenPolylineStitcher::pushToClosedResult(Shape& result_polygons, const OpenPolyline& polyline) +{ +#warning Check whether the polyline is explicitely closed + result_polygons.emplace_back(polyline.getPoints(), true); +} + +template<> +void PolylineStitcher::pushToClosedResult(ClosedLinesSet& result_polygons, const OpenPolyline& polyline) +{ +#warning Check whether the polyline is explicitely closed + result_polygons.emplace_back(polyline.getPoints(), true); +} + } // namespace cura diff --git a/src/utils/Simplify.cpp b/src/utils/Simplify.cpp index 179611b915..dc6a5a2971 100644 --- a/src/utils/Simplify.cpp +++ b/src/utils/Simplify.cpp @@ -6,7 +6,8 @@ #include #include //Priority queue to prioritise removing unimportant vertices. -#include "geometry/polyline.h" +#include "geometry/closed_polyline.h" +#include "geometry/open_polyline.h" #include "utils/ExtrusionLine.h" namespace cura @@ -54,15 +55,42 @@ LinesSet Simplify::polyline(const LinesSet& polylines) const LinesSet result; for (size_t i = 0; i < polylines.size(); ++i) { - result.push_back(polyline(polylines[i]), true); + result.push_back(polyline(polylines[i])); } return result; } -Polyline Simplify::polyline(const Polyline& polyline) const +MixedLinesSet Simplify::polyline(const MixedLinesSet& polylines) const { - assert(polyline.getType() != PolylineType::ExplicitelyClosed && "Simplify algorithm doesn't expect explicitely closed polylines"); - return simplify(polyline, polyline.isClosed()); + MixedLinesSet result; + for (const std::shared_ptr& polyline_ptr : polylines) + { + if (polyline_ptr) + { + if (std::shared_ptr open_polyline = std::dynamic_pointer_cast(polyline_ptr)) + { + result.push_back(std::make_shared(polyline(*open_polyline))); + } + if (std::shared_ptr closed_polyline = std::dynamic_pointer_cast(polyline_ptr)) + { + result.push_back(std::make_shared(polyline(*closed_polyline))); + } + } + } + return result; +} + +ClosedPolyline Simplify::polyline(const ClosedPolyline& polyline) const +{ + assert(polyline.addClosingSegment() && "Simplify algorithm doesn't expect explicitely closed polylines"); + constexpr bool is_closed = false; + return simplify(polyline, is_closed); +} + +OpenPolyline Simplify::polyline(const OpenPolyline& polyline) const +{ + constexpr bool is_closed = false; + return simplify(polyline, is_closed); } ExtrusionLine Simplify::polyline(const ExtrusionLine& polyline) const @@ -87,11 +115,7 @@ size_t Simplify::previousNotDeleted(size_t index, const std::vector& to_de return index; } -Polygon Simplify::createEmpty([[maybe_unused]] const Polygon& original) const -{ - return Polygon(); -} - +template<> ExtrusionLine Simplify::createEmpty(const ExtrusionLine& original) const { ExtrusionLine result(original.inset_idx_, original.is_odd_); @@ -99,6 +123,12 @@ ExtrusionLine Simplify::createEmpty(const ExtrusionLine& original) const return result; } +template +Polygonal Simplify::createEmpty(const Polygonal& /*original*/) const +{ + return Polygonal(); +} + void Simplify::appendVertex(Polyline& polygon, const Point2LL& vertex) const { polygon.push_back(vertex); @@ -180,4 +210,7 @@ coord_t Simplify::getAreaDeviation(const ExtrusionJunction& before, const Extrus } } +template LinesSet Simplify::polyline(const LinesSet& polylines) const; +template LinesSet Simplify::polyline(const LinesSet& polylines) const; + } // namespace cura diff --git a/src/utils/ToolpathVisualizer.cpp b/src/utils/ToolpathVisualizer.cpp index 213f3ee2a3..781ad724d3 100644 --- a/src/utils/ToolpathVisualizer.cpp +++ b/src/utils/ToolpathVisualizer.cpp @@ -25,7 +25,7 @@ void ToolpathVisualizer::toolpaths(const std::vector& all_segm s.from_.w_ *= w / .9; s.to_.w_ *= w / .9; Shape covered = s.toPolygons(false); - polys.add(covered); + polys.push_back(covered); } int c = 255 - 200 * (w - .25); SVG::ColorObject clr(c, c, c); diff --git a/src/utils/mixed_polyline_stitcher.cpp b/src/utils/mixed_polyline_stitcher.cpp new file mode 100644 index 0000000000..85e3e017b9 --- /dev/null +++ b/src/utils/mixed_polyline_stitcher.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2024 UltiMaker +// CuraEngine is released under the terms of the AGPLv3 or higher. + +#include "utils/mixed_polyline_stitcher.h" + +#include "geometry/mixed_lines_set.h" +#include "geometry/shape.h" + + +namespace cura +{ + +void MixedPolylineStitcher::stitch(const LinesSet& lines, MixedLinesSet& result, coord_t max_stitch_distance, coord_t snap_distance) +{ + OpenLinesSet open_lines; + ClosedLinesSet closed_lines; + + PolylineStitcher::stitch(lines, open_lines, closed_lines, max_stitch_distance, snap_distance); + + result.push_back(std::move(open_lines)); + + for (ClosedPolyline& closed_line : closed_lines) + { + // Base stitch method will create explicitely closed polylines, but won't tag them as such + // because it is a generic algorithm. Tag them now. +#warning Make sure that what is said here is true + closed_line.setExplicitelyClosed(true); + } + + result.push_back(std::move(closed_lines)); +} + +} // namespace cura diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index aba5860e45..1608514213 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -182,7 +182,7 @@ bool PolygonUtils::lineSegmentPolygonsIntersection( return closest_dist2 < within_max_dist2; } -Point2LL PolygonUtils::getVertexInwardNormal(const Polygon& poly, unsigned int point_idx) +Point2LL PolygonUtils::getVertexInwardNormal(const Polyline& poly, unsigned int point_idx) { Point2LL p1 = poly[point_idx]; @@ -220,7 +220,7 @@ Point2LL PolygonUtils::getVertexInwardNormal(const Polygon& poly, unsigned int p return n; } -Point2LL PolygonUtils::getBoundaryPointWithOffset(const Polygon& poly, unsigned int point_idx, int64_t offset) +Point2LL PolygonUtils::getBoundaryPointWithOffset(const Polyline& poly, unsigned int point_idx, int64_t offset) { return poly[point_idx] + normal(getVertexInwardNormal(poly, point_idx), -offset); } @@ -231,7 +231,7 @@ Point2LL PolygonUtils::moveInsideDiagonally(ClosestPoint point_on_boundary, int6 { return no_point; } -#warning Check that it does not actually copy the pointsset to the polygon object + const Polygon& poly = *point_on_boundary.poly_; Point2LL p0 = poly[point_on_boundary.point_idx_]; Point2LL p1 = poly[(point_on_boundary.point_idx_ + 1) % poly.size()]; @@ -584,7 +584,7 @@ Point2LL PolygonUtils::moveInside(const ClosestPoint& cpp, const int distance) { // the point which is assumed to be on the boundary doesn't have to be moved return cpp.location_; } - const Polygon& poly = *cpp.poly_; + const Polyline& poly = *cpp.poly_; unsigned int point_idx = cpp.point_idx_; const Point2LL& on_boundary = cpp.location_; @@ -1075,7 +1075,7 @@ std::vector> return ret; } -bool PolygonUtils::getNextPointWithDistance(Point2LL from, int64_t dist, const Polygon& poly, int start_idx, int poly_start_idx, GivenDistPoint& result) +bool PolygonUtils::getNextPointWithDistance(Point2LL from, int64_t dist, const OpenPolyline& poly, int start_idx, int poly_start_idx, GivenDistPoint& result) { Point2LL prev_poly_point = poly[(start_idx + poly_start_idx) % poly.size()]; @@ -1149,9 +1149,10 @@ bool PolygonUtils::getNextPointWithDistance(Point2LL from, int64_t dist, const P return false; } -ClosestPoint PolygonUtils::walk(const ClosestPoint& from, coord_t distance) +template +GenericClosestPoint PolygonUtils::walk(const GenericClosestPoint& from, coord_t distance) { - const Polygon& poly = *from.poly_; + const LineType& poly = *from.poly_; Point2LL last_vertex = from.p(); Point2LL next_vertex; size_t last_point_idx = from.point_idx_; @@ -1169,7 +1170,7 @@ ClosestPoint PolygonUtils::walk(const ClosestPoint& from, coord_t distance) last_point_idx = point_idx; } Point2LL result = next_vertex + normal(last_vertex - next_vertex, -distance); - return ClosestPoint(result, last_point_idx, &poly, from.poly_idx_); + return GenericClosestPoint(result, last_point_idx, &poly, from.poly_idx_); } std::optional PolygonUtils::getNextParallelIntersection(const ClosestPoint& start, const Point2LL& line_to, const coord_t dist, const bool forward) @@ -1523,7 +1524,7 @@ void PolygonUtils::fixSelfIntersections(const coord_t epsilon, Shape& polygon) { if (epsilon < 1) { - ClipperLib::SimplifyPolygons(polygon.asRawVector()); + polygon.simplify(); return; } @@ -1567,7 +1568,7 @@ void PolygonUtils::fixSelfIntersections(const coord_t epsilon, Shape& polygon) } } - ClipperLib::SimplifyPolygons(polygon.asRawVector()); + polygon.simplify(); } Shape PolygonUtils::unionManySmall(const Shape& polygon) @@ -1665,7 +1666,7 @@ Shape PolygonUtils::generateOutset(const Shape& inner_poly, size_t count, coord_ for (size_t index = 0; index < count; ++index) { current_outset = index == 0 ? inner_poly.offset(line_width / 2) : current_outset.offset(line_width); - outset.add(current_outset); + outset.push_back(current_outset); } return outset; @@ -1678,11 +1679,14 @@ Shape PolygonUtils::generateInset(const Shape& outer_poly, coord_t line_width, c Shape current_inset = outer_poly.offset(-(initial_inset + line_width / 2)); while (! current_inset.empty()) { - inset.add(current_inset); + inset.push_back(current_inset); current_inset = current_inset.offset(-line_width); } return inset; } +template GenericClosestPoint PolygonUtils::walk(const GenericClosestPoint& from, coord_t distance); +template GenericClosestPoint PolygonUtils::walk(const GenericClosestPoint& from, coord_t distance); + } // namespace cura From 60046cdb7cc80945292ab5f776766174d936c8d0 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 10 Apr 2024 21:33:33 +0200 Subject: [PATCH 026/135] Fixed crashes due to obvious mistakes --- include/geometry/lines_set.h | 4 ++-- src/geometry/shape.cpp | 2 +- src/utils/Simplify.cpp | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/include/geometry/lines_set.h b/include/geometry/lines_set.h index fe528465b1..08473a5217 100644 --- a/include/geometry/lines_set.h +++ b/include/geometry/lines_set.h @@ -110,7 +110,7 @@ class LinesSet void push_back(const LinesSet& other) { - lines_.insert(other.lines_.end(), other.lines_.begin(), other.lines_.end()); + lines_.insert(lines_.end(), other.lines_.begin(), other.lines_.end()); } void pop_back() @@ -151,7 +151,7 @@ class LinesSet std::vector::iterator erase(std::vector::const_iterator first, std::vector::const_iterator last) { - lines_.erase(first, last); + return lines_.erase(first, last); } LinesSet& operator=(LinesSet&& other) diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index 6763521d57..d982e217c9 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -853,7 +853,7 @@ Shape Shape::removeNearSelfIntersections() const map_poly& wpoly = mwpoly.back(); for (auto& path : polygon) { - wpoly.push_back(std::move(*reinterpret_cast>*>(&path))); + wpoly.push_back(std::move(*reinterpret_cast>*>(&path.getPoints()))); for (auto& point : wpoly.back()) { point.x /= 4; diff --git a/src/utils/Simplify.cpp b/src/utils/Simplify.cpp index dc6a5a2971..eb03df7cad 100644 --- a/src/utils/Simplify.cpp +++ b/src/utils/Simplify.cpp @@ -82,9 +82,7 @@ MixedLinesSet Simplify::polyline(const MixedLinesSet& polylines) const ClosedPolyline Simplify::polyline(const ClosedPolyline& polyline) const { - assert(polyline.addClosingSegment() && "Simplify algorithm doesn't expect explicitely closed polylines"); - constexpr bool is_closed = false; - return simplify(polyline, is_closed); + return simplify(polyline, polyline.isExplicitelyClosed()); } OpenPolyline Simplify::polyline(const OpenPolyline& polyline) const From 7206bc92130bb2012df427fcd74758f929447119 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 10 Apr 2024 10:59:37 +0200 Subject: [PATCH 027/135] Make min-distance to connecting piece dependant on line-distance. This fixes the issue that (near) 100% fill zig-zags had if you just make it anywhere near larger than a single line-distance. part of CURA-11597 --- src/infill.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/infill.cpp b/src/infill.cpp index ce5189973e..715cce1c61 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -751,7 +751,7 @@ void Infill::generateLinearBasedInfill( assert(scanline_idx - scanline_min_idx >= 0 && scanline_idx - scanline_min_idx < int(cut_list.size()) && "reading infill cutlist index out of bounds!"); cut_list[scanline_idx - scanline_min_idx].push_back(y); Point2LL scanline_linesegment_intersection(x, y); - zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, infill_line_width_ * 2); + zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, line_distance / 2); crossings_per_scanline[scanline_idx - min_scanline_index].emplace_back(scanline_linesegment_intersection, poly_idx, point_idx); } zigzag_connector_processor.registerVertex(p1); From 2116caeb1e439dd2e595c3a9cf219674fce712e8 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 11 Apr 2024 10:15:13 +0200 Subject: [PATCH 028/135] Code cleaning CURA-9830 --- include/PrimeTower.h | 2 +- include/geometry/closed_lines_set.h | 7 +- include/geometry/closed_polyline.h | 1 - include/geometry/lines_set.h | 3 +- include/geometry/open_lines_set.h | 11 --- include/geometry/points_set.h | 33 -------- include/geometry/shape.h | 7 -- include/infill/LightningLayer.h | 2 +- include/pathPlanning/Comb.h | 2 +- include/utils/ExtrusionLine.h | 2 + include/utils/polygonUtils.h | 61 ++++++++------- src/FffGcodeWriter.cpp | 3 - src/FffPolygonGenerator.cpp | 11 --- src/LayerPlan.cpp | 10 +-- src/PrimeTower.cpp | 2 +- src/TreeSupportTipGenerator.cpp | 2 +- src/WallToolPaths.cpp | 2 +- src/geometry/lines_set.cpp | 12 ++- src/geometry/points_set.cpp | 38 ---------- src/geometry/polyline.cpp | 2 +- src/geometry/shape.cpp | 11 --- src/infill.cpp | 2 +- src/infill/GyroidInfill.cpp | 12 +-- src/infill/LightningDistanceField.cpp | 2 +- src/infill/LightningLayer.cpp | 4 +- src/infill/SubDivCube.cpp | 6 +- src/pathPlanning/Comb.cpp | 28 +++---- src/utils/ExtrusionLine.cpp | 16 ++++ src/utils/Simplify.cpp | 15 ++-- src/utils/polygonUtils.cpp | 104 +++++++++++++------------- tests/utils/PolygonUtilsTest.cpp | 30 ++++---- 31 files changed, 171 insertions(+), 272 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index b1d5180a9d..ef3cb78859 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -38,7 +38,7 @@ class PrimeTower Point2LL post_wipe_point_; //!< Location to post-wipe the unused nozzle off on - std::vector prime_tower_start_locations_; //!< The differernt locations where to pre-wipe the active nozzle + std::vector prime_tower_start_locations_; //!< The differernt locations where to pre-wipe the active nozzle const unsigned int number_of_prime_tower_start_locations_ = 21; //!< The required size of \ref PrimeTower::wipe_locations MovesByExtruder prime_moves_; //!< For each extruder, the moves to be processed for actual priming. diff --git a/include/geometry/closed_lines_set.h b/include/geometry/closed_lines_set.h index 114fab92d6..bb4abd6fc1 100644 --- a/include/geometry/closed_lines_set.h +++ b/include/geometry/closed_lines_set.h @@ -14,12 +14,7 @@ namespace cura * \brief Convenience definition for a container that can hold only closed polylines. This makes it * explicit what the lines actually represent. */ -#warning Try with a using instead -class ClosedLinesSet : public LinesSet -{ -public: - ClosedLinesSet() = default; -}; +using ClosedLinesSet = LinesSet; } // namespace cura diff --git a/include/geometry/closed_polyline.h b/include/geometry/closed_polyline.h index 3d65f0b216..10db68cab3 100644 --- a/include/geometry/closed_polyline.h +++ b/include/geometry/closed_polyline.h @@ -21,7 +21,6 @@ class ClosedPolyline : public Polyline bool explicitely_closed_{ false }; public: -#warning try to set bool explicitely_closed as argument ClosedPolyline() = default; ClosedPolyline(const ClosedPolyline& other) = default; diff --git a/include/geometry/lines_set.h b/include/geometry/lines_set.h index 08473a5217..6562112ddd 100644 --- a/include/geometry/lines_set.h +++ b/include/geometry/lines_set.h @@ -195,8 +195,7 @@ class LinesSet /*! * Add a simple line consisting of two points */ -#warning rename to addSegment and move to mixed - void addLine(const Point2LL& from, const Point2LL& to); + void addSegment(const Point2LL& from, const Point2LL& to); coord_t length() const; diff --git a/include/geometry/open_lines_set.h b/include/geometry/open_lines_set.h index ea8cfcb9f4..74e2b3c878 100644 --- a/include/geometry/open_lines_set.h +++ b/include/geometry/open_lines_set.h @@ -15,17 +15,6 @@ namespace cura * explicit what the lines actually represent. */ using OpenLinesSet = LinesSet; -#warning Try with a using instead -/*class OpenLinesSet : public LinesSet -{ -public: - OpenLinesSet() = default; - - OpenLinesSet(const LinesSet& other) - : LinesSet(other) - { - } -};*/ } // namespace cura diff --git a/include/geometry/points_set.h b/include/geometry/points_set.h index d8b2a7797a..c0772d6252 100644 --- a/include/geometry/points_set.h +++ b/include/geometry/points_set.h @@ -16,24 +16,6 @@ class Point3Matrix; const static int clipper_init = (0); #define NO_INDEX (std::numeric_limits::max()) -#warning Move this somewhere else, or remove it... -template -bool shorterThan(const T& shape, const coord_t check_length) -{ - const auto* p0 = &shape.back(); - int64_t length = 0; - for (const auto& p1 : shape) - { - length += vSize(*p0 - p1); - if (length >= check_length) - { - return false; - } - p0 = &p1; - } - return true; -} - /*! * \brief Base class for all geometry containers representing a set of points. */ @@ -55,12 +37,6 @@ class PointsSet PointsSet(ClipperLib::Path&& points); - /*PointsSet& operator=(const PointsSet& other) - { - std::vector::operator=(other); - return *this; - }*/ - const std::vector& getPoints() const { return points_; @@ -207,15 +183,6 @@ class PointsSet PointsSet& operator=(PointsSet&& other) = default; -#warning seems to be unused - Point2LL min() const; - -#warning seems to be unused - Point2LL max() const; - -#warning seems to be unused - Point2LL closestPointTo(const Point2LL& p) const; - /*! * Translate all the points in some direction. * diff --git a/include/geometry/shape.h b/include/geometry/shape.h index 0545f5ff1e..ee5b168a6d 100644 --- a/include/geometry/shape.h +++ b/include/geometry/shape.h @@ -58,7 +58,6 @@ class Shape : public LinesSet Shape difference(const Shape& other) const; -#warning rename this to union Shape unionPolygons(const Shape& other, ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero) const; /*! @@ -85,12 +84,6 @@ class Shape : public LinesSet #warning Technically this should return a MixedLinesSet LinesSet intersection(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; - /*! - * Add the front to each polygon so that the polygon is represented as a polyline - */ -#warning This could probably be removed - void toPolylines(); - /*! * Split this poly line object into several line segment objects * and store them in the \p result diff --git a/include/infill/LightningLayer.h b/include/infill/LightningLayer.h index 6b74643570..76ab5eebbd 100644 --- a/include/infill/LightningLayer.h +++ b/include/infill/LightningLayer.h @@ -21,7 +21,7 @@ using SparseLightningTreeNodeGrid = SparsePointGridInclusive boundary_location; //!< in case the gounding location is on the boundary + std::optional boundary_location; //!< in case the gounding location is on the boundary Point2LL p() const; }; diff --git a/include/pathPlanning/Comb.h b/include/pathPlanning/Comb.h index 6d6802b10b..39b3b5456b 100644 --- a/include/pathPlanning/Comb.h +++ b/include/pathPlanning/Comb.h @@ -118,7 +118,7 @@ class Comb * \param comber[in] The combing calculator which has references to the offsets and boundaries to use in combing. * \return A pair of which the first is the crossing point on the inside boundary and the second the crossing point on the outside boundary */ - std::shared_ptr> + std::shared_ptr> findBestCrossing(const ExtruderTrain& train, const Shape& outside, const Polygon& from, const Point2LL estimated_start, const Point2LL estimated_end, Comb& comber); }; diff --git a/include/utils/ExtrusionLine.h b/include/utils/ExtrusionLine.h index cce89c9274..4fa770822f 100644 --- a/include/utils/ExtrusionLine.h +++ b/include/utils/ExtrusionLine.h @@ -230,6 +230,8 @@ struct ExtrusionLine * Get the minimal width of this path */ coord_t getMinimalWidth() const; + + bool shorterThan(const coord_t check_length) const; }; using VariableWidthLines = std::vector; // -struct GenericClosestPoint +struct ClosestPoint { Point2LL location_; //!< Result location const LineType* poly_{ nullptr }; //!< Line in which the result was found (or nullptr if no result was found) size_t poly_idx_; //!< The index of the polygon in some Polygons where ClosestPoint::poly can be found size_t point_idx_; //!< Index to the first point in the polygon of the line segment on which the result was found - GenericClosestPoint(Point2LL p, size_t pos, const LineType* poly) + ClosestPoint(Point2LL p, size_t pos, const LineType* poly) : location_(p) , poly_(poly) , poly_idx_(NO_INDEX) @@ -37,7 +36,7 @@ struct GenericClosestPoint { } - GenericClosestPoint(Point2LL p, size_t pos, const LineType* poly, size_t poly_idx) + ClosestPoint(Point2LL p, size_t pos, const LineType* poly, size_t poly_idx) : location_(p) , poly_(poly) , poly_idx_(poly_idx) @@ -45,14 +44,14 @@ struct GenericClosestPoint { } - GenericClosestPoint(const LineType* poly) + ClosestPoint(const LineType* poly) : poly_(poly) , poly_idx_(NO_INDEX) , point_idx_(NO_INDEX) { } - GenericClosestPoint() + ClosestPoint() : poly_idx_(NO_INDEX) , point_idx_(NO_INDEX) { @@ -68,7 +67,7 @@ struct GenericClosestPoint return point_idx_ != NO_INDEX; } - bool operator==(const GenericClosestPoint& rhs) const + bool operator==(const ClosestPoint& rhs) const { // no need to compare on poy_idx // it's sometimes unused while poly is always initialized @@ -76,16 +75,16 @@ struct GenericClosestPoint } }; -using ClosestPoint = GenericClosestPoint; +using ClosestPointPolygon = ClosestPoint; } // namespace cura namespace std { template<> -struct hash +struct hash { - size_t operator()(const cura::ClosestPoint& cpp) const + size_t operator()(const cura::ClosestPointPolygon& cpp) const { return std::hash()(cpp.p()); } @@ -151,7 +150,7 @@ class PolygonUtils * \param n_dots number of dots to spread out * \param result Where to store the generated points */ - static void spreadDots(PolygonsPointIndex start, PolygonsPointIndex end, unsigned int n_dots, std::vector& result); + static void spreadDots(PolygonsPointIndex start, PolygonsPointIndex end, unsigned int n_dots, std::vector& result); /*! * Generate a grid of dots inside of the area of the \p polygons. @@ -197,7 +196,7 @@ class PolygonUtils * \param point_on_boundary The object holding the point on the boundary along with the information of which line segment the point is on. * \param offset The distance the point has to be moved inward from the polygon. */ - static Point2LL moveInsideDiagonally(ClosestPoint point_on_boundary, int64_t inset); + static Point2LL moveInsideDiagonally(ClosestPointPolygon point_on_boundary, int64_t inset); /*! * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within the root of \p max_dist2 distance. @@ -239,7 +238,7 @@ class PolygonUtils * * \warning If \p loc_to_line_grid is used, it's best to have all and only \p polygons in there. * If \p from is not closest to \p polygons this function may - * return a ClosestPoint on a polygon in \p loc_to_line_grid which is not in \p polygons. + * return a ClosestPointPolygon on a polygon in \p loc_to_line_grid which is not in \p polygons. * * \param polygons The polygons onto which to move the point * \param from[in,out] The point to move. @@ -250,7 +249,7 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPoint moveInside2( + static ClosestPointPolygon moveInside2( const Shape& polygons, Point2LL& from, const int distance = 0, @@ -278,7 +277,7 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPoint moveInside2( + static ClosestPointPolygon moveInside2( const Shape& loc_to_line_polygons, const Polygon& polygon, Point2LL& from, @@ -312,7 +311,7 @@ class PolygonUtils * \param distance The distance by which to move the point. * \return A point at a \p distance from the point in \p cpp orthogonal to the boundary there. */ - static Point2LL moveInside(const ClosestPoint& cpp, const int distance); + static Point2LL moveInside(const ClosestPointPolygon& cpp, const int distance); /*! * The opposite of moveInside. @@ -324,7 +323,7 @@ class PolygonUtils * \param distance The distance by which to move the point. * \return A point at a \p distance from the point in \p cpp orthogonal to the boundary there. */ - static Point2LL moveOutside(const ClosestPoint& cpp, const int distance); + static Point2LL moveOutside(const ClosestPointPolygon& cpp, const int distance); /*! * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within \p distance. @@ -349,7 +348,7 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPoint ensureInsideOrOutside( + static ClosestPointPolygon ensureInsideOrOutside( const Shape& polygons, Point2LL& from, int preferred_dist_inside, @@ -381,10 +380,10 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The point on the polygon closest to \p from */ - static ClosestPoint ensureInsideOrOutside( + static ClosestPointPolygon ensureInsideOrOutside( const Shape& polygons, Point2LL& from, - const ClosestPoint& closest_polygon_point, + const ClosestPointPolygon& closest_polygon_point, int preferred_dist_inside, const Shape* loc_to_line_polygons = nullptr, const LocToLineGrid* loc_to_line_grid = nullptr, @@ -394,7 +393,7 @@ class PolygonUtils * * \warning Assumes \p poly1_result and \p poly2_result have their pos and poly fields initialized! */ - static void walkToNearestSmallestConnection(ClosestPoint& poly1_result, ClosestPoint& poly2_result); + static void walkToNearestSmallestConnection(ClosestPointPolygon& poly1_result, ClosestPointPolygon& poly2_result); /*! * Find the nearest closest point on a polygon from a given index. @@ -404,7 +403,7 @@ class PolygonUtils * \param start_idx The index of the point in the polygon from which to start looking. * \return The nearest point from \p start_idx going along the \p polygon (in both directions) with a locally minimal distance to \p from. */ - static ClosestPoint findNearestClosest(Point2LL from, const Polygon& polygon, int start_idx); + static ClosestPointPolygon findNearestClosest(Point2LL from, const Polygon& polygon, int start_idx); /*! * Find the nearest closest point on a polygon from a given index walking in one direction along the polygon. @@ -415,7 +414,7 @@ class PolygonUtils * \param direction The direction to walk: 1 for walking along the \p polygon, -1 for walking in opposite direction * \return The nearest point from \p start_idx going along the \p polygon with a locally minimal distance to \p from. */ - static ClosestPoint findNearestClosest(const Point2LL from, const Polygon& polygon, int start_idx, int direction); + static ClosestPointPolygon findNearestClosest(const Point2LL from, const Polygon& polygon, int start_idx, int direction); /*! * Find the point closest to \p from in all polygons in \p polygons. @@ -424,7 +423,7 @@ class PolygonUtils * * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. */ - static ClosestPoint findClosest(Point2LL from, const Shape& polygons, const std::function& penalty_function = no_penalty_function); + static ClosestPointPolygon findClosest(Point2LL from, const Shape& polygons, const std::function& penalty_function = no_penalty_function); /*! * Find the point closest to \p from in the polygon \p polygon. @@ -433,7 +432,7 @@ class PolygonUtils * * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. */ - static ClosestPoint findClosest(Point2LL from, const Polygon& polygon, const std::function& penalty_function = no_penalty_function); + static ClosestPointPolygon findClosest(Point2LL from, const Polygon& polygon, const std::function& penalty_function = no_penalty_function); /*! * Find the nearest vertex to \p from in \p polys @@ -474,7 +473,7 @@ class PolygonUtils * \param penalty_function A function returning a penalty term on the squared distance score of a candidate point. * \return The nearest point on the polygon if the polygon was within a distance equal to the cell_size of the SparsePointGridInclusive */ - static std::optional + static std::optional findClose(Point2LL from, const Shape& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function = no_penalty_function); /*! @@ -490,7 +489,7 @@ class PolygonUtils * \return A collection of near crossing from the \p from polygon to the \p destination polygon. Each element in the sollection is a pair with as first a cpp in the \p from * polygon and as second a cpp in the \p destination polygon. */ - static std::vector> findClose( + static std::vector> findClose( const Polygon& from, const Shape& destination, const LocToLineGrid& destination_loc_to_line, @@ -527,7 +526,7 @@ class PolygonUtils * Walk a given \p distance along the polygon from a given point \p from on the polygon */ template - static GenericClosestPoint walk(const GenericClosestPoint& from, coord_t distance); + static ClosestPoint walk(const ClosestPoint& from, coord_t distance); /*! * Get the point on a polygon which intersects a line parallel to a line going through the starting point and through another point. @@ -541,7 +540,7 @@ class PolygonUtils * \param forward Whether to look forward from \p start in the direction of the polygon, or go in the other direction. * \return The earliest point on the polygon in the given direction which crosses a line parallel to the given one at the distance \p dist - if any */ - static std::optional getNextParallelIntersection(const ClosestPoint& start, const Point2LL& line_to, const coord_t dist, const bool forward); + static std::optional getNextParallelIntersection(const ClosestPointPolygon& start, const Point2LL& line_to, const coord_t dist, const bool forward); /*! * Checks whether a given line segment collides with a given polygon(s). @@ -732,13 +731,13 @@ class PolygonUtils * Helper function for PolygonUtils::moveInside2: moves a point \p from which was moved onto \p closest_polygon_point towards inside/outside when it's not already * inside/outside by enough distance. * - * \param closest_polygon_point The ClosestPoint we have to move inside + * \param closest_polygon_point The ClosestPointPolygon we have to move inside * \param distance The distance by which to move the point. * \param from[in,out] The point to move. * \param max_dist2 The squared maximal allowed distance from the point to the nearest polygon. * \return The point on the polygon closest to \p from */ - static ClosestPoint _moveInside2(const ClosestPoint& closest_polygon_point, const int distance, Point2LL& from, const int64_t max_dist2); + static ClosestPointPolygon _moveInside2(const ClosestPointPolygon& closest_polygon_point, const int distance, Point2LL& from, const int64_t max_dist2); }; diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 73b5c0b853..45c19d6533 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1491,9 +1491,6 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan if ((layer_nr == 0) && (extruder_nr == mesh_group_settings.get("support_extruder_nr_layer_0").extruder_nr_)) { total_line_count += storage.support_brim.size(); - // LinesSet support_brim_lines = storage.support_brim; -#warning Check for bugs !! - // support_brim_lines.toPolylines(); gcode_layer.addLinesByOptimizer( storage.support_brim, gcode_layer.configs_storage_.skirt_brim_config_per_extruder[extruder_nr], diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 2266b344bc..8cc988d66c 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -1071,17 +1071,6 @@ void FffPolygonGenerator::processPlatformAdhesion(SliceDataStorage& storage) { skirt_brim.generateSupportBrim(); } - - for (const auto& extruder : Application::getInstance().current_slice_->scene.extruders) - { -#warning Using auto here apparently makes a copy and then the loop is useless -> double-check - /*Simplify simplifier(extruder.settings_); - for (auto skirt_brim_line : storage.skirt_brim[extruder.extruder_nr_]) - { - skirt_brim_line.closed_polygons = simplifier.polygon(skirt_brim_line.closed_polygons); - skirt_brim_line.open_polylines = simplifier.polyline(skirt_brim_line.open_polylines); - }*/ - } } diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 57ac191456..e1f67742fb 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -805,7 +805,7 @@ void LayerPlan::addWallLine( // to the first and last point of the intersected line segments alternating between // roofing and default_config's. LinesSet line_polys; - line_polys.addLine(p0, p1); + line_polys.addSegment(p0, p1); constexpr bool restitch = false; // only a single line doesn't need stitching auto roofing_line_segments = roofing_mask_.intersection(line_polys, restitch); @@ -878,7 +878,7 @@ void LayerPlan::addWallLine( // determine which segments of the line are bridges LinesSet line_polys; - line_polys.addLine(p0, p1); + line_polys.addSegment(p0, p1); constexpr bool restitch = false; // only a single line doesn't need stitching line_polys = bridge_wall_mask_.intersection(line_polys, restitch); @@ -1050,7 +1050,7 @@ void LayerPlan::addWall( // determine which segments of the line are bridges LinesSet line_polys; - line_polys.addLine(p0.p_, p1.p_); + line_polys.addSegment(p0.p_, p1.p_); constexpr bool restitch = false; // only a single line doesn't need stitching line_polys = bridge_wall_mask_.intersection(line_polys, restitch); @@ -1112,7 +1112,7 @@ void LayerPlan::addWall( bool first_line = true; const coord_t small_feature_max_length = settings.get("small_feature_max_length"); - const bool is_small_feature = (small_feature_max_length > 0) && (layer_nr_ == 0 || wall.inset_idx_ == 0) && cura::shorterThan(wall, small_feature_max_length); + const bool is_small_feature = (small_feature_max_length > 0) && (layer_nr_ == 0 || wall.inset_idx_ == 0) && wall.shorterThan(small_feature_max_length); Ratio small_feature_speed_factor = settings.get((layer_nr_ == 0) ? "small_feature_speed_factor_0" : "small_feature_speed_factor"); const Velocity min_speed = fan_speed_layer_time_settings_per_extruder_[getLastPlannedExtruderTrain()->extruder_nr_].cool_min_speed; small_feature_speed_factor = std::max((double)small_feature_speed_factor, (double)(min_speed / default_config.getSpeed())); @@ -1673,7 +1673,7 @@ void LayerPlan::spiralizeWallSlice( if (smooth_contours && ! is_bottom_layer && wall_point_idx < n_points) { // now find the point on the last wall that is closest to p - ClosestPoint cpp = PolygonUtils::findClosest(p, last_wall_polygons); + ClosestPointPolygon cpp = PolygonUtils::findClosest(p, last_wall_polygons); // if we found a point and it's not further away than max_dist2, use it if (cpp.isValid() && vSize2(cpp.location_ - p) <= max_dist2) diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 9dc4da4ef8..ca3c898101 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -629,7 +629,7 @@ void PrimeTower::gotoStartLocation(LayerPlan& gcode_layer, const int extruder_nr int current_start_location_idx = ((((extruder_nr + 1) * gcode_layer.getLayerNr()) % number_of_prime_tower_start_locations_) + number_of_prime_tower_start_locations_) % number_of_prime_tower_start_locations_; - const ClosestPoint wipe_location = prime_tower_start_locations_[current_start_location_idx]; + const ClosestPointPolygon wipe_location = prime_tower_start_locations_[current_start_location_idx]; const ExtruderTrain& train = Application::getInstance().current_slice_->scene.extruders[extruder_nr]; const coord_t inward_dist = train.settings_.get("machine_nozzle_size") * 3 / 2; const coord_t start_dist = train.settings_.get("machine_nozzle_size") * 2; diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 5453444934..0ef1fd1fb8 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -266,7 +266,7 @@ LinesSet TreeSupportTipGenerator::ensureMaximumDistancePolyline(co coord_t current_distance = std::max(distance, coord_t(FUDGE_LENGTH * 2)); if (length < 2 * distance && min_points <= 1) { - GenericClosestPoint middle_point(part[0], 0, &part); + ClosestPoint middle_point(part[0], 0, &part); middle_point = PolygonUtils::walk(middle_point, coord_t(length / 2)); line.push_back(middle_point.location_); } diff --git a/src/WallToolPaths.cpp b/src/WallToolPaths.cpp index b747493cf7..b144d0ebfb 100644 --- a/src/WallToolPaths.cpp +++ b/src/WallToolPaths.cpp @@ -286,7 +286,7 @@ void WallToolPaths::removeSmallLines(std::vector& toolpaths) { min_width = std::min(min_width, j.w_); } - if (line.is_odd_ && ! line.is_closed_ && shorterThan(line, min_width / 2)) + if (line.is_odd_ && ! line.is_closed_ && line.shorterThan(min_width / 2)) { // remove line line = std::move(inset.back()); inset.erase(--inset.end()); diff --git a/src/geometry/lines_set.cpp b/src/geometry/lines_set.cpp index 8451ba0a3d..c1edb9c4d0 100644 --- a/src/geometry/lines_set.cpp +++ b/src/geometry/lines_set.cpp @@ -75,7 +75,7 @@ size_t LinesSet::pointCount() const } template<> -void LinesSet::addLine(const Point2LL& from, const Point2LL& to) +void LinesSet::addSegment(const Point2LL& from, const Point2LL& to) { lines_.emplace_back(std::initializer_list{ from, to }); } @@ -341,10 +341,16 @@ void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::Poly { for (const LineType& line : getLines()) { -#warning No dynamic cast is required here... // In this context, the "Closed" argument means "Is a surface" so it should be only // true for actual filled polygons. Closed polylines are to be treated as lines here. - clipper.AddPath(line.getPoints(), PolyTyp, dynamic_cast(&line) != nullptr); + if constexpr (std::is_same::value) + { + clipper.AddPath(line.getPoints(), PolyTyp, true); + } + else + { + clipper.AddPath(line.getPoints(), PolyTyp, false); + } } } diff --git a/src/geometry/points_set.cpp b/src/geometry/points_set.cpp index b22105a839..4712b97f52 100644 --- a/src/geometry/points_set.cpp +++ b/src/geometry/points_set.cpp @@ -41,44 +41,6 @@ void PointsSet::applyMatrix(const Point3Matrix& matrix) } } -Point2LL PointsSet::min() const -{ - Point2LL ret = Point2LL(POINT_MAX, POINT_MAX); - for (Point2LL point : points_) - { - ret.X = std::min(ret.X, point.X); - ret.Y = std::min(ret.Y, point.Y); - } - return ret; -} - -Point2LL PointsSet::max() const -{ - Point2LL ret = Point2LL(POINT_MIN, POINT_MIN); - for (Point2LL point : points_) - { - ret.X = std::max(ret.X, point.X); - ret.Y = std::max(ret.Y, point.Y); - } - return ret; -} - -Point2LL PointsSet::closestPointTo(const Point2LL& p) const -{ - const Point2LL* ret = &p; - double bestDist = std::numeric_limits::max(); - for (const Point2LL& point : points_) - { - double dist = vSize2f(p - point); - if (dist < bestDist) - { - ret = &point; - bestDist = dist; - } - } - return *ret; -} - void PointsSet::translate(const Point2LL& translation) { for (Point2LL& point : points_) diff --git a/src/geometry/polyline.cpp b/src/geometry/polyline.cpp index fb75fd9a7e..c0447509f6 100644 --- a/src/geometry/polyline.cpp +++ b/src/geometry/polyline.cpp @@ -152,7 +152,7 @@ bool Polyline::shorterThan(const coord_t check_length) const void Polyline::splitIntoSegments(OpenLinesSet& result) const { -#warning reserve space before adding all the segments + result.reserve(result.size() + segmentsCount()); for (auto it = beginSegments(); it != endSegments(); ++it) { result.emplace_back(std::initializer_list{ (*it).start, (*it).end }); diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index d982e217c9..10ef1e2663 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -303,17 +303,6 @@ Shape Shape::execute(ClipperLib::PolyFillType pft) const clipper.Execute(ClipperLib::ctXor, ret, pft); return Shape(std::move(ret)); } -/* -void Polygons::toPolylines() -{ - for (PolygonRef poly : *this) - { - if (poly.empty()) - continue; - poly.emplace_back(poly.front()); - } -} -*/ Shape Shape::offsetMulti(const std::vector& offset_dists) const { diff --git a/src/infill.cpp b/src/infill.cpp index 4edb595819..6f15f2a1c1 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -576,7 +576,7 @@ void Infill::addLineInfill( { // segment is too short to create infill continue; } - result.addLine(rotation_matrix.unapply(Point2LL(x, crossings[crossing_idx])), rotation_matrix.unapply(Point2LL(x, crossings[crossing_idx + 1]))); + result.addSegment(rotation_matrix.unapply(Point2LL(x, crossings[crossing_idx])), rotation_matrix.unapply(Point2LL(x, crossings[crossing_idx + 1]))); } scanline_idx += 1; } diff --git a/src/infill/GyroidInfill.cpp b/src/infill/GyroidInfill.cpp index 12159e1b0f..ca67b9fb60 100644 --- a/src/infill/GyroidInfill.cpp +++ b/src/infill/GyroidInfill.cpp @@ -82,19 +82,19 @@ void GyroidInfill::generateTotalGyroidInfill(LinesSet& result_line if (last_inside && current_inside) { // line doesn't hit the boundary, add the whole line - result.addLine(last, current); + result.addSegment(last, current); } else if (last_inside != current_inside) { // line hits the boundary, add the part that's inside the boundary LinesSet line; - line.addLine(last, current); + line.addSegment(last, current); constexpr bool restitch = false; // only a single line doesn't need stitching line = in_outline.intersection(line, restitch); if (line.size() > 0) { // some of the line is inside the boundary - result.addLine(line[0][0], line[0][1]); + result.addSegment(line[0][0], line[0][1]); if (zig_zaggify) { chain_end[chain_end_index] = line[0][(line[0][0] != last && line[0][0] != current) ? 0 : 1]; @@ -174,19 +174,19 @@ void GyroidInfill::generateTotalGyroidInfill(LinesSet& result_line if (last_inside && current_inside) { // line doesn't hit the boundary, add the whole line - result.addLine(last, current); + result.addSegment(last, current); } else if (last_inside != current_inside) { // line hits the boundary, add the part that's inside the boundary LinesSet line; - line.addLine(last, current); + line.addSegment(last, current); constexpr bool restitch = false; // only a single line doesn't need stitching line = in_outline.intersection(line, restitch); if (line.size() > 0) { // some of the line is inside the boundary - result.addLine(line[0][0], line[0][1]); + result.addSegment(line[0][0], line[0][1]); if (zig_zaggify) { chain_end[chain_end_index] = line[0][(line[0][0] != last && line[0][0] != current) ? 0 : 1]; diff --git a/src/infill/LightningDistanceField.cpp b/src/infill/LightningDistanceField.cpp index efc18dfcb8..bda9d7e27c 100644 --- a/src/infill/LightningDistanceField.cpp +++ b/src/infill/LightningDistanceField.cpp @@ -20,7 +20,7 @@ LightningDistanceField::LightningDistanceField(const coord_t& radius, const Shap std::vector regular_dots = PolygonUtils::spreadDotsArea(current_overhang, cell_size_); for (const auto& p : regular_dots) { - const ClosestPoint cpp = PolygonUtils::findClosest(p, current_outline); + const ClosestPointPolygon cpp = PolygonUtils::findClosest(p, current_outline); const coord_t dist_to_boundary = vSize(p - cpp.p()); unsupported_points_.emplace_back(p, dist_to_boundary); } diff --git a/src/infill/LightningLayer.cpp b/src/infill/LightningLayer.cpp index ae97013241..d7c575290a 100644 --- a/src/infill/LightningLayer.cpp +++ b/src/infill/LightningLayer.cpp @@ -87,7 +87,7 @@ GroundingLocation LightningLayer::getBestGroundingLocation( const SparseLightningTreeNodeGrid& tree_node_locator, const LightningTreeNodeSPtr& exclude_tree) { - ClosestPoint cpp = PolygonUtils::findClosest(unsupported_location, current_outlines); + ClosestPointPolygon cpp = PolygonUtils::findClosest(unsupported_location, current_outlines); Point2LL node_location = cpp.p(); const coord_t within_dist = vSize(node_location - unsupported_location); @@ -120,7 +120,7 @@ GroundingLocation LightningLayer::getBestGroundingLocation( } else { - return GroundingLocation{ sub_tree, std::optional() }; + return GroundingLocation{ sub_tree, std::optional() }; } } diff --git a/src/infill/SubDivCube.cpp b/src/infill/SubDivCube.cpp index 1f68d77609..ce26aadf8c 100644 --- a/src/infill/SubDivCube.cpp +++ b/src/infill/SubDivCube.cpp @@ -100,7 +100,7 @@ void SubDivCube::generateSubdivisionLines(const coord_t z, LinesSet& line_group = directional_line_groups[dir_idx]; for (unsigned int line_idx = 0; line_idx < line_group.size(); line_idx++) { - result.addLine(line_group[line_idx][0], line_group[line_idx][1]); + result.addSegment(line_group[line_idx][0], line_group[line_idx][1]); } } } @@ -238,7 +238,7 @@ coord_t SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, const LayerI Point2LL centerpoint = location; bool inside = collide.inside(centerpoint); - ClosestPoint border_point = PolygonUtils::moveInside2(collide, centerpoint); + ClosestPointPolygon border_point = PolygonUtils::moveInside2(collide, centerpoint); Point2LL diff = border_point.location_ - location; *distance2 = vSize2(diff); if (inside) @@ -283,7 +283,7 @@ void SubDivCube::addLineAndCombine(LinesSet& group, Point2LL from, continue; } } - group.addLine(from, to); + group.addSegment(from, to); } } // namespace cura diff --git a/src/pathPlanning/Comb.cpp b/src/pathPlanning/Comb.cpp index f1fbf8e475..a5659a29e6 100644 --- a/src/pathPlanning/Comb.cpp +++ b/src/pathPlanning/Comb.cpp @@ -428,7 +428,7 @@ bool Comb::moveInside(Shape& boundary_inside, bool is_inside, LocToLineGrid* ins { if (is_inside) { - ClosestPoint cpp + ClosestPointPolygon cpp = PolygonUtils::ensureInsideOrOutside(boundary_inside, dest_point, offset_extra_start_end_, max_moveInside_distance2_, &boundary_inside, inside_loc_to_line); if (! cpp.isValid()) { @@ -456,7 +456,7 @@ void Comb::Crossing::findCrossingInOrMid(const PartsView& partsView_inside, cons }); dest_part_ = partsView_inside.assemblePart(dest_part_idx_); - ClosestPoint boundary_crossing_point; + ClosestPointPolygon boundary_crossing_point; { // set [result] to a point on the destination part closest to close_to (but also a bit close to _dest_point) std::unordered_set dest_part_poly_indices; for (unsigned int poly_idx : partsView_inside[dest_part_idx_]) @@ -476,7 +476,7 @@ void Comb::Crossing::findCrossingInOrMid(const PartsView& partsView_inside, cons if (dist2_score_here < dist2_score) { dist2_score = dist2_score_here; - boundary_crossing_point = ClosestPoint(closest_here, boundary_segment.point_idx_, &boundary_segment.getPolygon(), boundary_segment.poly_idx_); + boundary_crossing_point = ClosestPointPolygon(closest_here, boundary_segment.point_idx_, &boundary_segment.getPolygon(), boundary_segment.poly_idx_); } return true; }; @@ -489,7 +489,7 @@ void Comb::Crossing::findCrossingInOrMid(const PartsView& partsView_inside, cons result = dest_point_; } - ClosestPoint crossing_1_in_cp = PolygonUtils::ensureInsideOrOutside( + ClosestPointPolygon crossing_1_in_cp = PolygonUtils::ensureInsideOrOutside( dest_part_, result, boundary_crossing_point, @@ -524,7 +524,7 @@ bool Comb::Crossing::findOutside(const ExtruderTrain& train, const Shape& outsid { return vSize2((candidate - preferred_crossing_1_out) / 2); }); - std::optional crossing_1_out_cpp = PolygonUtils::findClose(in_or_mid_, outside, comber.getOutsideLocToLine(train), close_to_penalty_function); + std::optional crossing_1_out_cpp = PolygonUtils::findClose(in_or_mid_, outside, comber.getOutsideLocToLine(train), close_to_penalty_function); if (crossing_1_out_cpp) { out_ = PolygonUtils::moveOutside(*crossing_1_out_cpp, comber.offset_dist_to_get_from_on_the_polygon_to_outside_); @@ -539,7 +539,7 @@ bool Comb::Crossing::findOutside(const ExtruderTrain& train, const Shape& outsid { // if move is too far over in_between // find crossing closer by assert(dest_crossing_poly_ && "destination crossing poly should have been instantiated!"); - std::shared_ptr> best = findBestCrossing(train, outside, **dest_crossing_poly_, dest_point_, close_to, comber); + std::shared_ptr> best = findBestCrossing(train, outside, **dest_crossing_poly_, dest_point_, close_to, comber); if (best) { in_or_mid_ = PolygonUtils::moveInside(best->first, comber.offset_dist_to_get_from_on_the_polygon_to_outside_); @@ -554,7 +554,7 @@ bool Comb::Crossing::findOutside(const ExtruderTrain& train, const Shape& outsid } -std::shared_ptr> Comb::Crossing::findBestCrossing( +std::shared_ptr> Comb::Crossing::findBestCrossing( const ExtruderTrain& train, const Shape& outside, const Polygon& from, @@ -562,13 +562,13 @@ std::shared_ptr> Comb::Crossing::findBestC const Point2LL estimated_end, Comb& comber) { - ClosestPoint* best_in = nullptr; - ClosestPoint* best_out = nullptr; + ClosestPointPolygon* best_in = nullptr; + ClosestPointPolygon* best_out = nullptr; coord_t best_detour_score = std::numeric_limits::max(); coord_t best_crossing_dist2; - std::vector> crossing_out_candidates = PolygonUtils::findClose(from, outside, comber.getOutsideLocToLine(train)); + std::vector> crossing_out_candidates = PolygonUtils::findClose(from, outside, comber.getOutsideLocToLine(train)); bool seen_close_enough_connection = false; - for (std::pair& crossing_candidate : crossing_out_candidates) + for (std::pair& crossing_candidate : crossing_out_candidates) { const coord_t crossing_dist2 = vSize2(crossing_candidate.first.location_ - crossing_candidate.second.location_); if (crossing_dist2 > comber.max_crossing_dist2_ * 2) @@ -603,7 +603,7 @@ std::shared_ptr> Comb::Crossing::findBestC } if (best_detour_score == std::numeric_limits::max()) { // i.e. if best_in == nullptr or if best_out == nullptr - return std::shared_ptr>(); + return std::shared_ptr>(); } if (best_crossing_dist2 > comber.max_crossing_dist2_) { // find closer point on line segments, rather than moving between vertices of the polygons only @@ -611,10 +611,10 @@ std::shared_ptr> Comb::Crossing::findBestC best_crossing_dist2 = vSize2(best_in->location_ - best_out->location_); if (best_crossing_dist2 > comber.max_crossing_dist2_) { - return std::shared_ptr>(); + return std::shared_ptr>(); } } - return std::make_shared>(*best_in, *best_out); + return std::make_shared>(*best_in, *best_out); } } // namespace cura diff --git a/src/utils/ExtrusionLine.cpp b/src/utils/ExtrusionLine.cpp index c0c274e8a6..0da925d771 100644 --- a/src/utils/ExtrusionLine.cpp +++ b/src/utils/ExtrusionLine.cpp @@ -44,4 +44,20 @@ coord_t ExtrusionLine::getMinimalWidth() const ->w_; } +bool ExtrusionLine::shorterThan(const coord_t check_length) const +{ + const ExtrusionJunction* p0 = &back(); + int64_t length = 0; + for (const ExtrusionJunction& p1 : (*this)) + { + length += vSize(*p0 - p1); + if (length >= check_length) + { + return false; + } + p0 = &p1; + } + return true; +} + } // namespace cura diff --git a/src/utils/Simplify.cpp b/src/utils/Simplify.cpp index eb03df7cad..c215464cd2 100644 --- a/src/utils/Simplify.cpp +++ b/src/utils/Simplify.cpp @@ -65,16 +65,13 @@ MixedLinesSet Simplify::polyline(const MixedLinesSet& polylines) const MixedLinesSet result; for (const std::shared_ptr& polyline_ptr : polylines) { - if (polyline_ptr) + if (std::shared_ptr open_polyline = std::dynamic_pointer_cast(polyline_ptr)) { - if (std::shared_ptr open_polyline = std::dynamic_pointer_cast(polyline_ptr)) - { - result.push_back(std::make_shared(polyline(*open_polyline))); - } - if (std::shared_ptr closed_polyline = std::dynamic_pointer_cast(polyline_ptr)) - { - result.push_back(std::make_shared(polyline(*closed_polyline))); - } + result.push_back(std::make_shared(polyline(*open_polyline))); + } + if (std::shared_ptr closed_polyline = std::dynamic_pointer_cast(polyline_ptr)) + { + result.push_back(std::make_shared(polyline(*closed_polyline))); } } return result; diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index 1608514213..8153a96869 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -54,7 +54,7 @@ int64_t PolygonUtils::segmentLength(PolygonsPointIndex start, PolygonsPointIndex return segment_length; } -void PolygonUtils::spreadDots(PolygonsPointIndex start, PolygonsPointIndex end, unsigned int n_dots, std::vector& result) +void PolygonUtils::spreadDots(PolygonsPointIndex start, PolygonsPointIndex end, unsigned int n_dots, std::vector& result) { assert(start.poly_idx_ == end.poly_idx_); int64_t segment_length = segmentLength(start, end); @@ -225,7 +225,7 @@ Point2LL PolygonUtils::getBoundaryPointWithOffset(const Polyline& poly, unsigned return poly[point_idx] + normal(getVertexInwardNormal(poly, point_idx), -offset); } -Point2LL PolygonUtils::moveInsideDiagonally(ClosestPoint point_on_boundary, int64_t inset) +Point2LL PolygonUtils::moveInsideDiagonally(ClosestPointPolygon point_on_boundary, int64_t inset) { if (! point_on_boundary.isValid()) { @@ -250,7 +250,7 @@ unsigned int PolygonUtils::moveOutside(const Shape& polygons, Point2LL& from, in return moveInside(polygons, from, -distance, maxDist2); } -ClosestPoint PolygonUtils::moveInside2( +ClosestPointPolygon PolygonUtils::moveInside2( const Shape& polygons, Point2LL& from, const int distance, @@ -259,7 +259,7 @@ ClosestPoint PolygonUtils::moveInside2( const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) { - std::optional closest_polygon_point; + std::optional closest_polygon_point; if (loc_to_line_grid) { closest_polygon_point = findClose(from, *loc_to_line_polygons, *loc_to_line_grid, penalty_function); @@ -271,7 +271,7 @@ ClosestPoint PolygonUtils::moveInside2( return _moveInside2(*closest_polygon_point, distance, from, max_dist2); } -ClosestPoint PolygonUtils::moveInside2( +ClosestPointPolygon PolygonUtils::moveInside2( const Shape& loc_to_line_polygons, const Polygon& polygon, Point2LL& from, @@ -280,7 +280,7 @@ ClosestPoint PolygonUtils::moveInside2( const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) { - std::optional closest_polygon_point; + std::optional closest_polygon_point; if (loc_to_line_grid) { closest_polygon_point = findClose(from, loc_to_line_polygons, *loc_to_line_grid, penalty_function); @@ -292,11 +292,11 @@ ClosestPoint PolygonUtils::moveInside2( return _moveInside2(*closest_polygon_point, distance, from, max_dist2); } -ClosestPoint PolygonUtils::_moveInside2(const ClosestPoint& closest_polygon_point, const int distance, Point2LL& from, const int64_t max_dist2) +ClosestPointPolygon PolygonUtils::_moveInside2(const ClosestPointPolygon& closest_polygon_point, const int distance, Point2LL& from, const int64_t max_dist2) { if (! closest_polygon_point.isValid()) { - return ClosestPoint(); // stub with invalid indices to signify we haven't found any + return ClosestPointPolygon(); // stub with invalid indices to signify we haven't found any } const Point2LL v_boundary_from = from - closest_polygon_point.location_; Point2LL result = moveInside(closest_polygon_point, distance); @@ -318,7 +318,7 @@ ClosestPoint PolygonUtils::_moveInside2(const ClosestPoint& closest_polygon_poin { if (vSize2(v_boundary_from) > max_dist2) { - return ClosestPoint(closest_polygon_point.poly_); // stub with invalid indices to signify we haven't found any + return ClosestPointPolygon(closest_polygon_point.poly_); // stub with invalid indices to signify we haven't found any } else { @@ -569,12 +569,12 @@ unsigned int PolygonUtils::moveInside(const Polygon& polygon, Point2LL& from, in return 0; } -Point2LL PolygonUtils::moveOutside(const ClosestPoint& cpp, const int distance) +Point2LL PolygonUtils::moveOutside(const ClosestPointPolygon& cpp, const int distance) { return moveInside(cpp, -distance); } -Point2LL PolygonUtils::moveInside(const ClosestPoint& cpp, const int distance) +Point2LL PolygonUtils::moveInside(const ClosestPointPolygon& cpp, const int distance) { if (! cpp.isValid()) { @@ -620,7 +620,7 @@ Point2LL PolygonUtils::moveInside(const ClosestPoint& cpp, const int distance) } } -ClosestPoint PolygonUtils::ensureInsideOrOutside( +ClosestPointPolygon PolygonUtils::ensureInsideOrOutside( const Shape& polygons, Point2LL& from, int preferred_dist_inside, @@ -629,14 +629,14 @@ ClosestPoint PolygonUtils::ensureInsideOrOutside( const LocToLineGrid* loc_to_line_grid, const std::function& penalty_function) { - const ClosestPoint closest_polygon_point = moveInside2(polygons, from, preferred_dist_inside, max_dist2, loc_to_line_polygons, loc_to_line_grid, penalty_function); + const ClosestPointPolygon closest_polygon_point = moveInside2(polygons, from, preferred_dist_inside, max_dist2, loc_to_line_polygons, loc_to_line_grid, penalty_function); return ensureInsideOrOutside(polygons, from, closest_polygon_point, preferred_dist_inside, loc_to_line_polygons, loc_to_line_grid, penalty_function); } -ClosestPoint PolygonUtils::ensureInsideOrOutside( +ClosestPointPolygon PolygonUtils::ensureInsideOrOutside( const Shape& polygons, Point2LL& from, - const ClosestPoint& closest_polygon_point, + const ClosestPointPolygon& closest_polygon_point, int preferred_dist_inside, const Shape* loc_to_line_polygons, const LocToLineGrid* loc_to_line_grid, @@ -644,7 +644,7 @@ ClosestPoint PolygonUtils::ensureInsideOrOutside( { if (! closest_polygon_point.isValid()) { - return ClosestPoint(); // we couldn't move inside + return ClosestPointPolygon(); // we couldn't move inside } const Polygon& closest_poly = *closest_polygon_point.poly_; bool is_outside_boundary = closest_poly.orientation(); @@ -678,9 +678,9 @@ ClosestPoint PolygonUtils::ensureInsideOrOutside( = closest_poly.offset(offset / 2); // perform less inset, because chances are (thin parts of) the polygon will disappear, given that moveInside did an overshoot if (insetted.size() == 0) { - return ClosestPoint(); // we couldn't move inside + return ClosestPointPolygon(); // we couldn't move inside } - ClosestPoint inside = findClosest(from, insetted, penalty_function); + ClosestPointPolygon inside = findClosest(from, insetted, penalty_function); if (inside.isValid()) { bool is_inside = polygons.inside(inside.location_); @@ -689,7 +689,7 @@ ClosestPoint PolygonUtils::ensureInsideOrOutside( // Insetting from the reference polygon ended up outside another polygon. // Perform an offset on all polygons instead. Shape all_insetted = polygons.offset(-preferred_dist_inside); - ClosestPoint overall_inside = findClosest(from, all_insetted, penalty_function); + ClosestPointPolygon overall_inside = findClosest(from, all_insetted, penalty_function); bool overall_is_inside = polygons.inside(overall_inside.location_); if (overall_is_inside != (preferred_dist_inside > 0)) { @@ -737,7 +737,7 @@ ClosestPoint PolygonUtils::ensureInsideOrOutside( has_run = true; } #endif - return ClosestPoint(); + return ClosestPointPolygon(); } inside = overall_inside; } @@ -747,7 +747,7 @@ ClosestPoint PolygonUtils::ensureInsideOrOutside( } } -void PolygonUtils::walkToNearestSmallestConnection(ClosestPoint& poly1_result, ClosestPoint& poly2_result) +void PolygonUtils::walkToNearestSmallestConnection(ClosestPointPolygon& poly1_result, ClosestPointPolygon& poly2_result) { if (! poly1_result.isValid() || ! poly2_result.isValid()) { @@ -785,10 +785,10 @@ void PolygonUtils::walkToNearestSmallestConnection(ClosestPoint& poly1_result, C // o o >> should find connection here coord_t best_distance2 = vSize2(poly1_result.p() - poly2_result.p()); auto check_neighboring_vert - = [&best_distance2](const Polygon& from_poly, const Polygon& to_poly, ClosestPoint& from_poly_result, ClosestPoint& to_poly_result, bool vertex_after) + = [&best_distance2](const Polygon& from_poly, const Polygon& to_poly, ClosestPointPolygon& from_poly_result, ClosestPointPolygon& to_poly_result, bool vertex_after) { const Point2LL after_poly2_result = to_poly[(to_poly_result.point_idx_ + vertex_after) % to_poly.size()]; - const ClosestPoint poly1_after_poly2_result = findNearestClosest(after_poly2_result, from_poly, from_poly_result.point_idx_); + const ClosestPointPolygon poly1_after_poly2_result = findNearestClosest(after_poly2_result, from_poly, from_poly_result.point_idx_); const coord_t poly1_after_poly2_result_dist2 = vSize2(poly1_after_poly2_result.p() - after_poly2_result); if (poly1_after_poly2_result_dist2 < best_distance2) { @@ -806,14 +806,14 @@ void PolygonUtils::walkToNearestSmallestConnection(ClosestPoint& poly1_result, C poly2_result.poly_idx_ = poly2_idx; } -ClosestPoint PolygonUtils::findNearestClosest(Point2LL from, const Polygon& polygon, int start_idx) +ClosestPointPolygon PolygonUtils::findNearestClosest(Point2LL from, const Polygon& polygon, int start_idx) { - ClosestPoint forth = findNearestClosest(from, polygon, start_idx, 1); + ClosestPointPolygon forth = findNearestClosest(from, polygon, start_idx, 1); if (! forth.isValid()) { return forth; // stop computation } - ClosestPoint back = findNearestClosest(from, polygon, start_idx, -1); + ClosestPointPolygon back = findNearestClosest(from, polygon, start_idx, -1); assert(back.isValid()); if (vSize2(forth.location_ - from) < vSize2(back.location_ - from)) { @@ -825,11 +825,11 @@ ClosestPoint PolygonUtils::findNearestClosest(Point2LL from, const Polygon& poly } } -ClosestPoint PolygonUtils::findNearestClosest(Point2LL from, const Polygon& polygon, int start_idx, int direction) +ClosestPointPolygon PolygonUtils::findNearestClosest(Point2LL from, const Polygon& polygon, int start_idx, int direction) { if (polygon.size() == 0) { - return ClosestPoint(&polygon); + return ClosestPointPolygon(&polygon); } Point2LL aPoint = polygon[0]; Point2LL best = aPoint; @@ -855,16 +855,16 @@ ClosestPoint PolygonUtils::findNearestClosest(Point2LL from, const Polygon& poly } else { - return ClosestPoint(best, bestPos, &polygon); + return ClosestPointPolygon(best, bestPos, &polygon); } } - return ClosestPoint(best, bestPos, &polygon); + return ClosestPointPolygon(best, bestPos, &polygon); } -ClosestPoint PolygonUtils::findClosest(Point2LL from, const Shape& polygons, const std::function& penalty_function) +ClosestPointPolygon PolygonUtils::findClosest(Point2LL from, const Shape& polygons, const std::function& penalty_function) { - ClosestPoint none; + ClosestPointPolygon none; if (polygons.size() == 0) { @@ -884,7 +884,7 @@ ClosestPoint PolygonUtils::findClosest(Point2LL from, const Shape& polygons, con { return none; } - ClosestPoint best((*any_polygon)[0], 0, any_polygon, any_poly_idx); + ClosestPointPolygon best((*any_polygon)[0], 0, any_polygon, any_poly_idx); int64_t closestDist2_score = vSize2(from - best.location_) + penalty_function(best.location_); @@ -893,7 +893,7 @@ ClosestPoint PolygonUtils::findClosest(Point2LL from, const Shape& polygons, con const Polygon& poly = polygons[ply]; if (poly.size() == 0) continue; - ClosestPoint closest_here = findClosest(from, poly, penalty_function); + ClosestPointPolygon closest_here = findClosest(from, poly, penalty_function); if (! closest_here.isValid()) { continue; @@ -910,11 +910,11 @@ ClosestPoint PolygonUtils::findClosest(Point2LL from, const Shape& polygons, con return best; } -ClosestPoint PolygonUtils::findClosest(Point2LL from, const Polygon& polygon, const std::function& penalty_function) +ClosestPointPolygon PolygonUtils::findClosest(Point2LL from, const Polygon& polygon, const std::function& penalty_function) { if (polygon.size() == 0) { - return ClosestPoint(&polygon); + return ClosestPointPolygon(&polygon); } Point2LL aPoint = polygon[0]; Point2LL best = aPoint; @@ -941,7 +941,7 @@ ClosestPoint PolygonUtils::findClosest(Point2LL from, const Polygon& polygon, co } } - return ClosestPoint(best, bestPos, &polygon); + return ClosestPointPolygon(best, bestPos, &polygon); } PolygonsPointIndex PolygonUtils::findNearestVert(const Point2LL from, const Shape& polys) @@ -1008,7 +1008,7 @@ std::unique_ptr PolygonUtils::createLocToLineGrid(const Shape& po * * We could skip the duplication by keeping a vector of vectors of bools. */ -std::optional PolygonUtils::findClose(Point2LL from, const Shape& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function) +std::optional PolygonUtils::findClose(Point2LL from, const Shape& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function) { std::vector near_lines = loc_to_line.getNearby(from, loc_to_line.getCellSize()); @@ -1033,28 +1033,28 @@ std::optional PolygonUtils::findClose(Point2LL from, const Shape& } if (best_point_poly_idx.poly_idx_ == NO_INDEX) { - return std::optional(); + return std::optional(); } else { - return std::optional(std::in_place, best, best_point_poly_idx.point_idx_, &(polygons[best_point_poly_idx.poly_idx_]), best_point_poly_idx.poly_idx_); + return std::optional(std::in_place, best, best_point_poly_idx.point_idx_, &(polygons[best_point_poly_idx.poly_idx_]), best_point_poly_idx.poly_idx_); } } -std::vector> +std::vector> PolygonUtils::findClose(const Polygon& from, const Shape& destination, const LocToLineGrid& destination_loc_to_line, const std::function& penalty_function) { - std::vector> ret; + std::vector> ret; int p0_idx = from.size() - 1; Point2LL p0(from[p0_idx]); int grid_size = destination_loc_to_line.getCellSize(); for (unsigned int p1_idx = 0; p1_idx < from.size(); p1_idx++) { const Point2LL& p1 = from[p1_idx]; - std::optional best_here = findClose(p1, destination, destination_loc_to_line, penalty_function); + std::optional best_here = findClose(p1, destination, destination_loc_to_line, penalty_function); if (best_here) { - ret.push_back(std::make_pair(ClosestPoint(p1, p1_idx, &from), *best_here)); + ret.push_back(std::make_pair(ClosestPointPolygon(p1, p1_idx, &from), *best_here)); } Point2LL p0p1 = p1 - p0; int dist_to_p1 = vSize(p0p1); @@ -1066,7 +1066,7 @@ std::vector> best_here = findClose(x, destination, destination_loc_to_line, penalty_function); if (best_here) { - ret.push_back(std::make_pair(ClosestPoint(x, p0_idx, &from), *best_here)); + ret.push_back(std::make_pair(ClosestPointPolygon(x, p0_idx, &from), *best_here)); } } p0 = p1; @@ -1150,7 +1150,7 @@ bool PolygonUtils::getNextPointWithDistance(Point2LL from, int64_t dist, const O } template -GenericClosestPoint PolygonUtils::walk(const GenericClosestPoint& from, coord_t distance) +ClosestPoint PolygonUtils::walk(const ClosestPoint& from, coord_t distance) { const LineType& poly = *from.poly_; Point2LL last_vertex = from.p(); @@ -1170,10 +1170,10 @@ GenericClosestPoint PolygonUtils::walk(const GenericClosestPoint(result, last_point_idx, &poly, from.poly_idx_); + return ClosestPoint(result, last_point_idx, &poly, from.poly_idx_); } -std::optional PolygonUtils::getNextParallelIntersection(const ClosestPoint& start, const Point2LL& line_to, const coord_t dist, const bool forward) +std::optional PolygonUtils::getNextParallelIntersection(const ClosestPointPolygon& start, const Point2LL& line_to, const coord_t dist, const bool forward) { // <--o--t-----y----< poly 1 // : : @@ -1221,14 +1221,14 @@ std::optional PolygonUtils::getNextParallelIntersection(const Clos vert_before_idx = (next_point_idx > 0) ? vert_before_idx - 1 : poly.size() - 1; } assert(vert_before_idx < poly.size()); - return ClosestPoint(intersection, vert_before_idx, &poly); + return ClosestPointPolygon(intersection, vert_before_idx, &poly); } prev_vert = next_vert; prev_projected = projected; } - return std::optional(); + return std::optional(); } @@ -1686,7 +1686,7 @@ Shape PolygonUtils::generateInset(const Shape& outer_poly, coord_t line_width, c return inset; } -template GenericClosestPoint PolygonUtils::walk(const GenericClosestPoint& from, coord_t distance); -template GenericClosestPoint PolygonUtils::walk(const GenericClosestPoint& from, coord_t distance); +template ClosestPoint PolygonUtils::walk(const ClosestPoint& from, coord_t distance); +template ClosestPoint PolygonUtils::walk(const ClosestPoint& from, coord_t distance); } // namespace cura diff --git a/tests/utils/PolygonUtilsTest.cpp b/tests/utils/PolygonUtilsTest.cpp index 1758d3b495..1b1cf91f83 100644 --- a/tests/utils/PolygonUtilsTest.cpp +++ b/tests/utils/PolygonUtilsTest.cpp @@ -56,7 +56,7 @@ class MoveInsideTest : public testing::TestWithParam TEST_P(MoveInsideTest, MoveInside) { const MoveInsideParameters parameters = GetParam(); - const ClosestPoint cpp = PolygonUtils::findClosest(parameters.close_to, test_square); + const ClosestPointPolygon cpp = PolygonUtils::findClosest(parameters.close_to, test_square); Point2LL result = PolygonUtils::moveInside(cpp, parameters.distance); // FIXME: Clean-up message with ftm when CURA-8258 is implemented or when we use C++20 @@ -99,7 +99,7 @@ TEST_F(MoveInsideTest, cornerEdgeTest) const Point2LL supposed1(80, 80); // Allow two possible values here, since the behaviour for this edge case is not specified. const Point2LL supposed2(72, 100); constexpr coord_t distance = 28; - const ClosestPoint cpp = PolygonUtils::findClosest(close_to, test_square); + const ClosestPointPolygon cpp = PolygonUtils::findClosest(close_to, test_square); const Point2LL result = PolygonUtils::moveInside(cpp, distance); constexpr coord_t maximum_error = 10; @@ -120,7 +120,7 @@ TEST_F(MoveInsideTest, middleTest) const Point2LL supposed3(20, 50); const Point2LL supposed4(50, 20); constexpr coord_t distance = 20; - const ClosestPoint cpp = PolygonUtils::findClosest(close_to, test_square); + const ClosestPointPolygon cpp = PolygonUtils::findClosest(close_to, test_square); const Point2LL result = PolygonUtils::moveInside(cpp, distance); constexpr coord_t maximum_error = 10; @@ -142,7 +142,7 @@ TEST_F(MoveInsideTest, middleTestPenalty) const Point2LL supposed(80, 50); const Point2LL preferred_dir(120, 60); constexpr coord_t distance = 20; - const ClosestPoint cpp = PolygonUtils::findClosest( + const ClosestPointPolygon cpp = PolygonUtils::findClosest( close_to, test_square, [preferred_dir](Point2LL candidate) @@ -180,7 +180,7 @@ TEST_F(MoveInsideTest, pointyCorner) Point2LL result(from); Shape inside; inside.add(pointy_square); - ClosestPoint cpp = PolygonUtils::ensureInsideOrOutside(inside, result, 10); + ClosestPointPolygon cpp = PolygonUtils::ensureInsideOrOutside(inside, result, 10); ASSERT_NE(cpp.point_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_NE(cpp.poly_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; @@ -195,7 +195,7 @@ TEST_F(MoveInsideTest, pointyCornerFail) Shape inside; inside.add(pointy_square); - ClosestPoint cpp = PolygonUtils::moveInside2(inside, result, 10); + ClosestPointPolygon cpp = PolygonUtils::moveInside2(inside, result, 10); ASSERT_NE(cpp.point_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_NE(cpp.poly_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_FALSE(inside.inside(result)) << from << " could be moved inside, while it was designed to fail."; @@ -209,7 +209,7 @@ TEST_F(MoveInsideTest, outsidePointyCorner) Shape inside; inside.add(pointy_square); - const ClosestPoint cpp = PolygonUtils::ensureInsideOrOutside(inside, result, -10); + const ClosestPointPolygon cpp = PolygonUtils::ensureInsideOrOutside(inside, result, -10); ASSERT_NE(cpp.point_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_NE(cpp.poly_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_TRUE(! inside.inside(result)) << from << " couldn't be moved outside."; @@ -224,7 +224,7 @@ TEST_F(MoveInsideTest, outsidePointyCornerFail) Shape inside; inside.add(pointy_square); - const ClosestPoint cpp = PolygonUtils::moveInside2(inside, result, -10); + const ClosestPointPolygon cpp = PolygonUtils::moveInside2(inside, result, -10); ASSERT_NE(cpp.point_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_NE(cpp.poly_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; ASSERT_FALSE(! inside.inside(result)) << from << " could be moved outside to " << result << ", while it was designed to fail."; @@ -269,7 +269,7 @@ TEST_P(FindCloseTest, FindClose) polygons.add(test_square); auto loc_to_line = PolygonUtils::createLocToLineGrid(polygons, parameters.cell_size); - std::optional cpp; + std::optional cpp; if (parameters.penalty_function) { cpp = PolygonUtils::findClose(parameters.close_to, polygons, *loc_to_line, *parameters.penalty_function); @@ -341,12 +341,12 @@ class PolygonUtilsTest : public testing::Test TEST_F(PolygonUtilsTest, spreadDotsSegment) { - std::vector supposed; + std::vector supposed; supposed.emplace_back(Point2LL(50, 0), 0, test_squares[0], 0); supposed.emplace_back(Point2LL(100, 0), 1, test_squares[0], 0); supposed.emplace_back(Point2LL(100, 50), 1, test_squares[0], 0); - std::vector result; + std::vector result; PolygonUtils::spreadDots(PolygonsPointIndex(&test_squares, 0, 0), PolygonsPointIndex(&test_squares, 0, 2), 3, result); ASSERT_EQ(result.size(), supposed.size()); @@ -358,7 +358,7 @@ TEST_F(PolygonUtilsTest, spreadDotsSegment) TEST_F(PolygonUtilsTest, spreadDotsFull) { - std::vector supposed; + std::vector supposed; supposed.emplace_back(Point2LL(0, 0), 0, test_squares[0], 0); supposed.emplace_back(Point2LL(50, 0), 0, test_squares[0], 0); supposed.emplace_back(Point2LL(100, 0), 1, test_squares[0], 0); @@ -368,7 +368,7 @@ TEST_F(PolygonUtilsTest, spreadDotsFull) supposed.emplace_back(Point2LL(0, 100), 3, test_squares[0], 0); supposed.emplace_back(Point2LL(0, 50), 3, test_squares[0], 0); - std::vector result; + std::vector result; PolygonUtils::spreadDots(PolygonsPointIndex(&test_squares, 0, 0), PolygonsPointIndex(&test_squares, 0, 0), 8, result); ASSERT_EQ(result.size(), supposed.size()); @@ -416,8 +416,8 @@ class GetNextParallelIntersectionTest : public testing::TestWithParam computed = PolygonUtils::getNextParallelIntersection(start, parameters.line_to, parameters.dist, parameters.forward); + const ClosestPointPolygon start = PolygonUtils::findClosest(parameters.start_point, test_squares); + std::optional computed = PolygonUtils::getNextParallelIntersection(start, parameters.line_to, parameters.dist, parameters.forward); ASSERT_EQ(bool(parameters.predicted), bool(computed)) << "An answer was predicted but not computed, or computed but not predicted."; if (parameters.predicted) From 2e82935e6c0d2d81a812c842ef88206a938099a0 Mon Sep 17 00:00:00 2001 From: wawanbreton Date: Thu, 11 Apr 2024 08:15:54 +0000 Subject: [PATCH 029/135] Applied clang-format. --- src/utils/polygonUtils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index 8153a96869..e4371f5d6d 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -1008,7 +1008,8 @@ std::unique_ptr PolygonUtils::createLocToLineGrid(const Shape& po * * We could skip the duplication by keeping a vector of vectors of bools. */ -std::optional PolygonUtils::findClose(Point2LL from, const Shape& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function) +std::optional + PolygonUtils::findClose(Point2LL from, const Shape& polygons, const LocToLineGrid& loc_to_line, const std::function& penalty_function) { std::vector near_lines = loc_to_line.getNearby(from, loc_to_line.getCellSize()); From f05f5386c7fb2226d3630cebc429ee35f1850eb4 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 11 Apr 2024 11:01:19 +0200 Subject: [PATCH 030/135] Make line-overlap detection more conservative. (Tried a lot of other things as well, which makes it less predictable.) Clean up experiments, bring it back to basics, be quite conservative as this is only a patch and solving the whole 'scan-segments can be too close to the connector paths' probably requires properly rewriting the zig-zag algorithm -- which is way more like a feature. part of CURA-11597 --- include/infill/ZigzagConnectorProcessor.h | 2 ++ src/infill.cpp | 2 +- src/infill/ZigzagConnectorProcessor.cpp | 24 +++++++++++------------ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/include/infill/ZigzagConnectorProcessor.h b/include/infill/ZigzagConnectorProcessor.h index 9adb751430..9b1b979cf6 100644 --- a/include/infill/ZigzagConnectorProcessor.h +++ b/include/infill/ZigzagConnectorProcessor.h @@ -175,6 +175,8 @@ class ZigzagConnectorProcessor */ void addZagConnector(std::vector& points, bool is_endpiece); + bool handleConnectorToCloseToSegment(const coord_t scanline_x, const coord_t min_distance_to_scanline); + protected: const PointMatrix& rotation_matrix_; //!< The rotation matrix used to enforce the infill angle Polygons& result_; //!< The result of the computation diff --git a/src/infill.cpp b/src/infill.cpp index 715cce1c61..7164da9741 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -751,7 +751,7 @@ void Infill::generateLinearBasedInfill( assert(scanline_idx - scanline_min_idx >= 0 && scanline_idx - scanline_min_idx < int(cut_list.size()) && "reading infill cutlist index out of bounds!"); cut_list[scanline_idx - scanline_min_idx].push_back(y); Point2LL scanline_linesegment_intersection(x, y); - zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, line_distance / 2); + zigzag_connector_processor.registerScanlineSegmentIntersection(scanline_linesegment_intersection, scanline_idx, line_distance / 4); crossings_per_scanline[scanline_idx - min_scanline_index].emplace_back(scanline_linesegment_intersection, poly_idx, point_idx); } zigzag_connector_processor.registerVertex(p1); diff --git a/src/infill/ZigzagConnectorProcessor.cpp b/src/infill/ZigzagConnectorProcessor.cpp index 315735bb9a..c19cd46b4e 100644 --- a/src/infill/ZigzagConnectorProcessor.cpp +++ b/src/infill/ZigzagConnectorProcessor.cpp @@ -83,6 +83,15 @@ bool ZigzagConnectorProcessor::shouldAddCurrentConnector(int start_scanline_idx, return should_add; } +bool ZigzagConnectorProcessor::handleConnectorToCloseToSegment(const coord_t scanline_x, const coord_t min_distance_to_scanline) +{ + bool all_within_min_dist = ! current_connector_.empty(); + for (const auto& point : current_connector_) + { + all_within_min_dist &= std::abs(point.X - scanline_x) < min_distance_to_scanline; + } + return all_within_min_dist; +} void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index, coord_t min_distance_to_scanline) { @@ -97,20 +106,11 @@ void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2L else { // add the current connector if needed - if (shouldAddCurrentConnector(last_connector_index_, scanline_index)) + if (shouldAddCurrentConnector(last_connector_index_, scanline_index) && ! handleConnectorToCloseToSegment(intersection.X, min_distance_to_scanline)) { const bool is_this_endpiece = scanline_index == last_connector_index_; - bool close_to_line_except_intersect = true; - const coord_t min_dist2 = min_distance_to_scanline * min_distance_to_scanline; - for (const auto& point : current_connector_) - { - close_to_line_except_intersect &= std::abs(point.X - intersection.X) < min_distance_to_scanline; - } - if (current_connector_.empty() || ! close_to_line_except_intersect) - { - current_connector_.push_back(intersection); - addZagConnector(current_connector_, is_this_endpiece); - } + current_connector_.push_back(intersection); + addZagConnector(current_connector_, is_this_endpiece); } } From 449c209cda975a42c37f104286dc3b0443e97db9 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 11 Apr 2024 11:28:24 +0200 Subject: [PATCH 031/135] Only split up densities _completely_ when we zig-zaggify infill. Only do the new split-up in the rare cases where stuff goes wrong for now (= gradual fills + connected fill lines). We're not adjusting the percentages for not doubling/tripling/etc over an area anymore, since that would change too much at this juncture, make it less predicatble which lines in the layer below match up, and we have more walls anyway because of the zig-zagging. part of CURA-11597 --- src/skin.cpp | 8 ++++++-- src/support.cpp | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/skin.cpp b/src/skin.cpp index e342b58554..1bd59d165a 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -471,6 +471,7 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) const auto infill_wall_count = mesh.settings.get("infill_wall_line_count"); const auto infill_wall_width = mesh.settings.get("infill_line_width"); const auto infill_overlap = mesh.settings.get("infill_overlap_mm"); + const auto is_connected = mesh.settings.get("zig_zaggify_infill") || mesh.settings.get("infill_pattern") == EFillMethod::ZIG_ZAG; for (LayerIndex layer_idx = 0; layer_idx < static_cast(mesh.layers.size()); layer_idx++) { // loop also over layers which don't contain infill cause of bottom_ and top_layer to initialize their infill_area_per_combine_per_density SliceLayer& layer = mesh.layers[layer_idx]; @@ -497,7 +498,7 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) continue; } Polygons less_dense_infill = infill_area; // one step less dense with each infill_step - Polygons sum_more_dense; + Polygons sum_more_dense; // NOTE: Only used for zig-zag or connected fills. for (size_t infill_step = 0; infill_step < max_infill_steps; infill_step++) { LayerIndex min_layer = layer_idx + infill_step * gradual_infill_step_layer_count + static_cast(layer_skip_count); @@ -532,7 +533,10 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) const Polygons more_dense_infill = infill_area.difference(less_dense_infill); infill_area_per_combine_current_density.push_back( simplifier.polygon(more_dense_infill.difference(sum_more_dense).offset(-infill_wall_width).offset(infill_wall_width))); - sum_more_dense = sum_more_dense.unionPolygons(more_dense_infill); + if (is_connected) + { + sum_more_dense = sum_more_dense.unionPolygons(more_dense_infill); + } } part.infill_area_per_combine_per_density.emplace_back(); std::vector& infill_area_per_combine_current_density = part.infill_area_per_combine_per_density.back(); diff --git a/src/support.cpp b/src/support.cpp index e8546c55f0..4954501e0a 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -187,6 +187,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) const size_t max_density_steps = infill_extruder.settings_.get("gradual_support_infill_steps"); const coord_t wall_width = infill_extruder.settings_.get("support_line_width"); + const bool is_connected = infill_extruder.settings_.get("zig_zaggify_infill") || infill_extruder.settings_.get("infill_pattern") == EFillMethod::ZIG_ZAG; const Simplify simplifier(infill_extruder.settings_); // no early-out for this function; it needs to initialize the [infill_area_per_combine_per_density] @@ -235,7 +236,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) // calculate density areas for this island Polygons less_dense_support = infill_area; // one step less dense with each density_step - Polygons sum_more_dense; + Polygons sum_more_dense; // NOTE: Only used for zig-zag or connected fills. for (unsigned int density_step = 0; density_step < max_density_steps; ++density_step) { LayerIndex actual_min_layer{ layer_nr + density_step * gradual_support_step_layer_count + static_cast(layer_skip_count) }; @@ -295,7 +296,10 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); const Polygons more_dense_support = infill_area.difference(less_dense_support); support_area_current_density.push_back(simplifier.polygon(more_dense_support.difference(sum_more_dense).offset(-wall_width).offset(wall_width))); - sum_more_dense = sum_more_dense.unionPolygons(more_dense_support); + if (is_connected) + { + sum_more_dense = sum_more_dense.unionPolygons(more_dense_support); + } } support_infill_part.infill_area_per_combine_per_density_.emplace_back(); From 6592e502ead8022d6906d2643213706f54c3c880 Mon Sep 17 00:00:00 2001 From: rburema Date: Thu, 11 Apr 2024 09:29:36 +0000 Subject: [PATCH 032/135] Applied clang-format. --- src/skin.cpp | 2 +- src/support.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/skin.cpp b/src/skin.cpp index 1bd59d165a..32469b2766 100644 --- a/src/skin.cpp +++ b/src/skin.cpp @@ -498,7 +498,7 @@ void SkinInfillAreaComputation::generateGradualInfill(SliceMeshStorage& mesh) continue; } Polygons less_dense_infill = infill_area; // one step less dense with each infill_step - Polygons sum_more_dense; // NOTE: Only used for zig-zag or connected fills. + Polygons sum_more_dense; // NOTE: Only used for zig-zag or connected fills. for (size_t infill_step = 0; infill_step < max_infill_steps; infill_step++) { LayerIndex min_layer = layer_idx + infill_step * gradual_infill_step_layer_count + static_cast(layer_skip_count); diff --git a/src/support.cpp b/src/support.cpp index 4954501e0a..bafce3e6f2 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -236,7 +236,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) // calculate density areas for this island Polygons less_dense_support = infill_area; // one step less dense with each density_step - Polygons sum_more_dense; // NOTE: Only used for zig-zag or connected fills. + Polygons sum_more_dense; // NOTE: Only used for zig-zag or connected fills. for (unsigned int density_step = 0; density_step < max_density_steps; ++density_step) { LayerIndex actual_min_layer{ layer_nr + density_step * gradual_support_step_layer_count + static_cast(layer_skip_count) }; From eeec9636f7b3f749b790a1bea4c2901196cee027 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Thu, 11 Apr 2024 11:34:17 +0200 Subject: [PATCH 033/135] Morphologic opening operation was causing floating areas. Introduced earlier in this PR to solve some edge cases, but more trouble than it's worth it seems, at the very least when it's for support. part of CURA-11597 --- src/support.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/support.cpp b/src/support.cpp index bafce3e6f2..f5ad514faa 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -295,7 +295,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) support_infill_part.infill_area_per_combine_per_density_.emplace_back(); std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); const Polygons more_dense_support = infill_area.difference(less_dense_support); - support_area_current_density.push_back(simplifier.polygon(more_dense_support.difference(sum_more_dense).offset(-wall_width).offset(wall_width))); + support_area_current_density.push_back(simplifier.polygon(more_dense_support.difference(sum_more_dense))); if (is_connected) { sum_more_dense = sum_more_dense.unionPolygons(more_dense_support); @@ -304,7 +304,7 @@ void AreaSupport::generateGradualSupport(SliceDataStorage& storage) support_infill_part.infill_area_per_combine_per_density_.emplace_back(); std::vector& support_area_current_density = support_infill_part.infill_area_per_combine_per_density_.back(); - support_area_current_density.push_back(simplifier.polygon(infill_area.difference(sum_more_dense).offset(-wall_width).offset(wall_width))); + support_area_current_density.push_back(simplifier.polygon(infill_area.difference(sum_more_dense))); assert(support_infill_part.infill_area_per_combine_per_density_.size() != 0 && "support_infill_part.infill_area_per_combine_per_density should now be initialized"); #ifdef DEBUG From 53e566bc520ddb135e5bf24fef643f3525e3b8d5 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 11 Apr 2024 12:36:48 +0200 Subject: [PATCH 034/135] Fixed some possible issues CURA-9830 --- include/geometry/polyline.h | 17 +++++------------ src/SkirtBrim.cpp | 7 +------ src/infill.cpp | 3 --- src/utils/PolylineStitcher.cpp | 2 -- src/utils/mixed_polyline_stitcher.cpp | 1 - 5 files changed, 6 insertions(+), 24 deletions(-) diff --git a/include/geometry/polyline.h b/include/geometry/polyline.h index 8f7a162f35..6473811083 100644 --- a/include/geometry/polyline.h +++ b/include/geometry/polyline.h @@ -19,12 +19,12 @@ class OpenPolyline; * \brief Base class for various types of polylines. A polyline is basically a set of points, but * we geometrically interpret them forming a chain of segments between each other. * - * * Open Polyline : this represents a line that does not closes, i.e. the last point is different - * from the initial point + * * Open Polyline : this represents a line that does not close, i.e. the last point is different + * from the initial point (think of the U letter) * * Closed Polyline : a closed polyline has a final segment joining the last point and the - * initial one - * * Filled Polyline : this is a particular type of closed polyline, for which we consider that the - * "inside" part of the line forms a surface + * initial one (think of the O letter) + * * Polygon : this is a particular type of closed polyline, for which we consider that the + * "inside" part of the line forms a surface * * \note Historically, the open and closed polylines were not explicitely differenciated, so * sometimes we would use an open polyline with an extra point at the end, which virtually @@ -134,13 +134,6 @@ class Polyline : public PointsSet */ void simplify(const coord_t smallest_line_segment_squared = MM2INT(0.01) * MM2INT(0.01), const coord_t allowed_error_distance_squared = 25); - /*void pseudoClose() - { - if (size() >= 2) - { - push_back(front()); - } - }*/ private: /*! diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 13f691c178..cee9bc4caf 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -242,12 +242,7 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std const int reference_idx = std::get(offset.reference_outline_or_index_); const coord_t offset_dist = extruder_config.line_width_; - Shape local_brim = storage_.skirt_brim[offset.extruder_nr_][reference_idx].offset(offset_dist, ClipperLib::jtRound); - -#warning Is this required now we do all the offsetting in one pass ? - local_brim.unionPolygons(); - - brim.push_back(local_brim); + brim.push_back(storage_.skirt_brim[offset.extruder_nr_][reference_idx].offset(offset_dist, ClipperLib::jtRound)); } // limit brim lines to allowed areas, stitch them and store them in the result diff --git a/src/infill.cpp b/src/infill.cpp index 6f15f2a1c1..b1e0ca40a4 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -540,10 +540,7 @@ void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provid else { // make the polyline closed in order to handle cross_pattern_polygon as a polyline, rather than a closed polygon - cross_pattern_polygon.push_back(cross_pattern_polygon[0]); - LinesSet cross_pattern_polylines; -#warning No sure we should add the last point in this case cross_pattern_polylines.push_back(cross_pattern_polygon.toPseudoOpenPolyline()); LinesSet poly_lines = inner_contour_.intersection(cross_pattern_polylines); OpenPolylineStitcher::stitch(poly_lines, result_lines, result_polygons, infill_line_width_); diff --git a/src/utils/PolylineStitcher.cpp b/src/utils/PolylineStitcher.cpp index efc78b15c9..49e632647d 100644 --- a/src/utils/PolylineStitcher.cpp +++ b/src/utils/PolylineStitcher.cpp @@ -284,14 +284,12 @@ void ExtrusionLineStitcher::pushToClosedResult(VariableWidthLines& result_polygo template<> void OpenPolylineStitcher::pushToClosedResult(Shape& result_polygons, const OpenPolyline& polyline) { -#warning Check whether the polyline is explicitely closed result_polygons.emplace_back(polyline.getPoints(), true); } template<> void PolylineStitcher::pushToClosedResult(ClosedLinesSet& result_polygons, const OpenPolyline& polyline) { -#warning Check whether the polyline is explicitely closed result_polygons.emplace_back(polyline.getPoints(), true); } diff --git a/src/utils/mixed_polyline_stitcher.cpp b/src/utils/mixed_polyline_stitcher.cpp index 85e3e017b9..8095231d73 100644 --- a/src/utils/mixed_polyline_stitcher.cpp +++ b/src/utils/mixed_polyline_stitcher.cpp @@ -23,7 +23,6 @@ void MixedPolylineStitcher::stitch(const LinesSet& lines, MixedLin { // Base stitch method will create explicitely closed polylines, but won't tag them as such // because it is a generic algorithm. Tag them now. -#warning Make sure that what is said here is true closed_line.setExplicitelyClosed(true); } From a25fadaf73a0f1b1639f00007945d0956f7749c5 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Thu, 11 Apr 2024 15:36:07 +0200 Subject: [PATCH 035/135] Code cleaning CURA-9830 --- include/geometry/closed_polyline.h | 12 +- include/geometry/mixed_lines_set.h | 53 +- include/geometry/points_set.h | 8 +- include/geometry/polyline.h | 12 +- include/geometry/shape.h | 10 +- include/geometry/single_shape.h | 1 - src/FffGcodeWriter.cpp | 2 +- src/SkirtBrim.cpp | 2 +- src/geometry/closed_polyline.cpp | 12 + src/geometry/mixed_lines_set.cpp | 21 +- src/geometry/parts_view.cpp | 1 + src/geometry/points_set.cpp | 1 - src/geometry/polygon.cpp | 23 +- src/geometry/shape.cpp | 69 +- src/geometry/single_shape.cpp | 2 + src/multiVolumes.cpp | 1 + src/utils/Simplify.cpp | 2 +- src/utils/mixed_polyline_stitcher.cpp | 1 + src/utils/polygon.cpp | 1727 ------------------------- tests/InfillTest.cpp | 2 +- tests/LayerPlanTest.cpp | 60 +- tests/utils/AABBTest.cpp | 9 +- 22 files changed, 140 insertions(+), 1891 deletions(-) delete mode 100644 src/utils/polygon.cpp diff --git a/include/geometry/closed_polyline.h b/include/geometry/closed_polyline.h index 10db68cab3..f05f353ee2 100644 --- a/include/geometry/closed_polyline.h +++ b/include/geometry/closed_polyline.h @@ -50,17 +50,7 @@ class ClosedPolyline : public Polyline return ! explicitely_closed_; } - virtual size_t segmentsCount() const override - { - if (explicitely_closed_) - { - return size() >= 3 ? size() - 1 : 0; - } - else - { - return size() >= 2 ? size() : 0; - } - } + virtual size_t segmentsCount() const override; ClosedPolyline& operator=(const ClosedPolyline& other) { diff --git a/include/geometry/mixed_lines_set.h b/include/geometry/mixed_lines_set.h index a6d17bafb9..d67144bd69 100644 --- a/include/geometry/mixed_lines_set.h +++ b/include/geometry/mixed_lines_set.h @@ -19,37 +19,70 @@ class Shape; template class LinesSet; +using PolylinePtr = std::shared_ptr; +using OpenPolylinePtr = std::shared_ptr; /*! - * \brief Convenience definition for a container that can hold either open or closed polylines. + * \brief Convenience definition for a container that can hold any type of polyline. */ -class MixedLinesSet : public std::vector> +class MixedLinesSet : public std::vector { public: + /*! + * \brief Computes the offset of all the polylines contained in the set. The polylines may + * be of different types, and polylines are polygons are treated differently. + * \param distance The distance to increase the polylines from, or decrase if negative + * \param join_type The type of tip joint to be used (for open polylines only) + * \return A shape containing the offsetted polylines. This may contain many unjoined polygons, + * but no overlapping ones. + */ Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; + /*! @brief Adds a copy of the given polyline to the set + @note As we have to copy the whole points data, this is not very efficient */ void push_back(const OpenPolyline& line); + /*! @brief Adds a copy of the given polyline to the set + @note As we have to copy the whole points data, this is not very efficient */ + void push_back(const Polygon& line); + + /*! @brief Adds a copy of the given polyline to the set + * @note As we can move the points data, this is much more efficient than the above methods */ void push_back(OpenPolyline&& line); + /*! @brief Adds a copy of the given polyline to the set + * @note As we can move the points data, this is much more efficient than the above methods */ void push_back(ClosedPolyline&& line); - void push_back(const Polygon& line); + /*! @brief Adds the given shared pointer to the set. The pointer reference count will be incremeted but no data is actually copied. + * @note The is even more efficient than the above methods because it only involves copying a pointer */ + void push_back(const OpenPolylinePtr& line); - void push_back(const std::shared_ptr& line); + /*! @brief Adds the given shared pointer to the set. The pointer reference count will be incremeted but no data is actually copied. + * @note The is even more efficient than the above methods because it only involves copying a pointer */ + void push_back(const PolylinePtr& line); - void push_back(const std::shared_ptr& line); + /*! @brief Adds a copy of all the polygons contained in the shape + @note As we have to copy the whole points data, this is really not efficient */ + void push_back(const Shape& shape); - void push_back(LinesSet&& lines_set); + /*! @brief Adds a copy of all the polygons contained in the set + @note As we have to copy the whole points data, this is really not efficient */ + void push_back(const LinesSet& lines_set); + /*! @brief Adds a copy of all the polylines contained in the set + @note As we have to copy the whole points data, this is really not efficient */ void push_back(const LinesSet& lines_set); - void push_back(LinesSet&& lines_set); - - void push_back(const LinesSet& lines_set); + /*! @brief Adds a copy of all the polylines contained in the set + * @note As we can move the points data, this is much more efficient than the above methods */ + void push_back(LinesSet&& lines_set); - void push_back(const Shape& shape); + /*! @brief Adds a copy of all the polylines contained in the set + * @note As we can move the points data, this is much more efficient than the above methods */ + void push_back(LinesSet&& lines_set); + /*! \brief Computes the total lenght of all the polylines in the set */ coord_t length() const; }; diff --git a/include/geometry/points_set.h b/include/geometry/points_set.h index c0772d6252..3eb151fd59 100644 --- a/include/geometry/points_set.h +++ b/include/geometry/points_set.h @@ -22,7 +22,7 @@ const static int clipper_init = (0); class PointsSet { private: - std::vector points_; + ClipperLib::Path points_; public: PointsSet() = default; @@ -37,17 +37,17 @@ class PointsSet PointsSet(ClipperLib::Path&& points); - const std::vector& getPoints() const + const ClipperLib::Path& getPoints() const { return points_; } - std::vector& getPoints() + ClipperLib::Path& getPoints() { return points_; } - void setPoints(std::vector&& points) + void setPoints(ClipperLib::Path&& points) { points_ = points; } diff --git a/include/geometry/polyline.h b/include/geometry/polyline.h index 6473811083..a51b13240b 100644 --- a/include/geometry/polyline.h +++ b/include/geometry/polyline.h @@ -47,7 +47,7 @@ class Polyline : public PointsSet { } - Polyline(const std::vector& points) + Polyline(const ClipperLib::Path& points) : PointsSet(points) { } @@ -59,8 +59,18 @@ class Polyline : public PointsSet virtual ~Polyline() = default; + /*! + * \brief Indicates whether this polyline has a virtual closing segment between the last point + * in the set and the first one + * \return True if a segment between the last and first point should be considered + */ virtual bool addClosingSegment() const = 0; + /*! + * \brief Gets the total number of "full" segments in the polyline. Calling this is also safe if + * there are not enough points to make a valid polyline, so it can also be a good + * indicator of a "valid" polyline. + */ virtual size_t segmentsCount() const = 0; Polyline& operator=(const Polyline& other) diff --git a/include/geometry/shape.h b/include/geometry/shape.h index ee5b168a6d..16bfb8d59b 100644 --- a/include/geometry/shape.h +++ b/include/geometry/shape.h @@ -5,7 +5,6 @@ #define GEOMETRY_SHAPE_H #include "geometry/lines_set.h" -#include "geometry/polygon.h" #include "settings/types/Angle.h" namespace cura @@ -15,6 +14,8 @@ class Polygon; class Ratio; class SingleShape; class PartsView; +class PointMatrix; +class Point3Matrix; class Shape : public LinesSet { @@ -29,10 +30,7 @@ class Shape : public LinesSet Shape(Shape&& other) = default; - Shape(const std::initializer_list& initializer) - : LinesSet(initializer) - { - } + Shape(const std::initializer_list& initializer); explicit Shape(ClipperLib::Paths&& paths, bool explicitely_closed = clipper_explicitely_closed_); @@ -79,9 +77,9 @@ class Shape : public LinesSet * \param restitch Whether to stitch the resulting segments into longer polylines, or leave every segment as a single segment * \param max_stitch_distance The maximum distance for two polylines to be stitched together with a segment * \return The resulting polylines limited to the area of this Polygons object + * \todo This should technically return a MixedLinesSet, because it can definitely contain open and closed polylines, but that is a heavy change */ template -#warning Technically this should return a MixedLinesSet LinesSet intersection(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; /*! diff --git a/include/geometry/single_shape.h b/include/geometry/single_shape.h index d1eb0895d6..472302d01f 100644 --- a/include/geometry/single_shape.h +++ b/include/geometry/single_shape.h @@ -5,7 +5,6 @@ #define GEOMETRY_SINGLE_SHAPE_H #include "geometry/shape.h" -#include "point2ll.h" namespace cura { diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 45c19d6533..74c6a90ed9 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -1393,7 +1393,7 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan push_lines(offset.open_polylines); */ - for (const std::shared_ptr& line : offset) + for (const PolylinePtr& line : offset) { if (line->segmentsCount() > 0) { diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index cee9bc4caf..cc1177b819 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -261,7 +261,7 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std std::remove_if( result.begin(), result.end(), - [](const std::shared_ptr& line) + [](const PolylinePtr& line) { if (const std::shared_ptr open_line = dynamic_pointer_cast(line)) { diff --git a/src/geometry/closed_polyline.cpp b/src/geometry/closed_polyline.cpp index cdd3689551..f08cf9624e 100644 --- a/src/geometry/closed_polyline.cpp +++ b/src/geometry/closed_polyline.cpp @@ -8,6 +8,18 @@ namespace cura { +size_t ClosedPolyline::segmentsCount() const +{ + if (explicitely_closed_) + { + return size() >= 3 ? size() - 1 : 0; + } + else + { + return size() >= 2 ? size() : 0; + } +} + bool ClosedPolyline::inside(const Point2LL& p, bool border_result) const { int res = ClipperLib::PointInPolygon(p, getPoints()); diff --git a/src/geometry/mixed_lines_set.cpp b/src/geometry/mixed_lines_set.cpp index 2ad346e598..651c7bc927 100644 --- a/src/geometry/mixed_lines_set.cpp +++ b/src/geometry/mixed_lines_set.cpp @@ -6,6 +6,7 @@ #include #include "geometry/open_polyline.h" +#include "geometry/polygon.h" #include "geometry/shape.h" @@ -19,7 +20,7 @@ Shape MixedLinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, do // Return a shape that contains only actual polygons Shape result; - for (const std::shared_ptr& line : (*this)) + for (const PolylinePtr& line : (*this)) { if (const std::shared_ptr polygon = dynamic_pointer_cast(line)) { @@ -34,7 +35,7 @@ Shape MixedLinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, do Shape polygons; ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - for (const std::shared_ptr& line : (*this)) + for (const PolylinePtr& line : (*this)) { if (const std::shared_ptr polygon = dynamic_pointer_cast(line)) { @@ -82,32 +83,32 @@ Shape MixedLinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, do void MixedLinesSet::push_back(const OpenPolyline& line) { - std::vector>::push_back(std::make_shared(line)); + std::vector::push_back(std::make_shared(line)); } void MixedLinesSet::push_back(OpenPolyline&& line) { - std::vector>::push_back(std::make_shared(std::move(line))); + std::vector::push_back(std::make_shared(std::move(line))); } void MixedLinesSet::push_back(ClosedPolyline&& line) { - std::vector>::push_back(std::make_shared(std::move(line))); + std::vector::push_back(std::make_shared(std::move(line))); } void MixedLinesSet::push_back(const Polygon& line) { - std::vector>::push_back(std::make_shared(std::move(line))); + std::vector::push_back(std::make_shared(std::move(line))); } void MixedLinesSet::push_back(const std::shared_ptr& line) { - std::vector>::push_back(line); + std::vector::push_back(line); } -void MixedLinesSet::push_back(const std::shared_ptr& line) +void MixedLinesSet::push_back(const PolylinePtr& line) { - std::vector>::push_back(line); + std::vector::push_back(line); } void MixedLinesSet::push_back(LinesSet&& lines_set) @@ -157,7 +158,7 @@ coord_t MixedLinesSet::length() const begin(), end(), coord_t(0), - [](coord_t value, const std::shared_ptr& line) + [](coord_t value, const PolylinePtr& line) { return value + line->length(); }); diff --git a/src/geometry/parts_view.cpp b/src/geometry/parts_view.cpp index 0422cd0d92..7d84d2d757 100644 --- a/src/geometry/parts_view.cpp +++ b/src/geometry/parts_view.cpp @@ -3,6 +3,7 @@ #include "geometry/parts_view.h" +#include "geometry/polygon.h" #include "geometry/single_shape.h" namespace cura diff --git a/src/geometry/points_set.cpp b/src/geometry/points_set.cpp index 4712b97f52..29275d2117 100644 --- a/src/geometry/points_set.cpp +++ b/src/geometry/points_set.cpp @@ -3,7 +3,6 @@ #include "geometry/points_set.h" -#include "geometry/point2ll.h" #include "geometry/point3_matrix.h" #include "geometry/point_matrix.h" diff --git a/src/geometry/polygon.cpp b/src/geometry/polygon.cpp index 82f796dc4b..928684fdb6 100644 --- a/src/geometry/polygon.cpp +++ b/src/geometry/polygon.cpp @@ -3,30 +3,11 @@ #include "geometry/polygon.h" -// #include - -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -#include "utils/ListPolyIt.h" -#include "utils/linearAlg2D.h" - -// #include "utils/PolylineStitcher.h" #include "geometry/point3_matrix.h" #include "geometry/point_matrix.h" #include "geometry/shape.h" +#include "utils/ListPolyIt.h" +#include "utils/linearAlg2D.h" namespace cura { diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index 10ef1e2663..e0d893eef6 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -4,24 +4,15 @@ #include "geometry/shape.h" #include +#include #include -#include -#include -#include -#include -#include -#include -#include #include -#include #include -#include -#include -#include "geometry/closed_polyline.h" #include "geometry/mixed_lines_set.h" #include "geometry/parts_view.h" +#include "geometry/polygon.h" #include "geometry/single_shape.h" #include "settings/types/Ratio.h" #include "utils/OpenPolylineStitcher.h" @@ -35,6 +26,11 @@ Shape::Shape(ClipperLib::Paths&& paths, bool explicitely_closed) emplace_back(std::move(paths), explicitely_closed); } +Shape::Shape(const std::initializer_list& initializer) + : LinesSet(initializer) +{ +} + void Shape::emplace_back(ClipperLib::Paths&& paths, bool explicitely_closed) { reserve(size() + paths.size()); @@ -546,58 +542,7 @@ Shape Shape::toPolygons(ClipperLib::PolyTree& poly_tree) ClipperLib::PolyTreeToPaths(poly_tree, ret); return Shape(std::move(ret)); } -/* -[[maybe_unused]] Shape Shape::fromWkt(const std::string& wkt) -{ - typedef boost::geometry::model::d2::point_xy point_type; - typedef boost::geometry::model::polygon polygon_type; - - polygon_type poly; - boost::geometry::read_wkt(wkt, poly); - - Shape ret; - - Polygon outer; - for (const auto& point : poly.outer()) - { - outer.push_back(Point2LL(point.x(), point.y())); - } - ret.push_back(outer); - - for (const auto& hole : poly.inners()) - { - Polygon inner; - for (const auto& point : hole) - { - inner.push_back(Point2LL(point.x(), point.y())); - } - ret.push_back(inner); - } - - return ret; -} -[[maybe_unused]] void Shape::writeWkt(std::ostream& stream) const -{ - stream << "POLYGON ("; - const auto paths_str = (*this) - | ranges::views::transform( - [](const auto& path) - { - const auto line_string = ranges::views::concat(path, path | ranges::views::take(1)) - | ranges::views::transform( - [](const auto& point) - { - return fmt::format("{} {}", point.X, point.Y); - }) - | ranges::views::join(ranges::views::c_str(", ")) | ranges::to(); - return "(" + line_string + ")"; - }) - | ranges::views::join(ranges::views::c_str(", ")) | ranges::to(); - stream << paths_str; - stream << ")"; -} -*/ Shape Shape::smooth_outward(const AngleDegrees max_angle, int shortcut_length) const { Shape ret; diff --git a/src/geometry/single_shape.cpp b/src/geometry/single_shape.cpp index 09f28285dd..17205811e1 100644 --- a/src/geometry/single_shape.cpp +++ b/src/geometry/single_shape.cpp @@ -3,6 +3,8 @@ #include "geometry/single_shape.h" +#include "geometry/polygon.h" + namespace cura { diff --git a/src/multiVolumes.cpp b/src/multiVolumes.cpp index e89e2a3d19..6c607a55c9 100644 --- a/src/multiVolumes.cpp +++ b/src/multiVolumes.cpp @@ -7,6 +7,7 @@ #include "Application.h" #include "Slice.h" +#include "geometry/polygon.h" #include "settings/EnumSettings.h" #include "settings/types/LayerIndex.h" #include "slicer.h" diff --git a/src/utils/Simplify.cpp b/src/utils/Simplify.cpp index c215464cd2..7ec3e3e17d 100644 --- a/src/utils/Simplify.cpp +++ b/src/utils/Simplify.cpp @@ -63,7 +63,7 @@ LinesSet Simplify::polyline(const LinesSet& polylines) const MixedLinesSet Simplify::polyline(const MixedLinesSet& polylines) const { MixedLinesSet result; - for (const std::shared_ptr& polyline_ptr : polylines) + for (const PolylinePtr& polyline_ptr : polylines) { if (std::shared_ptr open_polyline = std::dynamic_pointer_cast(polyline_ptr)) { diff --git a/src/utils/mixed_polyline_stitcher.cpp b/src/utils/mixed_polyline_stitcher.cpp index 8095231d73..8792036108 100644 --- a/src/utils/mixed_polyline_stitcher.cpp +++ b/src/utils/mixed_polyline_stitcher.cpp @@ -4,6 +4,7 @@ #include "utils/mixed_polyline_stitcher.h" #include "geometry/mixed_lines_set.h" +#include "geometry/polygon.h" #include "geometry/shape.h" diff --git a/src/utils/polygon.cpp b/src/utils/polygon.cpp deleted file mode 100644 index 99cb2be1b9..0000000000 --- a/src/utils/polygon.cpp +++ /dev/null @@ -1,1727 +0,0 @@ -// Copyright (c) 2024 UltiMaker -// CuraEngine is released under the terms of the AGPLv3 or higher. - -#include "utils/polygon.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "utils/ListPolyIt.h" -#include "utils/PolylineStitcher.h" -#include "utils/linearAlg2D.h" // pointLiesOnTheRightOfLine - -namespace cura -{ - -size_t ConstPolygonRef::size() const -{ - return path->size(); -} - -bool ConstPolygonRef::empty() const -{ - return path->empty(); -} - -bool ConstPolygonRef::shorterThan(const coord_t check_length) const -{ - return cura::shorterThan(*this, check_length); -} - -bool ConstPolygonRef::_inside(Point2LL p, bool border_result) const -{ - const ConstPolygonRef thiss = *this; - if (size() < 1) - { - return false; - } - - int crossings = 0; - Point2LL p0 = back(); - for (unsigned int n = 0; n < size(); n++) - { - Point2LL p1 = thiss[n]; - // no tests unless the segment p0-p1 is at least partly at, or to right of, p.X - short comp = LinearAlg2D::pointLiesOnTheRightOfLine(p, p0, p1); - if (comp == 1) - { - crossings++; - } - else if (comp == 0) - { - return border_result; - } - p0 = p1; - } - return (crossings % 2) == 1; -} - - -Polygons ConstPolygonRef::intersection(const ConstPolygonRef& other) const -{ - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - clipper.AddPath(*path, ClipperLib::ptSubject, true); - clipper.AddPath(*other.path, ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctIntersection, ret.paths); - return ret; -} - -bool Polygons::empty() const -{ - return paths.empty(); -} - -Polygons Polygons::approxConvexHull(int extra_outset) -{ - constexpr int overshoot = MM2INT(100); // 10cm (hard-coded value). - - Polygons convex_hull; - // Perform the offset for each polygon one at a time. - // This is necessary because the polygons may overlap, in which case the offset could end up in an infinite loop. - // See http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperOffset/_Body.htm - for (const ClipperLib::Path& path : paths) - { - Polygons offset_result; - ClipperLib::ClipperOffset offsetter(1.2, 10.0); - offsetter.AddPath(path, ClipperLib::jtRound, ClipperLib::etClosedPolygon); - offsetter.Execute(offset_result.paths, overshoot); - convex_hull.add(offset_result); - } - return convex_hull.unionPolygons().offset(-overshoot + extra_outset, ClipperLib::jtRound); -} - -void Polygons::makeConvex() -{ - // early out if there is nothing to do - if (empty()) - { - return; - } - - // Andrew’s Monotone Chain Convex Hull Algorithm - std::vector points; - - for (const auto& poly : this->paths) - { - points.insert(points.end(), poly.begin(), poly.end()); - } - - ClipperLib::Path convexified; - auto make_sorted_poly_convex = [&convexified](std::vector& poly) - { - convexified.push_back(poly[0]); - - for (const auto window : poly | ranges::views::sliding(2)) - { - const Point2LL& current = window[0]; - const Point2LL& after = window[1]; - - if (LinearAlg2D::pointIsLeftOfLine(current, convexified.back(), after) < 0) - { - // Track backwards to make sure we haven't been in a concave pocket for multiple vertices already. - while (convexified.size() >= 2 - && (LinearAlg2D::pointIsLeftOfLine(convexified.back(), convexified[convexified.size() - 2], current) >= 0 - || LinearAlg2D::pointIsLeftOfLine(convexified.back(), convexified[convexified.size() - 2], convexified.front()) > 0)) - { - convexified.pop_back(); - } - convexified.push_back(current); - } - } - }; - - std::sort( - points.begin(), - points.end(), - [](Point2LL a, Point2LL b) - { - return a.X == b.X ? a.Y < b.Y : a.X < b.X; - }); - make_sorted_poly_convex(points); - std::reverse(points.begin(), points.end()); - make_sorted_poly_convex(points); - - this->paths = { convexified }; -} - -size_t Polygons::pointCount() const -{ - size_t count = 0; - for (const ClipperLib::Path& path : paths) - { - count += path.size(); - } - return count; -} - -bool Polygons::inside(Point2LL p, bool border_result) const -{ - int poly_count_inside = 0; - for (const ClipperLib::Path& poly : *this) - { - const int is_inside_this_poly = ClipperLib::PointInPolygon(p, poly); - if (is_inside_this_poly == -1) - { - return border_result; - } - poly_count_inside += is_inside_this_poly; - } - return (poly_count_inside % 2) == 1; -} - -bool PolygonsPart::inside(Point2LL p, bool border_result) const -{ - if (size() < 1) - { - return false; - } - if (! (*this)[0].inside(p, border_result)) - { - return false; - } - for (unsigned int n = 1; n < paths.size(); n++) - { - if ((*this)[n].inside(p, border_result)) - { - return false; - } - } - return true; -} - -bool Polygons::insideOld(Point2LL p, bool border_result) const -{ - const Polygons& thiss = *this; - if (size() < 1) - { - return false; - } - - int crossings = 0; - for (const ClipperLib::Path& poly : thiss) - { - Point2LL p0 = poly.back(); - for (const Point2LL& p1 : poly) - { - short comp = LinearAlg2D::pointLiesOnTheRightOfLine(p, p0, p1); - if (comp == 1) - { - crossings++; - } - else if (comp == 0) - { - return border_result; - } - p0 = p1; - } - } - return (crossings % 2) == 1; -} - -size_t Polygons::findInside(Point2LL p, bool border_result) -{ - Polygons& thiss = *this; - if (size() < 1) - { - return false; - } - - // NOTE: Keep these vectors fixed-size, they replace an (non-standard, sized at runtime) arrays. - std::vector min_x(size(), std::numeric_limits::max()); - std::vector crossings(size()); - - for (size_t poly_idx = 0; poly_idx < size(); poly_idx++) - { - PolygonRef poly = thiss[poly_idx]; - Point2LL p0 = poly.back(); - for (Point2LL& p1 : poly) - { - short comp = LinearAlg2D::pointLiesOnTheRightOfLine(p, p0, p1); - if (comp == 1) - { - crossings[poly_idx]++; - int64_t x; - if (p1.Y == p0.Y) - { - x = p0.X; - } - else - { - x = p0.X + (p1.X - p0.X) * (p.Y - p0.Y) / (p1.Y - p0.Y); - } - if (x < min_x[poly_idx]) - { - min_x[poly_idx] = x; - } - } - else if (border_result && comp == 0) - { - return poly_idx; - } - p0 = p1; - } - } - - int64_t min_x_uneven = std::numeric_limits::max(); - size_t ret = NO_INDEX; - size_t n_unevens = 0; - for (size_t array_idx = 0; array_idx < size(); array_idx++) - { - if (crossings[array_idx] % 2 == 1) - { - n_unevens++; - if (min_x[array_idx] < min_x_uneven) - { - min_x_uneven = min_x[array_idx]; - ret = array_idx; - } - } - } - if (n_unevens % 2 == 0) - { - ret = NO_INDEX; - } - return ret; -} - -Polygons Polygons::intersectionPolyLines(const Polygons& polylines, bool restitch, const coord_t max_stitch_distance) const -{ - Polygons split_polylines = polylines.splitPolylinesIntoSegments(); - - ClipperLib::PolyTree result; - ClipperLib::Clipper clipper(clipper_init); - clipper.AddPaths(split_polylines.paths, ClipperLib::ptSubject, false); - clipper.AddPaths(paths, ClipperLib::ptClip, true); - clipper.Execute(ClipperLib::ctIntersection, result); - Polygons ret; - ClipperLib::OpenPathsFromPolyTree(result, ret.paths); - - if (restitch) - { - Polygons result_lines, result_polygons; - const coord_t snap_distance = 10_mu; - PolylineStitcher::stitch(ret, result_lines, result_polygons, max_stitch_distance, snap_distance); - ret = result_lines; - // if polylines got stitched into polygons, split them back up into a polyline again, because the result only admits polylines - for (PolygonRef poly : result_polygons) - { - if (poly.empty()) - continue; - if (poly.size() > 2) - { - poly.emplace_back(poly[0]); - } - ret.add(poly); - } - } - - return ret; -} - -void Polygons::toPolylines() -{ - for (PolygonRef poly : *this) - { - if (poly.empty()) - continue; - poly.emplace_back(poly.front()); - } -} - -void Polygons::splitPolylinesIntoSegments(Polygons& result) const -{ - for (ConstPolygonRef poly : *this) - { - poly.splitPolylineIntoSegments(result); - } -} -Polygons Polygons::splitPolylinesIntoSegments() const -{ - Polygons ret; - splitPolylinesIntoSegments(ret); - return ret; -} - -void Polygons::splitPolygonsIntoSegments(Polygons& result) const -{ - for (ConstPolygonRef poly : *this) - { - poly.splitPolygonIntoSegments(result); - } -} -Polygons Polygons::splitPolygonsIntoSegments() const -{ - Polygons ret; - splitPolygonsIntoSegments(ret); - return ret; -} - -coord_t Polygons::polyLineLength() const -{ - coord_t length = 0; - for (ConstPolygonRef poly : *this) - { - length += poly.polylineLength(); - } - return length; -} - -Polygons Polygons::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const -{ - if (distance == 0) - { - return *this; - } - Polygons ret; - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - clipper.AddPaths(unionPolygons().paths, join_type, ClipperLib::etClosedPolygon); - clipper.MiterLimit = miter_limit; - clipper.Execute(ret.paths, distance); - return ret; -} - -Polygons Polygons::offset(const std::vector& offset_dists) const -{ - // we need as many offset-dists as points - assert(this->pointCount() == offset_dists.size()); - - Polygons ret; - int i = 0; - for (auto& poly_line : this->paths - | ranges::views::filter( - [](const auto& path) - { - return ! path.empty(); - })) - { - std::vector ret_poly_line; - - auto prev_p = poly_line.back(); - auto prev_dist = offset_dists[i + poly_line.size() - 1]; - - for (const auto& p : poly_line) - { - auto offset_dist = offset_dists[i]; - - auto vec_dir = prev_p - p; - - constexpr coord_t min_vec_len = 10; - if (vSize2(vec_dir) > min_vec_len * min_vec_len) - { - auto offset_p1 = turn90CCW(normal(vec_dir, prev_dist)); - auto offset_p2 = turn90CCW(normal(vec_dir, offset_dist)); - - ret_poly_line.emplace_back(prev_p + offset_p1); - ret_poly_line.emplace_back(p + offset_p2); - } - - prev_p = p; - prev_dist = offset_dist; - i++; - } - - ret.add(ret_poly_line); - } - - ClipperLib::SimplifyPolygons(ret.paths, ClipperLib::PolyFillType::pftPositive); - - return ret; -} - -Polygons ConstPolygonRef::offset(int distance, ClipperLib::JoinType join_type, double miter_limit) const -{ - if (distance == 0) - { - Polygons ret; - ret.add(*this); - return ret; - } - Polygons ret; - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - clipper.AddPath(*path, join_type, ClipperLib::etClosedPolygon); - clipper.MiterLimit = miter_limit; - clipper.Execute(ret.paths, distance); - return ret; -} - -void PolygonRef::removeColinearEdges(const AngleRadians max_deviation_angle) -{ - // TODO: Can be made more efficient (for example, use pointer-types for process-/skip-indices, so we can swap them without copy). - - size_t num_removed_in_iteration = 0; - do - { - num_removed_in_iteration = 0; - - std::vector process_indices(path->size(), true); - - bool go = true; - while (go) - { - go = false; - - const auto& rpath = *path; - const size_t pathlen = rpath.size(); - if (pathlen <= 3) - { - return; - } - - std::vector skip_indices(path->size(), false); - - ClipperLib::Path new_path; - for (size_t point_idx = 0; point_idx < pathlen; ++point_idx) - { - // Don't iterate directly over process-indices, but do it this way, because there are points _in_ process-indices that should nonetheless be skipped: - if (! process_indices[point_idx]) - { - new_path.push_back(rpath[point_idx]); - continue; - } - - // Should skip the last point for this iteration if the old first was removed (which can be seen from the fact that the new first was skipped): - if (point_idx == (pathlen - 1) && skip_indices[0]) - { - skip_indices[new_path.size()] = true; - go = true; - new_path.push_back(rpath[point_idx]); - break; - } - - const Point2LL& prev = rpath[(point_idx - 1 + pathlen) % pathlen]; - const Point2LL& pt = rpath[point_idx]; - const Point2LL& next = rpath[(point_idx + 1) % pathlen]; - - double angle = LinearAlg2D::getAngleLeft(prev, pt, next); // [0 : 2 * pi] - if (angle >= std::numbers::pi) - { - angle -= std::numbers::pi; - } // map [pi : 2 * pi] to [0 : pi] - - // Check if the angle is within limits for the point to 'make sense', given the maximum deviation. - // If the angle indicates near-parallel segments ignore the point 'pt' - if (angle > max_deviation_angle && angle < std::numbers::pi - max_deviation_angle) - { - new_path.push_back(pt); - } - else if (point_idx != (pathlen - 1)) - { - // Skip the next point, since the current one was removed: - skip_indices[new_path.size()] = true; - go = true; - new_path.push_back(next); - ++point_idx; - } - } - *path = new_path; - num_removed_in_iteration += pathlen - path->size(); - - process_indices.clear(); - process_indices.insert(process_indices.end(), skip_indices.begin(), skip_indices.end()); - } - } while (num_removed_in_iteration > 0); -} - -void PolygonRef::applyMatrix(const PointMatrix& matrix) -{ - for (unsigned int path_idx = 0; path_idx < path->size(); path_idx++) - { - (*path)[path_idx] = matrix.apply((*path)[path_idx]); - } -} -void PolygonRef::applyMatrix(const Point3Matrix& matrix) -{ - for (unsigned int path_idx = 0; path_idx < path->size(); path_idx++) - { - (*path)[path_idx] = matrix.apply((*path)[path_idx]); - } -} - -Polygons Polygons::getOutsidePolygons() const -{ - Polygons ret; - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree poly_tree; - constexpr bool paths_are_closed_polys = true; - clipper.AddPaths(paths, ClipperLib::ptSubject, paths_are_closed_polys); - clipper.Execute(ClipperLib::ctUnion, poly_tree); - - for (int outer_poly_idx = 0; outer_poly_idx < poly_tree.ChildCount(); outer_poly_idx++) - { - ClipperLib::PolyNode* child = poly_tree.Childs[outer_poly_idx]; - ret.emplace_back(child->Contour); - } - return ret; -} - -void Polygons::removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Polygons& ret) const -{ - for (int outer_poly_idx = 0; outer_poly_idx < node.ChildCount(); outer_poly_idx++) - { - ClipperLib::PolyNode* child = node.Childs[outer_poly_idx]; - if (remove_holes) - { - ret.emplace_back(child->Contour); - } - for (int hole_node_idx = 0; hole_node_idx < child->ChildCount(); hole_node_idx++) - { - ClipperLib::PolyNode& hole_node = *child->Childs[hole_node_idx]; - if ((hole_node.ChildCount() > 0) == remove_holes) - { - ret.emplace_back(hole_node.Contour); - removeEmptyHoles_processPolyTreeNode(hole_node, remove_holes, ret); - } - } - } -} - -void Polygons::removeSmallAreas(const double min_area_size, const bool remove_holes) -{ - auto new_end = paths.end(); - if (remove_holes) - { - for (auto it = paths.begin(); it < new_end;) - { - // All polygons smaller than target are removed by replacing them with a polygon from the back of the vector - if (std::abs(INT2MM2(ClipperLib::Area(*it))) < min_area_size) - { - *it = std::move(*--new_end); - continue; - } - it++; // Skipped on removal such that the polygon just swaped in is checked next - } - } - else - { - // For each polygon, computes the signed area, move small outlines at the end of the vector and keep references on small holes - std::vector small_holes; - for (auto it = paths.begin(); it < new_end;) - { - double area = INT2MM2(ClipperLib::Area(*it)); - if (std::abs(area) < min_area_size) - { - if (area >= 0) - { - --new_end; - if (it < new_end) - { - std::swap(*new_end, *it); - continue; - } - else - { // Don't self-swap the last Path - break; - } - } - else - { - small_holes.push_back(*it); - } - } - it++; // Skipped on removal such that the polygon just swaped in is checked next - } - - // Removes small holes that have their first point inside one of the removed outlines - // Iterating in reverse ensures that unprocessed small holes won't be moved - const auto removed_outlines_start = new_end; - for (auto hole_it = small_holes.rbegin(); hole_it < small_holes.rend(); hole_it++) - { - for (auto outline_it = removed_outlines_start; outline_it < paths.end(); outline_it++) - { - if (PolygonRef(*outline_it).inside(*hole_it->begin())) - { - **hole_it = std::move(*--new_end); - break; - } - } - } - } - paths.resize(new_end - paths.begin()); -} - -void Polygons::removeSmallCircumference(const coord_t min_circumference_size, const bool remove_holes) -{ - removeSmallAreaCircumference(0.0, min_circumference_size, remove_holes); -} - -void Polygons::removeSmallAreaCircumference(const double min_area_size, const coord_t min_circumference_size, const bool remove_holes) -{ - Polygons new_polygon; - - bool outline_is_removed = false; - for (ConstPolygonRef poly : paths) - { - double area = poly.area(); - auto circumference = poly.polygonLength(); - bool is_outline = area >= 0; - - if (is_outline) - { - if (circumference >= min_circumference_size && std::abs(area) >= min_area_size) - { - new_polygon.add(poly); - outline_is_removed = false; - } - else - { - outline_is_removed = true; - } - } - else if (outline_is_removed) - { - // containing parent outline is removed; hole should be removed as well - } - else if (! remove_holes || (circumference >= min_circumference_size && std::abs(area) >= min_area_size)) - { - // keep hole-polygon if we do not remove holes, or if its - // circumference is bigger then the minimum circumference size - new_polygon.add(poly); - } - } - - *this = new_polygon; -} - -void Polygons::removeDegenerateVerts() -{ - _removeDegenerateVerts(false); -} - -void Polygons::removeDegenerateVertsPolyline() -{ - _removeDegenerateVerts(true); -} - -void Polygons::_removeDegenerateVerts(const bool for_polyline) -{ - Polygons& thiss = *this; - for (size_t poly_idx = 0; poly_idx < size(); poly_idx++) - { - PolygonRef poly = thiss[poly_idx]; - Polygon result; - - auto isDegenerate = [](const Point2LL& last, const Point2LL& now, const Point2LL& next) - { - Point2LL last_line = now - last; - Point2LL next_line = next - now; - return dot(last_line, next_line) == -1 * vSize(last_line) * vSize(next_line); - }; - - // With polylines, skip the first and last vertex. - const size_t start_vertex = for_polyline ? 1 : 0; - const size_t end_vertex = for_polyline ? poly.size() - 1 : poly.size(); - for (size_t i = 0; i < start_vertex; ++i) - { - result.add(poly[i]); // Add everything before the start vertex. - } - - bool isChanged = false; - for (size_t idx = start_vertex; idx < end_vertex; idx++) - { - const Point2LL& last = (result.size() == 0) ? poly.back() : result.back(); - if (idx + 1 >= poly.size() && result.size() == 0) - { - break; - } - const Point2LL& next = (idx + 1 >= poly.size()) ? result[0] : poly[idx + 1]; - if (isDegenerate(last, poly[idx], next)) - { // lines are in the opposite direction - // don't add vert to the result - isChanged = true; - while (result.size() > 1 && isDegenerate(result[result.size() - 2], result.back(), next)) - { - result.pop_back(); - } - } - else - { - result.add(poly[idx]); - } - } - - for (size_t i = end_vertex; i < poly.size(); ++i) - { - result.add(poly[i]); // Add everything after the end vertex. - } - - if (isChanged) - { - if (for_polyline || result.size() > 2) - { - *poly = *result; - } - else - { - thiss.remove(poly_idx); - poly_idx--; // effectively the next iteration has the same poly_idx (referring to a new poly which is not yet processed) - } - } - } -} - -Polygons Polygons::toPolygons(ClipperLib::PolyTree& poly_tree) -{ - Polygons ret; - ClipperLib::PolyTreeToPaths(poly_tree, ret.paths); - return ret; -} - -[[maybe_unused]] Polygons Polygons::fromWkt(const std::string& wkt) -{ - typedef boost::geometry::model::d2::point_xy point_type; - typedef boost::geometry::model::polygon polygon_type; - - polygon_type poly; - boost::geometry::read_wkt(wkt, poly); - - Polygons ret; - - Polygon outer; - for (const auto& point : poly.outer()) - { - outer.add(Point2LL(point.x(), point.y())); - } - ret.add(outer); - - for (const auto& hole : poly.inners()) - { - Polygon inner; - for (const auto& point : hole) - { - inner.add(Point2LL(point.x(), point.y())); - } - ret.add(inner); - } - - return ret; -} - -[[maybe_unused]] void Polygons::writeWkt(std::ostream& stream) const -{ - stream << "POLYGON ("; - const auto paths_str = paths - | ranges::views::transform( - [](const auto& path) - { - const auto line_string = ranges::views::concat(path, path | ranges::views::take(1)) - | ranges::views::transform( - [](const auto& point) - { - return fmt::format("{} {}", point.X, point.Y); - }) - | ranges::views::join(ranges::views::c_str(", ")) | ranges::to(); - return "(" + line_string + ")"; - }) - | ranges::views::join(ranges::views::c_str(", ")) | ranges::to(); - stream << paths_str; - stream << ")"; -} - -bool ConstPolygonRef::smooth_corner_complex(const Point2LL p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length) -{ - // walk away from the corner until the shortcut > shortcut_length or it would smooth a piece inward - // - walk in both directions untill shortcut > shortcut_length - // - stop walking in one direction if it would otherwise cut off a corner in that direction - // - same in the other direction - // - stop if both are cut off - // walk by updating p0_it and p2_it - int64_t shortcut_length2 = shortcut_length * shortcut_length; - bool forward_is_blocked = false; - bool forward_is_too_far = false; - bool backward_is_blocked = false; - bool backward_is_too_far = false; - while (true) - { - const bool forward_has_converged = forward_is_blocked || forward_is_too_far; - const bool backward_has_converged = backward_is_blocked || backward_is_too_far; - if (forward_has_converged && backward_has_converged) - { - if (forward_is_too_far && backward_is_too_far && vSize2(p0_it.prev().p() - p2_it.next().p()) < shortcut_length2) - { - // o - // / \ . - // o o - // | | - // \ / . - // | | - // \ / . - // | | - // o o - --p0_it; - ++p2_it; - forward_is_too_far = false; // invalidate data - backward_is_too_far = false; // invalidate data - continue; - } - else - { - break; - } - } - smooth_outward_step(p1, shortcut_length2, p0_it, p2_it, forward_is_blocked, backward_is_blocked, forward_is_too_far, backward_is_too_far); - if (p0_it.prev() == p2_it || p0_it == p2_it) - { // stop if we went all the way around the polygon - // this should only be the case for hole polygons (?) - if (forward_is_too_far && backward_is_too_far) - { - // in case p0_it.prev() == p2_it : - // / . - // / /| - // | becomes | | - // \ \| - // \ . - // in case p0_it == p2_it : - // / . - // / becomes /| - // \ \| - // \ . - break; - } - else - { - // this whole polygon can be removed - return true; - } - } - } - - const Point2LL v02 = p2_it.p() - p0_it.p(); - const int64_t v02_size2 = vSize2(v02); - // set the following: - // p0_it = start point of line - // p2_it = end point of line - if (std::abs(v02_size2 - shortcut_length2) < shortcut_length * 10) // i.e. if (size2 < l * (l+10) && size2 > l * (l-10)) - { // v02 is approximately shortcut length - // handle this separately to avoid rounding problems below in the getPointOnLineWithDist function - // p0_it and p2_it are already correct - } - else if (! backward_is_blocked && ! forward_is_blocked) - { // introduce two new points - // 1----b---->2 - // ^ / - // | / - // | / - // |/ - // |a - // | - // 0 - const int64_t v02_size = sqrt(v02_size2); - - const ListPolyIt p0_2_it = p0_it.prev(); - const ListPolyIt p2_2_it = p2_it.next(); - const Point2LL p2_2 = p2_2_it.p(); - const Point2LL p0_2 = p0_2_it.p(); - const Point2LL v02_2 = p0_2 - p2_2; - const int64_t v02_2_size = vSize(v02_2); - double progress - = std::min(1.0, INT2MM(shortcut_length - v02_size) / INT2MM(v02_2_size - v02_size)); // account for rounding error when v02_2_size is approx equal to v02_size - assert(progress >= 0.0f && progress <= 1.0f && "shortcut length must be between last length and new length"); - const Point2LL new_p0 = p0_it.p() + (p0_2 - p0_it.p()) * progress; - p0_it = ListPolyIt::insertPointNonDuplicate(p0_2_it, p0_it, new_p0); - const Point2LL new_p2 = p2_it.p() + (p2_2 - p2_it.p()) * progress; - p2_it = ListPolyIt::insertPointNonDuplicate(p2_it, p2_2_it, new_p2); - } - else if (! backward_is_blocked) - { // forward is blocked, back is open - // | - // 1->b - // ^ : - // | / - // 0 : - // |/ - // |a - // | - // 0_2 - const ListPolyIt p0_2_it = p0_it.prev(); - const Point2LL p0 = p0_it.p(); - const Point2LL p0_2 = p0_2_it.p(); - const Point2LL p2 = p2_it.p(); - Point2LL new_p0; - bool success = LinearAlg2D::getPointOnLineWithDist(p2, p0, p0_2, shortcut_length, new_p0); - // shortcut length must be possible given that last length was ok and new length is too long - if (success) - { -#ifdef ASSERT_INSANE_OUTPUT - assert(new_p0.X < 400000 && new_p0.Y < 400000); -#endif // #ifdef ASSERT_INSANE_OUTPUT - p0_it = ListPolyIt::insertPointNonDuplicate(p0_2_it, p0_it, new_p0); - } - else - { // if not then a rounding error occured - if (vSize(p2 - p0_2) < vSize2(p2 - p0)) - { - p0_it = p0_2_it; // start shortcut at 0 - } - } - } - else if (! forward_is_blocked) - { // backward is blocked, front is open - // 1----2----b----------->2_2 - // ^ ,-' - // | ,-' - //--0.-' - // a - const ListPolyIt p2_2_it = p2_it.next(); - const Point2LL p0 = p0_it.p(); - const Point2LL p2 = p2_it.p(); - const Point2LL p2_2 = p2_2_it.p(); - Point2LL new_p2; - bool success = LinearAlg2D::getPointOnLineWithDist(p0, p2, p2_2, shortcut_length, new_p2); - // shortcut length must be possible given that last length was ok and new length is too long - if (success) - { -#ifdef ASSERT_INSANE_OUTPUT - assert(new_p2.X < 400000 && new_p2.Y < 400000); -#endif // #ifdef ASSERT_INSANE_OUTPUT - p2_it = ListPolyIt::insertPointNonDuplicate(p2_it, p2_2_it, new_p2); - } - else - { // if not then a rounding error occured - if (vSize(p2_2 - p0) < vSize2(p2 - p0)) - { - p2_it = p2_2_it; // start shortcut at 0 - } - } - } - else - { - // | - // __|2 - // | / > shortcut cannot be of the desired length - // ___|/ . - // 0 - // both are blocked and p0_it and p2_it are already correct - } - // delete all cut off points - while (p0_it.next() != p2_it) - { - p0_it.next().remove(); - } - return false; -} - -void ConstPolygonRef::smooth_outward_step( - const Point2LL p1, - const int64_t shortcut_length2, - ListPolyIt& p0_it, - ListPolyIt& p2_it, - bool& forward_is_blocked, - bool& backward_is_blocked, - bool& forward_is_too_far, - bool& backward_is_too_far) -{ - const bool forward_has_converged = forward_is_blocked || forward_is_too_far; - const bool backward_has_converged = backward_is_blocked || backward_is_too_far; - const Point2LL p0 = p0_it.p(); - const Point2LL p2 = p2_it.p(); - bool walk_forward - = ! forward_has_converged && (backward_has_converged || (vSize2(p2 - p1) < vSize2(p0 - p1))); // whether to walk along the p1-p2 direction or in the p1-p0 direction - - if (walk_forward) - { - const ListPolyIt p2_2_it = p2_it.next(); - const Point2LL p2_2 = p2_2_it.p(); - bool p2_is_left = LinearAlg2D::pointIsLeftOfLine(p2, p0, p2_2) >= 0; - if (! p2_is_left) - { - forward_is_blocked = true; - return; - } - - const Point2LL v02_2 = p2_2 - p0_it.p(); - if (vSize2(v02_2) > shortcut_length2) - { - forward_is_too_far = true; - return; - } - - p2_it = p2_2_it; // make one step in the forward direction - backward_is_blocked = false; // invalidate data about backward walking - backward_is_too_far = false; - return; - } - else - { - const ListPolyIt p0_2_it = p0_it.prev(); - const Point2LL p0_2 = p0_2_it.p(); - bool p0_is_left = LinearAlg2D::pointIsLeftOfLine(p0, p0_2, p2) >= 0; - if (! p0_is_left) - { - backward_is_blocked = true; - return; - } - - const Point2LL v02_2 = p2_it.p() - p0_2; - if (vSize2(v02_2) > shortcut_length2) - { - backward_is_too_far = true; - return; - } - - p0_it = p0_2_it; // make one step in the backward direction - forward_is_blocked = false; // invalidate data about forward walking - forward_is_too_far = false; - return; - } -} - -void ConstPolygonRef::smooth_corner_simple( - const Point2LL p0, - const Point2LL p1, - const Point2LL p2, - const ListPolyIt p0_it, - const ListPolyIt p1_it, - const ListPolyIt p2_it, - const Point2LL v10, - const Point2LL v12, - const Point2LL v02, - const int64_t shortcut_length, - double cos_angle) -{ - // 1----b---->2 - // ^ / - // | / - // | / - // |/ - // |a - // | - // 0 - // ideally a1_size == b1_size - if (vSize2(v02) <= shortcut_length * (shortcut_length + 10) // v02 is approximately shortcut length - || (cos_angle > 0.9999 && LinearAlg2D::getDist2FromLine(p2, p0, p1) < 20 * 20)) // p1 is degenerate - { - // handle this separately to avoid rounding problems below in the getPointOnLineWithDist function - p1_it.remove(); - // don't insert new elements - } - else - { - // compute the distance a1 == b1 to get vSize(ab)==shortcut_length with the given angle between v10 and v12 - // 1 - // /|\ . - // / | \ . - // / | \ . - // / | \ . - // a/____|____\b . - // m - // use trigonometry on the right-angled triangle am1 - double a1m_angle = acos(cos_angle) / 2; - const int64_t a1_size = shortcut_length / 2 / sin(a1m_angle); - if (a1_size * a1_size < vSize2(v10) && a1_size * a1_size < vSize2(v12)) - { - Point2LL a = p1 + normal(v10, a1_size); - Point2LL b = p1 + normal(v12, a1_size); -#ifdef ASSERT_INSANE_OUTPUT - assert(vSize(a) < 4000000); - assert(vSize(b) < 4000000); -#endif // #ifdef ASSERT_INSANE_OUTPUT - ListPolyIt::insertPointNonDuplicate(p0_it, p1_it, a); - ListPolyIt::insertPointNonDuplicate(p1_it, p2_it, b); - p1_it.remove(); - } - else if (vSize2(v12) < vSize2(v10)) - { - // b - // 1->2 - // ^ | - // | / - // | | - // |/ - // |a - // | - // 0 - const Point2LL& b = p2_it.p(); - Point2LL a; - bool success = LinearAlg2D::getPointOnLineWithDist(b, p1, p0, shortcut_length, a); - // v02 has to be longer than ab! - if (success) - { // if not success then assume a is negligibly close to 0, but rounding errors caused a problem -#ifdef ASSERT_INSANE_OUTPUT - assert(vSize(a) < 4000000); -#endif // #ifdef ASSERT_INSANE_OUTPUT - ListPolyIt::insertPointNonDuplicate(p0_it, p1_it, a); - } - p1_it.remove(); - } - else - { - // 1---------b----------->2 - // ^ ,-' - // | ,-' - // 0.-' - // a - const Point2LL& a = p0_it.p(); - Point2LL b; - bool success = LinearAlg2D::getPointOnLineWithDist(a, p1, p2, shortcut_length, b); - // v02 has to be longer than ab! - if (success) - { // if not success then assume b is negligibly close to 2, but rounding errors caused a problem -#ifdef ASSERT_INSANE_OUTPUT - assert(vSize(b) < 4000000); -#endif // #ifdef ASSERT_INSANE_OUTPUT - ListPolyIt::insertPointNonDuplicate(p1_it, p2_it, b); - } - p1_it.remove(); - } - } -} - -void ConstPolygonRef::smooth_outward(const AngleDegrees min_angle, int shortcut_length, PolygonRef result) const -{ - // example of smoothed out corner: - // - // 6 - // ^ - // | - // inside | outside - // 2>3>4>5 - // ^ / . - // | / . - // 1 / . - // ^ / . - // |/ . - // | - // | - // 0 - - int shortcut_length2 = shortcut_length * shortcut_length; - double cos_min_angle = cos(min_angle / 180 * std::numbers::pi); - - ListPolygon poly; - ListPolyIt::convertPolygonToList(*this, poly); - - { // remove duplicate vertices - ListPolyIt p1_it(poly, poly.begin()); - do - { - ListPolyIt next = p1_it.next(); - if (vSize2(p1_it.p() - next.p()) < 10 * 10) - { - p1_it.remove(); - } - p1_it = next; - } while (p1_it != ListPolyIt(poly, poly.begin())); - } - - ListPolyIt p1_it(poly, poly.begin()); - do - { - const Point2LL p1 = p1_it.p(); - ListPolyIt p0_it = p1_it.prev(); - ListPolyIt p2_it = p1_it.next(); - const Point2LL p0 = p0_it.p(); - const Point2LL p2 = p2_it.p(); - - const Point2LL v10 = p0 - p1; - const Point2LL v12 = p2 - p1; - double cos_angle = INT2MM(INT2MM(dot(v10, v12))) / vSizeMM(v10) / vSizeMM(v12); - bool is_left_angle = LinearAlg2D::pointIsLeftOfLine(p1, p0, p2) > 0; - if (cos_angle > cos_min_angle && is_left_angle) - { - // angle is so sharp that it can be removed - Point2LL v02 = p2_it.p() - p0_it.p(); - if (vSize2(v02) >= shortcut_length2) - { - smooth_corner_simple(p0, p1, p2, p0_it, p1_it, p2_it, v10, v12, v02, shortcut_length, cos_angle); - } - else - { - bool remove_poly = smooth_corner_complex(p1, p0_it, p2_it, shortcut_length); // edits p0_it and p2_it! - if (remove_poly) - { - // don't convert ListPolygon into result - return; - } - } - // update: - p1_it = p2_it; // next point to consider for whether it's an internal corner - } - else - { - ++p1_it; - } - } while (p1_it != ListPolyIt(poly, poly.begin())); - - ListPolyIt::convertListPolygonToPolygon(poly, result); -} - -Polygons Polygons::smooth_outward(const AngleDegrees max_angle, int shortcut_length) -{ - Polygons ret; - for (unsigned int p = 0; p < size(); p++) - { - PolygonRef poly(paths[p]); - if (poly.size() < 3) - { - continue; - } - if (poly.size() == 3) - { - ret.add(poly); - continue; - } - poly.smooth_outward(max_angle, shortcut_length, ret.newPoly()); - if (ret.back().size() < 3) - { - ret.paths.resize(ret.paths.size() - 1); - } - } - return ret; -} - - -void ConstPolygonRef::splitPolylineIntoSegments(Polygons& result) const -{ - Point2LL last = front(); - for (size_t idx = 1; idx < size(); idx++) - { - Point2LL p = (*this)[idx]; - result.addLine(last, p); - last = p; - } -} - -Polygons ConstPolygonRef::splitPolylineIntoSegments() const -{ - Polygons ret; - splitPolylineIntoSegments(ret); - return ret; -} - -void ConstPolygonRef::splitPolygonIntoSegments(Polygons& result) const -{ - splitPolylineIntoSegments(result); - result.addLine(back(), front()); -} - -Polygons ConstPolygonRef::splitPolygonIntoSegments() const -{ - Polygons ret; - splitPolygonIntoSegments(ret); - return ret; -} - -void ConstPolygonRef::smooth(int remove_length, PolygonRef result) const -{ - // a typical zigzag with the middle part to be removed by removing (1) : - // - // 3 - // ^ - // | - // | - // inside | outside - // 1--->2 - // ^ - // | - // | - // | - // 0 - const ConstPolygonRef& thiss = *path; - ClipperLib::Path* poly = result.path; - if (size() > 0) - { - poly->push_back(thiss[0]); - } - auto is_zigzag = [remove_length](const int64_t v02_size, const int64_t v12_size, const int64_t v13_size, const int64_t dot1, const int64_t dot2) - { - if (v12_size > remove_length) - { // v12 or v13 is too long - return false; - } - const bool p1_is_left_of_v02 = dot1 < 0; - if (! p1_is_left_of_v02) - { // removing p1 wouldn't smooth outward - return false; - } - const bool p2_is_left_of_v13 = dot2 > 0; - if (p2_is_left_of_v13) - { // l0123 doesn't constitute a zigzag ''|,, - return false; - } - if (-dot1 <= v02_size * v12_size / 2) - { // angle at p1 isn't sharp enough - return false; - } - if (-dot2 <= v13_size * v12_size / 2) - { // angle at p2 isn't sharp enough - return false; - } - return true; - }; - Point2LL v02 = thiss[2] - thiss[0]; - Point2LL v02T = turn90CCW(v02); - int64_t v02_size = vSize(v02); - bool force_push = false; - for (unsigned int poly_idx = 1; poly_idx < size(); poly_idx++) - { - const Point2LL& p1 = thiss[poly_idx]; - const Point2LL& p2 = thiss[(poly_idx + 1) % size()]; - const Point2LL& p3 = thiss[(poly_idx + 2) % size()]; - // v02 computed in last iteration - // v02_size as well - const Point2LL v12 = p2 - p1; - const int64_t v12_size = vSize(v12); - const Point2LL v13 = p3 - p1; - const int64_t v13_size = vSize(v13); - - // v02T computed in last iteration - const int64_t dot1 = dot(v02T, v12); - const Point2LL v13T = turn90CCW(v13); - const int64_t dot2 = dot(v13T, v12); - bool push_point = force_push || ! is_zigzag(v02_size, v12_size, v13_size, dot1, dot2); - force_push = false; - if (push_point) - { - poly->push_back(p1); - } - else - { - // do not add the current one to the result - force_push = true; // ensure the next point is added; it cannot also be a zigzag - } - v02T = v13T; - v02 = v13; - v02_size = v13_size; - } -} - -Polygons Polygons::smooth(int remove_length) const -{ - Polygons ret; - for (unsigned int p = 0; p < size(); p++) - { - ConstPolygonRef poly(paths[p]); - if (poly.size() < 3) - { - continue; - } - if (poly.size() == 3) - { - ret.add(poly); - continue; - } - poly.smooth(remove_length, ret.newPoly()); - PolygonRef back = ret.back(); - if (back.size() < 3) - { - back.path->resize(back.path->size() - 1); - } - } - return ret; -} - -void ConstPolygonRef::smooth2(int remove_length, PolygonRef result) const -{ - const ConstPolygonRef& thiss = *this; - ClipperLib::Path* poly = result.path; - if (thiss.size() > 0) - { - poly->push_back(thiss[0]); - } - for (unsigned int poly_idx = 1; poly_idx < thiss.size(); poly_idx++) - { - const Point2LL& last = thiss[poly_idx - 1]; - const Point2LL& now = thiss[poly_idx]; - const Point2LL& next = thiss[(poly_idx + 1) % thiss.size()]; - if (shorterThen(last - now, remove_length) && shorterThen(now - next, remove_length)) - { - poly_idx++; // skip the next line piece (dont escalate the removal of edges) - if (poly_idx < thiss.size()) - { - poly->push_back(thiss[poly_idx]); - } - } - else - { - poly->push_back(thiss[poly_idx]); - } - } -} - -Polygons Polygons::smooth2(int remove_length, int min_area) const -{ - Polygons ret; - for (unsigned int p = 0; p < size(); p++) - { - ConstPolygonRef poly(paths[p]); - if (poly.size() == 0) - { - continue; - } - if (poly.area() < min_area || poly.size() <= 5) // when optimally removing, a poly with 5 pieces results in a triangle. Smaller polys dont have area! - { - ret.add(poly); - continue; - } - if (poly.size() < 4) - { - ret.add(poly); - } - else - { - poly.smooth2(remove_length, ret.newPoly()); - } - } - return ret; -} - -double Polygons::area() const -{ - double area = 0.0; - for (unsigned int poly_idx = 0; poly_idx < size(); poly_idx++) - { - area += operator[](poly_idx).area(); - // note: holes already have negative area - } - return area; -} - -std::vector Polygons::splitIntoParts(bool unionAll) const -{ - std::vector ret; - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree resultPolyTree; - clipper.AddPaths(paths, ClipperLib::ptSubject, true); - if (unionAll) - clipper.Execute(ClipperLib::ctUnion, resultPolyTree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - else - clipper.Execute(ClipperLib::ctUnion, resultPolyTree); - - splitIntoParts_processPolyTreeNode(&resultPolyTree, ret); - return ret; -} - -void Polygons::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const -{ - for (int n = 0; n < node->ChildCount(); n++) - { - ClipperLib::PolyNode* child = node->Childs[n]; - PolygonsPart part; - part.add(child->Contour); - for (int i = 0; i < child->ChildCount(); i++) - { - part.add(child->Childs[i]->Contour); - splitIntoParts_processPolyTreeNode(child->Childs[i], ret); - } - ret.push_back(part); - } -} - -std::vector Polygons::sortByNesting() const -{ - std::vector ret; - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree resultPolyTree; - clipper.AddPaths(paths, ClipperLib::ptSubject, true); - clipper.Execute(ClipperLib::ctUnion, resultPolyTree); - - sortByNesting_processPolyTreeNode(&resultPolyTree, 0, ret); - return ret; -} - -void Polygons::sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const -{ - for (int n = 0; n < node->ChildCount(); n++) - { - ClipperLib::PolyNode* child = node->Childs[n]; - if (nesting_idx >= ret.size()) - { - ret.resize(nesting_idx + 1); - } - ret[nesting_idx].add(child->Contour); - sortByNesting_processPolyTreeNode(child, nesting_idx + 1, ret); - } -} - -Polygons Polygons::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const -{ - return this->offset(outer_offset).difference(this->offset(-inner_offset)); -} - -Polygons Polygons::removeNearSelfIntersections() const -{ - using map_pt = mapbox::geometry::point; - using map_ring = mapbox::geometry::linear_ring; - using map_poly = mapbox::geometry::polygon; - using map_mpoly = mapbox::geometry::multi_polygon; - - map_mpoly mwpoly; - - mapbox::geometry::wagyu::wagyu wagyu; - - for (auto& polygon : splitIntoParts()) - { - mwpoly.emplace_back(); - map_poly& wpoly = mwpoly.back(); - for (auto& path : polygon) - { - wpoly.push_back(std::move(*reinterpret_cast>*>(&path))); - for (auto& point : wpoly.back()) - { - point.x /= 4; - point.y /= 4; - } - wagyu.add_ring(wpoly.back()); - } - } - - map_mpoly sln; - - wagyu.execute(mapbox::geometry::wagyu::clip_type_union, sln, mapbox::geometry::wagyu::fill_type_even_odd, mapbox::geometry::wagyu::fill_type_even_odd); - - Polygons polys; - - for (auto& poly : sln) - { - for (auto& ring : poly) - { - ring.pop_back(); - for (auto& point : ring) - { - point.x *= 4; - point.y *= 4; - } - polys.add(*reinterpret_cast*>(&ring)); // NOTE: 'add' already moves the vector - } - } - polys = polys.unionPolygons(); - polys.removeColinearEdges(); - - return polys; -} - -size_t PartsView::getPartContaining(size_t poly_idx, size_t* boundary_poly_idx) const -{ - const PartsView& partsView = *this; - for (size_t part_idx_now = 0; part_idx_now < partsView.size(); part_idx_now++) - { - const std::vector& partView = partsView[part_idx_now]; - if (partView.size() == 0) - { - continue; - } - std::vector::const_iterator result = std::find(partView.begin(), partView.end(), poly_idx); - if (result != partView.end()) - { - if (boundary_poly_idx) - { - *boundary_poly_idx = partView[0]; - } - return part_idx_now; - } - } - return NO_INDEX; -} - -PolygonsPart PartsView::assemblePart(size_t part_idx) const -{ - const PartsView& partsView = *this; - PolygonsPart ret; - if (part_idx != NO_INDEX) - { - for (size_t poly_idx_ff : partsView[part_idx]) - { - ret.add(polygons_[poly_idx_ff]); - } - } - return ret; -} - -PolygonsPart PartsView::assemblePartContaining(size_t poly_idx, size_t* boundary_poly_idx) const -{ - PolygonsPart ret; - size_t part_idx = getPartContaining(poly_idx, boundary_poly_idx); - if (part_idx != NO_INDEX) - { - return assemblePart(part_idx); - } - return ret; -} - -PartsView Polygons::splitIntoPartsView(bool unionAll) -{ - Polygons reordered; - PartsView partsView(*this); - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree resultPolyTree; - clipper.AddPaths(paths, ClipperLib::ptSubject, true); - if (unionAll) - clipper.Execute(ClipperLib::ctUnion, resultPolyTree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); - else - clipper.Execute(ClipperLib::ctUnion, resultPolyTree); - - splitIntoPartsView_processPolyTreeNode(partsView, reordered, &resultPolyTree); - - (*this) = reordered; - return partsView; -} - -void Polygons::splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Polygons& reordered, ClipperLib::PolyNode* node) const -{ - for (int n = 0; n < node->ChildCount(); n++) - { - ClipperLib::PolyNode* child = node->Childs[n]; - partsView.emplace_back(); - size_t pos = partsView.size() - 1; - partsView[pos].push_back(reordered.size()); - reordered.add(child->Contour); // TODO: should this steal the internal representation for speed? - for (int i = 0; i < child->ChildCount(); i++) - { - partsView[pos].push_back(reordered.size()); - reordered.add(child->Childs[i]->Contour); - splitIntoPartsView_processPolyTreeNode(partsView, reordered, child->Childs[i]); - } - } -} - -void Polygons::ensureManifold() -{ - const Polygons& polys = *this; - std::vector duplicate_locations; - std::unordered_set poly_locations; - for (size_t poly_idx = 0; poly_idx < polys.size(); poly_idx++) - { - ConstPolygonRef poly = polys[poly_idx]; - for (size_t point_idx = 0; point_idx < poly.size(); point_idx++) - { - Point2LL p = poly[point_idx]; - if (poly_locations.find(p) != poly_locations.end()) - { - duplicate_locations.push_back(p); - } - poly_locations.emplace(p); - } - } - Polygons removal_dots; - for (Point2LL p : duplicate_locations) - { - PolygonRef dot = removal_dots.newPoly(); - dot.add(p + Point2LL(0, 5)); - dot.add(p + Point2LL(5, 0)); - dot.add(p + Point2LL(0, -5)); - dot.add(p + Point2LL(-5, 0)); - } - if (! removal_dots.empty()) - { - *this = polys.difference(removal_dots); - } -} - -} // namespace cura diff --git a/tests/InfillTest.cpp b/tests/InfillTest.cpp index 157404288f..8f9866e9ee 100644 --- a/tests/InfillTest.cpp +++ b/tests/InfillTest.cpp @@ -290,7 +290,7 @@ TEST_P(InfillTest, TestInfillSanity) Shape result_polygon_lines = params.result_polygons; for (Polygon& poly : result_polygon_lines) { - poly.add(poly.front()); + poly.push_back(poly.front()); } ASSERT_LE(std::abs(padded_shape_outline.intersectionPolyLines(result_polygon_lines, restitch).polyLineLength() - result_polygon_lines.polyLineLength()), maximum_error) << "Infill (lines) should not be outside target polygon."; diff --git a/tests/LayerPlanTest.cpp b/tests/LayerPlanTest.cpp index 3ca48893da..7c7afa13e7 100644 --- a/tests/LayerPlanTest.cpp +++ b/tests/LayerPlanTest.cpp @@ -320,30 +320,30 @@ class AddTravelTest : public LayerPlanTest, public testing::WithParamInterface("false", "false", "off", false, false, AddTravelTestScene::OPEN)) { - around_start_end.add(Point2LL(-100, -100)); - around_start_end.add(Point2LL(500100, -100)); - around_start_end.add(Point2LL(500100, 500100)); - around_start_end.add(Point2LL(-100, 500100)); - - around_start.add(Point2LL(-100, -100)); - around_start.add(Point2LL(100, -100)); - around_start.add(Point2LL(100, 100)); - around_start.add(Point2LL(-100, 100)); - - around_end.add(Point2LL(249900, 249900)); - around_end.add(Point2LL(250100, 249900)); - around_end.add(Point2LL(250100, 250100)); - around_end.add(Point2LL(249900, 249900)); - - between.add(Point2LL(250000, 240000)); - between.add(Point2LL(260000, 240000)); - between.add(Point2LL(260000, 300000)); - between.add(Point2LL(250000, 300000)); - - between_hole.add(Point2LL(250000, 240000)); - between_hole.add(Point2LL(250000, 300000)); - between_hole.add(Point2LL(260000, 300000)); - between_hole.add(Point2LL(260000, 240000)); + around_start_end.push_back(Point2LL(-100, -100)); + around_start_end.push_back(Point2LL(500100, -100)); + around_start_end.push_back(Point2LL(500100, 500100)); + around_start_end.push_back(Point2LL(-100, 500100)); + + around_start.push_back(Point2LL(-100, -100)); + around_start.push_back(Point2LL(100, -100)); + around_start.push_back(Point2LL(100, 100)); + around_start.push_back(Point2LL(-100, 100)); + + around_end.push_back(Point2LL(249900, 249900)); + around_end.push_back(Point2LL(250100, 249900)); + around_end.push_back(Point2LL(250100, 250100)); + around_end.push_back(Point2LL(249900, 249900)); + + between.push_back(Point2LL(250000, 240000)); + between.push_back(Point2LL(260000, 240000)); + between.push_back(Point2LL(260000, 300000)); + between.push_back(Point2LL(250000, 300000)); + + between_hole.push_back(Point2LL(250000, 240000)); + between_hole.push_back(Point2LL(250000, 300000)); + between_hole.push_back(Point2LL(260000, 300000)); + between_hole.push_back(Point2LL(260000, 240000)); } /*! @@ -371,24 +371,24 @@ class AddTravelTest : public LayerPlanTest, public testing::WithParamInterface + #include +#include + +#include "geometry/shape.h" + namespace cura { // NOLINTBEGIN(*-magic-numbers) @@ -161,4 +164,4 @@ TEST(AABBTest, TestToPolygon) } // NOLINTEND(*-magic-numbers) -} // namespace cura \ No newline at end of file +} // namespace cura From fdb724fda234cfad308bc920be8e065895a06000 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 12 Apr 2024 10:52:48 +0200 Subject: [PATCH 036/135] Fixed unit tests CURA-9830 --- benchmark/infill_benchmark.h | 36 +++++----- benchmark/wall_benchmark.h | 25 ++++--- include/geometry/lines_set.h | 29 ++++++++ include/geometry/points_set.h | 13 ++++ include/geometry/shape.h | 15 ++++ include/utils/polygonUtils.h | 2 +- src/geometry/shape.cpp | 66 ++++++++++++++++++ src/utils/polygonUtils.cpp | 2 +- stress_benchmark/stress_benchmark.cpp | 12 ++-- tests/InfillTest.cpp | 16 ++--- tests/PathOrderMonotonicTest.cpp | 95 ++++++++++++++++++-------- tests/PathOrderOptimizerTest.cpp | 16 ++--- tests/WallsComputationTest.cpp | 32 +++++---- tests/arcus/ArcusCommunicationTest.cpp | 24 ++++--- tests/arcus/MockCommunication.h | 5 +- tests/integration/SlicePhaseTest.cpp | 4 +- tests/utils/AABBTest.cpp | 10 ++- tests/utils/IntPointTest.cpp | 5 +- tests/utils/LinearAlg2DTest.cpp | 2 + tests/utils/PolygonConnectorTest.cpp | 35 ++++++---- tests/utils/PolygonTest.cpp | 37 +++++----- tests/utils/PolygonUtilsTest.cpp | 46 ++++++------- tests/utils/SimplifyTest.cpp | 70 +++++++++---------- 23 files changed, 392 insertions(+), 205 deletions(-) diff --git a/benchmark/infill_benchmark.h b/benchmark/infill_benchmark.h index a6a52b817a..4799e5f5cb 100644 --- a/benchmark/infill_benchmark.h +++ b/benchmark/infill_benchmark.h @@ -6,6 +6,7 @@ #include +#include "geometry/open_lines_set.h" #include "infill.h" namespace cura @@ -58,8 +59,8 @@ class InfillTest : public benchmark::Fixture ff_holes.back().emplace_back(MM2INT(60), MM2INT(40)); ff_holes.back().emplace_back(MM2INT(90), MM2INT(25)); - outline_polygons.add(square_shape); - outline_polygons.add(ff_holes); + outline_polygons.push_back(square_shape); + outline_polygons.push_back(ff_holes); settings.add("fill_outline_gaps", "false"); settings.add("meshfix_maximum_deviation", "0.1"); @@ -93,29 +94,30 @@ class InfillTest : public benchmark::Fixture BENCHMARK_DEFINE_F(InfillTest, Infill_generate_connect)(benchmark::State& st) { - Infill infill(pattern, - zig_zagify, - connect_polygons, - outline_polygons, - INFILL_LINE_WIDTH, - line_distance, - INFILL_OVERLAP, - INFILL_MULTIPLIER, - FILL_ANGLE, - Z, - SHIFT, - MAX_RESOLUTION, - MAX_DEVIATION); // There are some optional parameters, but these will do for now (future improvement?). + Infill infill( + pattern, + zig_zagify, + connect_polygons, + outline_polygons, + INFILL_LINE_WIDTH, + line_distance, + INFILL_OVERLAP, + INFILL_MULTIPLIER, + FILL_ANGLE, + Z, + SHIFT, + MAX_RESOLUTION, + MAX_DEVIATION); // There are some optional parameters, but these will do for now (future improvement?). for (auto _ : st) { std::vector result_paths; Shape result_polygons; - Shape result_lines; + OpenLinesSet result_lines; infill.generate(result_paths, result_polygons, result_lines, settings, 0, SectionType::INFILL, nullptr, nullptr); } } -BENCHMARK_REGISTER_F(InfillTest, Infill_generate_connect)->ArgsProduct({{true, false}, {400, 800, 1200}})->Unit(benchmark::kMillisecond); +BENCHMARK_REGISTER_F(InfillTest, Infill_generate_connect)->ArgsProduct({ { true, false }, { 400, 800, 1200 } })->Unit(benchmark::kMillisecond); } // namespace cura #endif // CURAENGINE_INFILL_BENCHMARK_H diff --git a/benchmark/wall_benchmark.h b/benchmark/wall_benchmark.h index 6b43a4255e..95d99d6a90 100644 --- a/benchmark/wall_benchmark.h +++ b/benchmark/wall_benchmark.h @@ -4,21 +4,20 @@ #ifndef CURAENGINE_WALL_BENCHMARK_H #define CURAENGINE_WALL_BENCHMARK_H +#include +#include +#include +#include #include -#include #include +#include #include "InsetOrderOptimizer.h" #include "WallsComputation.h" +#include "geometry/polygon.h" #include "settings/Settings.h" #include "sliceDataStorage.h" -#include "geometry/polygon.h" - -#include -#include -#include -#include namespace cura { @@ -85,7 +84,7 @@ class WallTestFixture : public benchmark::Fixture layer.parts.emplace_back(); SliceLayerPart& part = layer.parts.back(); - part.outline.add(ff_holes); + part.outline.push_back(ff_holes); } void TearDown(const ::benchmark::State& state) @@ -145,7 +144,7 @@ class HolesWallTestFixture : public benchmark::Fixture layer.parts.emplace_back(); SliceLayerPart& part = layer.parts.back(); - part.outline.add(shape.paths.front()); + part.outline.push_back(shape.front()); part.print_outline = shape; } @@ -168,7 +167,7 @@ BENCHMARK_DEFINE_F(WallTestFixture, InsetOrderOptimizer_getRegionOrder)(benchmar { walls_computation.generateWalls(&layer, SectionType::WALL); std::vector all_paths; - for (auto& line : layer.parts.back().wall_toolpaths | ranges::views::join ) + for (auto& line : layer.parts.back().wall_toolpaths | ranges::views::join) { all_paths.emplace_back(line); } @@ -184,7 +183,7 @@ BENCHMARK_DEFINE_F(WallTestFixture, InsetOrderOptimizer_getInsetOrder)(benchmark { walls_computation.generateWalls(&layer, SectionType::WALL); std::vector all_paths; - for (auto& line : layer.parts.back().wall_toolpaths | ranges::views::join ) + for (auto& line : layer.parts.back().wall_toolpaths | ranges::views::join) { all_paths.emplace_back(line); } @@ -210,7 +209,7 @@ BENCHMARK_DEFINE_F(HolesWallTestFixture, InsetOrderOptimizer_getRegionOrder)(ben { walls_computation.generateWalls(&layer, SectionType::WALL); std::vector all_paths; - for (auto& line : layer.parts.back().wall_toolpaths | ranges::views::join ) + for (auto& line : layer.parts.back().wall_toolpaths | ranges::views::join) { all_paths.emplace_back(line); } @@ -226,7 +225,7 @@ BENCHMARK_DEFINE_F(HolesWallTestFixture, InsetOrderOptimizer_getInsetOrder)(benc { walls_computation.generateWalls(&layer, SectionType::WALL); std::vector all_paths; - for (auto& line : layer.parts.back().wall_toolpaths | ranges::views::join ) + for (auto& line : layer.parts.back().wall_toolpaths | ranges::views::join) { all_paths.emplace_back(line); } diff --git a/include/geometry/lines_set.h b/include/geometry/lines_set.h index 6562112ddd..f012eaccf7 100644 --- a/include/geometry/lines_set.h +++ b/include/geometry/lines_set.h @@ -6,6 +6,8 @@ #include +#include + #include "geometry/point2ll.h" namespace cura @@ -25,6 +27,10 @@ class LinesSet private: std::vector lines_; +public: + // Requires for some std calls as a container + typedef LineType value_type; + public: LinesSet() = default; @@ -226,6 +232,29 @@ class LinesSet void addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; void addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; + + /*! + * \brief Display operator, useful for debugging/testing + */ + template + friend std::basic_ostream& operator<<(std::basic_ostream& os, const LinesSet& lines) + { + os << "LinesSet["; + + for (const LineType& line : lines | ranges::views::drop(1)) + { + os << line; + os << ", "; + } + + if (lines.size() > 1) + { + os << lines.back(); + } + + os << "]"; + return os; + } }; } // namespace cura diff --git a/include/geometry/points_set.h b/include/geometry/points_set.h index 3eb151fd59..73d4673c73 100644 --- a/include/geometry/points_set.h +++ b/include/geometry/points_set.h @@ -24,6 +24,10 @@ class PointsSet private: ClipperLib::Path points_; +public: + // Requires for some std calls as a container + typedef Point2LL value_type; + public: PointsSet() = default; @@ -195,6 +199,15 @@ class PointsSet */ void applyMatrix(const PointMatrix& matrix); void applyMatrix(const Point3Matrix& matrix); + + /*! + * \brief Display operator, useful for debugging/testing + */ + template + friend std::basic_ostream& operator<<(std::basic_ostream& os, const PointsSet& polygon) + { + return os << "PointsSet(" << polygon.getPoints() << ")"; + } }; } // namespace cura diff --git a/include/geometry/shape.h b/include/geometry/shape.h index 16bfb8d59b..6cce47e5e6 100644 --- a/include/geometry/shape.h +++ b/include/geometry/shape.h @@ -286,6 +286,21 @@ class Shape : public LinesSet */ void simplify(ClipperLib::PolyFillType fill_type = ClipperLib::pftEvenOdd); +#ifdef BUILD_TESTS + /*! + * @brief Import the polygon from a WKT string + * @param wkt The WKT string to read from + * @return Polygons The polygons read from the stream + */ + [[maybe_unused]] static Shape fromWkt(const std::string& wkt); + + /*! + * @brief Export the polygon to a WKT string + * @param stream The stream to write to + */ + [[maybe_unused]] void writeWkt(std::ostream& stream) const; +#endif + private: /*! * recursive part of \ref Polygons::removeEmptyHoles and \ref Polygons::getEmptyHoles diff --git a/include/utils/polygonUtils.h b/include/utils/polygonUtils.h index 159d27d7b6..6ece6b6561 100644 --- a/include/utils/polygonUtils.h +++ b/include/utils/polygonUtils.h @@ -228,7 +228,7 @@ class PolygonUtils * the polygon. * \return Always returns 0. */ - static unsigned int moveInside(const Polygon& polygon, Point2LL& from, int distance = 0, int64_t max_dist2 = std::numeric_limits::max()); + static unsigned int moveInside(const ClosedPolyline& polygon, Point2LL& from, int distance = 0, int64_t max_dist2 = std::numeric_limits::max()); /*! * Moves the point \p from onto the nearest polygon or leaves the point as-is, when the comb boundary is not within the root of \p max_dist2 distance. diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index e0d893eef6..0051cc26f9 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -7,6 +7,19 @@ #include #include +#ifdef BUILD_TESTS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + #include #include @@ -916,6 +929,59 @@ void Shape::applyMatrix(const Point3Matrix& matrix) } } +#ifdef BUILD_TESTS +[[maybe_unused]] Shape Shape::fromWkt(const std::string& wkt) +{ + typedef boost::geometry::model::d2::point_xy point_type; + typedef boost::geometry::model::polygon polygon_type; + + polygon_type poly; + boost::geometry::read_wkt(wkt, poly); + + Shape ret; + + Polygon outer; + for (const auto& point : poly.outer()) + { + outer.emplace_back(point.x(), point.y()); + } + ret.push_back(outer); + + for (const auto& hole : poly.inners()) + { + Polygon inner; + for (const auto& point : hole) + { + inner.emplace_back(point.x(), point.y()); + } + ret.push_back(inner); + } + + return ret; +} + +[[maybe_unused]] void Shape::writeWkt(std::ostream& stream) const +{ + stream << "POLYGON ("; + const auto paths_str = getLines() + | ranges::views::transform( + [](const Polygon& path) + { + const auto line_string = ranges::views::concat(path, path | ranges::views::take(1)) + | ranges::views::transform( + [](const Point2LL& point) + { + return fmt::format("{} {}", point.X, point.Y); + }) + | ranges::views::join(ranges::views::c_str(", ")) | ranges::to(); + return "(" + line_string + ")"; + }) + | ranges::views::join(ranges::views::c_str(", ")) | ranges::to(); + stream << paths_str; + stream << ")"; +} +#endif + template LinesSet Shape::intersection(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; template LinesSet Shape::intersection(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; template LinesSet Shape::intersection(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index e4371f5d6d..b6edcae9e2 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -451,7 +451,7 @@ size_t PolygonUtils::moveInside(const Shape& polygons, Point2LL& from, int dista } // Version that works on single PolygonRef. -unsigned int PolygonUtils::moveInside(const Polygon& polygon, Point2LL& from, int distance, int64_t maxDist2) +unsigned int PolygonUtils::moveInside(const ClosedPolyline &polygon, Point2LL& from, int distance, int64_t maxDist2) { // TODO: This is copied from the moveInside of Polygons. /* diff --git a/stress_benchmark/stress_benchmark.cpp b/stress_benchmark/stress_benchmark.cpp index a55ee0a6f2..3562e20ae0 100644 --- a/stress_benchmark/stress_benchmark.cpp +++ b/stress_benchmark/stress_benchmark.cpp @@ -20,12 +20,12 @@ #include #include "WallsComputation.h" +#include "geometry/polygon.h" #include "rapidjson/document.h" #include "rapidjson/stringbuffer.h" #include "rapidjson/writer.h" #include "settings/Settings.h" #include "sliceDataStorage.h" -#include "geometry/polygon.h" constexpr std::string_view USAGE = R"(Stress Benchmark. @@ -80,18 +80,18 @@ struct Resource cura::Polygon outer; for (const auto& point : boost_polygon.outer()) { - outer.add(cura::Point2LL(point.x(), point.y())); + outer.push_back(cura::Point2LL(point.x(), point.y())); } - polygon.add(outer); + polygon.push_back(outer); for (const auto& hole : boost_polygon.inners()) { cura::Polygon inner; for (const auto& point : hole) { - inner.add(cura::Point2LL(point.x(), point.y())); + inner.push_back(cura::Point2LL(point.x(), point.y())); } - polygon.add(inner); + polygon.push_back(inner); } polygons.push_back(polygon); @@ -149,7 +149,7 @@ void handleChildProcess(const auto& shapes, const auto& settings) { layer.parts.emplace_back(); cura::SliceLayerPart& part = layer.parts.back(); - part.outline.add(shape); + part.outline.push_back(shape); } cura::LayerIndex layer_idx(100); cura::WallsComputation walls_computation(settings, layer_idx); diff --git a/tests/InfillTest.cpp b/tests/InfillTest.cpp index 8f9866e9ee..dc2f20e2dd 100644 --- a/tests/InfillTest.cpp +++ b/tests/InfillTest.cpp @@ -76,7 +76,7 @@ class InfillTestParameters Shape outline_polygons; // Resulting infill: - Shape result_lines; + OpenLinesSet result_lines; Shape result_polygons; std::string name; @@ -89,7 +89,7 @@ class InfillTestParameters { } - InfillTestParameters(const InfillParameters& params, const size_t& test_polygon_id, Shape outline_polygons, Shape result_lines, Shape result_polygons) + InfillTestParameters(const InfillParameters& params, const size_t& test_polygon_id, Shape outline_polygons, OpenLinesSet result_lines, Shape result_polygons) : valid(true) , fail_reason("__") , params(params) @@ -177,7 +177,7 @@ InfillTestParameters generateInfillToTest(const InfillParameters& params, const Settings infill_settings; std::vector result_paths; Shape result_polygons; - Shape result_lines; + OpenLinesSet result_lines; infill.generate(result_paths, result_polygons, result_lines, infill_settings, 1, SectionType::INFILL, nullptr, nullptr); InfillTestParameters result = InfillTestParameters(params, test_polygon_id, outline_polygons, result_lines, result_polygons); @@ -267,7 +267,7 @@ TEST_P(InfillTest, TestInfillSanity) long double worst_case_zig_zag_added_area = 0; if (params.params.zig_zagify || params.params.pattern == EFillMethod::ZIG_ZAG) { - worst_case_zig_zag_added_area = params.outline_polygons.polygonLength() * INFILL_LINE_WIDTH; + worst_case_zig_zag_added_area = params.outline_polygons.length() * INFILL_LINE_WIDTH; } const double min_available_area = std::abs(params.outline_polygons.offset(static_cast(-params.params.line_distance) / 2).area()); @@ -275,8 +275,8 @@ TEST_P(InfillTest, TestInfillSanity) const long double min_expected_infill_area = (min_available_area * static_cast(INFILL_LINE_WIDTH)) / params.params.line_distance; const long double max_expected_infill_area = (max_available_area * INFILL_LINE_WIDTH) / params.params.line_distance + worst_case_zig_zag_added_area; - const long double out_infill_area = ((params.result_polygons.polygonLength() + params.result_lines.polyLineLength()) * static_cast(INFILL_LINE_WIDTH)) - / getPatternMultiplier(params.params.pattern); + const long double out_infill_area + = ((params.result_polygons.length() + params.result_lines.length()) * static_cast(INFILL_LINE_WIDTH)) / getPatternMultiplier(params.params.pattern); ASSERT_GT((coord_t)max_available_area, (coord_t)out_infill_area) << "Infill area should allways be less than the total area available."; ASSERT_GT((coord_t)out_infill_area, (coord_t)min_expected_infill_area) << "Infill area should be greater than the minimum area expected to be covered."; @@ -285,14 +285,14 @@ TEST_P(InfillTest, TestInfillSanity) const coord_t maximum_error = 10_mu; // potential rounding error const Shape padded_shape_outline = params.outline_polygons.offset(INFILL_LINE_WIDTH / 2); constexpr bool restitch = false; // No need to restitch polylines - that would introduce stitching errors. - ASSERT_LE(std::abs(padded_shape_outline.intersectionPolyLines(params.result_lines, restitch).polyLineLength() - params.result_lines.polyLineLength()), maximum_error) + ASSERT_LE(std::abs(padded_shape_outline.intersection(params.result_lines, restitch).length() - params.result_lines.length()), maximum_error) << "Infill (lines) should not be outside target polygon."; Shape result_polygon_lines = params.result_polygons; for (Polygon& poly : result_polygon_lines) { poly.push_back(poly.front()); } - ASSERT_LE(std::abs(padded_shape_outline.intersectionPolyLines(result_polygon_lines, restitch).polyLineLength() - result_polygon_lines.polyLineLength()), maximum_error) + ASSERT_LE(std::abs(padded_shape_outline.intersection(result_polygon_lines, restitch).length() - result_polygon_lines.length()), maximum_error) << "Infill (lines) should not be outside target polygon."; } diff --git a/tests/PathOrderMonotonicTest.cpp b/tests/PathOrderMonotonicTest.cpp index 108d1178ed..c6932c214b 100644 --- a/tests/PathOrderMonotonicTest.cpp +++ b/tests/PathOrderMonotonicTest.cpp @@ -2,24 +2,28 @@ // CuraEngine is released under the terms of the AGPLv3 or higher #include "PathOrderMonotonic.h" -#include "ReadTestPolygons.h" -#include "infill.h" -#include "slicer.h" -#include "utils/Coord_t.h" -#include "utils/math.h" -#include "geometry/polygon.h" -#include + #include #include #include #include +#include + +#include "ReadTestPolygons.h" +#include "geometry/polygon.h" +#include "infill.h" +#include "slicer.h" +#include "utils/Coord_t.h" +#include "utils/math.h" + // To diagnose failing tests with visual images, uncomment the following line: // #define TEST_PATHS_SVG_OUTPUT #ifdef TEST_PATHS_SVG_OUTPUT -#include "utils/SVG.h" #include + +#include "utils/SVG.h" #endif // TEST_PATHS_SVG_OUTPUT namespace cura @@ -30,22 +34,22 @@ class PathOrderMonotonicTest : public testing::TestWithParam& path) +inline Point2LL startVertex(const PathOrdering& path) { return (*path.vertices_)[path.start_vertex_]; } -inline Point2LL endVertex(const PathOrdering& path) +inline Point2LL endVertex(const PathOrdering& path) { return (*path.vertices_)[path.vertices_->size() - (1 + path.start_vertex_)]; } -coord_t projectPathAlongAxis(const PathOrdering& path, const Point2LL& vector) +coord_t projectPathAlongAxis(const PathOrdering& path, const Point2LL& vector) { return dot(startVertex(path), vector); } -coord_t projectEndAlongAxis(const PathOrdering& path, const Point2LL& vector) +coord_t projectEndAlongAxis(const PathOrdering& path, const Point2LL& vector) { return dot(endVertex(path), vector); } @@ -54,7 +58,8 @@ bool rangeOverlaps(const std::pair& range_b, const std::pair shapes; if (! readTestPolygons(filename, shapes)) @@ -81,7 +86,20 @@ bool getInfillLines(const std::string& filename, const AngleRadians& angle, Shap for (const auto& shape : shapes) { - Infill infill_comp(pattern, zig_zagify, connect_polygons, shape, infill_line_width, line_distance, infill_overlap, infill_multiplier, AngleDegrees(angle), z, shift, max_resolution, max_deviation); + Infill infill_comp( + pattern, + zig_zagify, + connect_polygons, + shape, + infill_line_width, + line_distance, + infill_overlap, + infill_multiplier, + AngleDegrees(angle), + z, + shift, + max_resolution, + max_deviation); Settings infill_settings; std::vector result_paths; Shape dummy_polys; @@ -91,7 +109,11 @@ bool getInfillLines(const std::string& filename, const AngleRadians& angle, Shap } #ifdef TEST_PATHS_SVG_OUTPUT -void writeDebugSVG(const std::string& original_filename, const AngleRadians& angle, const Point& monotonic_vec, const std::vector>>& sections) +void writeDebugSVG( + const std::string& original_filename, + const AngleRadians& angle, + const Point& monotonic_vec, + const std::vector>>& sections) { constexpr int buff_size = 1024; char buff[buff_size]; @@ -136,7 +158,7 @@ TEST_P(PathOrderMonotonicTest, SectionsTest) const auto params = GetParam(); const double angle_radians{ std::get<1>(params) }; const auto& filename = std::get<0>(params); - Shape polylines; + OpenLinesSet polylines; ASSERT_TRUE(getInfillLines(filename, angle_radians, polylines)) << "Input test-file could not be read, check setup."; const Point2LL& pt_r = polylines.begin()->at(0); @@ -146,15 +168,15 @@ TEST_P(PathOrderMonotonicTest, SectionsTest) const Point2LL perpendicular_axis{ turn90CCW(monotonic_axis) }; constexpr coord_t max_adjacent_distance = line_distance + 1; - PathOrderMonotonic object_under_test(angle_from_first_line, max_adjacent_distance, monotonic_axis * -1000); + PathOrderMonotonic object_under_test(angle_from_first_line, max_adjacent_distance, monotonic_axis * -1000); for (const auto& polyline : polylines) { - object_under_test.addPolyline(ConstPolygonPointer(polyline)); + object_under_test.addPolyline(&polyline); } object_under_test.optimize(); // Collect sections: - std::vector>> sections; + std::vector>> sections; sections.emplace_back(); coord_t last_path_mono_projection = projectPathAlongAxis(object_under_test.paths_.front(), monotonic_axis); for (const auto& path : object_under_test.paths_) @@ -202,7 +224,8 @@ TEST_P(PathOrderMonotonicTest, SectionsTest) const coord_t mono_b = projectPathAlongAxis(*it_b, monotonic_axis); if (mono_a < mono_b) { - EXPECT_FALSE(rangeOverlaps(perp_b_range, perp_a_range)) << "Perpendicular range overlaps for neighboring lines in different sections (next line of A / line in B)."; + EXPECT_FALSE(rangeOverlaps(perp_b_range, perp_a_range)) + << "Perpendicular range overlaps for neighboring lines in different sections (next line of A / line in B)."; } } } @@ -210,14 +233,28 @@ TEST_P(PathOrderMonotonicTest, SectionsTest) } } -const std::vector polygon_filenames = { - std::filesystem::path(__FILE__).parent_path().append("resources/polygon_concave.txt").string(), std::filesystem::path(__FILE__).parent_path().append("resources/polygon_concave_hole.txt").string(), - std::filesystem::path(__FILE__).parent_path().append("resources/polygon_square.txt").string(), std::filesystem::path(__FILE__).parent_path().append("resources/polygon_square_hole.txt").string(), - std::filesystem::path(__FILE__).parent_path().append("resources/polygon_triangle.txt").string(), std::filesystem::path(__FILE__).parent_path().append("resources/polygon_two_squares.txt").string(), - std::filesystem::path(__FILE__).parent_path().append("resources/polygon_slant_gap.txt").string(), std::filesystem::path(__FILE__).parent_path().append("resources/polygon_sawtooth.txt").string(), - std::filesystem::path(__FILE__).parent_path().append("resources/polygon_letter_y.txt").string() -}; -const std::vector angle_radians = { 0, 0.1, 0.25 * std::numbers::pi, 1.0, 0.5 * std::numbers::pi, 0.75 * std::numbers::pi, std::numbers::pi, 1.25 * std::numbers::pi, 4.0, 1.5 * std::numbers::pi, 1.75 * std::numbers::pi, 5.0, (2.0 * std::numbers::pi) - 0.1 }; +const std::vector polygon_filenames = { std::filesystem::path(__FILE__).parent_path().append("resources/polygon_concave.txt").string(), + std::filesystem::path(__FILE__).parent_path().append("resources/polygon_concave_hole.txt").string(), + std::filesystem::path(__FILE__).parent_path().append("resources/polygon_square.txt").string(), + std::filesystem::path(__FILE__).parent_path().append("resources/polygon_square_hole.txt").string(), + std::filesystem::path(__FILE__).parent_path().append("resources/polygon_triangle.txt").string(), + std::filesystem::path(__FILE__).parent_path().append("resources/polygon_two_squares.txt").string(), + std::filesystem::path(__FILE__).parent_path().append("resources/polygon_slant_gap.txt").string(), + std::filesystem::path(__FILE__).parent_path().append("resources/polygon_sawtooth.txt").string(), + std::filesystem::path(__FILE__).parent_path().append("resources/polygon_letter_y.txt").string() }; +const std::vector angle_radians = { 0, + 0.1, + 0.25 * std::numbers::pi, + 1.0, + 0.5 * std::numbers::pi, + 0.75 * std::numbers::pi, + std::numbers::pi, + 1.25 * std::numbers::pi, + 4.0, + 1.5 * std::numbers::pi, + 1.75 * std::numbers::pi, + 5.0, + (2.0 * std::numbers::pi) - 0.1 }; INSTANTIATE_TEST_SUITE_P(PathOrderMonotonicTestInstantiation, PathOrderMonotonicTest, testing::Combine(testing::ValuesIn(polygon_filenames), testing::ValuesIn(angle_radians))); // NOLINTEND(*-magic-numbers) diff --git a/tests/PathOrderOptimizerTest.cpp b/tests/PathOrderOptimizerTest.cpp index b4d4a32ee1..c8621ba3d8 100644 --- a/tests/PathOrderOptimizerTest.cpp +++ b/tests/PathOrderOptimizerTest.cpp @@ -15,7 +15,7 @@ class PathOrderOptimizerTest : public testing::Test /*! * A blank optimizer with no polygons added yet. Fresh and virgin. */ - PathOrderOptimizer optimizer; + PathOrderOptimizer optimizer; /*! * A simple isosceles triangle. Base length and height 50. @@ -29,12 +29,12 @@ class PathOrderOptimizerTest : public testing::Test void SetUp() override { - optimizer = PathOrderOptimizer(Point2LL(0, 0)); + optimizer = PathOrderOptimizer(Point2LL(0, 0)); triangle.clear(); - triangle.add(Point2LL(0, 0)); - triangle.add(Point2LL(50, 0)); - triangle.add(Point2LL(25, 50)); + triangle.push_back(Point2LL(0, 0)); + triangle.push_back(Point2LL(50, 0)); + triangle.push_back(Point2LL(25, 50)); } }; // NOLINTEND(misc-non-private-member-variables-in-classes) @@ -62,9 +62,9 @@ TEST_F(PathOrderOptimizerTest, ThreeTrianglesShortestOrder) far.translate(Point2LL(1000, 1000)); // Add them out of order so that it's clear that the optimization changes the order. - optimizer.addPolygon(middle); - optimizer.addPolygon(far); - optimizer.addPolygon(near); + optimizer.addPolygon(&middle); + optimizer.addPolygon(&far); + optimizer.addPolygon(&near); optimizer.optimize(); diff --git a/tests/WallsComputationTest.cpp b/tests/WallsComputationTest.cpp index 424a3c9b66..fc6d60a365 100644 --- a/tests/WallsComputationTest.cpp +++ b/tests/WallsComputationTest.cpp @@ -2,21 +2,25 @@ // CuraEngine is released under the terms of the AGPLv3 or higher #include "WallsComputation.h" //Unit under test. + +#include + +#include +#include + +#include + #include "InsetOrderOptimizer.h" //Unit also under test. +#include "geometry/polygon.h" //To create example polygons. #include "settings/Settings.h" //Settings to generate walls with. #include "sliceDataStorage.h" //Sl #include "slicer.h" -#include "geometry/polygon.h" //To create example polygons. -#include -#include -#include - -#include #ifdef WALLS_COMPUTATION_TEST_SVG_OUTPUT -#include "utils/SVG.h" -#include "geometry/polygon.h" #include + +#include "geometry/polygon.h" +#include "utils/SVG.h" #endif // WALLS_COMPUTATION_TEST_SVG_OUTPUT // NOLINTBEGIN(*-magic-numbers) @@ -48,7 +52,8 @@ class WallsComputationTest : public testing::Test */ Shape ff_holes; - WallsComputationTest() : walls_computation(settings, LayerIndex(100)) + WallsComputationTest() + : walls_computation(settings, LayerIndex(100)) { square_shape.emplace_back(); square_shape.back().emplace_back(0, 0); @@ -104,7 +109,7 @@ TEST_F(WallsComputationTest, GenerateWallsForLayerSinglePart) SliceLayer layer; layer.parts.emplace_back(); SliceLayerPart& part = layer.parts.back(); - part.outline.add(square_shape); + part.outline.push_back(square_shape); // Run the test. walls_computation.generateWalls(&layer, SectionType::WALL); @@ -113,7 +118,8 @@ TEST_F(WallsComputationTest, GenerateWallsForLayerSinglePart) EXPECT_FALSE(part.wall_toolpaths.empty()) << "There must be some walls."; EXPECT_GT(part.print_outline.area(), 0) << "The print outline must encompass the outer wall, so it must be more than 0."; EXPECT_LE(part.print_outline.area(), square_shape.area()) << "The print outline must stay within the bounds of the original part."; - EXPECT_GT(part.inner_area.area(), 0) << "The inner area must be within the innermost wall. There are not enough walls to fill the entire part, so there is a positive inner area."; + EXPECT_GT(part.inner_area.area(), 0) + << "The inner area must be within the innermost wall. There are not enough walls to fill the entire part, so there is a positive inner area."; EXPECT_EQ(layer.parts.size(), 1) << "There is still just 1 part."; } @@ -126,7 +132,7 @@ TEST_F(WallsComputationTest, GenerateWallsZeroWalls) SliceLayer layer; layer.parts.emplace_back(); SliceLayerPart& part = layer.parts.back(); - part.outline.add(square_shape); + part.outline.push_back(square_shape); // Run the test. walls_computation.generateWalls(&layer, SectionType::WALL); @@ -147,7 +153,7 @@ TEST_F(WallsComputationTest, WallToolPathsGetWeakOrder) SliceLayer layer; layer.parts.emplace_back(); SliceLayerPart& part = layer.parts.back(); - part.outline.add(ff_holes); + part.outline.push_back(ff_holes); // Run the test. walls_computation.generateWalls(&layer, SectionType::WALL); diff --git a/tests/arcus/ArcusCommunicationTest.cpp b/tests/arcus/ArcusCommunicationTest.cpp index cf66883c36..3c56047815 100644 --- a/tests/arcus/ArcusCommunicationTest.cpp +++ b/tests/arcus/ArcusCommunicationTest.cpp @@ -1,15 +1,17 @@ // Copyright (c) 2022 Ultimaker B.V. // CuraEngine is released under the terms of the AGPLv3 or higher. +#include +#include + +#include + #include "FffProcessor.h" #include "MockSocket.h" //To mock out the communication with the front-end. #include "communication/ArcusCommunicationPrivate.h" //To access the private fields of this communication class. +#include "geometry/polygon.h" //Create test shapes to send over the socket. #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" -#include "geometry/polygon.h" //Create test shapes to send over the socket. -#include -#include -#include // NOLINTBEGIN(*-magic-numbers) namespace cura @@ -47,24 +49,24 @@ class ArcusCommunicationTest : public testing::Test test_square.emplace_back(1000, 0); test_square.emplace_back(1000, 1000); test_square.emplace_back(0, 1000); - test_shapes.add(test_square); + test_shapes.push_back(test_square); test_square2.emplace_back(1100, 1500); test_square2.emplace_back(2000, 1500); test_square2.emplace_back(2000, -500); test_square2.emplace_back(1100, -500); - test_shapes.add(test_square2); + test_shapes.push_back(test_square2); test_triangle.emplace_back(0, 2100); test_triangle.emplace_back(500, 1100); test_triangle.emplace_back(1500, 2100); - test_shapes.add(test_triangle); + test_shapes.push_back(test_triangle); for (double a = 0; a < 1.0; a += .05) { - test_circle.add(Point2LL(2050, 2050) + Point2LL(std::cos(a * 2 * std::numbers::pi) * 500, std::sin(a * 2 * std::numbers::pi) * 500)); + test_circle.push_back(Point2LL(2050, 2050) + Point2LL(std::cos(a * 2 * std::numbers::pi) * 500, std::sin(a * 2 * std::numbers::pi) * 500)); } - test_shapes.add(test_circle); + test_shapes.push_back(test_circle); test_convex_shape.emplace_back(-300, 0); test_convex_shape.emplace_back(-100, 500); @@ -75,7 +77,7 @@ class ArcusCommunicationTest : public testing::Test test_convex_shape.emplace_back(-1500, 1500); test_convex_shape.emplace_back(-1600, 1100); test_convex_shape.emplace_back(-700, 200); - test_shapes.add(test_convex_shape); + test_shapes.push_back(test_convex_shape); } void TearDown() override @@ -170,4 +172,4 @@ TEST_F(ArcusCommunicationTest, SendProgress) } } // namespace cura -// NOLINTEND(*-magic-numbers) \ No newline at end of file +// NOLINTEND(*-magic-numbers) diff --git a/tests/arcus/MockCommunication.h b/tests/arcus/MockCommunication.h index 405ebc2878..fb1151c4e0 100644 --- a/tests/arcus/MockCommunication.h +++ b/tests/arcus/MockCommunication.h @@ -7,9 +7,10 @@ #include #include "communication/Communication.h" //The interface we're implementing. +#include "geometry/polygon.h" //In the signature of Communication. +#include "geometry/shape.h" #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" -#include "geometry/polygon.h" //In the signature of Communication. namespace cura { @@ -24,7 +25,7 @@ class MockCommunication : public Communication MOCK_CONST_METHOD0(isSequential, bool()); MOCK_CONST_METHOD1(sendProgress, void(double progress)); MOCK_METHOD3(sendLayerComplete, void(const LayerIndex::value_type& layer_nr, const coord_t& z, const coord_t& thickness)); - MOCK_METHOD5(sendPolygons, void(const PrintFeatureType& type, const Polygons& polygons, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity)); + MOCK_METHOD5(sendPolygons, void(const PrintFeatureType& type, const Shape& polygons, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity)); MOCK_METHOD5(sendPolygon, void(const PrintFeatureType& type, const Polygon& polygon, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity)); MOCK_METHOD5(sendLineTo, void(const PrintFeatureType& type, const Point2LL& to, const coord_t& line_width, const coord_t& line_thickness, const Velocity& velocity)); MOCK_METHOD1(sendCurrentPosition, void(const Point2LL& position)); diff --git a/tests/integration/SlicePhaseTest.cpp b/tests/integration/SlicePhaseTest.cpp index 9c6a0f641b..1a4fc1579e 100644 --- a/tests/integration/SlicePhaseTest.cpp +++ b/tests/integration/SlicePhaseTest.cpp @@ -7,10 +7,10 @@ #include "Application.h" // To set up a slice with settings. #include "Slice.h" // To set up a scene to slice. +#include "geometry/polygon.h" // Creating polygons to compare to sliced layers. #include "slicer.h" // Starts the slicing phase that we want to test. #include "utils/Coord_t.h" #include "utils/Matrix4x3D.h" // To load STL files. -#include "geometry/polygon.h" // Creating polygons to compare to sliced layers. #include "utils/polygonUtils.h" // Comparing similarity of polygons. namespace cura @@ -158,7 +158,7 @@ TEST_F(SlicePhaseTest, Cylinder1000) circle.emplace_back(x, y); } Shape circles; - circles.add(circle); + circles.push_back(circle); for (size_t layer_nr = 0; layer_nr < num_layers; layer_nr++) { diff --git a/tests/utils/AABBTest.cpp b/tests/utils/AABBTest.cpp index 8305798621..e3ad71f54c 100644 --- a/tests/utils/AABBTest.cpp +++ b/tests/utils/AABBTest.cpp @@ -7,6 +7,7 @@ #include +#include "geometry/polygon.h" #include "geometry/shape.h" namespace cura @@ -43,9 +44,12 @@ TEST(AABBTest, TestConstructPolygons) EXPECT_FALSE(polygons_box_a.contains(Point2LL(0, 0))) << "Box constructed from empty polygon shouldn't contain anything."; Shape polygons; - polygons.add(Polygon(ClipperLib::Path({ ClipperLib::IntPoint{ -10, -10 }, ClipperLib::IntPoint{ 10, -10 }, ClipperLib::IntPoint{ -5, -5 }, ClipperLib::IntPoint{ -10, 10 } }))); - polygons.add(Polygon(ClipperLib::Path({ ClipperLib::IntPoint{ 11, 11 }, ClipperLib::IntPoint{ -11, 11 }, ClipperLib::IntPoint{ 4, 4 }, ClipperLib::IntPoint{ 11, -11 } }))); - polygons.add(Polygon(ClipperLib::Path({ ClipperLib::IntPoint{ 2, 2 }, ClipperLib::IntPoint{ 2, 3 }, ClipperLib::IntPoint{ 3, 3 }, ClipperLib::IntPoint{ 3, 2 } }))); + polygons.push_back( + Polygon(ClipperLib::Path({ ClipperLib::IntPoint{ -10, -10 }, ClipperLib::IntPoint{ 10, -10 }, ClipperLib::IntPoint{ -5, -5 }, ClipperLib::IntPoint{ -10, 10 } }), false)); + polygons.push_back( + Polygon(ClipperLib::Path({ ClipperLib::IntPoint{ 11, 11 }, ClipperLib::IntPoint{ -11, 11 }, ClipperLib::IntPoint{ 4, 4 }, ClipperLib::IntPoint{ 11, -11 } }), false)); + polygons.push_back( + Polygon(ClipperLib::Path({ ClipperLib::IntPoint{ 2, 2 }, ClipperLib::IntPoint{ 2, 3 }, ClipperLib::IntPoint{ 3, 3 }, ClipperLib::IntPoint{ 3, 2 } }), false)); AABB polygons_box_b(polygons); diff --git a/tests/utils/IntPointTest.cpp b/tests/utils/IntPointTest.cpp index cd6d2f2a73..0dfe1e36b4 100644 --- a/tests/utils/IntPointTest.cpp +++ b/tests/utils/IntPointTest.cpp @@ -1,9 +1,12 @@ // Copyright (c) 2022 Ultimaker B.V. // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "geometry/point2ll.h" #include +#include "geometry/point2ll.h" +#include "geometry/point3_matrix.h" +#include "geometry/point_matrix.h" + // NOLINTBEGIN(*-magic-numbers) namespace cura { diff --git a/tests/utils/LinearAlg2DTest.cpp b/tests/utils/LinearAlg2DTest.cpp index b9e4f41bb0..fd0c3cde9b 100644 --- a/tests/utils/LinearAlg2DTest.cpp +++ b/tests/utils/LinearAlg2DTest.cpp @@ -7,6 +7,8 @@ #include +#include "geometry/point3_matrix.h" + // NOLINTBEGIN(*-magic-numbers) namespace cura { diff --git a/tests/utils/PolygonConnectorTest.cpp b/tests/utils/PolygonConnectorTest.cpp index c30fde412e..bc7ae275f6 100644 --- a/tests/utils/PolygonConnectorTest.cpp +++ b/tests/utils/PolygonConnectorTest.cpp @@ -2,11 +2,14 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "utils/PolygonConnector.h" // The class under test. -#include "utils/Coord_t.h" -#include "geometry/polygon.h" // To create polygons to test with. -#include + #include +#include + +#include "geometry/polygon.h" // To create polygons to test with. +#include "utils/Coord_t.h" + // NOLINTBEGIN(*-magic-numbers) namespace cura { @@ -70,7 +73,8 @@ TEST_F(PolygonConnectorTest, getBridgeNestedSquares) EXPECT_EQ(vSize(bridge->a_.from_point_ - bridge->a_.to_point_), 100) << "The polygons are 100 units spaced out concentrically, so this is the shortest possible bridge."; EXPECT_EQ(vSize(bridge->b_.from_point_ - bridge->b_.to_point_), 100) << "The second bridge should also be equally short in this case."; - EXPECT_EQ(LinearAlg2D::getDist2BetweenLineSegments(bridge->a_.from_point_, bridge->a_.to_point_, bridge->b_.from_point_, bridge->b_.to_point_), 100 * 100) << "The bridges should be spaced 1 line width (100 units) apart."; + EXPECT_EQ(LinearAlg2D::getDist2BetweenLineSegments(bridge->a_.from_point_, bridge->a_.to_point_, bridge->b_.from_point_, bridge->b_.to_point_), 100 * 100) + << "The bridges should be spaced 1 line width (100 units) apart."; EXPECT_LT(LinearAlg2D::pointIsLeftOfLine(bridge->b_.from_point_, bridge->a_.from_point_, bridge->a_.to_point_), 0) << "Connection B should be to the right of connection A."; EXPECT_LT(LinearAlg2D::pointIsLeftOfLine(bridge->b_.to_point_, bridge->a_.from_point_, bridge->a_.to_point_), 0) << "Connection B should be to the right of connection A."; } @@ -90,7 +94,8 @@ TEST_F(PolygonConnectorTest, getBridgeAdjacentSquares) EXPECT_EQ(vSize(bridge->a_.from_point_ - bridge->a_.to_point_), 100) << "The polygons are 100 units spaced apart, so this is the shortest possible bridge."; EXPECT_EQ(vSize(bridge->b_.from_point_ - bridge->b_.to_point_), 100) << "The second bridge should also be equally short in this case."; - EXPECT_EQ(LinearAlg2D::getDist2BetweenLineSegments(bridge->a_.from_point_, bridge->a_.to_point_, bridge->b_.from_point_, bridge->b_.to_point_), 100 * 100) << "The bridges should be spaced 1 line width (100 units) apart."; + EXPECT_EQ(LinearAlg2D::getDist2BetweenLineSegments(bridge->a_.from_point_, bridge->a_.to_point_, bridge->b_.from_point_, bridge->b_.to_point_), 100 * 100) + << "The bridges should be spaced 1 line width (100 units) apart."; EXPECT_LT(LinearAlg2D::pointIsLeftOfLine(bridge->b_.from_point_, bridge->a_.from_point_, bridge->a_.to_point_), 0) << "Connection B should be to the right of connection A."; EXPECT_LT(LinearAlg2D::pointIsLeftOfLine(bridge->b_.to_point_, bridge->a_.from_point_, bridge->a_.to_point_), 0) << "Connection B should be to the right of connection A."; } @@ -113,8 +118,10 @@ TEST_F(PolygonConnectorTest, getBridgeClosest) ASSERT_NE(bridge, std::nullopt) << "The two polygons are adjacent and spaced closely enough to bridge along their entire side, even with the slant."; - EXPECT_EQ(bridge->b_.from_point_, Point2LL(1000, 200)) << "The closest connection is [1000,200] -> [1100,200]. There is no space to the right of that, so bridge B should be there."; - EXPECT_EQ(bridge->b_.to_point_, Point2LL(1100, 200)) << "The closest connection is [1000,200] -> [1100,200]. There is no space to the right of that, so bridge B should be there."; + EXPECT_EQ(bridge->b_.from_point_, Point2LL(1000, 200)) + << "The closest connection is [1000,200] -> [1100,200]. There is no space to the right of that, so bridge B should be there."; + EXPECT_EQ(bridge->b_.to_point_, Point2LL(1100, 200)) + << "The closest connection is [1000,200] -> [1100,200]. There is no space to the right of that, so bridge B should be there."; EXPECT_GT(LinearAlg2D::pointIsLeftOfLine(bridge->a_.from_point_, bridge->b_.from_point_, bridge->b_.to_point_), 0) << "Connection A should be to the left of connection B."; EXPECT_GT(LinearAlg2D::pointIsLeftOfLine(bridge->a_.to_point_, bridge->b_.from_point_, bridge->b_.to_point_), 0) << "Connection A should be to the left of connection B."; } @@ -133,7 +140,8 @@ TEST_F(PolygonConnectorTest, getBridgeTooFar) std::optional> bridge = pc->getBridge(test_square, to_connect); - EXPECT_EQ(bridge, std::nullopt) << "The two polygons are 200 units apart where they are closest, which is more than 1.5 times the line width (100), so they can't be connected."; + EXPECT_EQ(bridge, std::nullopt) + << "The two polygons are 200 units apart where they are closest, which is more than 1.5 times the line width (100), so they can't be connected."; } /*! @@ -154,7 +162,8 @@ TEST_F(PolygonConnectorTest, getBridgeTooNarrow) std::optional> bridge = pc->getBridge(test_square, to_connect); - EXPECT_EQ(bridge, std::nullopt) << "Where the two polygons are adjacent is only 80 units wide. This is not enough to create a bridge with the connecting lines spaced 1 line width (100 units) apart."; + EXPECT_EQ(bridge, std::nullopt) + << "Where the two polygons are adjacent is only 80 units wide. This is not enough to create a bridge with the connecting lines spaced 1 line width (100 units) apart."; } /*! @@ -165,10 +174,10 @@ TEST_F(PolygonConnectorTest, getBridgeTooNarrow) TEST_F(PolygonConnectorTest, connectFourNested) { Shape connecting; - connecting.add(test_square_around); // 1200-wide square. - connecting.add(test_square); // 1000-wide square. - connecting.add(test_square.offset(-100)); // 800-wide square. - connecting.add(test_square.offset(-200)); // 600-wide square. + connecting.push_back(test_square_around); // 1200-wide square. + connecting.push_back(test_square); // 1000-wide square. + connecting.push_back(test_square.offset(-100)); // 800-wide square. + connecting.push_back(test_square.offset(-200)); // 600-wide square. pc->add(connecting); Shape output_polygons; diff --git a/tests/utils/PolygonTest.cpp b/tests/utils/PolygonTest.cpp index e2d7ec6839..13b218e484 100644 --- a/tests/utils/PolygonTest.cpp +++ b/tests/utils/PolygonTest.cpp @@ -5,7 +5,6 @@ #include -#include "geometry/closed_polyline.h" #include "geometry/open_polyline.h" #include "geometry/single_shape.h" #include "utils/Coord_t.h" @@ -82,9 +81,9 @@ class PolygonTest : public testing::Test small_area.emplace_back(10, 10); small_area.emplace_back(0, 10); } - void twoPolygonsAreEqual(Shape& polygon1, Shape& polygon2) const + void twoPolygonsAreEqual(Shape& shape1, Shape& shape2) const { - auto poly_cmp = [](const ClipperLib::Path& a, const ClipperLib::Path& b) + auto poly_cmp = [](const Polygon& a, const Polygon& b) { return std::lexicographical_compare( a.begin(), @@ -96,15 +95,15 @@ class PolygonTest : public testing::Test return p1 < p2; }); }; - std::sort(polygon1.begin(), polygon1.end(), poly_cmp); - std::sort(polygon2.begin(), polygon2.end(), poly_cmp); + std::sort(shape1.begin(), shape1.end(), poly_cmp); + std::sort(shape2.begin(), shape2.end(), poly_cmp); - std::vector difference; - std::set_difference(polygon1.begin(), polygon1.end(), polygon2.begin(), polygon2.end(), std::back_inserter(difference), poly_cmp); + LinesSet difference; + std::set_difference(shape1.begin(), shape1.end(), shape2.begin(), shape2.end(), std::back_inserter(difference), poly_cmp); ASSERT_TRUE(difference.empty()) << "Paths in polygon1 not found in polygon2:" << difference; difference.clear(); - std::set_difference(polygon2.begin(), polygon2.end(), polygon1.begin(), polygon1.end(), std::back_inserter(difference), poly_cmp); + std::set_difference(shape2.begin(), shape2.end(), shape1.begin(), shape1.end(), std::back_inserter(difference), poly_cmp); ASSERT_TRUE(difference.empty()) << "Paths in polygon2 not found in polygon1:" << difference; } }; @@ -567,24 +566,24 @@ TEST_F(PolygonTest, removeSmallAreas_complex) TEST_F(PolygonTest, openCloseLines) { // make some line - OpenPolyline openPolyline; - openPolyline.emplace_back(0, 0); - openPolyline.emplace_back(1000, 0); - openPolyline.emplace_back(1000, 1000); - openPolyline.emplace_back(0, 1000); + OpenPolyline open_polyline; + open_polyline.emplace_back(0, 0); + open_polyline.emplace_back(1000, 0); + open_polyline.emplace_back(1000, 1000); + open_polyline.emplace_back(0, 1000); // Make some casts and check that the results are consistent - EXPECT_EQ(openPolyline.length(), 3000); + EXPECT_EQ(open_polyline.length(), 3000); - ClosedPolyline& closedPolyline = openPolyline.toType(); - EXPECT_EQ(closedPolyline.length(), 4000); + ClosedPolyline closed_polyline(open_polyline.getPoints(), false); + EXPECT_EQ(closed_polyline.length(), 4000); - Polygon& polygon = openPolyline.toType(); + Polygon polygon(closed_polyline.getPoints(), false); EXPECT_EQ(polygon.area(), 1000000); // Check advanced calculations on segment length - EXPECT_TRUE(openPolyline.shorterThan(3500)); - EXPECT_FALSE(closedPolyline.shorterThan(3500)); + EXPECT_TRUE(open_polyline.shorterThan(3500)); + EXPECT_FALSE(closed_polyline.shorterThan(3500)); } } // namespace cura diff --git a/tests/utils/PolygonUtilsTest.cpp b/tests/utils/PolygonUtilsTest.cpp index 1b1cf91f83..ffa8b21612 100644 --- a/tests/utils/PolygonUtilsTest.cpp +++ b/tests/utils/PolygonUtilsTest.cpp @@ -5,9 +5,9 @@ #include -#include "utils/Coord_t.h" #include "geometry/point2ll.h" // Creating and testing with points. #include "geometry/polygon.h" // Creating polygons to test with. +#include "utils/Coord_t.h" // NOLINTBEGIN(*-magic-numbers) namespace cura @@ -71,7 +71,7 @@ TEST_P(MoveInsideTest, MoveInside2) { const MoveInsideParameters parameters = GetParam(); Shape polys; - polys.add(test_square); + polys.push_back(test_square); Point2LL result = parameters.close_to; PolygonUtils::moveInside2(polys, result, parameters.distance); ASSERT_LE(vSize(result - parameters.supposed), 10) << parameters.close_to << " moved with " << parameters.distance << " micron inside to " << result << "rather than " @@ -165,7 +165,7 @@ TEST_F(MoveInsideTest, cornerEdgeTest2) const Point2LL supposed2(72, 100); constexpr coord_t distance = 28; Shape polys; - polys.add(test_square); + polys.push_back(test_square); Point2LL result = close_to; PolygonUtils::moveInside2(polys, result, distance); @@ -179,7 +179,7 @@ TEST_F(MoveInsideTest, pointyCorner) const Point2LL from(55, 100); // Above pointy bit. Point2LL result(from); Shape inside; - inside.add(pointy_square); + inside.push_back(pointy_square); ClosestPointPolygon cpp = PolygonUtils::ensureInsideOrOutside(inside, result, 10); ASSERT_NE(cpp.point_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; @@ -193,7 +193,7 @@ TEST_F(MoveInsideTest, pointyCornerFail) const Point2LL from(55, 170); // Above pointy bit. Point2LL result(from); Shape inside; - inside.add(pointy_square); + inside.push_back(pointy_square); ClosestPointPolygon cpp = PolygonUtils::moveInside2(inside, result, 10); ASSERT_NE(cpp.point_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; @@ -207,7 +207,7 @@ TEST_F(MoveInsideTest, outsidePointyCorner) Point2LL result(from); const Point2LL supposed(50, 70); // 10 below pointy bit. Shape inside; - inside.add(pointy_square); + inside.push_back(pointy_square); const ClosestPointPolygon cpp = PolygonUtils::ensureInsideOrOutside(inside, result, -10); ASSERT_NE(cpp.point_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; @@ -222,7 +222,7 @@ TEST_F(MoveInsideTest, outsidePointyCornerFail) Point2LL result(from); const Point2LL supposed(50, 70); // 10 below pointy bit. Shape inside; - inside.add(pointy_square); + inside.push_back(pointy_square); const ClosestPointPolygon cpp = PolygonUtils::moveInside2(inside, result, -10); ASSERT_NE(cpp.point_idx_, NO_INDEX) << "Couldn't ensure point inside close to " << from << "."; @@ -266,7 +266,7 @@ TEST_P(FindCloseTest, FindClose) { const FindCloseParameters parameters = GetParam(); Shape polygons; - polygons.add(test_square); + polygons.push_back(test_square); auto loc_to_line = PolygonUtils::createLocToLineGrid(polygons, parameters.cell_size); std::optional cpp; @@ -323,28 +323,28 @@ class PolygonUtilsTest : public testing::Test test_square.emplace_back(100, 0); test_square.emplace_back(100, 100); test_square.emplace_back(0, 100); - test_squares.add(test_square); + test_squares.push_back(test_square); Polygon line; line.emplace_back(0, 0); line.emplace_back(100, 0); - test_line.add(line); + test_line.push_back(line); Polygon line_extra_vertices; line_extra_vertices.emplace_back(100, 0); line_extra_vertices.emplace_back(25, 0); line_extra_vertices.emplace_back(0, 0); line_extra_vertices.emplace_back(75, 0); - test_line_extra_vertices.add(line_extra_vertices); + test_line_extra_vertices.push_back(line_extra_vertices); } }; TEST_F(PolygonUtilsTest, spreadDotsSegment) { std::vector supposed; - supposed.emplace_back(Point2LL(50, 0), 0, test_squares[0], 0); - supposed.emplace_back(Point2LL(100, 0), 1, test_squares[0], 0); - supposed.emplace_back(Point2LL(100, 50), 1, test_squares[0], 0); + supposed.emplace_back(Point2LL(50, 0), 0, &test_squares[0], 0); + supposed.emplace_back(Point2LL(100, 0), 1, &test_squares[0], 0); + supposed.emplace_back(Point2LL(100, 50), 1, &test_squares[0], 0); std::vector result; PolygonUtils::spreadDots(PolygonsPointIndex(&test_squares, 0, 0), PolygonsPointIndex(&test_squares, 0, 2), 3, result); @@ -359,14 +359,14 @@ TEST_F(PolygonUtilsTest, spreadDotsSegment) TEST_F(PolygonUtilsTest, spreadDotsFull) { std::vector supposed; - supposed.emplace_back(Point2LL(0, 0), 0, test_squares[0], 0); - supposed.emplace_back(Point2LL(50, 0), 0, test_squares[0], 0); - supposed.emplace_back(Point2LL(100, 0), 1, test_squares[0], 0); - supposed.emplace_back(Point2LL(100, 50), 1, test_squares[0], 0); - supposed.emplace_back(Point2LL(100, 100), 2, test_squares[0], 0); - supposed.emplace_back(Point2LL(50, 100), 2, test_squares[0], 0); - supposed.emplace_back(Point2LL(0, 100), 3, test_squares[0], 0); - supposed.emplace_back(Point2LL(0, 50), 3, test_squares[0], 0); + supposed.emplace_back(Point2LL(0, 0), 0, &test_squares[0], 0); + supposed.emplace_back(Point2LL(50, 0), 0, &test_squares[0], 0); + supposed.emplace_back(Point2LL(100, 0), 1, &test_squares[0], 0); + supposed.emplace_back(Point2LL(100, 50), 1, &test_squares[0], 0); + supposed.emplace_back(Point2LL(100, 100), 2, &test_squares[0], 0); + supposed.emplace_back(Point2LL(50, 100), 2, &test_squares[0], 0); + supposed.emplace_back(Point2LL(0, 100), 3, &test_squares[0], 0); + supposed.emplace_back(Point2LL(0, 50), 3, &test_squares[0], 0); std::vector result; PolygonUtils::spreadDots(PolygonsPointIndex(&test_squares, 0, 0), PolygonsPointIndex(&test_squares, 0, 0), 8, result); @@ -408,7 +408,7 @@ class GetNextParallelIntersectionTest : public testing::TestWithParam Date: Fri, 12 Apr 2024 08:53:29 +0000 Subject: [PATCH 037/135] Applied clang-format. --- src/utils/polygonUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index b6edcae9e2..ba3372dc58 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -451,7 +451,7 @@ size_t PolygonUtils::moveInside(const Shape& polygons, Point2LL& from, int dista } // Version that works on single PolygonRef. -unsigned int PolygonUtils::moveInside(const ClosedPolyline &polygon, Point2LL& from, int distance, int64_t maxDist2) +unsigned int PolygonUtils::moveInside(const ClosedPolyline& polygon, Point2LL& from, int distance, int64_t maxDist2) { // TODO: This is copied from the moveInside of Polygons. /* From cccbfe3feb711cc099bdb39ce9dafce276f75b59 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 12 Apr 2024 16:27:59 +0200 Subject: [PATCH 038/135] Code cleaning CURA-9830 --- include/geometry/closed_polyline.h | 6 +- include/geometry/polygon.h | 20 +- include/geometry/shape.h | 15 -- include/support.h | 4 +- include/utils/Simplify.h | 313 ++++++----------------------- src/ConicalOverhang.cpp | 1 + src/slicer.cpp | 6 +- src/support.cpp | 1 + src/utils/Simplify.cpp | 203 +++++++++++++++++++ 9 files changed, 286 insertions(+), 283 deletions(-) diff --git a/include/geometry/closed_polyline.h b/include/geometry/closed_polyline.h index f05f353ee2..fe660cd79e 100644 --- a/include/geometry/closed_polyline.h +++ b/include/geometry/closed_polyline.h @@ -21,7 +21,11 @@ class ClosedPolyline : public Polyline bool explicitely_closed_{ false }; public: - ClosedPolyline() = default; + ClosedPolyline(bool explicitely_closed = false) + : Polyline() + , explicitely_closed_(explicitely_closed) + { + } ClosedPolyline(const ClosedPolyline& other) = default; diff --git a/include/geometry/polygon.h b/include/geometry/polygon.h index 652b28997c..4902ed47a8 100644 --- a/include/geometry/polygon.h +++ b/include/geometry/polygon.h @@ -16,7 +16,10 @@ class AngleDegrees; class Polygon : public ClosedPolyline { public: - Polygon() = default; + Polygon(bool explicitely_closed = false) + : ClosedPolyline(explicitely_closed) + { + } Polygon(const Polygon& other) = default; @@ -174,19 +177,4 @@ class Polygon : public ClosedPolyline } // namespace cura -namespace std -{ -#if 0 -template<> -struct hash -{ - size_t operator()(const cura::PolygonPointer& poly) const - { - const cura::ConstPolygonRef ref = *static_cast(poly); - return std::hash()(&*ref); - } -}; -#endif -} // namespace std - #endif // GEOMETRY_POLYGON_H diff --git a/include/geometry/shape.h b/include/geometry/shape.h index 6cce47e5e6..a236b04dc0 100644 --- a/include/geometry/shape.h +++ b/include/geometry/shape.h @@ -316,19 +316,4 @@ class Shape : public LinesSet } // namespace cura -namespace std -{ -#if 0 -template<> -struct hash -{ - size_t operator()(const cura::PolygonPointer& poly) const - { - const cura::ConstPolygonRef ref = *static_cast(poly); - return std::hash()(&*ref); - } -}; -#endif -} // namespace std - #endif // GEOMETRY_SHAPE_H diff --git a/include/support.h b/include/support.h index 36412b4dcb..0d6eaeffa6 100644 --- a/include/support.h +++ b/include/support.h @@ -7,8 +7,8 @@ #include #include -#include "geometry/polygon.h" #include "settings/types/LayerIndex.h" +#include "utils/Coord_t.h" namespace cura { @@ -17,6 +17,8 @@ class Settings; class SliceDataStorage; class SliceMeshStorage; class Slicer; +class Polygon; +class Shape; class AreaSupport { diff --git a/include/utils/Simplify.h b/include/utils/Simplify.h index 5e5ac0b5fd..3406fe6d00 100644 --- a/include/utils/Simplify.h +++ b/include/utils/Simplify.h @@ -4,10 +4,9 @@ #ifndef UTILS_SIMPLIFY_H #define UTILS_SIMPLIFY_H -#include "../settings/Settings.h" //To load the parameters from a Settings object. -#include "geometry/mixed_lines_set.h" -#include "geometry/polygon.h" -#include "linearAlg2D.h" //To calculate line deviations and intersecting lines. +#include "geometry/point2ll.h" +#include "utils/Coord_t.h" + namespace cura { @@ -16,6 +15,13 @@ template class LinesSet; struct ExtrusionLine; struct ExtrusionJunction; +class MixedLinesSet; +class Settings; +class Shape; +class Polygon; +class OpenPolyline; +class ClosedPolyline; +class Polyline; /*! * Utility class to reduce the resolution of polygons and polylines, under @@ -156,240 +162,6 @@ class Simplify */ constexpr static coord_t min_resolution = 5; // 5 units, regardless of how big those are, to allow for rounding errors. - template - bool detectSmall(const Polygonal& polygon, const coord_t& min_size) const - { - if (polygon.size() < min_size) // For polygon, 2 or fewer vertices is degenerate. Delete it. For polyline, 1 vertex is degenerate. - { - return true; - } - if (polygon.size() == min_size) - { - const auto a = getPosition(polygon[0]); - const auto b = getPosition(polygon[1]); - const auto c = getPosition(polygon[polygon.size() - 1]); - if (std::max(std::max(vSize2(b - a), vSize2(c - a)), vSize2(c - b)) < min_resolution * min_resolution) - { - // ... unless they are degenetate. - return true; - } - } - return false; - } - - /*! - * The main simplification algorithm starts here. - * \tparam Polygonal A polygonal object, which is a list of vertices. - * \param polygon The polygonal chain to simplify. - * \param is_closed Whether this is a closed polygon or an open polyline. - * \return A simplified polygonal chain. - */ - template - Polygonal simplify(const Polygonal& polygon, const bool is_closed) const - { - const size_t min_size = is_closed ? 3 : 2; - if (detectSmall(polygon, min_size)) - { - return createEmpty(polygon); - } - if (polygon.size() == min_size) // For polygon, don't reduce below 3. For polyline, not below 2. - { - return polygon; - } - - std::vector to_delete(polygon.size(), false); - auto comparator = [](const std::pair& vertex_a, const std::pair& vertex_b) - { - return vertex_a.second > vertex_b.second || (vertex_a.second == vertex_b.second && vertex_a.first > vertex_b.first); - }; - std::priority_queue, std::vector>, decltype(comparator)> by_importance(comparator); - - Polygonal result = polygon; // Make a copy so that we can also shift vertices. - for (int64_t current_removed = -1; (polygon.size() - current_removed) > min_size && current_removed != 0;) - { - current_removed = 0; - - // Add the initial points. - for (size_t i = 0; i < result.size(); ++i) - { - if (to_delete[i]) - { - continue; - } - const coord_t vertex_importance = importance(result, to_delete, i, is_closed); - by_importance.emplace(i, vertex_importance); - } - - // Iteratively remove the least important point until a threshold. - coord_t vertex_importance = 0; - while (! by_importance.empty() && (polygon.size() - current_removed) > min_size) - { - std::pair vertex = by_importance.top(); - by_importance.pop(); - // The importance may have changed since this vertex was inserted. Re-compute it now. - // If it doesn't change, it's safe to process. - vertex_importance = importance(result, to_delete, vertex.first, is_closed); - if (vertex_importance != vertex.second) - { - by_importance.emplace(vertex.first, vertex_importance); // Re-insert with updated importance. - continue; - } - - if (vertex_importance <= max_deviation_ * max_deviation_) - { - current_removed += remove(result, to_delete, vertex.first, vertex_importance, is_closed) ? 1 : 0; - } - } - } - - // Now remove the marked vertices in one sweep. - Polygonal filtered = createEmpty(polygon); - for (size_t i = 0; i < result.size(); ++i) - { - if (! to_delete[i]) - { - appendVertex(filtered, result[i]); - } - } - - if (detectSmall(filtered, min_size)) - { - return createEmpty(filtered); - } - return filtered; - } - - /*! - * A measure of the importance of a vertex. - * \tparam Polygonal A polygonal object, which is a list of vertices. - * \param polygon The polygon or polyline the vertex is part of. - * \param to_delete For each vertex, whether it is set to be deleted. - * \param index The vertex index to compute the importance of. - * \param is_closed Whether the polygon is closed (a polygon) or open - * (a polyline). - * \return A measure of how important the vertex is. Higher importance means - * that the vertex should probably be retained in the output. - */ - template - coord_t importance(const Polygonal& polygon, const std::vector& to_delete, const size_t index, const bool is_closed) const - { - const size_t poly_size = polygon.size(); - if (! is_closed && (index == 0 || index == poly_size - 1)) - { - return std::numeric_limits::max(); // Endpoints of the polyline must always be retained. - } - // From here on out we can safely look at the vertex neighbors and assume it's a polygon. We won't go out of bounds of the polyline. - - const Point2LL& vertex = getPosition(polygon[index]); - const size_t before_index = previousNotDeleted(index, to_delete); - const size_t after_index = nextNotDeleted(index, to_delete); - - const coord_t area_deviation = getAreaDeviation(polygon[before_index], polygon[index], polygon[after_index]); - if (area_deviation > max_area_deviation_) // Removing this line causes the variable line width to get flattened out too much. - { - return std::numeric_limits::max(); - } - - const Point2LL& before = getPosition(polygon[before_index]); - const Point2LL& after = getPosition(polygon[after_index]); - const coord_t deviation2 = LinearAlg2D::getDist2FromLine(vertex, before, after); - if (deviation2 <= min_resolution * min_resolution) // Deviation so small that it's always desired to remove them. - { - return deviation2; - } - if (vSize2(before - vertex) > max_resolution_ * max_resolution_ && vSize2(after - vertex) > max_resolution_ * max_resolution_) - { - return std::numeric_limits::max(); // Long line segments, no need to remove this one. - } - return deviation2; - } - - /*! - * Mark a vertex for removal. - * - * This function looks in the vertex and the four edges surrounding it to - * determine the best way to remove the given vertex. It may choose instead - * to delete an edge, fusing two vertices together. - * \tparam Polygonal A polygonal object, which is a list of vertices. - * \param polygon The polygon to remove a vertex from. - * \param to_delete The vertices that have been marked for deletion so far. - * This will be edited in-place. - * \param vertex The index of the vertex to remove. - * \param deviation2 The previously found deviation for this vertex. - * \param is_closed Whether we're working on a closed polygon or an open - \return Whether something is actually removed - * polyline. - */ - template - bool remove(Polygonal& polygon, std::vector& to_delete, const size_t vertex, const coord_t deviation2, const bool is_closed) const - { - if (deviation2 <= min_resolution * min_resolution) - { - // At less than the minimum resolution we're always allowed to delete the vertex. - // Even if the adjacent line segments are very long. - to_delete[vertex] = true; - return true; - } - - const size_t before = previousNotDeleted(vertex, to_delete); - const size_t after = nextNotDeleted(vertex, to_delete); - const Point2LL& vertex_position = getPosition(polygon[vertex]); - const Point2LL& before_position = getPosition(polygon[before]); - const Point2LL& after_position = getPosition(polygon[after]); - const coord_t length2_before = vSize2(vertex_position - before_position); - const coord_t length2_after = vSize2(vertex_position - after_position); - - if (length2_before <= max_resolution_ * max_resolution_ && length2_after <= max_resolution_ * max_resolution_) // Both adjacent line segments are short. - { - // Removing this vertex does little harm. No long lines will be shifted. - to_delete[vertex] = true; - return true; - } - - // Otherwise, one edge next to this vertex is longer than max_resolution. The other is shorter. - // In this case we want to remove the short edge by replacing it with a vertex where the two surrounding edges intersect. - // Find the two line segments surrounding the short edge here ("before" and "after" edges). - Point2LL before_from, before_to, after_from, after_to; - if (length2_before <= length2_after) // Before is the shorter line. - { - if (! is_closed && before == 0) // No edge before the short edge. - { - return false; // Edge cannot be deleted without shifting a long edge. Don't remove anything. - } - const size_t before_before = previousNotDeleted(before, to_delete); - before_from = getPosition(polygon[before_before]); - before_to = getPosition(polygon[before]); - after_from = getPosition(polygon[vertex]); - after_to = getPosition(polygon[after]); - } - else - { - if (! is_closed && after == polygon.size() - 1) // No edge after the short edge. - { - return false; // Edge cannot be deleted without shifting a long edge. Don't remove anything. - } - const size_t after_after = nextNotDeleted(after, to_delete); - before_from = getPosition(polygon[before]); - before_to = getPosition(polygon[vertex]); - after_from = getPosition(polygon[after]); - after_to = getPosition(polygon[after_after]); - } - Point2LL intersection; - const bool did_intersect = LinearAlg2D::lineLineIntersection(before_from, before_to, after_from, after_to, intersection); - if (! did_intersect) // Lines are parallel. - { - return false; // Cannot remove edge without shifting a long edge. Don't remove anything. - } - const coord_t intersection_deviation = LinearAlg2D::getDist2FromLineSegment(before_to, intersection, after_from); - if (intersection_deviation <= max_deviation_ * max_deviation_) // Intersection point doesn't deviate too much. Use it! - { - to_delete[vertex] = true; - polygon[length2_before <= length2_after ? before : after] = createIntersection(polygon[before], intersection, polygon[after]); - return true; - } - return false; - } - /*! * Helper method to find the index of the next vertex that is not about to * get deleted. @@ -416,15 +188,6 @@ class Simplify */ size_t previousNotDeleted(size_t index, const std::vector& to_delete) const; - /*! - * Create an empty polygonal with the same properties as an original polygon, - * but without the vertex data. - * \param original The polygonal to copy the properties from. - * \return An empty polygonal. - */ - template - Polygonal createEmpty(const Polygonal& original) const; - /*! * Append a vertex to this polygon. * @@ -504,6 +267,62 @@ class Simplify * \return The area deviation that would be caused by removing the vertex. */ coord_t getAreaDeviation(const ExtrusionJunction& before, const ExtrusionJunction& vertex, const ExtrusionJunction& after) const; + +private: + /*! + * Create an empty polygonal with the same properties as an original polygon, + * but without the vertex data. + * \param original The polygonal to copy the properties from. + * \return An empty polygonal. + */ + template + Polygonal createEmpty(const Polygonal& original) const; + + template + bool detectSmall(const Polygonal& polygon, const coord_t& min_size) const; + + /*! + * The main simplification algorithm starts here. + * \tparam Polygonal A polygonal object, which is a list of vertices. + * \param polygon The polygonal chain to simplify. + * \param is_closed Whether this is a closed polygon or an open polyline. + * \return A simplified polygonal chain. + */ + template + Polygonal simplify(const Polygonal& polygon, const bool is_closed) const; + + /*! + * A measure of the importance of a vertex. + * \tparam Polygonal A polygonal object, which is a list of vertices. + * \param polygon The polygon or polyline the vertex is part of. + * \param to_delete For each vertex, whether it is set to be deleted. + * \param index The vertex index to compute the importance of. + * \param is_closed Whether the polygon is closed (a polygon) or open + * (a polyline). + * \return A measure of how important the vertex is. Higher importance means + * that the vertex should probably be retained in the output. + */ + template + coord_t importance(const Polygonal& polygon, const std::vector& to_delete, const size_t index, const bool is_closed) const; + + /*! + * Mark a vertex for removal. + * + * This function looks in the vertex and the four edges surrounding it to + * determine the best way to remove the given vertex. It may choose instead + * to delete an edge, fusing two vertices together. + * \tparam Polygonal A polygonal object, which is a list of vertices. + * \param polygon The polygon to remove a vertex from. + * \param to_delete The vertices that have been marked for deletion so far. + * This will be edited in-place. + * \param vertex The index of the vertex to remove. + * \param deviation2 The previously found deviation for this vertex. + * \param is_closed Whether we're working on a closed polygon or an open + \return Whether something is actually removed + * polyline. + */ + template + bool remove(Polygonal& polygon, std::vector& to_delete, const size_t vertex, const coord_t deviation2, const bool is_closed) const; }; } // namespace cura diff --git a/src/ConicalOverhang.cpp b/src/ConicalOverhang.cpp index 1cf720b745..571bf0c76e 100644 --- a/src/ConicalOverhang.cpp +++ b/src/ConicalOverhang.cpp @@ -4,6 +4,7 @@ #include "ConicalOverhang.h" +#include "geometry/polygon.h" #include "geometry/single_shape.h" #include "mesh.h" #include "settings/types/Angle.h" //To process the overhang angle. diff --git a/src/slicer.cpp b/src/slicer.cpp index ba257594bf..cb923c7c6e 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -45,7 +45,7 @@ void SlicerLayer::makeBasicPolygonLoops(OpenLinesSet& open_polylines) void SlicerLayer::makeBasicPolygonLoop(OpenLinesSet& open_polylines, const size_t start_segment_idx) { - OpenPolyline poly; + Polygon poly(true); poly.push_back(segments[start_segment_idx].start); for (int segment_idx = start_segment_idx; segment_idx != -1;) @@ -56,12 +56,12 @@ void SlicerLayer::makeBasicPolygonLoop(OpenLinesSet& open_polylines, const size_ segment_idx = getNextSegmentIdx(segment, start_segment_idx); if (segment_idx == static_cast(start_segment_idx)) { // polyon is closed - polygons.push_back(Polygon(std::move(poly.getPoints()), true)); + polygons.push_back(std::move(poly)); return; } } // polygon couldn't be closed - open_polylines.push_back(poly); + open_polylines.emplace_back(std::move(poly.getPoints())); } int SlicerLayer::tryFaceNextSegmentIdx(const SlicerSegment& segment, const int face_idx, const size_t start_segment_idx) const diff --git a/src/support.cpp b/src/support.cpp index 9a960ac8ac..c040f6dc6e 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -35,6 +35,7 @@ #include "slicer.h" #include "utils/Simplify.h" #include "utils/ThreadPool.h" +#include "utils/linearAlg2D.h" #include "utils/math.h" namespace cura diff --git a/src/utils/Simplify.cpp b/src/utils/Simplify.cpp index 7ec3e3e17d..330ac36871 100644 --- a/src/utils/Simplify.cpp +++ b/src/utils/Simplify.cpp @@ -7,8 +7,11 @@ #include //Priority queue to prioritise removing unimportant vertices. #include "geometry/closed_polyline.h" +#include "geometry/mixed_lines_set.h" #include "geometry/open_polyline.h" +#include "settings/Settings.h" //To load the parameters from a Settings object. #include "utils/ExtrusionLine.h" +#include "utils/linearAlg2D.h" //To calculate line deviations and intersecting lines. namespace cura { @@ -205,6 +208,206 @@ coord_t Simplify::getAreaDeviation(const ExtrusionJunction& before, const Extrus } } +template +bool Simplify::detectSmall(const Polygonal& polygon, const coord_t& min_size) const +{ + if (polygon.size() < min_size) // For polygon, 2 or fewer vertices is degenerate. Delete it. For polyline, 1 vertex is degenerate. + { + return true; + } + if (polygon.size() == min_size) + { + const auto a = getPosition(polygon[0]); + const auto b = getPosition(polygon[1]); + const auto c = getPosition(polygon[polygon.size() - 1]); + if (std::max(std::max(vSize2(b - a), vSize2(c - a)), vSize2(c - b)) < min_resolution * min_resolution) + { + // ... unless they are degenetate. + return true; + } + } + return false; +} + +template +Polygonal Simplify::simplify(const Polygonal& polygon, const bool is_closed) const +{ + const size_t min_size = is_closed ? 3 : 2; + if (detectSmall(polygon, min_size)) + { + return createEmpty(polygon); + } + if (polygon.size() == min_size) // For polygon, don't reduce below 3. For polyline, not below 2. + { + return polygon; + } + + std::vector to_delete(polygon.size(), false); + auto comparator = [](const std::pair& vertex_a, const std::pair& vertex_b) + { + return vertex_a.second > vertex_b.second || (vertex_a.second == vertex_b.second && vertex_a.first > vertex_b.first); + }; + std::priority_queue, std::vector>, decltype(comparator)> by_importance(comparator); + + Polygonal result = polygon; // Make a copy so that we can also shift vertices. + for (int64_t current_removed = -1; (polygon.size() - current_removed) > min_size && current_removed != 0;) + { + current_removed = 0; + + // Add the initial points. + for (size_t i = 0; i < result.size(); ++i) + { + if (to_delete[i]) + { + continue; + } + const coord_t vertex_importance = importance(result, to_delete, i, is_closed); + by_importance.emplace(i, vertex_importance); + } + + // Iteratively remove the least important point until a threshold. + coord_t vertex_importance = 0; + while (! by_importance.empty() && (polygon.size() - current_removed) > min_size) + { + std::pair vertex = by_importance.top(); + by_importance.pop(); + // The importance may have changed since this vertex was inserted. Re-compute it now. + // If it doesn't change, it's safe to process. + vertex_importance = importance(result, to_delete, vertex.first, is_closed); + if (vertex_importance != vertex.second) + { + by_importance.emplace(vertex.first, vertex_importance); // Re-insert with updated importance. + continue; + } + + if (vertex_importance <= max_deviation_ * max_deviation_) + { + current_removed += remove(result, to_delete, vertex.first, vertex_importance, is_closed) ? 1 : 0; + } + } + } + + // Now remove the marked vertices in one sweep. + Polygonal filtered = createEmpty(polygon); + for (size_t i = 0; i < result.size(); ++i) + { + if (! to_delete[i]) + { + appendVertex(filtered, result[i]); + } + } + + if (detectSmall(filtered, min_size)) + { + return createEmpty(filtered); + } + return filtered; +} + +template +coord_t Simplify::importance(const Polygonal& polygon, const std::vector& to_delete, const size_t index, const bool is_closed) const +{ + const size_t poly_size = polygon.size(); + if (! is_closed && (index == 0 || index == poly_size - 1)) + { + return std::numeric_limits::max(); // Endpoints of the polyline must always be retained. + } + // From here on out we can safely look at the vertex neighbors and assume it's a polygon. We won't go out of bounds of the polyline. + + const Point2LL& vertex = getPosition(polygon[index]); + const size_t before_index = previousNotDeleted(index, to_delete); + const size_t after_index = nextNotDeleted(index, to_delete); + + const coord_t area_deviation = getAreaDeviation(polygon[before_index], polygon[index], polygon[after_index]); + if (area_deviation > max_area_deviation_) // Removing this line causes the variable line width to get flattened out too much. + { + return std::numeric_limits::max(); + } + + const Point2LL& before = getPosition(polygon[before_index]); + const Point2LL& after = getPosition(polygon[after_index]); + const coord_t deviation2 = LinearAlg2D::getDist2FromLine(vertex, before, after); + if (deviation2 <= min_resolution * min_resolution) // Deviation so small that it's always desired to remove them. + { + return deviation2; + } + if (vSize2(before - vertex) > max_resolution_ * max_resolution_ && vSize2(after - vertex) > max_resolution_ * max_resolution_) + { + return std::numeric_limits::max(); // Long line segments, no need to remove this one. + } + return deviation2; +} + +template +bool Simplify::remove(Polygonal& polygon, std::vector& to_delete, const size_t vertex, const coord_t deviation2, const bool is_closed) const +{ + if (deviation2 <= min_resolution * min_resolution) + { + // At less than the minimum resolution we're always allowed to delete the vertex. + // Even if the adjacent line segments are very long. + to_delete[vertex] = true; + return true; + } + + const size_t before = previousNotDeleted(vertex, to_delete); + const size_t after = nextNotDeleted(vertex, to_delete); + const Point2LL& vertex_position = getPosition(polygon[vertex]); + const Point2LL& before_position = getPosition(polygon[before]); + const Point2LL& after_position = getPosition(polygon[after]); + const coord_t length2_before = vSize2(vertex_position - before_position); + const coord_t length2_after = vSize2(vertex_position - after_position); + + if (length2_before <= max_resolution_ * max_resolution_ && length2_after <= max_resolution_ * max_resolution_) // Both adjacent line segments are short. + { + // Removing this vertex does little harm. No long lines will be shifted. + to_delete[vertex] = true; + return true; + } + + // Otherwise, one edge next to this vertex is longer than max_resolution. The other is shorter. + // In this case we want to remove the short edge by replacing it with a vertex where the two surrounding edges intersect. + // Find the two line segments surrounding the short edge here ("before" and "after" edges). + Point2LL before_from, before_to, after_from, after_to; + if (length2_before <= length2_after) // Before is the shorter line. + { + if (! is_closed && before == 0) // No edge before the short edge. + { + return false; // Edge cannot be deleted without shifting a long edge. Don't remove anything. + } + const size_t before_before = previousNotDeleted(before, to_delete); + before_from = getPosition(polygon[before_before]); + before_to = getPosition(polygon[before]); + after_from = getPosition(polygon[vertex]); + after_to = getPosition(polygon[after]); + } + else + { + if (! is_closed && after == polygon.size() - 1) // No edge after the short edge. + { + return false; // Edge cannot be deleted without shifting a long edge. Don't remove anything. + } + const size_t after_after = nextNotDeleted(after, to_delete); + before_from = getPosition(polygon[before]); + before_to = getPosition(polygon[vertex]); + after_from = getPosition(polygon[after]); + after_to = getPosition(polygon[after_after]); + } + Point2LL intersection; + const bool did_intersect = LinearAlg2D::lineLineIntersection(before_from, before_to, after_from, after_to, intersection); + if (! did_intersect) // Lines are parallel. + { + return false; // Cannot remove edge without shifting a long edge. Don't remove anything. + } + const coord_t intersection_deviation = LinearAlg2D::getDist2FromLineSegment(before_to, intersection, after_from); + if (intersection_deviation <= max_deviation_ * max_deviation_) // Intersection point doesn't deviate too much. Use it! + { + to_delete[vertex] = true; + polygon[length2_before <= length2_after ? before : after] = createIntersection(polygon[before], intersection, polygon[after]); + return true; + } + return false; +} + template LinesSet Simplify::polyline(const LinesSet& polylines) const; template LinesSet Simplify::polyline(const LinesSet& polylines) const; From 38965fdd895df3ed10cb1b2bec307c4d0ec4f97c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 12 Apr 2024 17:13:09 +0200 Subject: [PATCH 039/135] Fixed crash CURA-9830 --- src/LayerPlan.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index e1f67742fb..751f45149c 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -1422,6 +1422,10 @@ void LayerPlan::addLinesInGivenOrder( { const PathOrdering& path = lines[order_idx]; const Polyline& polyline = *path.vertices_; + if (polyline.segmentsCount() == 0) + { + continue; + } const size_t start_idx = path.start_vertex_; assert(start_idx == 0 || start_idx == polyline.size() - 1 || path.is_closed_); const Point2LL start = polyline[start_idx]; From e8ace68a39e2679180e38bb2abb1113f3b6e1de2 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 15 Apr 2024 09:22:21 +0200 Subject: [PATCH 040/135] Fixed crash CURA-9830 --- src/LayerPlan.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 751f45149c..efd586191b 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -1551,6 +1551,11 @@ void LayerPlan::addLinesMonotonic( for (size_t line_idx = 0; line_idx < line_order.paths_.size(); ++line_idx) { const OpenPolyline& polyline = *line_order.paths_[line_idx].vertices_; + if (polyline.segmentsCount() == 0) + { + continue; + } + const bool inside_exclusion = is_inside_exclusion(polyline); const bool next_would_have_been_included = inside_exclusion && (line_idx < line_order.paths_.size() - 1 && is_inside_exclusion(*line_order.paths_[line_idx + 1].vertices_)); if (inside_exclusion && last_would_have_been_excluded && next_would_have_been_included) From 5ef2368ae7c6bfaab2e1c2fd643b38779c622b80 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 15 Apr 2024 13:12:02 +0200 Subject: [PATCH 041/135] Slight code optimization CURA-9830 --- src/geometry/shape.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index 0051cc26f9..791e571659 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -717,7 +717,7 @@ void Shape::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std:: part.emplace_back(std::move(child->Childs[i]->Contour)); splitIntoParts_processPolyTreeNode(child->Childs[i], ret); } - ret.push_back(part); + ret.push_back(std::move(part)); } } From 4351444a2b581fc2e4ed9869581fe7e3cd18420d Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 15 Apr 2024 13:28:09 +0200 Subject: [PATCH 042/135] Code cleaning CURA-9830 --- src/geometry/shape.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index 791e571659..a50ec4f7b1 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -678,16 +678,9 @@ double Shape::area() const 0.0, [](double total, const Polygon& poly) { + // note: holes already have negative area return total + poly.area(); }); - - double area = 0.0; - for (unsigned int poly_idx = 0; poly_idx < size(); poly_idx++) - { - area += operator[](poly_idx).area(); - // note: holes already have negative area - } - return area; } std::vector Shape::splitIntoParts(bool unionAll) const From 71718c33f43cf6e69655ba14006f2577f653a75f Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 15 Apr 2024 15:13:54 +0200 Subject: [PATCH 043/135] Slight optimization CURA-9830 --- include/geometry/lines_set.h | 8 ++++---- include/geometry/polygon.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/geometry/lines_set.h b/include/geometry/lines_set.h index f012eaccf7..ba12ad4bc5 100644 --- a/include/geometry/lines_set.h +++ b/include/geometry/lines_set.h @@ -160,15 +160,15 @@ class LinesSet return lines_.erase(first, last); } - LinesSet& operator=(LinesSet&& other) + LinesSet& operator=(const LinesSet& other) { - lines_ = std::move(other.lines_); + lines_ = other.lines_; return *this; } - LinesSet& operator=(const LinesSet& other) + LinesSet& operator=(LinesSet&& other) { - lines_ = other.lines_; + lines_ = std::move(other.lines_); return *this; } diff --git a/include/geometry/polygon.h b/include/geometry/polygon.h index 4902ed47a8..2dc4519eaf 100644 --- a/include/geometry/polygon.h +++ b/include/geometry/polygon.h @@ -48,7 +48,7 @@ class Polygon : public ClosedPolyline Polygon& operator=(Polygon&& other) { - Polyline::operator=(other); + Polyline::operator=(std::move(other)); return *this; } From 1e043b06ca8ad6195d8bd08e6d45be2c73a63390 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 16 Apr 2024 09:11:06 +0200 Subject: [PATCH 044/135] Fixed missing union before offsetting, and some cleaning CURA-9830 --- include/geometry/shape.h | 7 +++- include/geometry/single_shape.h | 4 +- src/WallsComputation.cpp | 3 +- src/geometry/lines_set.cpp | 74 +++------------------------------ src/geometry/shape.cpp | 18 +++++++- 5 files changed, 31 insertions(+), 75 deletions(-) diff --git a/include/geometry/shape.h b/include/geometry/shape.h index a236b04dc0..a853b1cf77 100644 --- a/include/geometry/shape.h +++ b/include/geometry/shape.h @@ -30,7 +30,7 @@ class Shape : public LinesSet Shape(Shape&& other) = default; - Shape(const std::initializer_list& initializer); + Shape(const std::vector& polygons); explicit Shape(ClipperLib::Paths&& paths, bool explicitely_closed = clipper_explicitely_closed_); @@ -68,6 +68,11 @@ class Shape : public LinesSet Shape intersection(const Shape& other) const; + /*! @brief Overridden definition of offset() + * @note The behavior of this method is exactly the same, but it just exists because it allows + * for a performance optimization */ + Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; + /*! * Intersect polylines with the area covered by the shape. * diff --git a/include/geometry/single_shape.h b/include/geometry/single_shape.h index 472302d01f..08a9e421d9 100644 --- a/include/geometry/single_shape.h +++ b/include/geometry/single_shape.h @@ -25,7 +25,7 @@ class SingleShape : public Shape /*! * Tests whether the given point is inside this polygon part. - * \param p The point to test whether it is inside. + * \param p The point to test whether it is insisinglehde. * \param border_result If the point is exactly on the border, this will be * returned instead. */ @@ -34,4 +34,4 @@ class SingleShape : public Shape } // namespace cura -#endif // GEOMETRY_MONO_SHAPE_H +#endif // GEOMETRY_SINGLE_SHAPE_H diff --git a/src/WallsComputation.cpp b/src/WallsComputation.cpp index 1d0b1380b9..4f02bedc91 100644 --- a/src/WallsComputation.cpp +++ b/src/WallsComputation.cpp @@ -84,7 +84,8 @@ void WallsComputation::generateWalls(SliceLayerPart* part, SectionType section_t part->wall_toolpaths = wall_tool_paths.getToolPaths(); part->inner_area = wall_tool_paths.getInnerContour(); } - part->outline = SingleShape{ Simplify(settings_).polygon(part->outline) }; + + part->outline = SingleShape({ Simplify(settings_).polygon(part->outline) }); part->print_outline = part->outline; } diff --git a/src/geometry/lines_set.cpp b/src/geometry/lines_set.cpp index c1edb9c4d0..5d1fa1d61c 100644 --- a/src/geometry/lines_set.cpp +++ b/src/geometry/lines_set.cpp @@ -162,13 +162,11 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType join_type { if (distance == 0) { - Shape result; - result.push_back(getLines()); - return result; + return Shape(getLines()); } ClipperLib::Paths ret; ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - addPaths(clipper, join_type, ClipperLib::etClosedPolygon); + Shape(getLines()).unionPolygons().addPaths(clipper, join_type, ClipperLib::etClosedPolygon); clipper.MiterLimit = miter_limit; clipper.Execute(ret, static_cast(distance)); return Shape(std::move(ret)); @@ -203,71 +201,6 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType join return result; } -#if 0 -template<> -Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType joinType, double miter_limit) const -{ -#error Implement me if required - Shape result; - - if (distance != 0) - { - Shape polygons; - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - - for (const LineType& line : lines_) - { - if (const Polygon* polygon = dynamic_cast(&line)) - { - // Union all polygons first and add them later - polygons.push_back(*polygon); - - /*temp = Shape(asRawVector()).unionPolygons(); - actual_polygons = &temp.asRawVector(); - end_type = ClipperLib::etClosedPolygon;*/ - } - else - { - ClipperLib::EndType end_type; - - if (line.addClosingSegment()) - { - end_type = ClipperLib::etClosedLine; - } - else if (joinType == ClipperLib::jtMiter) - { - end_type = ClipperLib::etOpenSquare; - } - else - { - end_type = ClipperLib::etOpenRound; - } - - clipper.AddPath(line.getPoints(), joinType, end_type); - } - } - - if (! polygons.empty()) - { - polygons = polygons.unionPolygons(); - - for (const Polygon& polygon : polygons) - { - clipper.AddPath(polygon.getPoints(), joinType, ClipperLib::etClosedPolygon); - } - } - - clipper.MiterLimit = miter_limit; - - ClipperLib::Paths result; - clipper.Execute(result, static_cast(distance)); - return Shape(std::move(result)); - } - - return result; -} -#endif - template void LinesSet::removeDegenerateVerts() { @@ -372,6 +305,7 @@ template coord_t LinesSet::length() const; template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; template void LinesSet::removeDegenerateVerts(); template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; +template void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; template void LinesSet::push_back(const OpenPolyline& line, bool checkNonEmpty); template void LinesSet::push_back(OpenPolyline&& line, bool checkNonEmpty); template void LinesSet::push_back(LinesSet&& lines_set); @@ -384,6 +318,7 @@ template coord_t LinesSet::length() const; template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; template void LinesSet::removeDegenerateVerts(); template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; +template void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; template void LinesSet::push_back(const ClosedPolyline& line, bool checkNonEmpty); template void LinesSet::push_back(ClosedPolyline&& line, bool checkNonEmpty); template void LinesSet::push_back(LinesSet&& lines_set); @@ -397,6 +332,7 @@ template coord_t LinesSet::length() const; template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; template void LinesSet::removeDegenerateVerts(); template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; +template void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; template void LinesSet::push_back(const Polygon& line, bool checkNonEmpty); template void LinesSet::push_back(Polygon&& line, bool checkNonEmpty); template void LinesSet::push_back(LinesSet&& lines_set); diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index a50ec4f7b1..ef6565f8d3 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -39,8 +39,8 @@ Shape::Shape(ClipperLib::Paths&& paths, bool explicitely_closed) emplace_back(std::move(paths), explicitely_closed); } -Shape::Shape(const std::initializer_list& initializer) - : LinesSet(initializer) +Shape::Shape(const std::vector& polygons) + : LinesSet(polygons) { } @@ -173,6 +173,20 @@ Shape Shape::intersection(const Shape& other) const return Shape(std::move(ret)); } +Shape Shape::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const +{ + if (distance == 0) + { + return Shape(getLines()); + } + ClipperLib::Paths ret; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + unionPolygons().addPaths(clipper, join_type, ClipperLib::etClosedPolygon); + clipper.MiterLimit = miter_limit; + clipper.Execute(ret, static_cast(distance)); + return Shape(std::move(ret)); +} + bool Shape::inside(const Point2LL& p, bool border_result) const { int poly_count_inside = 0; From c472eccfcbb1571dfe2f723e8722fe93744d8cef Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 16 Apr 2024 12:14:50 +0200 Subject: [PATCH 045/135] Code documentation and cleaning CURA-9830 --- include/geometry/closed_polyline.h | 52 ++++++++++++-- include/geometry/generic_closed_polyline.h | 39 ---------- include/geometry/lines_set.h | 77 +++++++++++++++----- include/geometry/mixed_lines_set.h | 67 +++++++++++------ include/geometry/open_polyline.h | 32 +++++++++ include/geometry/points_set.h | 36 +++++++--- include/geometry/polygon.h | 43 +++++++++-- include/geometry/polyline.h | 31 +++++++- include/geometry/polyline_type.h | 20 ------ include/geometry/segment_iterator.h | 5 +- include/geometry/shape.h | 83 +++++++++------------- src/geometry/lines_set.cpp | 18 ++--- src/geometry/polyline.cpp | 2 +- src/geometry/shape.cpp | 46 ++---------- 14 files changed, 328 insertions(+), 223 deletions(-) delete mode 100644 include/geometry/generic_closed_polyline.h delete mode 100644 include/geometry/polyline_type.h diff --git a/include/geometry/closed_polyline.h b/include/geometry/closed_polyline.h index fe660cd79e..5d4fa438c5 100644 --- a/include/geometry/closed_polyline.h +++ b/include/geometry/closed_polyline.h @@ -11,49 +11,93 @@ namespace cura class OpenPolyline; +/*! @brief This describes a polyline which forms a closed path. + * + * The path may be closed: + * * Explicitely, which means the last point is at the same position as the first point. + * In this case, in order to iterate over the segments, you just have to iterate over + * the actual points. + * * Implicitely, which means the last and first point are at different positions. In this + * case, to iterate over the segments, you have to consider an additional segment + * between the last and first point + * + * The difference is made because it is easier to iterate over segments when the path is + * explicitely closed, but ClipperLib uses implicitely closed paths. It is also a bit healthier + * to use implicitely closed because there is no risk that the first and last point become different + */ class ClosedPolyline : public Polyline { private: - /*! If true, that means the last point in the list is at the same position as the start point, - * making it explicitely closed. - * If false, you have to add an additional segment between the end point and the start point to - * actually have the line closed. */ bool explicitely_closed_{ false }; public: + /*! + * \brief Builds an empty closed polyline + * \param explicitely_closed Indicates whether the line will be explicitely closed + * \warning By default, the line is tagged as explicitely closed. We need this default + * constructor in various places, but be careful that the interpretation of the points + * added later will depend on this. + */ ClosedPolyline(bool explicitely_closed = false) : Polyline() , explicitely_closed_(explicitely_closed) { } + /*! + * \brief Creates a copy of the given polyline + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ ClosedPolyline(const ClosedPolyline& other) = default; + /*! + * \brief Constructor that takes ownership of the inner points list from the given polyline + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ ClosedPolyline(ClosedPolyline&& other) = default; + /*! + * \brief Constructor with a points initializer list, provided for convenience + * \param explicitely_closed Specify whether the given points form an explicitely closed line + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ ClosedPolyline(const std::initializer_list& initializer, bool explicitely_closed) : Polyline(initializer) , explicitely_closed_(explicitely_closed) { } + /*! + * \brief Constructor with an existing list of points + * \param explicitely_closed Specify whether the given points form an explicitely closed line + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ explicit ClosedPolyline(const ClipperLib::Path& points, bool explicitely_closed) : Polyline(points) , explicitely_closed_(explicitely_closed) { } + /*! + * \brief Constructor that takes ownership of the given list of points + * \param explicitely_closed Specify whether the given points form an explicitely closed line + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ explicit ClosedPolyline(ClipperLib::Path&& points, bool explicitely_closed) : Polyline(points) , explicitely_closed_(explicitely_closed) { } + /*! @see Polyline::addClosingSegment() */ virtual bool addClosingSegment() const { return ! explicitely_closed_; } + /*! @see Polyline::addClosingSegment() */ virtual size_t segmentsCount() const override; ClosedPolyline& operator=(const ClosedPolyline& other) diff --git a/include/geometry/generic_closed_polyline.h b/include/geometry/generic_closed_polyline.h deleted file mode 100644 index 70c741024b..0000000000 --- a/include/geometry/generic_closed_polyline.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2023 UltiMaker -// CuraEngine is released under the terms of the AGPLv3 or higher - -#ifndef GEOMETRY_GENERIC_CLOSED_POLYLINE_H -#define GEOMETRY_GENERIC_CLOSED_POLYLINE_H - -#include "geometry/point2ll.h" -#include "geometry/polyline.h" -#include "geometry/polyline_type.h" - -namespace cura -{ -/* -template -class GenericClosedPolyline : public Polyline -{ -public: - GenericClosedPolyline() = default; - - GenericClosedPolyline(const std::initializer_list& initializer) - : Polyline(initializer) - { - } - - GenericClosedPolyline(const std::vector& points) - : Polyline(points) - { - } - - GenericClosedPolyline& operator=(const GenericClosedPolyline& other) - { - Polyline::operator=(other); - return *this; - } -}; -*/ -} // namespace cura - -#endif // GEOMETRY_GENERIC_CLOSED_POLYLINE_H diff --git a/include/geometry/lines_set.h b/include/geometry/lines_set.h index ba12ad4bc5..df4a68596a 100644 --- a/include/geometry/lines_set.h +++ b/include/geometry/lines_set.h @@ -28,26 +28,51 @@ class LinesSet std::vector lines_; public: - // Requires for some std calls as a container + // Required for some std calls as a container typedef LineType value_type; public: + /*! \brief Builds an empty set */ LinesSet() = default; + /*! + * \brief Creates a copy of the given lines set + * \warning A copy of the points list is made, so this constructor can be very slow + */ LinesSet(const LinesSet& other) = default; + /*! + * \brief Constructor that takes the inner lines list from the given set + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ LinesSet(LinesSet&& other) = default; + /*! + * \brief Constructor with an existing set of lines + * \warning A copy of the lines set is made, so this constructor can be very slow + */ LinesSet(const std::vector& lines) : lines_(lines) { } + /*! + * \brief Constructor that takes ownership of the data from the given set of lines + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ LinesSet(std::vector&& lines) : lines_(std::move(lines)) { } + /*! + * \brief Constructor that takes ownership of the data from the given set of lines + * \warning This constructor is actually only defined for a LinesSet containing OpenPolyline + * objects, because closed ones require an additional argument + */ + template::value>::type> LinesSet(ClipperLib::Paths&& paths); const std::vector& getLines() const @@ -105,15 +130,35 @@ class LinesSet return lines_.front(); } + /*! + * \brief Pushes the given line at the end of the set + * \param checkNonEmpty If true, we will check that the line is not empty, + * and discard it in case it is + * \warning A copy of the line is made, so this method may be slow + */ void push_back(const LineType& line, bool checkNonEmpty = false); + /*! + * \brief Pushes the given line at the end of the set and takes ownership of the inner data + * \param checkNonEmpty If true, we will check that the line is not empty, + * and discard it in case it is + * \warning This method is fast because it does not allocate data, but it will clear + * the source object + */ void push_back(LineType&& line, bool checkNonEmpty = false); - void push_back(ClipperLib::Paths&& paths); - + /*! + * \brief Pushes an entier set at the end and takes ownership of the inner data + * \warning This method is fast because it does not allocate data, but it will clear + * the source object + */ template void push_back(LinesSet&& lines_set); + /*! + * \brief Pushes an entier set at the end + * \warning A copy of all the lines is made, so this method may be slow + */ void push_back(const LinesSet& other) { lines_.insert(lines_.end(), other.lines_.begin(), other.lines_.end()); @@ -188,35 +233,25 @@ class LinesSet return lines_.back(); } - //!< Return the amount of points in all lines + /*! \brief Return the amount of points in all lines */ size_t pointCount() const; /*! * Remove a line from the list and move the last line to its place - * * \warning changes the order of the lines! */ void removeAt(size_t index); - /*! - * Add a simple line consisting of two points - */ + /*! \brief Add a simple line consisting of two points */ void addSegment(const Point2LL& from, const Point2LL& to); + /*! \brief Get the total length of all the lines */ coord_t length() const; void splitIntoSegments(LinesSet& result) const; LinesSet splitIntoSegments() const; - /*! - * Removes overlapping consecutive line segments which don't delimit a - * positive area. - * - * This function is meant to work on polygons, not polylines. When misused - * on polylines, it may cause too many vertices to be removed. - * See \ref removeDegenerateVertsPolyline for a version that works on - * polylines. - */ + /*! \brief Removes overlapping consecutive line segments which don't delimit a positive area */ void removeDegenerateVerts(); Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; @@ -229,8 +264,16 @@ class LinesSet */ Shape tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; + /*! + * \brief Utility method to add all the lines to a ClipperLib::Clipper object + * \note This method needs to be public but you shouldn't need to use it from outside + */ void addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; + /*! + * \brief Utility method to add all the lines to a ClipperLib::ClipperOffset object + * \note This method needs to be public but you shouldn't need to use it from outside + */ void addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; /*! diff --git a/include/geometry/mixed_lines_set.h b/include/geometry/mixed_lines_set.h index d67144bd69..4e3b5bea21 100644 --- a/include/geometry/mixed_lines_set.h +++ b/include/geometry/mixed_lines_set.h @@ -38,48 +38,73 @@ class MixedLinesSet : public std::vector */ Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; - /*! @brief Adds a copy of the given polyline to the set - @note As we have to copy the whole points data, this is not very efficient */ + /*! + * @brief Adds a copy of the given polyline to the set + * @note As we have to copy the whole points data, this is not very efficient + */ void push_back(const OpenPolyline& line); - /*! @brief Adds a copy of the given polyline to the set - @note As we have to copy the whole points data, this is not very efficient */ + /*! + * @brief Adds a copy of the given polyline to the set + * @note As we have to copy the whole points data, this is not very efficient + */ void push_back(const Polygon& line); - /*! @brief Adds a copy of the given polyline to the set - * @note As we can move the points data, this is much more efficient than the above methods */ + /*! + * @brief Adds a copy of the given polyline to the set + * @note As we can move the points data, this is much more efficient than the above methods, + * but will clear the source data + */ void push_back(OpenPolyline&& line); - /*! @brief Adds a copy of the given polyline to the set - * @note As we can move the points data, this is much more efficient than the above methods */ + /*! + * @brief Adds a copy of the given polyline to the set + * @note As we can move the points data, this is much more efficient than the above methods, + * but will clear the source data + */ void push_back(ClosedPolyline&& line); - /*! @brief Adds the given shared pointer to the set. The pointer reference count will be incremeted but no data is actually copied. - * @note The is even more efficient than the above methods because it only involves copying a pointer */ + /*! + * @brief Adds the given shared pointer to the set. The pointer reference count will be incremeted but no data is actually copied. + * @note The is even more efficient than the above methods because it only involves copying a pointer + */ void push_back(const OpenPolylinePtr& line); - /*! @brief Adds the given shared pointer to the set. The pointer reference count will be incremeted but no data is actually copied. - * @note The is even more efficient than the above methods because it only involves copying a pointer */ + /*! + * @brief Adds the given shared pointer to the set. The pointer reference count will be incremeted but no data is actually copied. + * @note The is even more efficient than the above methods because it only involves copying a pointer + */ void push_back(const PolylinePtr& line); - /*! @brief Adds a copy of all the polygons contained in the shape - @note As we have to copy the whole points data, this is really not efficient */ + /*! + * @brief Adds a copy of all the polygons contained in the shape + * @note As we have to copy the whole points data, this is really not efficient + */ void push_back(const Shape& shape); - /*! @brief Adds a copy of all the polygons contained in the set - @note As we have to copy the whole points data, this is really not efficient */ + /*! + * @brief Adds a copy of all the polygons contained in the set + * @note As we have to copy the whole points data, this is really not efficient + */ void push_back(const LinesSet& lines_set); - /*! @brief Adds a copy of all the polylines contained in the set - @note As we have to copy the whole points data, this is really not efficient */ + /*! + * @brief Adds a copy of all the polylines contained in the set + * @note As we have to copy the whole points data, this is really not efficient + */ void push_back(const LinesSet& lines_set); - /*! @brief Adds a copy of all the polylines contained in the set - * @note As we can move the points data, this is much more efficient than the above methods */ + /*! + * @brief Adds a copy of all the polylines contained in the set + * @note As we can move the points data, this is much more efficient than the above methods, + * but will clear the source data + */ void push_back(LinesSet&& lines_set); /*! @brief Adds a copy of all the polylines contained in the set - * @note As we can move the points data, this is much more efficient than the above methods */ + * @note As we can move the points data, this is much more efficient than the above methods, + * but will clear the source data + */ void push_back(LinesSet&& lines_set); /*! \brief Computes the total lenght of all the polylines in the set */ diff --git a/include/geometry/open_polyline.h b/include/geometry/open_polyline.h index 9b1dff3aa3..8facf89ef6 100644 --- a/include/geometry/open_polyline.h +++ b/include/geometry/open_polyline.h @@ -9,35 +9,67 @@ namespace cura { +/*! + * @brief Represents a polyline that is explicitely not closed + * @note Open polylines are sometimes used to represent actually closed polylines. In this case + * the first and last point are at the very same position. This should not be done, but + * it exists all around the engine for historical reasons. The behavior is however deprecated + * and should not be used in the future + */ class OpenPolyline : public Polyline { public: + /*! @brief Builds an empty polyline */ OpenPolyline() = default; + /*! + * \brief Creates a copy of the given polyline + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ OpenPolyline(const OpenPolyline& other) = default; + /*! + * \brief Constructor that takes ownership of the inner points list from the given polyline + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ OpenPolyline(OpenPolyline&& other) = default; + /*! + * \brief Constructor with a points initializer list, provided for convenience + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ OpenPolyline(const std::initializer_list& initializer) : Polyline(initializer) { } + /*! + * \brief Constructor with an existing list of points + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ OpenPolyline(const ClipperLib::Path& points) : Polyline(points) { } + /*! + * \brief Constructor that takes ownership of the given list of points + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ OpenPolyline(ClipperLib::Path&& points) : Polyline(std::move(points)) { } + /*! @see Polyline::addClosingSegment() */ virtual bool addClosingSegment() const override { return false; // Definitely not } + /*! @see Polyline::segmentsCount() */ virtual size_t segmentsCount() const override { return size() > 1 ? size() - 1 : 0; diff --git a/include/geometry/points_set.h b/include/geometry/points_set.h index 73d4673c73..587230dcb1 100644 --- a/include/geometry/points_set.h +++ b/include/geometry/points_set.h @@ -25,20 +25,43 @@ class PointsSet ClipperLib::Path points_; public: - // Requires for some std calls as a container + // Required for some std calls as a container typedef Point2LL value_type; public: + /*! \brief Builds an empty set */ PointsSet() = default; + /*! + * \brief Creates a copy of the given points set + * \warning A copy of the points set is made, so this constructor is somehow "slow" + */ PointsSet(const PointsSet& other) = default; + /*! + * \brief Constructor that takes ownership of the inner points from the given set + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ PointsSet(PointsSet&& other) = default; + /*! + * \brief Constructor with a points initializer list, provided for convenience + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ PointsSet(const std::initializer_list& initializer); + /*! + * \brief Constructor with an existing list of points + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ PointsSet(const ClipperLib::Path& points); + /*! + * \brief Constructor that takes ownership of the given list of points + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ PointsSet(ClipperLib::Path&& points); const ClipperLib::Path& getPoints() const @@ -188,21 +211,16 @@ class PointsSet PointsSet& operator=(PointsSet&& other) = default; /*! - * Translate all the points in some direction. - * + * \brief Translate all the points in some direction. * \param translation The direction in which to move the points */ void translate(const Point2LL& translation); - /*! - * Apply a matrix to each vertex in this set - */ + /*! \brief Apply a matrix to each vertex in this set */ void applyMatrix(const PointMatrix& matrix); void applyMatrix(const Point3Matrix& matrix); - /*! - * \brief Display operator, useful for debugging/testing - */ + /*! \brief Display operator, useful for debugging/testing */ template friend std::basic_ostream& operator<<(std::basic_ostream& os, const PointsSet& polygon) { diff --git a/include/geometry/polygon.h b/include/geometry/polygon.h index 2dc4519eaf..d3ca1e1803 100644 --- a/include/geometry/polygon.h +++ b/include/geometry/polygon.h @@ -13,28 +13,64 @@ class Shape; class ListPolyIt; class AngleDegrees; +/*! + * \brief A Polygon is a specific type of polyline, for which we consider that the "inside" part of + * the line forms a surface + */ class Polygon : public ClosedPolyline { public: + /*! + * \brief Builds an empty polygon + * \param explicitely_closed Indicates whether the contour line will be explicitely closed + * \warning By default, the contour line is tagged as explicitely closed. We need this default + * constructor in various places, but be careful that the interpretation of the points + * added later will depend on this. + */ Polygon(bool explicitely_closed = false) : ClosedPolyline(explicitely_closed) { } + /*! + * \brief Creates a copy of the given polygon + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ Polygon(const Polygon& other) = default; + /*! + * \brief Constructor that takes ownership of the inner points list from the given polygon + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ Polygon(Polygon&& other) = default; + /*! + * \brief Constructor with a points initializer list, provided for convenience + * \param explicitely_closed Specify whether the given points form an explicitely closed line + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ Polygon(const std::initializer_list& initializer, bool explicitely_closed) : ClosedPolyline(initializer, explicitely_closed) { } + /*! + * \brief Constructor with an existing list of points + * \param explicitely_closed Specify whether the given points form an explicitely closed line + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ explicit Polygon(const ClipperLib::Path& points, bool explicitely_closed) : ClosedPolyline(points, explicitely_closed) { } + /*! + * \brief Constructor that takes ownership of the given list of points + * \param explicitely_closed Specify whether the given points form an explicitely closed line + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ explicit Polygon(ClipperLib::Path&& points, bool explicitely_closed) : ClosedPolyline(points, explicitely_closed) { @@ -53,12 +89,9 @@ class Polygon : public ClosedPolyline } /*! - * Compute the morphological intersection between this polygon and another. - * - * Note that the result may consist of multiple polygons, if you have bad - * luck. - * + * \brief Compute the morphological intersection between this polygon and another. * \param other The polygon with which to intersect this polygon. + * \note The result may consist of multiple polygons, if you have bad luck. */ Shape intersection(const Polygon& other) const; diff --git a/include/geometry/polyline.h b/include/geometry/polyline.h index a51b13240b..0a72dcd285 100644 --- a/include/geometry/polyline.h +++ b/include/geometry/polyline.h @@ -36,22 +36,45 @@ class Polyline : public PointsSet using segments_iterator = SegmentIterator; using const_segments_iterator = SegmentIterator; + /*! \brief Builds an empty polyline */ Polyline() = default; + /*! + * \brief Creates a copy of the given polyline + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ Polyline(const Polyline& other) = default; + /*! + * \brief Constructor that takes ownership of the inner points list from the given polyline + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ Polyline(Polyline&& other) = default; + /*! + * \brief Constructor with a points initializer list, provided for convenience + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ Polyline(const std::initializer_list& initializer) : PointsSet(initializer) { } + /*! + * \brief Constructor with an existing list of points + * \warning A copy of the points list is made, so this constructor is somehow "slow" + */ Polyline(const ClipperLib::Path& points) : PointsSet(points) { } + /*! + * \brief Constructor that takes ownership of the given list of points + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ Polyline(ClipperLib::Path&& points) : PointsSet(points) { @@ -60,8 +83,8 @@ class Polyline : public PointsSet virtual ~Polyline() = default; /*! - * \brief Indicates whether this polyline has a virtual closing segment between the last point - * in the set and the first one + * \brief Indicates whether this polyline has an additional closing segment between the last + * point in the set and the first one * \return True if a segment between the last and first point should be considered */ virtual bool addClosingSegment() const = 0; @@ -85,12 +108,16 @@ class Polyline : public PointsSet return *this; } + /*! \brief Provides a begin iterator to iterate over all the segments of the line */ const_segments_iterator beginSegments() const; + /*! \brief Provides an end iterator to iterate over all the segments of the line */ const_segments_iterator endSegments() const; + /*! \brief Provides a begin iterator to iterate over all the segments of the line */ segments_iterator beginSegments(); + /*! \brief Provides an end iterator to iterate over all the segments of the line */ segments_iterator endSegments(); /*! diff --git a/include/geometry/polyline_type.h b/include/geometry/polyline_type.h deleted file mode 100644 index f203722086..0000000000 --- a/include/geometry/polyline_type.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2024 UltiMaker -// CuraEngine is released under the terms of the AGPLv3 or higher - -#ifndef UTILS_POLYLINE_TYPE_H -#define UTILS_POLYLINE_TYPE_H - -namespace cura -{ - -enum class PolylineType -{ - Open, // Line is open and has no wise - ImplicitelyClosed, // Line is closed by having a virtual additional segment between last and first vertices - ExplicitelyClosed, // Line is closed by having the same point twice at beginning and end of list - Filled -}; - -} // namespace cura - -#endif // UTILS_POLYLINE_TYPE_H diff --git a/include/geometry/segment_iterator.h b/include/geometry/segment_iterator.h index 8da9c21eb4..9866e1ff73 100644 --- a/include/geometry/segment_iterator.h +++ b/include/geometry/segment_iterator.h @@ -9,11 +9,11 @@ namespace cura { -// Custom iterator to loop over the segments of an existing polygon/polyline +// Custom iterator to loop over the segments of a polyline template struct SegmentIterator { - // Transitory structure used to iterate over segments within a polygon/polyline + // Transitory structure used to iterate over segments within a polyline struct Segment { using PointType = typename std::conditional::type; @@ -22,6 +22,7 @@ struct SegmentIterator PointType& end; }; + // Define type values so that std library methods can use this iterator using iterator_category = std::random_access_iterator_tag; using value_type = Segment; using difference_type = std::ptrdiff_t; diff --git a/include/geometry/shape.h b/include/geometry/shape.h index a853b1cf77..52acb4c9bf 100644 --- a/include/geometry/shape.h +++ b/include/geometry/shape.h @@ -17,21 +17,47 @@ class PartsView; class PointMatrix; class Point3Matrix; +/*! + * @brief A Shape is a set of polygons that together form a complex shape. Some of the polygons may + * be contained inside others, being actually "holes" of the shape. For example, if you + * wanted to represent the "8" digit with polygons, you would need 1 for the outline and 2 + * for the "holes" so the shape would contain a total of 3 polygons. + */ class Shape : public LinesSet { public: - // Clipper returns implicitely closed polygons + // Clipper expects and returns implicitely closed polygons static constexpr bool clipper_explicitely_closed_ = false; public: + /*! \brief Constructor of an empty shape */ Shape() = default; + /*! + * \brief Creates a copy of the given shape + * \warning A copy of the points list is made, so this constructor can be very slow + */ Shape(const Shape& other) = default; + /*! + * \brief Constructor that takes the inner polygons list from the given shape + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ Shape(Shape&& other) = default; + /*! + * \brief Constructor with an existing set of polygons + * \warning A copy of the polygons set is made, so this constructor can be very slow + */ Shape(const std::vector& polygons); + /*! + * \brief Constructor that takes ownership of the given list of points + * \param explicitely_closed Specify whether the given points form an explicitely closed line + * \warning This constructor is fast because it does not allocate data, but it will clear + * the source object + */ explicit Shape(ClipperLib::Paths&& paths, bool explicitely_closed = clipper_explicitely_closed_); Shape& operator=(const Shape& other); @@ -48,11 +74,6 @@ class Shape : public LinesSet LinesSet::emplace_back(args...); } - /*! - * Convert ClipperLib::PolyTree to a Shape object, - * which uses ClipperLib::Paths instead of ClipperLib::PolyTree - */ - static Shape toPolygons(ClipperLib::PolyTree& poly_tree); Shape difference(const Shape& other) const; @@ -61,16 +82,15 @@ class Shape : public LinesSet /*! * Union all polygons with each other (When polygons.add(polygon) has been called for overlapping polygons) */ - Shape unionPolygons() const - { - return unionPolygons(Shape()); - } + Shape unionPolygons() const; Shape intersection(const Shape& other) const; - /*! @brief Overridden definition of offset() + /*! + * @brief Overridden definition of LinesSet::offset() * @note The behavior of this method is exactly the same, but it just exists because it allows - * for a performance optimization */ + * for a performance optimization + */ Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; /*! @@ -87,20 +107,6 @@ class Shape : public LinesSet template LinesSet intersection(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; - /*! - * Split this poly line object into several line segment objects - * and store them in the \p result - */ - void splitPolylinesIntoSegments(Shape& result) const; - Shape splitPolylinesIntoSegments() const; - - /*! - * Split this polygon object into several line segment objects - * and store them in the \p result - */ - void splitPolygonsIntoSegments(Shape& result) const; - Shape splitPolygonsIntoSegments() const; - Shape xorPolygons(const Shape& other, ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const; Shape execute(ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const; @@ -135,16 +141,14 @@ class Shape : public LinesSet size_t findInside(const Point2LL& p, bool border_result = false) const; /*! - * Approximates the convex hull of the polygons. + * \brief Approximates the convex hull of the polygons. * \p extra_outset Extra offset outward * \return the convex hull (approximately) * */ Shape approxConvexHull(int extra_outset = 0) const; - /*! - * Make each of the polygons convex - */ + /*! \brief Make each of the polygons convex */ void makeConvex(); /*! @@ -250,31 +254,12 @@ class Shape : public LinesSet */ void ensureManifold(); - Point2LL min() const; - - Point2LL max() const; - void applyMatrix(const PointMatrix& matrix); void applyMatrix(const Point3Matrix& matrix); Shape offsetMulti(const std::vector& offset_dists) const; - /*! - * @brief Export the polygon to a WKT string - * - * @param stream The stream to write to - */ - //[[maybe_unused]] void writeWkt(std::ostream& stream) const; - - /*! - * @brief Import the polygon from a WKT string - * - * @param wkt The WKT string to read from - * @return Shape The polygons read from the stream - */ - //[[maybe_unused]] static Shape fromWkt(const std::string& wkt); - /*! * @brief Remove self-intersections from the polygons * _note_: this function uses wagyu to remove the self intersections. diff --git a/src/geometry/lines_set.cpp b/src/geometry/lines_set.cpp index 5d1fa1d61c..4514831163 100644 --- a/src/geometry/lines_set.cpp +++ b/src/geometry/lines_set.cpp @@ -12,8 +12,9 @@ namespace cura { -template -LinesSet::LinesSet(ClipperLib::Paths&& paths) +template<> +template<> +LinesSet::LinesSet(ClipperLib::Paths&& paths) { reserve(paths.size()); for (ClipperLib::Path& path : paths) @@ -40,16 +41,6 @@ void LinesSet::push_back(LineType&& line, bool checkNonEmpty) } } -template -void LinesSet::push_back(ClipperLib::Paths&& paths) -{ - reserve(size() + paths.size()); - for (ClipperLib::Path& path : paths) - { - lines_.emplace_back(std::move(path)); - } -} - template template void LinesSet::push_back(LinesSet&& lines_set) @@ -151,7 +142,7 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType jo } ClipperLib::Paths ret; ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - addPaths(clipper, join_type, ClipperLib::etClosedPolygon); + addPaths(clipper, join_type, ClipperLib::etClosedLine); clipper.MiterLimit = miter_limit; clipper.Execute(ret, static_cast(distance)); return Shape(std::move(ret)); @@ -296,7 +287,6 @@ void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib } } -template LinesSet::LinesSet(ClipperLib::Paths&& paths); template size_t LinesSet::pointCount() const; template void LinesSet::removeAt(size_t index); template void LinesSet::splitIntoSegments(OpenLinesSet& result) const; diff --git a/src/geometry/polyline.cpp b/src/geometry/polyline.cpp index c0447509f6..0f8d98de29 100644 --- a/src/geometry/polyline.cpp +++ b/src/geometry/polyline.cpp @@ -155,7 +155,7 @@ void Polyline::splitIntoSegments(OpenLinesSet& result) const result.reserve(result.size() + segmentsCount()); for (auto it = beginSegments(); it != endSegments(); ++it) { - result.emplace_back(std::initializer_list{ (*it).start, (*it).end }); + result.emplace_back(OpenPolyline({ (*it).start, (*it).end })); } } diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index ef6565f8d3..874914293c 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -163,6 +163,11 @@ Shape Shape::unionPolygons(const Shape& other, ClipperLib::PolyFillType fill_typ return Shape(std::move(ret)); } +Shape Shape::unionPolygons() const +{ + return unionPolygons(Shape()); +} + Shape Shape::intersection(const Shape& other) const { ClipperLib::Paths ret; @@ -177,7 +182,7 @@ Shape Shape::offset(coord_t distance, ClipperLib::JoinType join_type, double mit { if (distance == 0) { - return Shape(getLines()); + return Shape(*this); } ClipperLib::Paths ret; ClipperLib::ClipperOffset clipper(miter_limit, 10.0); @@ -563,13 +568,6 @@ Shape Shape::processEvenOdd(ClipperLib::PolyFillType poly_fill_type) const return Shape(std::move(ret)); } -Shape Shape::toPolygons(ClipperLib::PolyTree& poly_tree) -{ - ClipperLib::Paths ret; - ClipperLib::PolyTreeToPaths(poly_tree, ret); - return Shape(std::move(ret)); -} - Shape Shape::smooth_outward(const AngleDegrees max_angle, int shortcut_length) const { Shape ret; @@ -888,38 +886,6 @@ void Shape::ensureManifold() } } -Point2LL Shape::min() const -{ - Point2LL ret = Point2LL(POINT_MAX, POINT_MAX); - - for (const Polygon& polygon : *this) - { - for (const Point2LL& p : polygon) - { - ret.X = std::min(ret.X, p.X); - ret.Y = std::min(ret.Y, p.Y); - } - } - - return ret; -} - -Point2LL Shape::max() const -{ - Point2LL ret = Point2LL(POINT_MIN, POINT_MIN); - - for (const Polygon& polygon : *this) - { - for (const Point2LL& p : polygon) - { - ret.X = std::max(ret.X, p.X); - ret.Y = std::max(ret.Y, p.Y); - } - } - - return ret; -} - void Shape::applyMatrix(const PointMatrix& matrix) { for (Polygon& polygon : *this) From 862118a30c4e0a4ea5a383ed63c87a59248a335b Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 16 Apr 2024 14:17:56 +0200 Subject: [PATCH 046/135] Early-out optimization of critical methods + code cleaning CURA-9830 --- include/geometry/lines_set.h | 2 + include/geometry/shape.h | 16 --- src/geometry/lines_set.cpp | 71 +++++++++---- src/geometry/shape.cpp | 187 +++++++++++++++++++---------------- 4 files changed, 156 insertions(+), 120 deletions(-) diff --git a/include/geometry/lines_set.h b/include/geometry/lines_set.h index df4a68596a..2b527d93f2 100644 --- a/include/geometry/lines_set.h +++ b/include/geometry/lines_set.h @@ -264,6 +264,8 @@ class LinesSet */ Shape tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; + void translate(const Point2LL& delta); + /*! * \brief Utility method to add all the lines to a ClipperLib::Clipper object * \note This method needs to be public but you shouldn't need to use it from outside diff --git a/include/geometry/shape.h b/include/geometry/shape.h index 52acb4c9bf..30c65b32f8 100644 --- a/include/geometry/shape.h +++ b/include/geometry/shape.h @@ -184,10 +184,6 @@ class Shape : public LinesSet void removeColinearEdges(const AngleRadians max_deviation_angle = AngleRadians(0.0005)); - void scale(const Ratio& ratio); - - void translate(const Point2LL& delta); - /*! * Remove all but the polygons on the very outside. * Exclude holes and parts within holes. @@ -195,18 +191,6 @@ class Shape : public LinesSet */ Shape getOutsidePolygons() const; - /*! - * Exclude holes which have no parts inside of them. - * \return the resulting polygons. - */ - Shape removeEmptyHoles() const; - - /*! - * Return hole polygons which have no parts inside of them. - * \return the resulting polygons. - */ - Shape getEmptyHoles() const; - /*! * Split up the polygons into groups according to the even-odd rule. * Each SingleShape in the result has an outline as first polygon, whereas the rest are holes. diff --git a/src/geometry/lines_set.cpp b/src/geometry/lines_set.cpp index 4514831163..c556cf3770 100644 --- a/src/geometry/lines_set.cpp +++ b/src/geometry/lines_set.cpp @@ -128,10 +128,26 @@ Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t ou return offset(outer_offset).difference(offset(-inner_offset)); } +template +void LinesSet::translate(const Point2LL& delta) +{ + if (delta.X != 0 || delta.Y != 0) + { + for (LineType& line : getLines()) + { + line.translate(delta); + } + } +} + template<> Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const { - if (distance == 0) + if (empty()) + { + return Shape(); + } + else if (distance == 0) { Shape result; for (const ClosedPolyline& line : getLines()) @@ -140,36 +156,50 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType jo } return result; } - ClipperLib::Paths ret; - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - addPaths(clipper, join_type, ClipperLib::etClosedLine); - clipper.MiterLimit = miter_limit; - clipper.Execute(ret, static_cast(distance)); - return Shape(std::move(ret)); + else + { + ClipperLib::Paths ret; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + addPaths(clipper, join_type, ClipperLib::etClosedLine); + clipper.MiterLimit = miter_limit; + clipper.Execute(ret, static_cast(distance)); + return Shape(std::move(ret)); + } } template<> Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const { - if (distance == 0) + if (empty()) + { + return Shape(); + } + else if (distance == 0) { return Shape(getLines()); } - ClipperLib::Paths ret; - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - Shape(getLines()).unionPolygons().addPaths(clipper, join_type, ClipperLib::etClosedPolygon); - clipper.MiterLimit = miter_limit; - clipper.Execute(ret, static_cast(distance)); - return Shape(std::move(ret)); + else + { + ClipperLib::Paths ret; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + Shape(getLines()).unionPolygons().addPaths(clipper, join_type, ClipperLib::etClosedPolygon); + clipper.MiterLimit = miter_limit; + clipper.Execute(ret, static_cast(distance)); + return Shape(std::move(ret)); + } } template<> Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const { - Shape result; - - if (distance != 0) + if (empty() || distance == 0) + { + return Shape(); + } + else { + Shape result; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); ClipperLib::EndType end_type; if (join_type == ClipperLib::jtMiter) @@ -187,9 +217,9 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType join ClipperLib::Paths result_paths; clipper.Execute(result_paths, static_cast(distance)); result = Shape(std::move(result_paths)); - } - return result; + return result; + } } template @@ -293,6 +323,7 @@ template void LinesSet::splitIntoSegments(OpenLinesSet& result) co template OpenLinesSet LinesSet::splitIntoSegments() const; template coord_t LinesSet::length() const; template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template void LinesSet::translate(const Point2LL& delta); template void LinesSet::removeDegenerateVerts(); template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; template void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; @@ -306,6 +337,7 @@ template void LinesSet::splitIntoSegments(OpenLinesSet& result) template OpenLinesSet LinesSet::splitIntoSegments() const; template coord_t LinesSet::length() const; template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template void LinesSet::translate(const Point2LL& delta); template void LinesSet::removeDegenerateVerts(); template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; template void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; @@ -320,6 +352,7 @@ template void LinesSet::splitIntoSegments(OpenLinesSet& result) const; template OpenLinesSet LinesSet::splitIntoSegments() const; template coord_t LinesSet::length() const; template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template void LinesSet::translate(const Point2LL& delta); template void LinesSet::removeDegenerateVerts(); template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; template void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; diff --git a/src/geometry/shape.cpp b/src/geometry/shape.cpp index 874914293c..2df71ce5ad 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/shape.cpp @@ -145,22 +145,48 @@ void Shape::makeConvex() Shape Shape::difference(const Shape& other) const { - ClipperLib::Paths ret; - ClipperLib::Clipper clipper(clipper_init); - addPaths(clipper, ClipperLib::ptSubject); - other.addPaths(clipper, ClipperLib::ptClip); - clipper.Execute(ClipperLib::ctDifference, ret); - return Shape(std::move(ret)); + if (empty()) + { + return Shape(); + } + else if (other.empty()) + { + return Shape(*this); + } + else + { + ClipperLib::Paths ret; + ClipperLib::Clipper clipper(clipper_init); + addPaths(clipper, ClipperLib::ptSubject); + other.addPaths(clipper, ClipperLib::ptClip); + clipper.Execute(ClipperLib::ctDifference, ret); + return Shape(std::move(ret)); + } } Shape Shape::unionPolygons(const Shape& other, ClipperLib::PolyFillType fill_type) const { - ClipperLib::Paths ret; - ClipperLib::Clipper clipper(clipper_init); - addPaths(clipper, ClipperLib::ptSubject); - other.addPaths(clipper, ClipperLib::ptSubject); - clipper.Execute(ClipperLib::ctUnion, ret, fill_type, fill_type); - return Shape(std::move(ret)); + if (empty() && other.empty()) + { + return Shape(); + } + else if (empty() && other.size() <= 1) + { + return other; + } + else if (other.empty() && size() <= 1) + { + return *this; + } + else + { + ClipperLib::Paths ret; + ClipperLib::Clipper clipper(clipper_init); + addPaths(clipper, ClipperLib::ptSubject); + other.addPaths(clipper, ClipperLib::ptSubject); + clipper.Execute(ClipperLib::ctUnion, ret, fill_type, fill_type); + return Shape(std::move(ret)); + } } Shape Shape::unionPolygons() const @@ -170,26 +196,40 @@ Shape Shape::unionPolygons() const Shape Shape::intersection(const Shape& other) const { - ClipperLib::Paths ret; - ClipperLib::Clipper clipper(clipper_init); - addPaths(clipper, ClipperLib::ptSubject); - other.addPaths(clipper, ClipperLib::ptClip); - clipper.Execute(ClipperLib::ctIntersection, ret); - return Shape(std::move(ret)); + if (empty() || other.empty()) + { + return Shape(); + } + else + { + ClipperLib::Paths ret; + ClipperLib::Clipper clipper(clipper_init); + addPaths(clipper, ClipperLib::ptSubject); + other.addPaths(clipper, ClipperLib::ptClip); + clipper.Execute(ClipperLib::ctIntersection, ret); + return Shape(std::move(ret)); + } } Shape Shape::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const { - if (distance == 0) + if (empty()) { - return Shape(*this); + return Shape(); + } + else if (distance == 0) + { + return *this; + } + else + { + ClipperLib::Paths ret; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + unionPolygons().addPaths(clipper, join_type, ClipperLib::etClosedPolygon); + clipper.MiterLimit = miter_limit; + clipper.Execute(ret, static_cast(distance)); + return Shape(std::move(ret)); } - ClipperLib::Paths ret; - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - unionPolygons().addPaths(clipper, join_type, ClipperLib::etClosedPolygon); - clipper.MiterLimit = miter_limit; - clipper.Execute(ret, static_cast(distance)); - return Shape(std::move(ret)); } bool Shape::inside(const Point2LL& p, bool border_result) const @@ -275,6 +315,11 @@ size_t Shape::findInside(const Point2LL& p, bool border_result) const template OpenLinesSet Shape::intersection(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const { + if (empty() || polylines.empty()) + { + return OpenLinesSet(); + } + LinesSet split_polylines = polylines.splitIntoSegments(); ClipperLib::PolyTree result; @@ -315,12 +360,23 @@ OpenLinesSet Shape::intersection(const LinesSet& polylines, bool resti Shape Shape::xorPolygons(const Shape& other, ClipperLib::PolyFillType pft) const { - ClipperLib::Paths ret; - ClipperLib::Clipper clipper(clipper_init); - addPaths(clipper, ClipperLib::ptSubject); - other.addPaths(clipper, ClipperLib::ptClip); - clipper.Execute(ClipperLib::ctXor, ret, pft); - return Shape(std::move(ret)); + if (empty()) + { + return other; + } + else if (other.empty()) + { + return *this; + } + else + { + ClipperLib::Paths ret; + ClipperLib::Clipper clipper(clipper_init); + addPaths(clipper, ClipperLib::ptSubject); + other.addPaths(clipper, ClipperLib::ptClip); + clipper.Execute(ClipperLib::ctXor, ret, pft); + return Shape(std::move(ret)); + } } Shape Shape::execute(ClipperLib::PolyFillType pft) const @@ -382,6 +438,15 @@ Shape Shape::offsetMulti(const std::vector& offset_dists) const Shape Shape::getOutsidePolygons() const { + if (empty()) + { + return Shape(); + } + else if (size() == 1) + { + return *this; + } + Shape ret; ClipperLib::Clipper clipper(clipper_init); ClipperLib::PolyTree poly_tree; @@ -396,32 +461,6 @@ Shape Shape::getOutsidePolygons() const return ret; } -Shape Shape::removeEmptyHoles() const -{ - Shape ret; - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree poly_tree; - addPaths(clipper, ClipperLib::ptSubject); - clipper.Execute(ClipperLib::ctUnion, poly_tree); - - bool remove_holes = true; - removeEmptyHoles_processPolyTreeNode(poly_tree, remove_holes, ret); - return ret; -} - -Shape Shape::getEmptyHoles() const -{ - Shape ret; - ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree poly_tree; - addPaths(clipper, ClipperLib::ptSubject); - clipper.Execute(ClipperLib::ctUnion, poly_tree); - - bool remove_holes = false; - removeEmptyHoles_processPolyTreeNode(poly_tree, remove_holes, ret); - return ret; -} - void Shape::removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Shape& ret) const { for (size_t outer_poly_idx = 0; outer_poly_idx < static_cast(node.ChildCount()); outer_poly_idx++) @@ -655,33 +694,6 @@ void Shape::removeColinearEdges(const AngleRadians max_deviation_angle) } } -void Shape::scale(const Ratio& ratio) -{ - if (ratio == 1.) - { - return; - } - - for (auto& points : *this) - { - for (auto& pt : points) - { - pt = pt * static_cast(ratio); - } - } -} - -void Shape::translate(const Point2LL& delta) -{ - if (delta.X != 0 || delta.Y != 0) - { - for (Polygon& polygon : *this) - { - polygon.translate(delta); - } - } -} - double Shape::area() const { return std::accumulate( @@ -842,6 +854,11 @@ Shape Shape::removeNearSelfIntersections() const void Shape::simplify(ClipperLib::PolyFillType fill_type) { + if (empty()) + { + return; + } + // This is the actual content from clipper.cpp::SimplifyPolygons, but rewritten here in order // to avoid a list copy ClipperLib::Clipper clipper; From 784cba4512953cb5c7034ee109731e2178976082 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 16 Apr 2024 16:57:43 +0200 Subject: [PATCH 047/135] Added isValid method on polylines CURA-9830 --- include/geometry/closed_polyline.h | 3 +++ include/geometry/open_polyline.h | 6 ++++++ include/geometry/polyline.h | 6 ++++++ src/LayerPlan.cpp | 4 ++-- src/geometry/closed_polyline.cpp | 5 +++++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/include/geometry/closed_polyline.h b/include/geometry/closed_polyline.h index 5d4fa438c5..d6033f4857 100644 --- a/include/geometry/closed_polyline.h +++ b/include/geometry/closed_polyline.h @@ -100,6 +100,9 @@ class ClosedPolyline : public Polyline /*! @see Polyline::addClosingSegment() */ virtual size_t segmentsCount() const override; + /*! @see Polyline::isValid() */ + virtual bool isValid() const override; + ClosedPolyline& operator=(const ClosedPolyline& other) { Polyline::operator=(other); diff --git a/include/geometry/open_polyline.h b/include/geometry/open_polyline.h index 8facf89ef6..1268a609c6 100644 --- a/include/geometry/open_polyline.h +++ b/include/geometry/open_polyline.h @@ -75,6 +75,12 @@ class OpenPolyline : public Polyline return size() > 1 ? size() - 1 : 0; } + /*! @see Polyline::isValid() */ + virtual bool isValid() const override + { + return size() >= 2; + } + OpenPolyline& operator=(OpenPolyline&& other) { Polyline::operator=(std::move(other)); diff --git a/include/geometry/polyline.h b/include/geometry/polyline.h index 0a72dcd285..8cb77d671c 100644 --- a/include/geometry/polyline.h +++ b/include/geometry/polyline.h @@ -96,6 +96,12 @@ class Polyline : public PointsSet */ virtual size_t segmentsCount() const = 0; + /*! + * \brief Indicates whether the points set form a valid polyline, i.e. if it has enough points + * according to its type. + */ + virtual bool isValid() const = 0; + Polyline& operator=(const Polyline& other) { PointsSet::operator=(other); diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index efd586191b..29f50d71cb 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -1422,7 +1422,7 @@ void LayerPlan::addLinesInGivenOrder( { const PathOrdering& path = lines[order_idx]; const Polyline& polyline = *path.vertices_; - if (polyline.segmentsCount() == 0) + if (! polyline.isValid()) { continue; } @@ -1551,7 +1551,7 @@ void LayerPlan::addLinesMonotonic( for (size_t line_idx = 0; line_idx < line_order.paths_.size(); ++line_idx) { const OpenPolyline& polyline = *line_order.paths_[line_idx].vertices_; - if (polyline.segmentsCount() == 0) + if (! polyline.isValid()) { continue; } diff --git a/src/geometry/closed_polyline.cpp b/src/geometry/closed_polyline.cpp index f08cf9624e..3ff2e75c0f 100644 --- a/src/geometry/closed_polyline.cpp +++ b/src/geometry/closed_polyline.cpp @@ -20,6 +20,11 @@ size_t ClosedPolyline::segmentsCount() const } } +bool ClosedPolyline::isValid() const +{ + return size() >= (explicitely_closed_ ? 4 : 3); +} + bool ClosedPolyline::inside(const Point2LL& p, bool border_result) const { int res = ClipperLib::PointInPolygon(p, getPoints()); From 97eb08f0cb2a01cadb6ebc1e01078acf4b127f6c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 17 Apr 2024 13:21:04 +0200 Subject: [PATCH 048/135] Add links to online documentation CURA-9830 --- include/geometry/closed_polyline.h | 1 + include/geometry/lines_set.h | 1 + include/geometry/mixed_lines_set.h | 1 + include/geometry/open_polyline.h | 1 + include/geometry/points_set.h | 1 + include/geometry/polygon.h | 1 + include/geometry/polyline.h | 1 + include/geometry/shape.h | 1 + include/geometry/single_shape.h | 6 ++++-- 9 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/geometry/closed_polyline.h b/include/geometry/closed_polyline.h index d6033f4857..dfbd8a9d63 100644 --- a/include/geometry/closed_polyline.h +++ b/include/geometry/closed_polyline.h @@ -12,6 +12,7 @@ namespace cura class OpenPolyline; /*! @brief This describes a polyline which forms a closed path. + * @sa https://github.com/Ultimaker/CuraEngine/wiki/Geometric-Base-Types#closedpolyline * * The path may be closed: * * Explicitely, which means the last point is at the same position as the first point. diff --git a/include/geometry/lines_set.h b/include/geometry/lines_set.h index 2b527d93f2..5ae4b288d5 100644 --- a/include/geometry/lines_set.h +++ b/include/geometry/lines_set.h @@ -20,6 +20,7 @@ class OpenPolyline; /*! * \brief Base class for all geometry containers representing a set of polylines. + * \sa https://github.com/Ultimaker/CuraEngine/wiki/Geometric-Base-Types#linesset */ template class LinesSet diff --git a/include/geometry/mixed_lines_set.h b/include/geometry/mixed_lines_set.h index 4e3b5bea21..a0c25fc2d2 100644 --- a/include/geometry/mixed_lines_set.h +++ b/include/geometry/mixed_lines_set.h @@ -24,6 +24,7 @@ using OpenPolylinePtr = std::shared_ptr; /*! * \brief Convenience definition for a container that can hold any type of polyline. + * \sa https://github.com/Ultimaker/CuraEngine/wiki/Geometric-Base-Types#mixedlinesset */ class MixedLinesSet : public std::vector { diff --git a/include/geometry/open_polyline.h b/include/geometry/open_polyline.h index 1268a609c6..b7faca260d 100644 --- a/include/geometry/open_polyline.h +++ b/include/geometry/open_polyline.h @@ -11,6 +11,7 @@ namespace cura /*! * @brief Represents a polyline that is explicitely not closed + * @sa https://github.com/Ultimaker/CuraEngine/wiki/Geometric-Base-Types#openpolyline * @note Open polylines are sometimes used to represent actually closed polylines. In this case * the first and last point are at the very same position. This should not be done, but * it exists all around the engine for historical reasons. The behavior is however deprecated diff --git a/include/geometry/points_set.h b/include/geometry/points_set.h index 587230dcb1..69963de9ac 100644 --- a/include/geometry/points_set.h +++ b/include/geometry/points_set.h @@ -18,6 +18,7 @@ const static int clipper_init = (0); /*! * \brief Base class for all geometry containers representing a set of points. + * \sa https://github.com/Ultimaker/CuraEngine/wiki/Geometric-Base-Types#pointsset */ class PointsSet { diff --git a/include/geometry/polygon.h b/include/geometry/polygon.h index d3ca1e1803..ad1d2deaa5 100644 --- a/include/geometry/polygon.h +++ b/include/geometry/polygon.h @@ -16,6 +16,7 @@ class AngleDegrees; /*! * \brief A Polygon is a specific type of polyline, for which we consider that the "inside" part of * the line forms a surface + * \sa https://github.com/Ultimaker/CuraEngine/wiki/Geometric-Base-Types#polygon */ class Polygon : public ClosedPolyline { diff --git a/include/geometry/polyline.h b/include/geometry/polyline.h index 8cb77d671c..89f0c02486 100644 --- a/include/geometry/polyline.h +++ b/include/geometry/polyline.h @@ -18,6 +18,7 @@ class OpenPolyline; /*! * \brief Base class for various types of polylines. A polyline is basically a set of points, but * we geometrically interpret them forming a chain of segments between each other. + * \sa https://github.com/Ultimaker/CuraEngine/wiki/Geometric-Base-Types#pointsset * * * Open Polyline : this represents a line that does not close, i.e. the last point is different * from the initial point (think of the U letter) diff --git a/include/geometry/shape.h b/include/geometry/shape.h index 30c65b32f8..cf39b7b385 100644 --- a/include/geometry/shape.h +++ b/include/geometry/shape.h @@ -22,6 +22,7 @@ class Point3Matrix; * be contained inside others, being actually "holes" of the shape. For example, if you * wanted to represent the "8" digit with polygons, you would need 1 for the outline and 2 * for the "holes" so the shape would contain a total of 3 polygons. + * @sa https://github.com/Ultimaker/CuraEngine/wiki/Geometric-Base-Types#shape */ class Shape : public LinesSet { diff --git a/include/geometry/single_shape.h b/include/geometry/single_shape.h index 08a9e421d9..0e8008a983 100644 --- a/include/geometry/single_shape.h +++ b/include/geometry/single_shape.h @@ -12,9 +12,11 @@ namespace cura class Polygon; /*! - * A single area with holes. The first polygon is the outline, while the rest are holes within this outline. + * @brief A single area with holes. The first polygon is the outline, while the rest are holes within this outline. + * @sa https://github.com/Ultimaker/CuraEngine/wiki/Geometric-Base-Types#singleshape * - * This class has little more functionality than Shape, but serves to show that a specific instance is ordered such that the first Polygon is the outline and the rest are holes. + * This class has little more functionality than Shape, but serves to show that a specific instance + * is ordered such that the first Polygon is the outline and the rest are holes. */ class SingleShape : public Shape { From 513927496c23425e27539088598d4ee6ae67b008 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 17 Apr 2024 14:53:53 +0200 Subject: [PATCH 049/135] Minor code cleaning and optimization CURA-11597 --- include/infill/ZigzagConnectorProcessor.h | 2 +- src/infill/ZigzagConnectorProcessor.cpp | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/include/infill/ZigzagConnectorProcessor.h b/include/infill/ZigzagConnectorProcessor.h index 9b1b979cf6..5bc629b685 100644 --- a/include/infill/ZigzagConnectorProcessor.h +++ b/include/infill/ZigzagConnectorProcessor.h @@ -175,7 +175,7 @@ class ZigzagConnectorProcessor */ void addZagConnector(std::vector& points, bool is_endpiece); - bool handleConnectorToCloseToSegment(const coord_t scanline_x, const coord_t min_distance_to_scanline); + bool handleConnectorTooCloseToSegment(const coord_t scanline_x, const coord_t min_distance_to_scanline); protected: const PointMatrix& rotation_matrix_; //!< The rotation matrix used to enforce the infill angle diff --git a/src/infill/ZigzagConnectorProcessor.cpp b/src/infill/ZigzagConnectorProcessor.cpp index c19cd46b4e..4e28dee774 100644 --- a/src/infill/ZigzagConnectorProcessor.cpp +++ b/src/infill/ZigzagConnectorProcessor.cpp @@ -83,14 +83,23 @@ bool ZigzagConnectorProcessor::shouldAddCurrentConnector(int start_scanline_idx, return should_add; } -bool ZigzagConnectorProcessor::handleConnectorToCloseToSegment(const coord_t scanline_x, const coord_t min_distance_to_scanline) +bool ZigzagConnectorProcessor::handleConnectorTooCloseToSegment(const coord_t scanline_x, const coord_t min_distance_to_scanline) { - bool all_within_min_dist = ! current_connector_.empty(); - for (const auto& point : current_connector_) + if (current_connector_.empty()) { - all_within_min_dist &= std::abs(point.X - scanline_x) < min_distance_to_scanline; + return false; + } + else + { + return std::find_if( + current_connector_.begin(), + current_connector_.end(), + [scanline_x, min_distance_to_scanline](const Point2LL& point) + { + return std::abs(point.X - scanline_x) >= min_distance_to_scanline; + }) + == current_connector_.end(); } - return all_within_min_dist; } void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2LL& intersection, int scanline_index, coord_t min_distance_to_scanline) @@ -106,7 +115,7 @@ void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point2L else { // add the current connector if needed - if (shouldAddCurrentConnector(last_connector_index_, scanline_index) && ! handleConnectorToCloseToSegment(intersection.X, min_distance_to_scanline)) + if (shouldAddCurrentConnector(last_connector_index_, scanline_index) && ! handleConnectorTooCloseToSegment(intersection.X, min_distance_to_scanline)) { const bool is_this_endpiece = scanline_index == last_connector_index_; current_connector_.push_back(intersection); From 5e62a8524b9444b2b342746514cdfd044e67ab7a Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Fri, 19 Apr 2024 16:54:02 +0200 Subject: [PATCH 050/135] Add support z-seam type to inset order optimization The implementation of the order optimizer has been updated to account for the z-seam type for support. This includes adjustment of the start point calculation and Both 'InsetOrderOptimizer' and 'PathOrderOptimizer' classes have been modified to accommodate these changes. CURA-11227 --- include/InsetOrderOptimizer.h | 1 + include/PathOrderOptimizer.h | 55 +++++++++++++++++++++++++++++++-- include/settings/EnumSettings.h | 1 + src/FffGcodeWriter.cpp | 12 ++++++- src/InsetOrderOptimizer.cpp | 16 ++++++++++ src/settings/Settings.cpp | 2 ++ 6 files changed, 84 insertions(+), 3 deletions(-) diff --git a/include/InsetOrderOptimizer.h b/include/InsetOrderOptimizer.h index 7ff5300090..3a09d460f4 100644 --- a/include/InsetOrderOptimizer.h +++ b/include/InsetOrderOptimizer.h @@ -106,6 +106,7 @@ class InsetOrderOptimizer const ZSeamConfig& z_seam_config_; const std::vector& paths_; const LayerIndex layer_nr_; + std::vector mesh_paths_; std::vector> inset_polys_; // vector of vectors holding the inset polygons Polygons retraction_region_; // After printing an outer wall, move into this region so that retractions do not leave visible blobs. Calculated lazily if needed (see diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index df1cc07c7e..e049816620 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -59,6 +59,10 @@ namespace cura template class PathOrderOptimizer { +private: + std::vector mesh_paths_{}; + size_t min_size_support_zeam_ = 0; + public: using OrderablePath = PathOrdering; /*! @@ -118,6 +122,8 @@ class PathOrderOptimizer , reverse_direction_(reverse_direction) , _group_outer_walls(group_outer_walls) , order_requirements_(&order_requirements) + , mesh_paths_ {} + { } @@ -131,6 +137,12 @@ class PathOrderOptimizer paths_.emplace_back(polygon, is_closed); } + void addMeshPathsinfo(const std::vector& polylines, const size_t min_distance) + { + constexpr bool is_closed = true; + mesh_paths_ = polylines; + min_size_support_zeam_ = min_distance; + } /*! * Add a new polyline to be optimized. * \param polyline The polyline to optimize. @@ -199,7 +211,7 @@ class PathOrderOptimizer // For some Z seam types the start position can be pre-computed. // This is faster since we don't need to re-compute the start position at each step then. - precompute_start &= seam_config_.type_ == EZSeamType::RANDOM || seam_config_.type_ == EZSeamType::USER_SPECIFIED || seam_config_.type_ == EZSeamType::SHARPEST_CORNER; + precompute_start &= seam_config_.type_ == EZSeamType::SUPPORT || seam_config_.type_ == EZSeamType::RANDOM || seam_config_.type_ == EZSeamType::USER_SPECIFIED || seam_config_.type_ == EZSeamType::SHARPEST_CORNER; if (precompute_start) { for (auto& path : paths_) @@ -561,6 +573,24 @@ class PathOrderOptimizer return best_candidate->vertices_; } + bool isVertexCloseToPolygonPath(Point2LL point) + { + for( const auto& points : ranges::front(mesh_paths_)) + { + for (const auto& polygon_point : points) + { + double distance = std::sqrt(std::pow(static_cast(polygon_point.X - point.X), 2) + std::pow(static_cast(polygon_point.Y - point.Y), 2)); + + if (distance <= min_size_support_zeam_) + { + return true; + } + } + } + + return false; + } + OrderablePath* findClosestPath(Point2LL start_position, std::vector candidate_paths) { coord_t best_distance2 = std::numeric_limits::max(); @@ -604,6 +634,21 @@ class PathOrderOptimizer return best_candidate; } + + size_t pathIfzeamSupportIsCloseToModel(size_t best_pos, const OrderablePath& path) + { + if (!mesh_paths_.empty()) + { + Point2LL current_candidate = (*path.converted_)[best_pos]; + if (isVertexCloseToPolygonPath(current_candidate)) + { + best_pos = pathIfzeamSupportIsCloseToModel(best_pos+1, path); + } + } + return best_pos; + } + + /*! * Find the vertex which will be the starting point of printing a polygon or * polyline. @@ -674,7 +719,8 @@ class PathOrderOptimizer // angles > 0 are convex (right turning) double corner_shift; - if (seam_config_.type_ == EZSeamType::SHORTEST) + + if ((seam_config_.type_ == EZSeamType::SHORTEST) || (seam_config_.type_ == EZSeamType::SUPPORT)) { // the more a corner satisfies our criteria, the closer it appears to be // shift 10mm for a very acute corner @@ -740,6 +786,11 @@ class PathOrderOptimizer } } + if (seam_config_.type_ == EZSeamType::SUPPORT) + { + best_i = pathIfzeamSupportIsCloseToModel(best_i, path); + + } return best_i; } diff --git a/include/settings/EnumSettings.h b/include/settings/EnumSettings.h index 18bd091569..367b27d223 100644 --- a/include/settings/EnumSettings.h +++ b/include/settings/EnumSettings.h @@ -70,6 +70,7 @@ enum class EZSeamType SHORTEST, USER_SPECIFIED, SHARPEST_CORNER, + SUPPORT, /* The 'Skirt/brim' type behaves like shortest, except it doesn't try to do tie-breaking for similar locations to * the last attempt, as that gives a different result when the seams are next to each other instead of on top. diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 040b7d8376..982c9dd7aa 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -33,6 +33,7 @@ #include "utils/Simplify.h" //Removing micro-segments created by offsetting. #include "utils/ThreadPool.h" #include "utils/linearAlg2D.h" +#include "utils/polygonUtils.h" #include "utils/math.h" #include "utils/orderOptimizer.h" @@ -3451,7 +3452,16 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer const GCodePathConfig& config = configs[0]; constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; - const ZSeamConfig z_seam_config(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); + ZSeamConfig z_seam_config; + Point2LL start_pos; + + start_pos = gcode_layer.getLastPlannedPositionOrStartingPosition(); + z_seam_config = ZSeamConfig(EZSeamType::SUPPORT, + start_pos, + EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, + false); + + InsetOrderOptimizer wall_orderer( *this, storage, diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 82d4199d01..7b732d31c0 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -70,6 +70,7 @@ InsetOrderOptimizer::InsetOrderOptimizer( , z_seam_config_(z_seam_config) , paths_(paths) , layer_nr_(gcode_layer.getLayerNr()) + , mesh_paths_{} { } @@ -112,6 +113,21 @@ bool InsetOrderOptimizer::addToLayer() order_optimizer.addPolyline(&line); } } + if (z_seam_config_.type_== EZSeamType::SUPPORT) + { + for (std::shared_ptr mesh_ptr : storage_.meshes) + { + auto& mesh = *mesh_ptr; + for (auto &part : mesh.layers[layer_nr_].parts) + { + mesh_paths_.push_back(part.print_outline.paths); + } + } + if (!mesh_paths_.empty()) + { + order_optimizer.addMeshPathsinfo(mesh_paths_,settings_.get("support_z_seam_min_distance")); + } + } order_optimizer.optimize(); diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index d946ec4496..9724281593 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -513,6 +513,8 @@ EZSeamType Settings::get(const std::string& key) const return EZSeamType::SHARPEST_CORNER; case "plugin"_sw: return EZSeamType::PLUGIN; + case "support"_sw: + return EZSeamType::SUPPORT; default: return EZSeamType::SHORTEST; } From 8c6d99eb821f6194cf17150b657cbe5c5ea8ad7f Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Fri, 19 Apr 2024 14:55:53 +0000 Subject: [PATCH 051/135] Applied clang-format. --- include/PathOrderOptimizer.h | 12 ++++++------ src/FffGcodeWriter.cpp | 7 ++----- src/InsetOrderOptimizer.cpp | 8 ++++---- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index e049816620..684128a5f9 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -122,7 +122,7 @@ class PathOrderOptimizer , reverse_direction_(reverse_direction) , _group_outer_walls(group_outer_walls) , order_requirements_(&order_requirements) - , mesh_paths_ {} + , mesh_paths_{} { } @@ -211,7 +211,8 @@ class PathOrderOptimizer // For some Z seam types the start position can be pre-computed. // This is faster since we don't need to re-compute the start position at each step then. - precompute_start &= seam_config_.type_ == EZSeamType::SUPPORT || seam_config_.type_ == EZSeamType::RANDOM || seam_config_.type_ == EZSeamType::USER_SPECIFIED || seam_config_.type_ == EZSeamType::SHARPEST_CORNER; + precompute_start &= seam_config_.type_ == EZSeamType::SUPPORT || seam_config_.type_ == EZSeamType::RANDOM || seam_config_.type_ == EZSeamType::USER_SPECIFIED + || seam_config_.type_ == EZSeamType::SHARPEST_CORNER; if (precompute_start) { for (auto& path : paths_) @@ -575,7 +576,7 @@ class PathOrderOptimizer bool isVertexCloseToPolygonPath(Point2LL point) { - for( const auto& points : ranges::front(mesh_paths_)) + for (const auto& points : ranges::front(mesh_paths_)) { for (const auto& polygon_point : points) { @@ -637,12 +638,12 @@ class PathOrderOptimizer size_t pathIfzeamSupportIsCloseToModel(size_t best_pos, const OrderablePath& path) { - if (!mesh_paths_.empty()) + if (! mesh_paths_.empty()) { Point2LL current_candidate = (*path.converted_)[best_pos]; if (isVertexCloseToPolygonPath(current_candidate)) { - best_pos = pathIfzeamSupportIsCloseToModel(best_pos+1, path); + best_pos = pathIfzeamSupportIsCloseToModel(best_pos + 1, path); } } return best_pos; @@ -789,7 +790,6 @@ class PathOrderOptimizer if (seam_config_.type_ == EZSeamType::SUPPORT) { best_i = pathIfzeamSupportIsCloseToModel(best_i, path); - } return best_i; } diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 982c9dd7aa..da17d2c13c 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -33,9 +33,9 @@ #include "utils/Simplify.h" //Removing micro-segments created by offsetting. #include "utils/ThreadPool.h" #include "utils/linearAlg2D.h" -#include "utils/polygonUtils.h" #include "utils/math.h" #include "utils/orderOptimizer.h" +#include "utils/polygonUtils.h" namespace cura { @@ -3456,10 +3456,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer Point2LL start_pos; start_pos = gcode_layer.getLastPlannedPositionOrStartingPosition(); - z_seam_config = ZSeamConfig(EZSeamType::SUPPORT, - start_pos, - EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, - false); + z_seam_config = ZSeamConfig(EZSeamType::SUPPORT, start_pos, EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); InsetOrderOptimizer wall_orderer( diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 7b732d31c0..409900584d 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -113,19 +113,19 @@ bool InsetOrderOptimizer::addToLayer() order_optimizer.addPolyline(&line); } } - if (z_seam_config_.type_== EZSeamType::SUPPORT) + if (z_seam_config_.type_ == EZSeamType::SUPPORT) { for (std::shared_ptr mesh_ptr : storage_.meshes) { auto& mesh = *mesh_ptr; - for (auto &part : mesh.layers[layer_nr_].parts) + for (auto& part : mesh.layers[layer_nr_].parts) { mesh_paths_.push_back(part.print_outline.paths); } } - if (!mesh_paths_.empty()) + if (! mesh_paths_.empty()) { - order_optimizer.addMeshPathsinfo(mesh_paths_,settings_.get("support_z_seam_min_distance")); + order_optimizer.addMeshPathsinfo(mesh_paths_, settings_.get("support_z_seam_min_distance")); } } From fe02797035a248840e1cc16c89a723aa7f4ac037 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 22 Apr 2024 12:39:43 +0200 Subject: [PATCH 052/135] pin version 5.7.1 --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index e6c16b939b..25ea096dd3 100644 --- a/conandata.yml +++ b/conandata.yml @@ -1,4 +1,4 @@ -version: "5.7.0" +version: "5.7.1" requirements: - "scripta/0.1.0@ultimaker/testing" requirements_arcus: From 9d35904f20a05f20b2bf977681d7eda3f82b1b14 Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Tue, 23 Apr 2024 13:48:59 +0200 Subject: [PATCH 053/135] Update z-seam handling and improve path optimization This update tweaks handling of the z-seam by allowing it to shift away from the model based on specific settings. It also introduces better path optimization, by calculating the shortest distance from a point to a line segment, optimizing how the best position is retrieved if such support exists and dealing with edge cases where no optimal starting path is found. CURA-11227 --- include/PathOrderOptimizer.h | 61 ++++++++++++++++++++++++++++++------ src/FffGcodeWriter.cpp | 15 ++++++--- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 684128a5f9..a8d6cec840 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -211,7 +211,7 @@ class PathOrderOptimizer // For some Z seam types the start position can be pre-computed. // This is faster since we don't need to re-compute the start position at each step then. - precompute_start &= seam_config_.type_ == EZSeamType::SUPPORT || seam_config_.type_ == EZSeamType::RANDOM || seam_config_.type_ == EZSeamType::USER_SPECIFIED + precompute_start &= seam_config_.type_ == EZSeamType::RANDOM || seam_config_.type_ == EZSeamType::USER_SPECIFIED || seam_config_.type_ == EZSeamType::SHARPEST_CORNER; if (precompute_start) { @@ -578,17 +578,46 @@ class PathOrderOptimizer { for (const auto& points : ranges::front(mesh_paths_)) { - for (const auto& polygon_point : points) + const int len = points.size(); + + for (int i = 0; i < len; ++i) { - double distance = std::sqrt(std::pow(static_cast(polygon_point.X - point.X), 2) + std::pow(static_cast(polygon_point.Y - point.Y), 2)); + const auto& polygon_point1 = points[i]; + const auto& polygon_point2 = points[(i + 1) % len]; // Ensures looping back to the first point to create the final segment + + // Definitions + double x = static_cast(point.X); + double y = static_cast(point.Y); + double x1 = static_cast(polygon_point1.X); + double y1 = static_cast(polygon_point1.Y); + double x2 = static_cast(polygon_point2.X); + double y2 = static_cast(polygon_point2.Y); + + // Calculate the shortest distance from the point to the line segment + double dx = x2 - x1; + double dy = y2 - y1; + + // Calculate the t parameter + double t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); + + // If t is outside bounds [0,1], point is closest to an endpoint of the segment + t = std::max(0.0, std::min(1.0, t)); + + // Compute the coordinates of the point on the line segment nearest to the external point + double nearestX = x1 + t * dx; + double nearestY = y1 + t * dy; + + // Calculate squared distance from external point to its nearest point on the line segment + double dx_nearest = x - nearestX; + double dy_nearest = y - nearestY; + double squared_distance = dx_nearest*dx_nearest + dy_nearest*dy_nearest; - if (distance <= min_size_support_zeam_) + if (squared_distance <= min_size_support_zeam_ * min_size_support_zeam_) { return true; } } } - return false; } @@ -638,14 +667,28 @@ class PathOrderOptimizer size_t pathIfzeamSupportIsCloseToModel(size_t best_pos, const OrderablePath& path) { - if (! mesh_paths_.empty()) + static size_t number_of_paths_analysed = 0; + size_t path_size = path.converted_->size(); + if (path_size > number_of_paths_analysed) { - Point2LL current_candidate = (*path.converted_)[best_pos]; - if (isVertexCloseToPolygonPath(current_candidate)) + if (! mesh_paths_.empty()) { - best_pos = pathIfzeamSupportIsCloseToModel(best_pos + 1, path); + Point2LL current_candidate = (path.converted_)->at(best_pos); + if (isVertexCloseToPolygonPath(current_candidate)) + { + size_t next_best_position = (path_size > best_pos + 1) ? best_pos + 1 : 0; + best_pos = pathIfzeamSupportIsCloseToModel(next_best_position, path); + number_of_paths_analysed +=1; + } } } + else + { + number_of_paths_analysed = 0; + spdlog::warn("no start path found for support z seam distance"); + // We can also calculate the best point to start at this point. + // This usually happens when the distance of support seam from model is bigger than the whole support wall points. + } return best_pos; } diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index da17d2c13c..b34b284c25 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -33,9 +33,9 @@ #include "utils/Simplify.h" //Removing micro-segments created by offsetting. #include "utils/ThreadPool.h" #include "utils/linearAlg2D.h" +#include "utils/polygonUtils.h" #include "utils/math.h" #include "utils/orderOptimizer.h" -#include "utils/polygonUtils.h" namespace cura { @@ -3452,11 +3452,18 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer const GCodePathConfig& config = configs[0]; constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; + EZSeamType z_seam_type = EZSeamType::SHORTEST; ZSeamConfig z_seam_config; - Point2LL start_pos; + Point2LL start_pos = gcode_layer.getLastPlannedPositionOrStartingPosition(); + if (infill_extruder.settings_.get("support_z_seam_away_from_model")) + { + z_seam_type = EZSeamType::SUPPORT; + } - start_pos = gcode_layer.getLastPlannedPositionOrStartingPosition(); - z_seam_config = ZSeamConfig(EZSeamType::SUPPORT, start_pos, EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); + z_seam_config = ZSeamConfig(z_seam_type, + start_pos, + EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, + false); InsetOrderOptimizer wall_orderer( From 17d5828bb844ab2144c46866d3e82172efdf4c84 Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Tue, 23 Apr 2024 11:49:32 +0000 Subject: [PATCH 054/135] Applied clang-format. --- include/PathOrderOptimizer.h | 7 +++---- src/FffGcodeWriter.cpp | 7 ++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index a8d6cec840..2163561cdb 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -211,8 +211,7 @@ class PathOrderOptimizer // For some Z seam types the start position can be pre-computed. // This is faster since we don't need to re-compute the start position at each step then. - precompute_start &= seam_config_.type_ == EZSeamType::RANDOM || seam_config_.type_ == EZSeamType::USER_SPECIFIED - || seam_config_.type_ == EZSeamType::SHARPEST_CORNER; + precompute_start &= seam_config_.type_ == EZSeamType::RANDOM || seam_config_.type_ == EZSeamType::USER_SPECIFIED || seam_config_.type_ == EZSeamType::SHARPEST_CORNER; if (precompute_start) { for (auto& path : paths_) @@ -610,7 +609,7 @@ class PathOrderOptimizer // Calculate squared distance from external point to its nearest point on the line segment double dx_nearest = x - nearestX; double dy_nearest = y - nearestY; - double squared_distance = dx_nearest*dx_nearest + dy_nearest*dy_nearest; + double squared_distance = dx_nearest * dx_nearest + dy_nearest * dy_nearest; if (squared_distance <= min_size_support_zeam_ * min_size_support_zeam_) { @@ -678,7 +677,7 @@ class PathOrderOptimizer { size_t next_best_position = (path_size > best_pos + 1) ? best_pos + 1 : 0; best_pos = pathIfzeamSupportIsCloseToModel(next_best_position, path); - number_of_paths_analysed +=1; + number_of_paths_analysed += 1; } } } diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index b34b284c25..e9e4bed92d 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -33,9 +33,9 @@ #include "utils/Simplify.h" //Removing micro-segments created by offsetting. #include "utils/ThreadPool.h" #include "utils/linearAlg2D.h" -#include "utils/polygonUtils.h" #include "utils/math.h" #include "utils/orderOptimizer.h" +#include "utils/polygonUtils.h" namespace cura { @@ -3460,10 +3460,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer z_seam_type = EZSeamType::SUPPORT; } - z_seam_config = ZSeamConfig(z_seam_type, - start_pos, - EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, - false); + z_seam_config = ZSeamConfig(z_seam_type, start_pos, EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); InsetOrderOptimizer wall_orderer( From 4cdd1166eb5bf4afdf6915e0ece59d7f84b393eb Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Tue, 23 Apr 2024 14:01:04 +0200 Subject: [PATCH 055/135] Refactor PathOrderOptimizer logic and adjust warnings Refactored the logic of the PathOrderOptimizer function to ensure 'number_of_paths_analysed' is increased and reset only in the suitable scenarios. Also, corrected the case of a warning message related to the 'z seam distance'. CURA-11227 --- include/PathOrderOptimizer.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 2163561cdb..821df2c8da 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -677,17 +677,22 @@ class PathOrderOptimizer { size_t next_best_position = (path_size > best_pos + 1) ? best_pos + 1 : 0; best_pos = pathIfzeamSupportIsCloseToModel(next_best_position, path); - number_of_paths_analysed += 1; + } + else + { + number_of_paths_analysed = 0; + return best_pos; } } + number_of_paths_analysed +=1; } else { - number_of_paths_analysed = 0; - spdlog::warn("no start path found for support z seam distance"); + spdlog::warn("No start path found for support z seam distance"); // We can also calculate the best point to start at this point. // This usually happens when the distance of support seam from model is bigger than the whole support wall points. } + number_of_paths_analysed = 0; return best_pos; } From 765569c96e454a6f65f87497d262476ed98c510b Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Tue, 23 Apr 2024 12:01:36 +0000 Subject: [PATCH 056/135] Applied clang-format. --- include/PathOrderOptimizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 821df2c8da..4f9bf9d173 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -684,7 +684,7 @@ class PathOrderOptimizer return best_pos; } } - number_of_paths_analysed +=1; + number_of_paths_analysed += 1; } else { From d89c4d6271beb35c494632bf3457ae2438f0b9ba Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Tue, 23 Apr 2024 14:56:57 +0200 Subject: [PATCH 057/135] Added documentation CURA-11227 --- include/PathOrderOptimizer.h | 49 ++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 4f9bf9d173..f25e3a1a96 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -573,6 +573,21 @@ class PathOrderOptimizer return best_candidate->vertices_; } + /** + * @brief Checks if the given vertex is close to any polygon path defined by the front of the mesh_paths_. + * + * The function iteratively checks the shortest distance from the point to each line segment in the polygon. + * A line segment is defined by each pair of consecutive points in the polygon. + * If the shortest distance is less than or equal to min_size_support_zeam_, the function returns true. + * This implies that the vertex is considered "close" to the polygon path. + * The check is performed against all polygons in the front of the mesh_paths_. + * + * @param point Vertex of interest, provided as a 2D point in the LongLong (LL) coordinate space. + * @return Returns true if the vertex is close to any line segment in the polygon path, false otherwise. + * + * @note The closeness is judged based on the minimum Zeam support size. + * @note The distance check is performed on the squared distance to avoid costly square root operations. + */ bool isVertexCloseToPolygonPath(Point2LL point) { for (const auto& points : ranges::front(mesh_paths_)) @@ -663,10 +678,28 @@ class PathOrderOptimizer return best_candidate; } + /** + * @brief Analyze the positions in a path and determine the next optimal position based on a proximity criterion. + * + * This function iteratively examines positions along the given path, checking if the position is close to 3D model. + * Each position is specified by an index, starting with `best_pos`. If the position is close to the model according to + * `isVertexCloseToPolygonPath` function, the function recursively calls itself with the next position. This process is + * repeated until all positions have been checked or `number_of_paths_analysed` becomes equal to `path_size`. + * If `number_of_paths_analysed` becomes equal to `path_size`, it logs a warning and returns the current best position. + * + * @param best_pos The index of the initial position for analysis in the path. + * @param path An OrderablePath instance containing the path to be examined. + * @param number_of_paths_analysed Optionally, the initial index of paths analysed. Defaults to 0. + * @return The index of the next optimal position in the path sequence. May be the same as the input `best_pos`, + * or may be incremented to a different location based on the proximity criterion. + * + * @note This function uses recursion to evaluate each position in the path. + * @note The process stops prematurely if no start path is found for the support z seam distance. + * This typically happens when the distance of the support seam from the model is bigger than all the support wall points. + */ - size_t pathIfzeamSupportIsCloseToModel(size_t best_pos, const OrderablePath& path) + size_t pathIfzeamSupportIsCloseToModel(size_t best_pos, const OrderablePath& path, size_t number_of_paths_analysed) { - static size_t number_of_paths_analysed = 0; size_t path_size = path.converted_->size(); if (path_size > number_of_paths_analysed) { @@ -676,15 +709,10 @@ class PathOrderOptimizer if (isVertexCloseToPolygonPath(current_candidate)) { size_t next_best_position = (path_size > best_pos + 1) ? best_pos + 1 : 0; - best_pos = pathIfzeamSupportIsCloseToModel(next_best_position, path); - } - else - { - number_of_paths_analysed = 0; - return best_pos; + number_of_paths_analysed += 1; + best_pos = pathIfzeamSupportIsCloseToModel(next_best_position, path, number_of_paths_analysed); } } - number_of_paths_analysed += 1; } else { @@ -692,7 +720,6 @@ class PathOrderOptimizer // We can also calculate the best point to start at this point. // This usually happens when the distance of support seam from model is bigger than the whole support wall points. } - number_of_paths_analysed = 0; return best_pos; } @@ -836,7 +863,7 @@ class PathOrderOptimizer if (seam_config_.type_ == EZSeamType::SUPPORT) { - best_i = pathIfzeamSupportIsCloseToModel(best_i, path); + best_i = pathIfzeamSupportIsCloseToModel(best_i, path, 0); } return best_i; } From 9504610d72612e22da5572992dd95d64cea81e37 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 26 Apr 2024 14:32:41 +0200 Subject: [PATCH 058/135] File naming uniformization CURA-9830 --- CMakeLists.txt | 22 +++++++++---------- benchmark/infill_benchmark.h | 2 +- benchmark/wall_benchmark.h | 2 +- include/BeadingStrategy/BeadingStrategy.h | 2 +- include/BoostInterface.hpp | 4 ++-- include/ExtruderPlan.h | 2 +- include/InterlockingGenerator.h | 4 ++-- include/LayerPlan.h | 2 +- include/PrimeTower.h | 2 +- include/SkeletalTrapezoidation.h | 2 +- include/SkeletalTrapezoidationJoint.h | 2 +- include/SupportInfillPart.h | 4 ++-- include/TopSurface.h | 2 +- include/TreeModelVolumes.h | 2 +- include/TreeSupport.h | 2 +- include/TreeSupportBaseCircle.h | 2 +- include/TreeSupportElement.h | 2 +- include/TreeSupportTipGenerator.h | 2 +- include/TreeSupportUtils.h | 2 +- include/WallToolPaths.h | 2 +- include/communication/Communication.h | 2 +- include/gcodeExport.h | 2 +- .../{closed_lines_set.h => ClosedLinesSet.h} | 4 ++-- .../{closed_polyline.h => ClosedPolyline.h} | 2 +- include/geometry/{lines_set.h => LinesSet.h} | 2 +- .../{mixed_lines_set.h => MixedLinesSet.h} | 0 .../{open_lines_set.h => OpenLinesSet.h} | 4 ++-- .../{open_polyline.h => OpenPolyline.h} | 2 +- .../geometry/{parts_view.h => PartsView.h} | 0 include/geometry/{point2ll.h => Point2LL.h} | 2 +- include/geometry/{point3ll.h => Point3LL.h} | 0 .../{point3_matrix.h => Point3Matrix.h} | 4 ++-- .../{point_matrix.h => PointMatrix.h} | 2 +- .../geometry/{points_set.h => PointsSet.h} | 2 +- include/geometry/{polygon.h => Polygon.h} | 2 +- include/geometry/{polyline.h => Polyline.h} | 4 ++-- .../{segment_iterator.h => SegmentIterator.h} | 2 +- include/geometry/{shape.h => Shape.h} | 2 +- .../{single_shape.h => SingleShape.h} | 2 +- include/infill.h | 2 +- include/infill/LightningDistanceField.h | 2 +- include/infill/LightningTreeNode.h | 4 ++-- include/infill/SubDivCube.h | 8 +++---- include/infill/ZigzagConnectorProcessor.h | 2 +- include/pathPlanning/Comb.h | 6 ++--- include/pathPlanning/CombPath.h | 2 +- include/pathPlanning/GCodePath.h | 2 +- include/pathPlanning/LinePolygonsCrossings.h | 4 ++-- include/plugins/converters.h | 2 +- include/plugins/slots.h | 4 ++-- include/plugins/types.h | 4 ++-- include/settings/ZSeamConfig.h | 2 +- include/sliceDataStorage.h | 10 ++++----- include/slicer.h | 4 ++-- include/utils/AABB.h | 2 +- include/utils/AABB3D.h | 2 +- include/utils/ExtrusionJunction.h | 2 +- include/utils/ExtrusionLine.h | 4 ++-- include/utils/ExtrusionSegment.h | 4 ++-- include/utils/HalfEdge.h | 2 +- include/utils/HalfEdgeNode.h | 2 +- include/utils/ListPolyIt.h | 2 +- include/utils/MinimumSpanningTree.h | 2 +- ...ine_stitcher.h => MixedPolylineStitcher.h} | 4 ++-- include/utils/OpenPolylineStitcher.h | 4 ++-- include/utils/Point3D.h | 2 +- include/utils/Point3F.h | 2 +- include/utils/PolygonConnector.h | 4 ++-- include/utils/PolygonsPointIndex.h | 6 ++--- include/utils/SVG.h | 2 +- include/utils/Simplify.h | 2 +- include/utils/SparseGrid.h | 2 +- include/utils/SparseLineGrid.h | 2 +- include/utils/SparsePointGrid.h | 2 +- include/utils/SparsePointGridInclusive.h | 2 +- include/utils/SquareGrid.h | 2 +- include/utils/ToolpathVisualizer.h | 2 +- include/utils/VoxelUtils.h | 4 ++-- include/utils/linearAlg2D.h | 2 +- include/utils/orderOptimizer.h | 2 +- include/utils/polygonUtils.h | 2 +- src/ConicalOverhang.cpp | 4 ++-- src/FffGcodeWriter.cpp | 4 ++-- src/FffPolygonGenerator.cpp | 2 +- src/GCodePathConfig.cpp | 2 +- src/InterlockingGenerator.cpp | 2 +- src/Mold.cpp | 4 ++-- src/SkirtBrim.cpp | 5 ++--- src/bridge.cpp | 4 ++-- src/communication/ArcusCommunication.cpp | 2 +- ...closed_polyline.cpp => ClosedPolyline.cpp} | 4 ++-- src/geometry/{lines_set.cpp => LinesSet.cpp} | 8 +++---- ...{mixed_lines_set.cpp => MixedLinesSet.cpp} | 8 +++---- .../{parts_view.cpp => PartsView.cpp} | 6 ++--- .../{points_set.cpp => PointsSet.cpp} | 6 ++--- src/geometry/{polygon.cpp => Polygon.cpp} | 8 +++---- src/geometry/{polyline.cpp => Polyline.cpp} | 4 ++-- src/geometry/{shape.cpp => Shape.cpp} | 10 ++++----- .../{single_shape.cpp => SingleShape.cpp} | 4 ++-- src/infill.cpp | 2 +- src/infill/GyroidInfill.cpp | 6 ++--- src/infill/LightningTreeNode.cpp | 2 +- src/infill/SierpinskiFill.cpp | 2 +- src/infill/SierpinskiFillProvider.cpp | 2 +- src/infill/SubDivCube.cpp | 4 ++-- src/infill/ZigzagConnectorProcessor.cpp | 8 +++---- src/multiVolumes.cpp | 2 +- src/plugins/converters.cpp | 2 +- src/settings/Settings.cpp | 4 ++-- src/utils/AABB.cpp | 4 ++-- src/utils/ListPolyIt.cpp | 2 +- src/utils/Matrix4x3D.cpp | 2 +- ...stitcher.cpp => MixedPolylineStitcher.cpp} | 8 +++---- src/utils/Point3LL.cpp | 2 +- src/utils/PolygonsPointIndex.cpp | 2 +- src/utils/PolylineStitcher.cpp | 4 ++-- src/utils/SVG.cpp | 4 ++-- src/utils/Simplify.cpp | 6 ++--- src/utils/VoronoiUtils.cpp | 2 +- src/utils/linearAlg2D.cpp | 4 ++-- src/utils/polygonUtils.cpp | 6 ++--- stress_benchmark/stress_benchmark.cpp | 2 +- tests/ClipperTest.cpp | 2 +- tests/PathOrderMonotonicTest.cpp | 2 +- tests/ReadTestPolygons.cpp | 2 +- tests/ReadTestPolygons.h | 2 +- tests/WallsComputationTest.cpp | 4 ++-- tests/arcus/ArcusCommunicationTest.cpp | 2 +- tests/arcus/MockCommunication.h | 4 ++-- tests/integration/SlicePhaseTest.cpp | 2 +- tests/utils/AABB3DTest.cpp | 2 +- tests/utils/AABBTest.cpp | 4 ++-- tests/utils/IntPointTest.cpp | 6 ++--- tests/utils/LinearAlg2DTest.cpp | 2 +- tests/utils/PolygonConnectorTest.cpp | 2 +- tests/utils/PolygonTest.cpp | 6 ++--- tests/utils/PolygonUtilsTest.cpp | 4 ++-- tests/utils/SmoothTest.cpp | 4 ++-- tests/utils/StringTest.cpp | 2 +- 139 files changed, 227 insertions(+), 228 deletions(-) rename include/geometry/{closed_lines_set.h => ClosedLinesSet.h} (86%) rename include/geometry/{closed_polyline.h => ClosedPolyline.h} (99%) rename include/geometry/{lines_set.h => LinesSet.h} (99%) rename include/geometry/{mixed_lines_set.h => MixedLinesSet.h} (100%) rename include/geometry/{open_lines_set.h => OpenLinesSet.h} (86%) rename include/geometry/{open_polyline.h => OpenPolyline.h} (98%) rename include/geometry/{parts_view.h => PartsView.h} (100%) rename include/geometry/{point2ll.h => Point2LL.h} (99%) rename include/geometry/{point3ll.h => Point3LL.h} (100%) rename include/geometry/{point3_matrix.h => Point3Matrix.h} (97%) rename include/geometry/{point_matrix.h => PointMatrix.h} (98%) rename include/geometry/{points_set.h => PointsSet.h} (99%) rename include/geometry/{polygon.h => Polygon.h} (99%) rename include/geometry/{polyline.h => Polyline.h} (99%) rename include/geometry/{segment_iterator.h => SegmentIterator.h} (98%) rename include/geometry/{shape.h => Shape.h} (99%) rename include/geometry/{single_shape.h => SingleShape.h} (97%) rename include/utils/{mixed_polyline_stitcher.h => MixedPolylineStitcher.h} (88%) rename src/geometry/{closed_polyline.cpp => ClosedPolyline.cpp} (93%) rename src/geometry/{lines_set.cpp => LinesSet.cpp} (98%) rename src/geometry/{mixed_lines_set.cpp => MixedLinesSet.cpp} (96%) rename src/geometry/{parts_view.cpp => PartsView.cpp} (93%) rename src/geometry/{points_set.cpp => PointsSet.cpp} (88%) rename src/geometry/{polygon.cpp => Polygon.cpp} (99%) rename src/geometry/{polyline.cpp => Polyline.cpp} (98%) rename src/geometry/{shape.cpp => Shape.cpp} (99%) rename src/geometry/{single_shape.cpp => SingleShape.cpp} (91%) rename src/utils/{mixed_polyline_stitcher.cpp => MixedPolylineStitcher.cpp} (85%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 32f0cdafa4..3d3cb270ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,17 +152,17 @@ set(engine_SRCS # Except main.cpp. src/utils/ToolpathVisualizer.cpp src/utils/VoronoiUtils.cpp src/utils/VoxelUtils.cpp - src/utils/mixed_polyline_stitcher.cpp - - src/geometry/polygon.cpp - src/geometry/shape.cpp - src/geometry/points_set.cpp - src/geometry/single_shape.cpp - src/geometry/parts_view.cpp - src/geometry/lines_set.cpp - src/geometry/polyline.cpp - src/geometry/closed_polyline.cpp - src/geometry/mixed_lines_set.cpp + src/utils/MixedPolylineStitcher.cpp + + src/geometry/Polygon.cpp + src/geometry/Shape.cpp + src/geometry/PointsSet.cpp + src/geometry/SingleShape.cpp + src/geometry/PartsView.cpp + src/geometry/LinesSet.cpp + src/geometry/Polyline.cpp + src/geometry/ClosedPolyline.cpp + src/geometry/MixedLinesSet.cpp ) add_library(_CuraEngine STATIC ${engine_SRCS} ${engine_PB_SRCS}) diff --git a/benchmark/infill_benchmark.h b/benchmark/infill_benchmark.h index 4799e5f5cb..e95b9d9fc3 100644 --- a/benchmark/infill_benchmark.h +++ b/benchmark/infill_benchmark.h @@ -6,7 +6,7 @@ #include -#include "geometry/open_lines_set.h" +#include "geometry/OpenLinesSet.h" #include "infill.h" namespace cura diff --git a/benchmark/wall_benchmark.h b/benchmark/wall_benchmark.h index 95d99d6a90..089524cf9c 100644 --- a/benchmark/wall_benchmark.h +++ b/benchmark/wall_benchmark.h @@ -15,7 +15,7 @@ #include "InsetOrderOptimizer.h" #include "WallsComputation.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "settings/Settings.h" #include "sliceDataStorage.h" diff --git a/include/BeadingStrategy/BeadingStrategy.h b/include/BeadingStrategy/BeadingStrategy.h index 76d53cf677..68d2c31be1 100644 --- a/include/BeadingStrategy/BeadingStrategy.h +++ b/include/BeadingStrategy/BeadingStrategy.h @@ -8,7 +8,7 @@ #include "../settings/types/Angle.h" #include "../settings/types/Ratio.h" //For the wall transition threshold. -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/BoostInterface.hpp b/include/BoostInterface.hpp index 3b584aba8f..b7a305dd54 100644 --- a/include/BoostInterface.hpp +++ b/include/BoostInterface.hpp @@ -7,8 +7,8 @@ #include #include -#include "geometry/point2ll.h" -#include "geometry/polygon.h" +#include "geometry/Point2LL.h" +#include "geometry/Polygon.h" #include "utils/PolygonsSegmentIndex.h" diff --git a/include/ExtruderPlan.h b/include/ExtruderPlan.h index 785fc43944..7d8d1e3de6 100644 --- a/include/ExtruderPlan.h +++ b/include/ExtruderPlan.h @@ -7,7 +7,7 @@ #include "FanSpeedLayerTime.h" #include "RetractionConfig.h" #include "gcodeExport.h" -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" #include "pathPlanning/GCodePath.h" #include "pathPlanning/NozzleTempInsert.h" #include "pathPlanning/TimeMaterialEstimates.h" diff --git a/include/InterlockingGenerator.h b/include/InterlockingGenerator.h index d9359bd518..3ab4e27335 100644 --- a/include/InterlockingGenerator.h +++ b/include/InterlockingGenerator.h @@ -8,8 +8,8 @@ #include #include -#include "geometry/point_matrix.h" -#include "geometry/polygon.h" +#include "geometry/PointMatrix.h" +#include "geometry/Polygon.h" #include "utils/VoxelUtils.h" namespace cura diff --git a/include/LayerPlan.h b/include/LayerPlan.h index 205779c088..dda622b603 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -10,7 +10,7 @@ #include "PathOrderOptimizer.h" #include "SpaceFillType.h" #include "gcodeExport.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "pathPlanning/GCodePath.h" #include "pathPlanning/NozzleTempInsert.h" #include "pathPlanning/TimeMaterialEstimates.h" diff --git a/include/PrimeTower.h b/include/PrimeTower.h index ef3cb78859..0fa4a02c05 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -8,7 +8,7 @@ #include #include "ExtruderUse.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "settings/EnumSettings.h" #include "settings/types/LayerIndex.h" #include "utils/polygonUtils.h" diff --git a/include/SkeletalTrapezoidation.h b/include/SkeletalTrapezoidation.h index 153c3ac040..fafb69a002 100644 --- a/include/SkeletalTrapezoidation.h +++ b/include/SkeletalTrapezoidation.h @@ -14,7 +14,7 @@ #include "SkeletalTrapezoidationEdge.h" #include "SkeletalTrapezoidationGraph.h" #include "SkeletalTrapezoidationJoint.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "settings/types/Ratio.h" #include "utils/ExtrusionJunction.h" #include "utils/ExtrusionLine.h" diff --git a/include/SkeletalTrapezoidationJoint.h b/include/SkeletalTrapezoidationJoint.h index 43101b03fb..059f6d50d1 100644 --- a/include/SkeletalTrapezoidationJoint.h +++ b/include/SkeletalTrapezoidationJoint.h @@ -7,7 +7,7 @@ #include // smart pointers #include "BeadingStrategy/BeadingStrategy.h" -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/SupportInfillPart.h b/include/SupportInfillPart.h index ff73156d73..c864a67be6 100644 --- a/include/SupportInfillPart.h +++ b/include/SupportInfillPart.h @@ -6,8 +6,8 @@ #include -#include "geometry/polygon.h" -#include "geometry/single_shape.h" +#include "geometry/Polygon.h" +#include "geometry/SingleShape.h" #include "utils/AABB.h" #include "utils/ExtrusionLine.h" diff --git a/include/TopSurface.h b/include/TopSurface.h index d9f876c614..e54438904b 100644 --- a/include/TopSurface.h +++ b/include/TopSurface.h @@ -5,7 +5,7 @@ #define TOPSURFACE_H #include "GCodePathConfig.h" -#include "geometry/shape.h" +#include "geometry/Shape.h" namespace cura { diff --git a/include/TreeModelVolumes.h b/include/TreeModelVolumes.h index 892ad99e89..0dee5f62c1 100644 --- a/include/TreeModelVolumes.h +++ b/include/TreeModelVolumes.h @@ -10,7 +10,7 @@ #include #include "TreeSupportSettings.h" -#include "geometry/polygon.h" //For polygon parameters. +#include "geometry/Polygon.h" //For polygon parameters. #include "settings/EnumSettings.h" //To store whether X/Y or Z distance gets priority. #include "settings/types/LayerIndex.h" //Part of the RadiusLayerPair. #include "sliceDataStorage.h" diff --git a/include/TreeSupport.h b/include/TreeSupport.h index 459b6f7c5f..a4f1be756a 100644 --- a/include/TreeSupport.h +++ b/include/TreeSupport.h @@ -10,7 +10,7 @@ #include "TreeSupportEnums.h" #include "TreeSupportSettings.h" #include "boost/functional/hash.hpp" // For combining hashes -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "polyclipping/clipper.hpp" #include "settings/EnumSettings.h" #include "sliceDataStorage.h" diff --git a/include/TreeSupportBaseCircle.h b/include/TreeSupportBaseCircle.h index d802d11a9e..9010e066b3 100644 --- a/include/TreeSupportBaseCircle.h +++ b/include/TreeSupportBaseCircle.h @@ -7,7 +7,7 @@ #include -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "settings/types/Angle.h" #include "utils/Coord_t.h" diff --git a/include/TreeSupportElement.h b/include/TreeSupportElement.h index 3076883a30..b633aa863c 100644 --- a/include/TreeSupportElement.h +++ b/include/TreeSupportElement.h @@ -10,7 +10,7 @@ #include "TreeModelVolumes.h" #include "TreeSupportBaseCircle.h" #include "TreeSupportEnums.h" -#include "geometry/shape.h" +#include "geometry/Shape.h" #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" diff --git a/include/TreeSupportTipGenerator.h b/include/TreeSupportTipGenerator.h index e704e166d1..c68e889319 100644 --- a/include/TreeSupportTipGenerator.h +++ b/include/TreeSupportTipGenerator.h @@ -11,7 +11,7 @@ #include "TreeSupportEnums.h" #include "TreeSupportSettings.h" #include "boost/functional/hash.hpp" // For combining hashes -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "polyclipping/clipper.hpp" #include "settings/EnumSettings.h" #include "sliceDataStorage.h" diff --git a/include/TreeSupportUtils.h b/include/TreeSupportUtils.h index bc09302e34..a0c1b407f9 100644 --- a/include/TreeSupportUtils.h +++ b/include/TreeSupportUtils.h @@ -12,7 +12,7 @@ #include "TreeSupportEnums.h" #include "TreeSupportSettings.h" #include "boost/functional/hash.hpp" // For combining hashes -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "infill.h" #include "polyclipping/clipper.hpp" #include "settings/EnumSettings.h" diff --git a/include/WallToolPaths.h b/include/WallToolPaths.h index 7ac6a95c0f..ff1df0a63a 100644 --- a/include/WallToolPaths.h +++ b/include/WallToolPaths.h @@ -7,7 +7,7 @@ #include #include "BeadingStrategy/BeadingStrategyFactory.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "settings/Settings.h" #include "utils/ExtrusionLine.h" #include "utils/section_type.h" diff --git a/include/communication/Communication.h b/include/communication/Communication.h index 20e88ebb1a..9bc990c11e 100644 --- a/include/communication/Communication.h +++ b/include/communication/Communication.h @@ -4,7 +4,7 @@ #ifndef COMMUNICATION_H #define COMMUNICATION_H -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" #include "settings/types/LayerIndex.h" #include "settings/types/Velocity.h" diff --git a/include/gcodeExport.h b/include/gcodeExport.h index 455282b7ca..052fa85582 100644 --- a/include/gcodeExport.h +++ b/include/gcodeExport.h @@ -11,7 +11,7 @@ #include // for stream.str() #include -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" #include "settings/EnumSettings.h" #include "settings/Settings.h" //For MAX_EXTRUDERS. #include "settings/types/LayerIndex.h" diff --git a/include/geometry/closed_lines_set.h b/include/geometry/ClosedLinesSet.h similarity index 86% rename from include/geometry/closed_lines_set.h rename to include/geometry/ClosedLinesSet.h index bb4abd6fc1..405da85a79 100644 --- a/include/geometry/closed_lines_set.h +++ b/include/geometry/ClosedLinesSet.h @@ -4,8 +4,8 @@ #ifndef GEOMETRY_CLOSED_LINES_SET_H #define GEOMETRY_CLOSED_LINES_SET_H -#include "geometry/closed_polyline.h" -#include "geometry/lines_set.h" +#include "geometry/ClosedPolyline.h" +#include "geometry/LinesSet.h" namespace cura { diff --git a/include/geometry/closed_polyline.h b/include/geometry/ClosedPolyline.h similarity index 99% rename from include/geometry/closed_polyline.h rename to include/geometry/ClosedPolyline.h index dfbd8a9d63..607ed4d6e7 100644 --- a/include/geometry/closed_polyline.h +++ b/include/geometry/ClosedPolyline.h @@ -4,7 +4,7 @@ #ifndef GEOMETRY_CLOSED_POLYLINE_H #define GEOMETRY_CLOSED_POLYLINE_H -#include "geometry/polyline.h" +#include "geometry/Polyline.h" namespace cura { diff --git a/include/geometry/lines_set.h b/include/geometry/LinesSet.h similarity index 99% rename from include/geometry/lines_set.h rename to include/geometry/LinesSet.h index 5ae4b288d5..a0cf46ed10 100644 --- a/include/geometry/lines_set.h +++ b/include/geometry/LinesSet.h @@ -8,7 +8,7 @@ #include -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/geometry/mixed_lines_set.h b/include/geometry/MixedLinesSet.h similarity index 100% rename from include/geometry/mixed_lines_set.h rename to include/geometry/MixedLinesSet.h diff --git a/include/geometry/open_lines_set.h b/include/geometry/OpenLinesSet.h similarity index 86% rename from include/geometry/open_lines_set.h rename to include/geometry/OpenLinesSet.h index 74e2b3c878..aefe77044a 100644 --- a/include/geometry/open_lines_set.h +++ b/include/geometry/OpenLinesSet.h @@ -4,8 +4,8 @@ #ifndef GEOMETRY_OPEN_LINES_SET_H #define GEOMETRY_OPEN_LINES_SET_H -#include "geometry/lines_set.h" -#include "geometry/open_polyline.h" +#include "geometry/LinesSet.h" +#include "geometry/OpenPolyline.h" namespace cura { diff --git a/include/geometry/open_polyline.h b/include/geometry/OpenPolyline.h similarity index 98% rename from include/geometry/open_polyline.h rename to include/geometry/OpenPolyline.h index b7faca260d..ec40501e8c 100644 --- a/include/geometry/open_polyline.h +++ b/include/geometry/OpenPolyline.h @@ -4,7 +4,7 @@ #ifndef GEOMETRY_OPEN_POLYLINE_H #define GEOMETRY_OPEN_POLYLINE_H -#include "geometry/polyline.h" +#include "geometry/Polyline.h" namespace cura { diff --git a/include/geometry/parts_view.h b/include/geometry/PartsView.h similarity index 100% rename from include/geometry/parts_view.h rename to include/geometry/PartsView.h diff --git a/include/geometry/point2ll.h b/include/geometry/Point2LL.h similarity index 99% rename from include/geometry/point2ll.h rename to include/geometry/Point2LL.h index 393e43ea93..0349b03bd5 100644 --- a/include/geometry/point2ll.h +++ b/include/geometry/Point2LL.h @@ -16,7 +16,7 @@ Integer points are used to avoid floating point rounding errors, and because Cli #include //#include -#include "point3ll.h" +#include "geometry/Point3LL.h" #ifdef __GNUC__ #define DEPRECATED(func) func __attribute__((deprecated)) diff --git a/include/geometry/point3ll.h b/include/geometry/Point3LL.h similarity index 100% rename from include/geometry/point3ll.h rename to include/geometry/Point3LL.h diff --git a/include/geometry/point3_matrix.h b/include/geometry/Point3Matrix.h similarity index 97% rename from include/geometry/point3_matrix.h rename to include/geometry/Point3Matrix.h index 1d6ad31201..0ff53ed6e5 100644 --- a/include/geometry/point3_matrix.h +++ b/include/geometry/Point3Matrix.h @@ -4,8 +4,8 @@ #ifndef GEOMETRY_POINT3_MATRIX_H #define GEOMETRY_POINT3_MATRIX_H -#include "point3ll.h" -#include "point_matrix.h" +#include "geometry/Point3LL.h" +#include "geometry/PointMatrix.h" namespace cura { diff --git a/include/geometry/point_matrix.h b/include/geometry/PointMatrix.h similarity index 98% rename from include/geometry/point_matrix.h rename to include/geometry/PointMatrix.h index 381cda6264..10b04cbc6e 100644 --- a/include/geometry/point_matrix.h +++ b/include/geometry/PointMatrix.h @@ -4,7 +4,7 @@ #ifndef GEOMETRY_POINT_MATRIX_H #define GEOMETRY_POINT_MATRIX_H -#include "point2ll.h" +#include "geometry/Point2LL.h" namespace cura diff --git a/include/geometry/points_set.h b/include/geometry/PointsSet.h similarity index 99% rename from include/geometry/points_set.h rename to include/geometry/PointsSet.h index 69963de9ac..08013e89bc 100644 --- a/include/geometry/points_set.h +++ b/include/geometry/PointsSet.h @@ -4,7 +4,7 @@ #ifndef GEOMETRY_POINTS_SET_H #define GEOMETRY_POINTS_SET_H -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" #include "utils/Coord_t.h" namespace cura diff --git a/include/geometry/polygon.h b/include/geometry/Polygon.h similarity index 99% rename from include/geometry/polygon.h rename to include/geometry/Polygon.h index ad1d2deaa5..12a70b3843 100644 --- a/include/geometry/polygon.h +++ b/include/geometry/Polygon.h @@ -4,7 +4,7 @@ #ifndef GEOMETRY_POLYGON_H #define GEOMETRY_POLYGON_H -#include "closed_polyline.h" +#include "geometry/ClosedPolyline.h" namespace cura { diff --git a/include/geometry/polyline.h b/include/geometry/Polyline.h similarity index 99% rename from include/geometry/polyline.h rename to include/geometry/Polyline.h index 89f0c02486..f3a5dc3599 100644 --- a/include/geometry/polyline.h +++ b/include/geometry/Polyline.h @@ -4,8 +4,8 @@ #ifndef GEOMETRY_POLYLINE_H #define GEOMETRY_POLYLINE_H -#include "geometry/points_set.h" -#include "geometry/segment_iterator.h" +#include "geometry/PointsSet.h" +#include "geometry/SegmentIterator.h" namespace cura { diff --git a/include/geometry/segment_iterator.h b/include/geometry/SegmentIterator.h similarity index 98% rename from include/geometry/segment_iterator.h rename to include/geometry/SegmentIterator.h index 9866e1ff73..5147e86267 100644 --- a/include/geometry/segment_iterator.h +++ b/include/geometry/SegmentIterator.h @@ -4,7 +4,7 @@ #ifndef GEOMETRY_SEGMENT_ITERATOR_H #define GEOMETRY_SEGMENT_ITERATOR_H -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/geometry/shape.h b/include/geometry/Shape.h similarity index 99% rename from include/geometry/shape.h rename to include/geometry/Shape.h index cf39b7b385..76ce3fd200 100644 --- a/include/geometry/shape.h +++ b/include/geometry/Shape.h @@ -4,7 +4,7 @@ #ifndef GEOMETRY_SHAPE_H #define GEOMETRY_SHAPE_H -#include "geometry/lines_set.h" +#include "geometry/LinesSet.h" #include "settings/types/Angle.h" namespace cura diff --git a/include/geometry/single_shape.h b/include/geometry/SingleShape.h similarity index 97% rename from include/geometry/single_shape.h rename to include/geometry/SingleShape.h index 0e8008a983..e9d7f92b93 100644 --- a/include/geometry/single_shape.h +++ b/include/geometry/SingleShape.h @@ -4,7 +4,7 @@ #ifndef GEOMETRY_SINGLE_SHAPE_H #define GEOMETRY_SINGLE_SHAPE_H -#include "geometry/shape.h" +#include "geometry/Shape.h" namespace cura { diff --git a/include/infill.h b/include/infill.h index daeba97d8f..605516ab6c 100644 --- a/include/infill.h +++ b/include/infill.h @@ -8,7 +8,7 @@ #include -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" #include "infill/LightningGenerator.h" #include "infill/ZigzagConnectorProcessor.h" #include "settings/EnumSettings.h" //For infill types. diff --git a/include/infill/LightningDistanceField.h b/include/infill/LightningDistanceField.h index d9aa62b41a..1968e40e8a 100644 --- a/include/infill/LightningDistanceField.h +++ b/include/infill/LightningDistanceField.h @@ -5,7 +5,7 @@ #define LIGHTNING_DISTANCE_FIELD_H #include "../utils/SquareGrid.h" //Tracking for each location the distance to overhang. -#include "geometry/polygon.h" //Using outlines to fill and tracking overhang. +#include "geometry/Polygon.h" //Using outlines to fill and tracking overhang. namespace cura { diff --git a/include/infill/LightningTreeNode.h b/include/infill/LightningTreeNode.h index 74a7496f62..877c55d8f9 100644 --- a/include/infill/LightningTreeNode.h +++ b/include/infill/LightningTreeNode.h @@ -10,8 +10,8 @@ #include #include "../utils/polygonUtils.h" -#include "geometry/polygon.h" -#include "geometry/shape.h" +#include "geometry/Polygon.h" +#include "geometry/Shape.h" namespace cura { diff --git a/include/infill/SubDivCube.h b/include/infill/SubDivCube.h index cea8cae2ac..0be7790c00 100644 --- a/include/infill/SubDivCube.h +++ b/include/infill/SubDivCube.h @@ -4,10 +4,10 @@ #ifndef INFILL_SUBDIVCUBE_H #define INFILL_SUBDIVCUBE_H -#include "geometry/point2ll.h" -#include "geometry/point3_matrix.h" -#include "geometry/point3ll.h" -#include "geometry/point_matrix.h" +#include "geometry/Point2LL.h" +#include "geometry/Point3Matrix.h" +#include "geometry/Point3LL.h" +#include "geometry/PointMatrix.h" #include "settings/types/LayerIndex.h" #include "settings/types/Ratio.h" diff --git a/include/infill/ZigzagConnectorProcessor.h b/include/infill/ZigzagConnectorProcessor.h index 5e869fc5fc..e0880778b8 100644 --- a/include/infill/ZigzagConnectorProcessor.h +++ b/include/infill/ZigzagConnectorProcessor.h @@ -6,7 +6,7 @@ #include -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/pathPlanning/Comb.h b/include/pathPlanning/Comb.h index 39b3b5456b..35bca5a480 100644 --- a/include/pathPlanning/Comb.h +++ b/include/pathPlanning/Comb.h @@ -7,9 +7,9 @@ #include // To find the maximum for coord_t. #include // shared_ptr -#include "geometry/parts_view.h" -#include "geometry/polygon.h" -#include "geometry/single_shape.h" +#include "geometry/PartsView.h" +#include "geometry/Polygon.h" +#include "geometry/SingleShape.h" #include "settings/types/LayerIndex.h" // To store the layer on which we comb. #include "utils/polygonUtils.h" diff --git a/include/pathPlanning/CombPath.h b/include/pathPlanning/CombPath.h index 2d73555141..0b904d2a5a 100644 --- a/include/pathPlanning/CombPath.h +++ b/include/pathPlanning/CombPath.h @@ -4,7 +4,7 @@ #ifndef PATH_PLANNING_COMB_PATH_H #define PATH_PLANNING_COMB_PATH_H -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/pathPlanning/GCodePath.h b/include/pathPlanning/GCodePath.h index f91c917007..09160202d9 100644 --- a/include/pathPlanning/GCodePath.h +++ b/include/pathPlanning/GCodePath.h @@ -10,7 +10,7 @@ #include "GCodePathConfig.h" #include "SpaceFillType.h" #include "TimeMaterialEstimates.h" -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" #include "settings/types/Ratio.h" #include "sliceDataStorage.h" diff --git a/include/pathPlanning/LinePolygonsCrossings.h b/include/pathPlanning/LinePolygonsCrossings.h index 00a584cb9c..d937a35c03 100644 --- a/include/pathPlanning/LinePolygonsCrossings.h +++ b/include/pathPlanning/LinePolygonsCrossings.h @@ -5,8 +5,8 @@ #define PATH_PLANNING_LINE_POLYGONS_CROSSINGS_H #include "CombPath.h" -#include "geometry/point_matrix.h" -#include "geometry/polygon.h" +#include "geometry/PointMatrix.h" +#include "geometry/Polygon.h" #include "utils/polygonUtils.h" namespace cura diff --git a/include/plugins/converters.h b/include/plugins/converters.h index 41e1af61dc..ed0aac9e8a 100644 --- a/include/plugins/converters.h +++ b/include/plugins/converters.h @@ -27,7 +27,7 @@ #include "cura/plugins/slots/postprocess/v0/modify.pb.h" #include "cura/plugins/slots/simplify/v0/modify.grpc.pb.h" #include "cura/plugins/slots/simplify/v0/modify.pb.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "pathPlanning/GCodePath.h" #include "pathPlanning/SpeedDerivatives.h" #include "plugins/metadata.h" diff --git a/include/plugins/slots.h b/include/plugins/slots.h index 3ead61bc95..3abef56cf1 100644 --- a/include/plugins/slots.h +++ b/include/plugins/slots.h @@ -17,8 +17,8 @@ #include "cura/plugins/slots/postprocess/v0/modify.grpc.pb.h" #include "cura/plugins/slots/simplify/v0/modify.grpc.pb.h" #include "cura/plugins/v0/slot_id.pb.h" -#include "geometry/point2ll.h" -#include "geometry/polygon.h" +#include "geometry/Point2LL.h" +#include "geometry/Polygon.h" #include "infill.h" #include "plugins/converters.h" #include "plugins/slotproxy.h" diff --git a/include/plugins/types.h b/include/plugins/types.h index df2132614e..f3abfc9ad1 100644 --- a/include/plugins/types.h +++ b/include/plugins/types.h @@ -11,8 +11,8 @@ #include #include "cura/plugins/v0/slot_id.pb.h" -#include "geometry/point2ll.h" -#include "geometry/polygon.h" +#include "geometry/Point2LL.h" +#include "geometry/Polygon.h" namespace fmt { diff --git a/include/settings/ZSeamConfig.h b/include/settings/ZSeamConfig.h index 8aea9866d6..9626786690 100644 --- a/include/settings/ZSeamConfig.h +++ b/include/settings/ZSeamConfig.h @@ -5,7 +5,7 @@ #define ZSEAMCONFIG_H #include "EnumSettings.h" //For EZSeamType and EZSeamCornerPrefType. -#include "geometry/point2ll.h" //To store the preferred seam position. +#include "geometry/Point2LL.h" //To store the preferred seam position. namespace cura { diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 5f732e12df..5db2025df9 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -13,11 +13,11 @@ #include "SupportInfillPart.h" #include "TopSurface.h" #include "WipeScriptConfig.h" -#include "geometry/mixed_lines_set.h" -#include "geometry/open_lines_set.h" -#include "geometry/point2ll.h" -#include "geometry/polygon.h" -#include "geometry/single_shape.h" +#include "geometry/MixedLinesSet.h" +#include "geometry/OpenLinesSet.h" +#include "geometry/Point2LL.h" +#include "geometry/Polygon.h" +#include "geometry/SingleShape.h" #include "settings/Settings.h" //For MAX_EXTRUDERS. #include "settings/types/Angle.h" //Infill angles. #include "settings/types/LayerIndex.h" diff --git a/include/slicer.h b/include/slicer.h index 7204edfd99..290fe0d3d2 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -8,8 +8,8 @@ #include #include -#include "geometry/open_lines_set.h" -#include "geometry/shape.h" +#include "geometry/OpenLinesSet.h" +#include "geometry/Shape.h" #include "settings/EnumSettings.h" /* diff --git a/include/utils/AABB.h b/include/utils/AABB.h index bbd9a44367..4ef49afd37 100644 --- a/include/utils/AABB.h +++ b/include/utils/AABB.h @@ -4,7 +4,7 @@ #ifndef UTILS_AABB_H #define UTILS_AABB_H -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/utils/AABB3D.h b/include/utils/AABB3D.h index a505c0cf52..402135be66 100644 --- a/include/utils/AABB3D.h +++ b/include/utils/AABB3D.h @@ -4,7 +4,7 @@ #ifndef UTILS_AABB3D_H #define UTILS_AABB3D_H -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" #include "utils/AABB.h" namespace cura diff --git a/include/utils/ExtrusionJunction.h b/include/utils/ExtrusionJunction.h index d1621fa75f..f431a73f94 100644 --- a/include/utils/ExtrusionJunction.h +++ b/include/utils/ExtrusionJunction.h @@ -5,7 +5,7 @@ #ifndef UTILS_EXTRUSION_JUNCTION_H #define UTILS_EXTRUSION_JUNCTION_H -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/utils/ExtrusionLine.h b/include/utils/ExtrusionLine.h index 4fa770822f..987ce1b783 100644 --- a/include/utils/ExtrusionLine.h +++ b/include/utils/ExtrusionLine.h @@ -10,8 +10,8 @@ #include #include "ExtrusionJunction.h" -#include "geometry/polygon.h" -#include "geometry/shape.h" +#include "geometry/Polygon.h" +#include "geometry/Shape.h" namespace cura { diff --git a/include/utils/ExtrusionSegment.h b/include/utils/ExtrusionSegment.h index ce4da45ad8..55f62c6055 100644 --- a/include/utils/ExtrusionSegment.h +++ b/include/utils/ExtrusionSegment.h @@ -8,8 +8,8 @@ #include #include "ExtrusionJunction.h" -#include "geometry/point2ll.h" -#include "geometry/polygon.h" +#include "geometry/Point2LL.h" +#include "geometry/Polygon.h" #include "polygonUtils.h" namespace cura diff --git a/include/utils/HalfEdge.h b/include/utils/HalfEdge.h index 8a79343daf..4f6f3671d5 100644 --- a/include/utils/HalfEdge.h +++ b/include/utils/HalfEdge.h @@ -8,7 +8,7 @@ #include #include "Coord_t.h" -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/utils/HalfEdgeNode.h b/include/utils/HalfEdgeNode.h index 117e3c285d..118655324c 100644 --- a/include/utils/HalfEdgeNode.h +++ b/include/utils/HalfEdgeNode.h @@ -6,7 +6,7 @@ #include -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/utils/ListPolyIt.h b/include/utils/ListPolyIt.h index 3a9eaf3dfd..ee990fd9a7 100644 --- a/include/utils/ListPolyIt.h +++ b/include/utils/ListPolyIt.h @@ -7,7 +7,7 @@ #include #include -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura diff --git a/include/utils/MinimumSpanningTree.h b/include/utils/MinimumSpanningTree.h index 4b88607f94..866c0d17e6 100644 --- a/include/utils/MinimumSpanningTree.h +++ b/include/utils/MinimumSpanningTree.h @@ -8,7 +8,7 @@ #include #include -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/utils/mixed_polyline_stitcher.h b/include/utils/MixedPolylineStitcher.h similarity index 88% rename from include/utils/mixed_polyline_stitcher.h rename to include/utils/MixedPolylineStitcher.h index d6ad13a453..5d511ec60a 100644 --- a/include/utils/mixed_polyline_stitcher.h +++ b/include/utils/MixedPolylineStitcher.h @@ -5,8 +5,8 @@ #define UTILS_MIXED_POLYLINE_STITCHER_H #include "PolylineStitcher.h" -#include "geometry/closed_lines_set.h" -#include "geometry/open_lines_set.h" +#include "geometry/ClosedLinesSet.h" +#include "geometry/OpenLinesSet.h" namespace cura { diff --git a/include/utils/OpenPolylineStitcher.h b/include/utils/OpenPolylineStitcher.h index bca7c2442e..b99cd91c41 100644 --- a/include/utils/OpenPolylineStitcher.h +++ b/include/utils/OpenPolylineStitcher.h @@ -5,8 +5,8 @@ #define UTILS_OPEN_POLYLINE_STITCHER_H #include "PolylineStitcher.h" -#include "geometry/open_lines_set.h" -#include "geometry/shape.h" +#include "geometry/OpenLinesSet.h" +#include "geometry/Shape.h" namespace cura { diff --git a/include/utils/Point3D.h b/include/utils/Point3D.h index 0fb3b540a0..6000d9be76 100644 --- a/include/utils/Point3D.h +++ b/include/utils/Point3D.h @@ -7,7 +7,7 @@ #include #include -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura diff --git a/include/utils/Point3F.h b/include/utils/Point3F.h index 68aa4ab737..e67702937c 100644 --- a/include/utils/Point3F.h +++ b/include/utils/Point3F.h @@ -8,7 +8,7 @@ #include #include "Point3D.h" -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura diff --git a/include/utils/PolygonConnector.h b/include/utils/PolygonConnector.h index 1526dc5cd1..39bb8c0373 100644 --- a/include/utils/PolygonConnector.h +++ b/include/utils/PolygonConnector.h @@ -9,8 +9,8 @@ #endif #include -#include "geometry/point2ll.h" -#include "geometry/polygon.h" +#include "geometry/Point2LL.h" +#include "geometry/Polygon.h" #include "linearAlg2D.h" #include "polygonUtils.h" #include "settings/types/Ratio.h" diff --git a/include/utils/PolygonsPointIndex.h b/include/utils/PolygonsPointIndex.h index 92d83a8a2c..a9e94709f5 100644 --- a/include/utils/PolygonsPointIndex.h +++ b/include/utils/PolygonsPointIndex.h @@ -6,9 +6,9 @@ #include -#include "geometry/point2ll.h" -#include "geometry/polygon.h" -#include "geometry/shape.h" +#include "geometry/Point2LL.h" +#include "geometry/Polygon.h" +#include "geometry/Shape.h" namespace cura diff --git a/include/utils/SVG.h b/include/utils/SVG.h index afe9c8cb52..96bcfa0a45 100644 --- a/include/utils/SVG.h +++ b/include/utils/SVG.h @@ -12,7 +12,7 @@ #include "AABB.h" #include "ExtrusionLine.h" //To accept variable-width paths. #include "NoCopy.h" -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/utils/Simplify.h b/include/utils/Simplify.h index 3406fe6d00..6968b7e7e4 100644 --- a/include/utils/Simplify.h +++ b/include/utils/Simplify.h @@ -4,7 +4,7 @@ #ifndef UTILS_SIMPLIFY_H #define UTILS_SIMPLIFY_H -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" #include "utils/Coord_t.h" diff --git a/include/utils/SparseGrid.h b/include/utils/SparseGrid.h index 0b6e306e22..4705d69a60 100644 --- a/include/utils/SparseGrid.h +++ b/include/utils/SparseGrid.h @@ -11,7 +11,7 @@ #include #include "SquareGrid.h" -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/utils/SparseLineGrid.h b/include/utils/SparseLineGrid.h index 61c01089c4..197767d30b 100644 --- a/include/utils/SparseLineGrid.h +++ b/include/utils/SparseLineGrid.h @@ -12,7 +12,7 @@ #include "SVG.h" // debug #include "SparseGrid.h" -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/utils/SparsePointGrid.h b/include/utils/SparsePointGrid.h index 44fd27cfa6..cb90667095 100644 --- a/include/utils/SparsePointGrid.h +++ b/include/utils/SparsePointGrid.h @@ -10,7 +10,7 @@ #include #include "SparseGrid.h" -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/utils/SparsePointGridInclusive.h b/include/utils/SparsePointGridInclusive.h index 55bd35d5aa..f5f30dc65d 100644 --- a/include/utils/SparsePointGridInclusive.h +++ b/include/utils/SparsePointGridInclusive.h @@ -10,7 +10,7 @@ #include #include "SparsePointGrid.h" -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/utils/SquareGrid.h b/include/utils/SquareGrid.h index cf10414339..90665d5e81 100644 --- a/include/utils/SquareGrid.h +++ b/include/utils/SquareGrid.h @@ -9,7 +9,7 @@ #include #include -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/utils/ToolpathVisualizer.h b/include/utils/ToolpathVisualizer.h index 1a5b245cd7..57f808b702 100644 --- a/include/utils/ToolpathVisualizer.h +++ b/include/utils/ToolpathVisualizer.h @@ -4,7 +4,7 @@ #include "ExtrusionSegment.h" #include "SVG.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" namespace cura { diff --git a/include/utils/VoxelUtils.h b/include/utils/VoxelUtils.h index 7be999f7f0..9eaca6e447 100644 --- a/include/utils/VoxelUtils.h +++ b/include/utils/VoxelUtils.h @@ -7,8 +7,8 @@ #include #include -#include "geometry/point2ll.h" -#include "geometry/polygon.h" +#include "geometry/Point2LL.h" +#include "geometry/Polygon.h" namespace cura { diff --git a/include/utils/linearAlg2D.h b/include/utils/linearAlg2D.h index 796c040c46..b9f08fb45b 100644 --- a/include/utils/linearAlg2D.h +++ b/include/utils/linearAlg2D.h @@ -4,7 +4,7 @@ #ifndef UTILS_LINEAR_ALG_2D_H #define UTILS_LINEAR_ALG_2D_H -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/utils/orderOptimizer.h b/include/utils/orderOptimizer.h index 558c9bbfe2..e6e3eb0c39 100644 --- a/include/utils/orderOptimizer.h +++ b/include/utils/orderOptimizer.h @@ -9,7 +9,7 @@ #include // pair #include -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" namespace cura { diff --git a/include/utils/polygonUtils.h b/include/utils/polygonUtils.h index 6ece6b6561..ef740a7def 100644 --- a/include/utils/polygonUtils.h +++ b/include/utils/polygonUtils.h @@ -12,7 +12,7 @@ #include "PolygonsPointIndex.h" #include "SparseLineGrid.h" #include "SparsePointGridInclusive.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" namespace cura { diff --git a/src/ConicalOverhang.cpp b/src/ConicalOverhang.cpp index 571bf0c76e..3bba0c9b4c 100644 --- a/src/ConicalOverhang.cpp +++ b/src/ConicalOverhang.cpp @@ -4,8 +4,8 @@ #include "ConicalOverhang.h" -#include "geometry/polygon.h" -#include "geometry/single_shape.h" +#include "geometry/Polygon.h" +#include "geometry/SingleShape.h" #include "mesh.h" #include "settings/types/Angle.h" //To process the overhang angle. #include "settings/types/LayerIndex.h" diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 74c6a90ed9..10a03f2a70 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -27,8 +27,8 @@ #include "WallToolPaths.h" #include "bridge.h" #include "communication/Communication.h" //To send layer view data. -#include "geometry/open_polyline.h" -#include "geometry/point_matrix.h" +#include "geometry/OpenPolyline.h" +#include "geometry/PointMatrix.h" #include "infill.h" #include "progress/Progress.h" #include "raft.h" diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 8cc988d66c..3361ebaa45 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -49,7 +49,7 @@ #include "utils/ThreadPool.h" #include "utils/gettime.h" #include "utils/math.h" -#include "geometry/open_polyline.h" +#include "geometry/OpenPolyline.h" #include "utils/Simplify.h" // clang-format on diff --git a/src/GCodePathConfig.cpp b/src/GCodePathConfig.cpp index a1a2179f6f..35e81edbb3 100644 --- a/src/GCodePathConfig.cpp +++ b/src/GCodePathConfig.cpp @@ -3,7 +3,7 @@ #include "GCodePathConfig.h" -#include "geometry/point2ll.h" // INT2MM +#include "geometry/Point2LL.h" // INT2MM namespace cura { diff --git a/src/InterlockingGenerator.cpp b/src/InterlockingGenerator.cpp index 263171ff45..ccbf6fa374 100644 --- a/src/InterlockingGenerator.cpp +++ b/src/InterlockingGenerator.cpp @@ -12,7 +12,7 @@ #include "Application.h" #include "Slice.h" -#include "geometry/point_matrix.h" +#include "geometry/PointMatrix.h" #include "settings/types/LayerIndex.h" #include "slicer.h" #include "utils/VoxelUtils.h" diff --git a/src/Mold.cpp b/src/Mold.cpp index 2813b3bb31..097690bf85 100644 --- a/src/Mold.cpp +++ b/src/Mold.cpp @@ -7,8 +7,8 @@ #include "ExtruderTrain.h" #include "Scene.h" #include "Slice.h" -#include "geometry/open_polyline.h" -#include "geometry/point2ll.h" +#include "geometry/OpenPolyline.h" +#include "geometry/Point2LL.h" #include "settings/types/Ratio.h" #include "sliceDataStorage.h" #include "slicer.h" diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index cc1177b819..9472471ab8 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -8,14 +8,13 @@ #include "Application.h" #include "ExtruderTrain.h" #include "Slice.h" -#include "geometry/shape.h" +#include "geometry/Shape.h" #include "settings/EnumSettings.h" #include "settings/types/Ratio.h" #include "sliceDataStorage.h" #include "support.h" -//#include "utils/OpenPolylineStitcher.h" +#include "utils/MixedPolylineStitcher.h" #include "utils/Simplify.h" -#include "utils/mixed_polyline_stitcher.h" namespace cura { diff --git a/src/bridge.cpp b/src/bridge.cpp index ebf281c247..726eccdb4c 100644 --- a/src/bridge.cpp +++ b/src/bridge.cpp @@ -3,8 +3,8 @@ #include "bridge.h" -#include "geometry/open_lines_set.h" -#include "geometry/polygon.h" +#include "geometry/OpenLinesSet.h" +#include "geometry/Polygon.h" #include "settings/types/Ratio.h" #include "sliceDataStorage.h" #include "utils/AABB.h" diff --git a/src/communication/ArcusCommunication.cpp b/src/communication/ArcusCommunication.cpp index fb321aeb8b..0f0fd4e6d3 100644 --- a/src/communication/ArcusCommunication.cpp +++ b/src/communication/ArcusCommunication.cpp @@ -33,7 +33,7 @@ #include "communication/ArcusCommunicationPrivate.h" //Our PIMPL. #include "communication/Listener.h" //To listen to the Arcus socket. #include "communication/SliceDataStruct.h" //To store sliced layer data. -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "plugins/slots.h" #include "settings/types/LayerIndex.h" //To point to layers. #include "settings/types/Velocity.h" //To send to layer view how fast stuff is printing. diff --git a/src/geometry/closed_polyline.cpp b/src/geometry/ClosedPolyline.cpp similarity index 93% rename from src/geometry/closed_polyline.cpp rename to src/geometry/ClosedPolyline.cpp index 3ff2e75c0f..f9ae903ab5 100644 --- a/src/geometry/closed_polyline.cpp +++ b/src/geometry/ClosedPolyline.cpp @@ -1,9 +1,9 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "geometry/closed_polyline.h" +#include "geometry/ClosedPolyline.h" -#include "geometry/open_polyline.h" +#include "geometry/OpenPolyline.h" namespace cura { diff --git a/src/geometry/lines_set.cpp b/src/geometry/LinesSet.cpp similarity index 98% rename from src/geometry/lines_set.cpp rename to src/geometry/LinesSet.cpp index c556cf3770..6635c1b407 100644 --- a/src/geometry/lines_set.cpp +++ b/src/geometry/LinesSet.cpp @@ -1,13 +1,13 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "geometry/lines_set.h" +#include "geometry/LinesSet.h" #include -#include "geometry/open_lines_set.h" -#include "geometry/polygon.h" -#include "geometry/shape.h" +#include "geometry/OpenLinesSet.h" +#include "geometry/Polygon.h" +#include "geometry/Shape.h" namespace cura { diff --git a/src/geometry/mixed_lines_set.cpp b/src/geometry/MixedLinesSet.cpp similarity index 96% rename from src/geometry/mixed_lines_set.cpp rename to src/geometry/MixedLinesSet.cpp index 651c7bc927..88714178e7 100644 --- a/src/geometry/mixed_lines_set.cpp +++ b/src/geometry/MixedLinesSet.cpp @@ -1,13 +1,13 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "geometry/mixed_lines_set.h" +#include "geometry/MixedLinesSet.h" #include -#include "geometry/open_polyline.h" -#include "geometry/polygon.h" -#include "geometry/shape.h" +#include "geometry/OpenPolyline.h" +#include "geometry/Polygon.h" +#include "geometry/Shape.h" namespace cura diff --git a/src/geometry/parts_view.cpp b/src/geometry/PartsView.cpp similarity index 93% rename from src/geometry/parts_view.cpp rename to src/geometry/PartsView.cpp index 7d84d2d757..5e080b2aea 100644 --- a/src/geometry/parts_view.cpp +++ b/src/geometry/PartsView.cpp @@ -1,10 +1,10 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "geometry/parts_view.h" +#include "geometry/PartsView.h" -#include "geometry/polygon.h" -#include "geometry/single_shape.h" +#include "geometry/Polygon.h" +#include "geometry/SingleShape.h" namespace cura { diff --git a/src/geometry/points_set.cpp b/src/geometry/PointsSet.cpp similarity index 88% rename from src/geometry/points_set.cpp rename to src/geometry/PointsSet.cpp index 29275d2117..e839f7c55a 100644 --- a/src/geometry/points_set.cpp +++ b/src/geometry/PointsSet.cpp @@ -1,10 +1,10 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "geometry/points_set.h" +#include "geometry/PointsSet.h" -#include "geometry/point3_matrix.h" -#include "geometry/point_matrix.h" +#include "geometry/Point3Matrix.h" +#include "geometry/PointMatrix.h" namespace cura { diff --git a/src/geometry/polygon.cpp b/src/geometry/Polygon.cpp similarity index 99% rename from src/geometry/polygon.cpp rename to src/geometry/Polygon.cpp index 928684fdb6..cd75b3ecd7 100644 --- a/src/geometry/polygon.cpp +++ b/src/geometry/Polygon.cpp @@ -1,11 +1,11 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "geometry/polygon.h" +#include "geometry/Polygon.h" -#include "geometry/point3_matrix.h" -#include "geometry/point_matrix.h" -#include "geometry/shape.h" +#include "geometry/Point3Matrix.h" +#include "geometry/PointMatrix.h" +#include "geometry/Shape.h" #include "utils/ListPolyIt.h" #include "utils/linearAlg2D.h" diff --git a/src/geometry/polyline.cpp b/src/geometry/Polyline.cpp similarity index 98% rename from src/geometry/polyline.cpp rename to src/geometry/Polyline.cpp index 0f8d98de29..bd43c9c948 100644 --- a/src/geometry/polyline.cpp +++ b/src/geometry/Polyline.cpp @@ -1,11 +1,11 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "geometry/polyline.h" +#include "geometry/Polyline.h" #include -#include "geometry/open_lines_set.h" +#include "geometry/OpenLinesSet.h" #include "settings/types/Angle.h" #include "utils/linearAlg2D.h" diff --git a/src/geometry/shape.cpp b/src/geometry/Shape.cpp similarity index 99% rename from src/geometry/shape.cpp rename to src/geometry/Shape.cpp index 2df71ce5ad..412346b3ed 100644 --- a/src/geometry/shape.cpp +++ b/src/geometry/Shape.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "geometry/shape.h" +#include "geometry/Shape.h" #include #include @@ -23,10 +23,10 @@ #include #include -#include "geometry/mixed_lines_set.h" -#include "geometry/parts_view.h" -#include "geometry/polygon.h" -#include "geometry/single_shape.h" +#include "geometry/MixedLinesSet.h" +#include "geometry/PartsView.h" +#include "geometry/Polygon.h" +#include "geometry/SingleShape.h" #include "settings/types/Ratio.h" #include "utils/OpenPolylineStitcher.h" #include "utils/linearAlg2D.h" diff --git a/src/geometry/single_shape.cpp b/src/geometry/SingleShape.cpp similarity index 91% rename from src/geometry/single_shape.cpp rename to src/geometry/SingleShape.cpp index 17205811e1..19b0702dc3 100644 --- a/src/geometry/single_shape.cpp +++ b/src/geometry/SingleShape.cpp @@ -1,9 +1,9 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "geometry/single_shape.h" +#include "geometry/SingleShape.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" namespace cura { diff --git a/src/infill.cpp b/src/infill.cpp index b1e0ca40a4..9cb7b8d7f6 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -11,7 +11,7 @@ #include #include "WallToolPaths.h" -#include "geometry/point_matrix.h" +#include "geometry/PointMatrix.h" #include "infill/GyroidInfill.h" #include "infill/ImageBasedDensityProvider.h" #include "infill/LightningGenerator.h" diff --git a/src/infill/GyroidInfill.cpp b/src/infill/GyroidInfill.cpp index ca67b9fb60..8641e995ef 100644 --- a/src/infill/GyroidInfill.cpp +++ b/src/infill/GyroidInfill.cpp @@ -3,9 +3,9 @@ #include "infill/GyroidInfill.h" -#include "geometry/open_polyline.h" -#include "geometry/polygon.h" -#include "geometry/shape.h" +#include "geometry/OpenPolyline.h" +#include "geometry/Polygon.h" +#include "geometry/Shape.h" #include "utils/AABB.h" #include "utils/linearAlg2D.h" diff --git a/src/infill/LightningTreeNode.cpp b/src/infill/LightningTreeNode.cpp index 8873030320..6fb978d895 100644 --- a/src/infill/LightningTreeNode.cpp +++ b/src/infill/LightningTreeNode.cpp @@ -3,7 +3,7 @@ #include "infill/LightningTreeNode.h" -#include "geometry/open_polyline.h" +#include "geometry/OpenPolyline.h" #include "utils/linearAlg2D.h" using namespace cura; diff --git a/src/infill/SierpinskiFill.cpp b/src/infill/SierpinskiFill.cpp index 54b9ad729c..8c5663b1b1 100644 --- a/src/infill/SierpinskiFill.cpp +++ b/src/infill/SierpinskiFill.cpp @@ -10,7 +10,7 @@ #include -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "infill/ImageBasedDensityProvider.h" #include "infill/UniformDensityProvider.h" #include "utils/AABB3D.h" diff --git a/src/infill/SierpinskiFillProvider.cpp b/src/infill/SierpinskiFillProvider.cpp index 643770162c..769029aa11 100644 --- a/src/infill/SierpinskiFillProvider.cpp +++ b/src/infill/SierpinskiFillProvider.cpp @@ -5,7 +5,7 @@ #include -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "infill/ImageBasedDensityProvider.h" #include "infill/UniformDensityProvider.h" #include "utils/AABB3D.h" diff --git a/src/infill/SubDivCube.cpp b/src/infill/SubDivCube.cpp index ce26aadf8c..5fe15a2c7c 100644 --- a/src/infill/SubDivCube.cpp +++ b/src/infill/SubDivCube.cpp @@ -5,8 +5,8 @@ #include -#include "geometry/polygon.h" -#include "geometry/shape.h" +#include "geometry/Polygon.h" +#include "geometry/Shape.h" #include "settings/types/Angle.h" //For the infill angle. #include "sliceDataStorage.h" #include "utils/math.h" diff --git a/src/infill/ZigzagConnectorProcessor.cpp b/src/infill/ZigzagConnectorProcessor.cpp index ffe86771d0..b20b036b9c 100644 --- a/src/infill/ZigzagConnectorProcessor.cpp +++ b/src/infill/ZigzagConnectorProcessor.cpp @@ -5,10 +5,10 @@ #include -#include "geometry/open_polyline.h" -#include "geometry/point_matrix.h" -#include "geometry/polygon.h" -#include "geometry/shape.h" +#include "geometry/OpenPolyline.h" +#include "geometry/PointMatrix.h" +#include "geometry/Polygon.h" +#include "geometry/Shape.h" using namespace cura; diff --git a/src/multiVolumes.cpp b/src/multiVolumes.cpp index 6c607a55c9..7e0e9eb838 100644 --- a/src/multiVolumes.cpp +++ b/src/multiVolumes.cpp @@ -7,7 +7,7 @@ #include "Application.h" #include "Slice.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "settings/EnumSettings.h" #include "settings/types/LayerIndex.h" #include "slicer.h" diff --git a/src/plugins/converters.cpp b/src/plugins/converters.cpp index d106d0d038..de518aa9c2 100644 --- a/src/plugins/converters.cpp +++ b/src/plugins/converters.cpp @@ -11,7 +11,7 @@ #include "GCodePathConfig.h" #include "WallToolPaths.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "pathPlanning/GCodePath.h" #include "pathPlanning/SpeedDerivatives.h" #include "settings/Settings.h" diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index 3dcd486f28..36bd83d9f2 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -18,8 +18,8 @@ #include "BeadingStrategy/BeadingStrategyFactory.h" #include "ExtruderTrain.h" #include "Slice.h" -#include "geometry/polygon.h" -#include "geometry/shape.h" +#include "geometry/Polygon.h" +#include "geometry/Shape.h" #include "settings/EnumSettings.h" #include "settings/FlowTempGraph.h" #include "settings/types/Angle.h" diff --git a/src/utils/AABB.cpp b/src/utils/AABB.cpp index 7f04f79ad6..3229852a30 100644 --- a/src/utils/AABB.cpp +++ b/src/utils/AABB.cpp @@ -5,8 +5,8 @@ #include -#include "geometry/polygon.h" -#include "geometry/shape.h" +#include "geometry/Polygon.h" +#include "geometry/Shape.h" #include "utils/linearAlg2D.h" namespace cura diff --git a/src/utils/ListPolyIt.cpp b/src/utils/ListPolyIt.cpp index 1f8929896d..8eeb6887e6 100644 --- a/src/utils/ListPolyIt.cpp +++ b/src/utils/ListPolyIt.cpp @@ -6,7 +6,7 @@ #include // isfinite #include // ostream -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "utils/AABB.h" // for debug output svg html #include "utils/SVG.h" diff --git a/src/utils/Matrix4x3D.cpp b/src/utils/Matrix4x3D.cpp index d23abba21f..7e68fbfbbc 100644 --- a/src/utils/Matrix4x3D.cpp +++ b/src/utils/Matrix4x3D.cpp @@ -3,7 +3,7 @@ #include "utils/Matrix4x3D.h" //The definitions we're implementing. -#include "geometry/point2ll.h" //Conversion directly into integer-based coordinates. +#include "geometry/Point2LL.h" //Conversion directly into integer-based coordinates. #include "settings/types/Ratio.h" //Scale factor. #include "utils/Point3D.h" //This matrix gets applied to floating point coordinates. diff --git a/src/utils/mixed_polyline_stitcher.cpp b/src/utils/MixedPolylineStitcher.cpp similarity index 85% rename from src/utils/mixed_polyline_stitcher.cpp rename to src/utils/MixedPolylineStitcher.cpp index 8792036108..3b2842a21d 100644 --- a/src/utils/mixed_polyline_stitcher.cpp +++ b/src/utils/MixedPolylineStitcher.cpp @@ -1,11 +1,11 @@ // Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "utils/mixed_polyline_stitcher.h" +#include "utils/MixedPolylineStitcher.h" -#include "geometry/mixed_lines_set.h" -#include "geometry/polygon.h" -#include "geometry/shape.h" +#include "geometry/MixedLinesSet.h" +#include "geometry/Polygon.h" +#include "geometry/Shape.h" namespace cura diff --git a/src/utils/Point3LL.cpp b/src/utils/Point3LL.cpp index 6a72feb929..d12b31414f 100644 --- a/src/utils/Point3LL.cpp +++ b/src/utils/Point3LL.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2022 Ultimaker B.V. // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "geometry/point3ll.h" //The headers we're implementing. +#include "geometry/Point3LL.h" //The headers we're implementing. namespace cura { diff --git a/src/utils/PolygonsPointIndex.cpp b/src/utils/PolygonsPointIndex.cpp index 44a45fb49f..3618e53a96 100644 --- a/src/utils/PolygonsPointIndex.cpp +++ b/src/utils/PolygonsPointIndex.cpp @@ -3,7 +3,7 @@ #include "utils/PolygonsPointIndex.h" -#include "geometry/shape.h" +#include "geometry/Shape.h" namespace cura { diff --git a/src/utils/PolylineStitcher.cpp b/src/utils/PolylineStitcher.cpp index 49e632647d..4be8805032 100644 --- a/src/utils/PolylineStitcher.cpp +++ b/src/utils/PolylineStitcher.cpp @@ -3,8 +3,8 @@ #include "utils/PolylineStitcher.h" -#include "geometry/closed_lines_set.h" -#include "geometry/open_lines_set.h" +#include "geometry/ClosedLinesSet.h" +#include "geometry/OpenLinesSet.h" #include "utils/ExtrusionLineStitcher.h" #include "utils/OpenPolylineStitcher.h" #include "utils/PolygonsPointIndex.h" diff --git a/src/utils/SVG.cpp b/src/utils/SVG.cpp index d3f3357d36..a546f55bbf 100644 --- a/src/utils/SVG.cpp +++ b/src/utils/SVG.cpp @@ -7,8 +7,8 @@ #include -#include "geometry/polygon.h" -#include "geometry/single_shape.h" +#include "geometry/Polygon.h" +#include "geometry/SingleShape.h" #include "utils/ExtrusionLine.h" #include "utils/Point3D.h" diff --git a/src/utils/Simplify.cpp b/src/utils/Simplify.cpp index 330ac36871..c31efa5abc 100644 --- a/src/utils/Simplify.cpp +++ b/src/utils/Simplify.cpp @@ -6,9 +6,9 @@ #include #include //Priority queue to prioritise removing unimportant vertices. -#include "geometry/closed_polyline.h" -#include "geometry/mixed_lines_set.h" -#include "geometry/open_polyline.h" +#include "geometry/ClosedPolyline.h" +#include "geometry/MixedLinesSet.h" +#include "geometry/OpenPolyline.h" #include "settings/Settings.h" //To load the parameters from a Settings object. #include "utils/ExtrusionLine.h" #include "utils/linearAlg2D.h" //To calculate line deviations and intersecting lines. diff --git a/src/utils/VoronoiUtils.cpp b/src/utils/VoronoiUtils.cpp index 8833974be2..3533a98d00 100644 --- a/src/utils/VoronoiUtils.cpp +++ b/src/utils/VoronoiUtils.cpp @@ -8,7 +8,7 @@ #include -#include "geometry/point_matrix.h" +#include "geometry/PointMatrix.h" #include "utils/linearAlg2D.h" #include "utils/macros.h" diff --git a/src/utils/linearAlg2D.cpp b/src/utils/linearAlg2D.cpp index b75b333e0b..554dacdc65 100644 --- a/src/utils/linearAlg2D.cpp +++ b/src/utils/linearAlg2D.cpp @@ -7,8 +7,8 @@ #include #include // atan2 -#include "geometry/point3_matrix.h" -#include "geometry/point_matrix.h" +#include "geometry/Point3Matrix.h" +#include "geometry/PointMatrix.h" #include "utils/math.h" namespace cura diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index ba3372dc58..07022274aa 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -10,9 +10,9 @@ #include -#include "geometry/open_polyline.h" -#include "geometry/point_matrix.h" -#include "geometry/single_shape.h" +#include "geometry/OpenPolyline.h" +#include "geometry/PointMatrix.h" +#include "geometry/SingleShape.h" #include "infill.h" #include "utils/SparsePointGridInclusive.h" #include "utils/linearAlg2D.h" diff --git a/stress_benchmark/stress_benchmark.cpp b/stress_benchmark/stress_benchmark.cpp index 3562e20ae0..0fa07371a8 100644 --- a/stress_benchmark/stress_benchmark.cpp +++ b/stress_benchmark/stress_benchmark.cpp @@ -20,7 +20,7 @@ #include #include "WallsComputation.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "rapidjson/document.h" #include "rapidjson/stringbuffer.h" #include "rapidjson/writer.h" diff --git a/tests/ClipperTest.cpp b/tests/ClipperTest.cpp index e88990e7d4..7bcc755eda 100644 --- a/tests/ClipperTest.cpp +++ b/tests/ClipperTest.cpp @@ -9,7 +9,7 @@ // #define TEST_INFILL_SVG_OUTPUT #ifdef TEST_INFILL_SVG_OUTPUT #include "utils/SVG.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include #endif // TEST_INFILL_SVG_OUTPUT diff --git a/tests/PathOrderMonotonicTest.cpp b/tests/PathOrderMonotonicTest.cpp index c6932c214b..d8c81186a1 100644 --- a/tests/PathOrderMonotonicTest.cpp +++ b/tests/PathOrderMonotonicTest.cpp @@ -12,7 +12,7 @@ #include #include "ReadTestPolygons.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "infill.h" #include "slicer.h" #include "utils/Coord_t.h" diff --git a/tests/ReadTestPolygons.cpp b/tests/ReadTestPolygons.cpp index fdaef7d883..be4b5bbe87 100644 --- a/tests/ReadTestPolygons.cpp +++ b/tests/ReadTestPolygons.cpp @@ -5,7 +5,7 @@ #include -#include "geometry/shape.h" +#include "geometry/Shape.h" #include "utils/Coord_t.h" // NOTE: See the documentation in the header-file for an explanation of this simple file format. diff --git a/tests/ReadTestPolygons.h b/tests/ReadTestPolygons.h index 9baaba4721..5c237025b1 100644 --- a/tests/ReadTestPolygons.h +++ b/tests/ReadTestPolygons.h @@ -4,7 +4,7 @@ #ifndef READ_TEST_POLYGONS_H #define READ_TEST_POLYGONS_H -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include #include diff --git a/tests/WallsComputationTest.cpp b/tests/WallsComputationTest.cpp index fc6d60a365..edbdfd35d9 100644 --- a/tests/WallsComputationTest.cpp +++ b/tests/WallsComputationTest.cpp @@ -11,7 +11,7 @@ #include #include "InsetOrderOptimizer.h" //Unit also under test. -#include "geometry/polygon.h" //To create example polygons. +#include "geometry/Polygon.h" //To create example polygons. #include "settings/Settings.h" //Settings to generate walls with. #include "sliceDataStorage.h" //Sl #include "slicer.h" @@ -19,7 +19,7 @@ #ifdef WALLS_COMPUTATION_TEST_SVG_OUTPUT #include -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include "utils/SVG.h" #endif // WALLS_COMPUTATION_TEST_SVG_OUTPUT diff --git a/tests/arcus/ArcusCommunicationTest.cpp b/tests/arcus/ArcusCommunicationTest.cpp index 3c56047815..69434dd06d 100644 --- a/tests/arcus/ArcusCommunicationTest.cpp +++ b/tests/arcus/ArcusCommunicationTest.cpp @@ -9,7 +9,7 @@ #include "FffProcessor.h" #include "MockSocket.h" //To mock out the communication with the front-end. #include "communication/ArcusCommunicationPrivate.h" //To access the private fields of this communication class. -#include "geometry/polygon.h" //Create test shapes to send over the socket. +#include "geometry/Polygon.h" //Create test shapes to send over the socket. #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" diff --git a/tests/arcus/MockCommunication.h b/tests/arcus/MockCommunication.h index fb1151c4e0..0f95cee769 100644 --- a/tests/arcus/MockCommunication.h +++ b/tests/arcus/MockCommunication.h @@ -7,8 +7,8 @@ #include #include "communication/Communication.h" //The interface we're implementing. -#include "geometry/polygon.h" //In the signature of Communication. -#include "geometry/shape.h" +#include "geometry/Polygon.h" //In the signature of Communication. +#include "geometry/Shape.h" #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" diff --git a/tests/integration/SlicePhaseTest.cpp b/tests/integration/SlicePhaseTest.cpp index 1a4fc1579e..a809d5e0f5 100644 --- a/tests/integration/SlicePhaseTest.cpp +++ b/tests/integration/SlicePhaseTest.cpp @@ -7,7 +7,7 @@ #include "Application.h" // To set up a slice with settings. #include "Slice.h" // To set up a scene to slice. -#include "geometry/polygon.h" // Creating polygons to compare to sliced layers. +#include "geometry/Polygon.h" // Creating polygons to compare to sliced layers. #include "slicer.h" // Starts the slicing phase that we want to test. #include "utils/Coord_t.h" #include "utils/Matrix4x3D.h" // To load STL files. diff --git a/tests/utils/AABB3DTest.cpp b/tests/utils/AABB3DTest.cpp index 7cf43eee56..31c12017dc 100644 --- a/tests/utils/AABB3DTest.cpp +++ b/tests/utils/AABB3DTest.cpp @@ -4,7 +4,7 @@ #include "utils/AABB3D.h" #include "utils/AABB.h" #include "utils/Coord_t.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" #include #include diff --git a/tests/utils/AABBTest.cpp b/tests/utils/AABBTest.cpp index e3ad71f54c..cc2968d3f1 100644 --- a/tests/utils/AABBTest.cpp +++ b/tests/utils/AABBTest.cpp @@ -7,8 +7,8 @@ #include -#include "geometry/polygon.h" -#include "geometry/shape.h" +#include "geometry/Polygon.h" +#include "geometry/Shape.h" namespace cura { diff --git a/tests/utils/IntPointTest.cpp b/tests/utils/IntPointTest.cpp index 0dfe1e36b4..742991be3f 100644 --- a/tests/utils/IntPointTest.cpp +++ b/tests/utils/IntPointTest.cpp @@ -3,9 +3,9 @@ #include -#include "geometry/point2ll.h" -#include "geometry/point3_matrix.h" -#include "geometry/point_matrix.h" +#include "geometry/Point2LL.h" +#include "geometry/Point3Matrix.h" +#include "geometry/PointMatrix.h" // NOLINTBEGIN(*-magic-numbers) namespace cura diff --git a/tests/utils/LinearAlg2DTest.cpp b/tests/utils/LinearAlg2DTest.cpp index fd0c3cde9b..6f61acae6d 100644 --- a/tests/utils/LinearAlg2DTest.cpp +++ b/tests/utils/LinearAlg2DTest.cpp @@ -7,7 +7,7 @@ #include -#include "geometry/point3_matrix.h" +#include "geometry/Point3Matrix.h" // NOLINTBEGIN(*-magic-numbers) namespace cura diff --git a/tests/utils/PolygonConnectorTest.cpp b/tests/utils/PolygonConnectorTest.cpp index bc7ae275f6..b2b08af3c0 100644 --- a/tests/utils/PolygonConnectorTest.cpp +++ b/tests/utils/PolygonConnectorTest.cpp @@ -7,7 +7,7 @@ #include -#include "geometry/polygon.h" // To create polygons to test with. +#include "geometry/Polygon.h" // To create polygons to test with. #include "utils/Coord_t.h" // NOLINTBEGIN(*-magic-numbers) diff --git a/tests/utils/PolygonTest.cpp b/tests/utils/PolygonTest.cpp index 13b218e484..cf39e89dab 100644 --- a/tests/utils/PolygonTest.cpp +++ b/tests/utils/PolygonTest.cpp @@ -1,12 +1,12 @@ // Copyright (c) 2022 Ultimaker B.V. // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "geometry/polygon.h" // The class under test. +#include "geometry/Polygon.h" // The class under test. #include -#include "geometry/open_polyline.h" -#include "geometry/single_shape.h" +#include "geometry/OpenPolyline.h" +#include "geometry/SingleShape.h" #include "utils/Coord_t.h" #include "utils/SVG.h" // helper functions #include "utils/polygonUtils.h" // helper functions diff --git a/tests/utils/PolygonUtilsTest.cpp b/tests/utils/PolygonUtilsTest.cpp index ffa8b21612..cc1907390e 100644 --- a/tests/utils/PolygonUtilsTest.cpp +++ b/tests/utils/PolygonUtilsTest.cpp @@ -5,8 +5,8 @@ #include -#include "geometry/point2ll.h" // Creating and testing with points. -#include "geometry/polygon.h" // Creating polygons to test with. +#include "geometry/Point2LL.h" // Creating and testing with points. +#include "geometry/Polygon.h" // Creating polygons to test with. #include "utils/Coord_t.h" // NOLINTBEGIN(*-magic-numbers) diff --git a/tests/utils/SmoothTest.cpp b/tests/utils/SmoothTest.cpp index 0354728feb..d2b0be63bc 100644 --- a/tests/utils/SmoothTest.cpp +++ b/tests/utils/SmoothTest.cpp @@ -7,9 +7,9 @@ #include -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" #include "utils/actions/smooth.h" -#include "geometry/polygon.h" +#include "geometry/Polygon.h" namespace cura { diff --git a/tests/utils/StringTest.cpp b/tests/utils/StringTest.cpp index e9e7b7673e..a0c172fbc8 100644 --- a/tests/utils/StringTest.cpp +++ b/tests/utils/StringTest.cpp @@ -2,7 +2,7 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "utils/string.h" // The file under test. -#include "geometry/point2ll.h" +#include "geometry/Point2LL.h" #include // NOLINTBEGIN(*-magic-numbers) From 7a6edd3b17e48c939623d759d5ffdb2bd6db2f9d Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 26 Apr 2024 14:38:58 +0200 Subject: [PATCH 059/135] Update copyright year CURA-9830 --- include/geometry/LinesSet.h | 2 +- include/geometry/MixedLinesSet.h | 2 +- include/geometry/OpenPolyline.h | 2 +- include/geometry/PartsView.h | 2 +- include/geometry/PointsSet.h | 2 +- include/geometry/Polygon.h | 2 +- include/geometry/Polyline.h | 2 +- include/geometry/SegmentIterator.h | 2 +- include/geometry/Shape.h | 2 +- include/geometry/SingleShape.h | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index a0cf46ed10..bcff3cb766 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef GEOMETRY_LINES_SET_H diff --git a/include/geometry/MixedLinesSet.h b/include/geometry/MixedLinesSet.h index a0c25fc2d2..cf0c4f0e65 100644 --- a/include/geometry/MixedLinesSet.h +++ b/include/geometry/MixedLinesSet.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef GEOMETRY_MIXED_LINES_SET_H diff --git a/include/geometry/OpenPolyline.h b/include/geometry/OpenPolyline.h index ec40501e8c..849bc18c70 100644 --- a/include/geometry/OpenPolyline.h +++ b/include/geometry/OpenPolyline.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef GEOMETRY_OPEN_POLYLINE_H diff --git a/include/geometry/PartsView.h b/include/geometry/PartsView.h index 2ce9c8a8fd..f43c8c1d21 100644 --- a/include/geometry/PartsView.h +++ b/include/geometry/PartsView.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef GEOMETRY_PARTS_VIEW_H diff --git a/include/geometry/PointsSet.h b/include/geometry/PointsSet.h index 08013e89bc..ae084e61ce 100644 --- a/include/geometry/PointsSet.h +++ b/include/geometry/PointsSet.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef GEOMETRY_POINTS_SET_H diff --git a/include/geometry/Polygon.h b/include/geometry/Polygon.h index 12a70b3843..9a24abeaf0 100644 --- a/include/geometry/Polygon.h +++ b/include/geometry/Polygon.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef GEOMETRY_POLYGON_H diff --git a/include/geometry/Polyline.h b/include/geometry/Polyline.h index f3a5dc3599..ae6b88cb6b 100644 --- a/include/geometry/Polyline.h +++ b/include/geometry/Polyline.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef GEOMETRY_POLYLINE_H diff --git a/include/geometry/SegmentIterator.h b/include/geometry/SegmentIterator.h index 5147e86267..764d15469e 100644 --- a/include/geometry/SegmentIterator.h +++ b/include/geometry/SegmentIterator.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef GEOMETRY_SEGMENT_ITERATOR_H diff --git a/include/geometry/Shape.h b/include/geometry/Shape.h index 76ce3fd200..6ed24d20d5 100644 --- a/include/geometry/Shape.h +++ b/include/geometry/Shape.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef GEOMETRY_SHAPE_H diff --git a/include/geometry/SingleShape.h b/include/geometry/SingleShape.h index e9d7f92b93..a1a185c1df 100644 --- a/include/geometry/SingleShape.h +++ b/include/geometry/SingleShape.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef GEOMETRY_SINGLE_SHAPE_H From da1e21c009d44693fe28b3a5ec74058e75821270 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 26 Apr 2024 14:49:26 +0200 Subject: [PATCH 060/135] Made push_back parameter more explicit CURA-9830 --- include/geometry/LinesSet.h | 16 ++++++++++------ src/geometry/LinesSet.cpp | 20 ++++++++++---------- src/slicer.cpp | 4 ++-- src/utils/Simplify.cpp | 2 +- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index bcff3cb766..757505ff88 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -18,6 +18,12 @@ template class LinesSet; class OpenPolyline; +enum class CheckNonEmptyParam +{ + OnlyIfNotEmpty, + EvenIfEmpty +}; + /*! * \brief Base class for all geometry containers representing a set of polylines. * \sa https://github.com/Ultimaker/CuraEngine/wiki/Geometric-Base-Types#linesset @@ -133,20 +139,18 @@ class LinesSet /*! * \brief Pushes the given line at the end of the set - * \param checkNonEmpty If true, we will check that the line is not empty, - * and discard it in case it is + * \param checkNonEmpty Indicates whether we should check for the line to be non-empty before adding it * \warning A copy of the line is made, so this method may be slow */ - void push_back(const LineType& line, bool checkNonEmpty = false); + void push_back(const LineType& line, CheckNonEmptyParam checkNonEmpty = CheckNonEmptyParam::EvenIfEmpty); /*! * \brief Pushes the given line at the end of the set and takes ownership of the inner data - * \param checkNonEmpty If true, we will check that the line is not empty, - * and discard it in case it is + * \param checkNonEmpty Indicates whether we should check for the line to be non-empty before adding it * \warning This method is fast because it does not allocate data, but it will clear * the source object */ - void push_back(LineType&& line, bool checkNonEmpty = false); + void push_back(LineType&& line, CheckNonEmptyParam checkNonEmpty = CheckNonEmptyParam::EvenIfEmpty); /*! * \brief Pushes an entier set at the end and takes ownership of the inner data diff --git a/src/geometry/LinesSet.cpp b/src/geometry/LinesSet.cpp index 6635c1b407..3d811eefa3 100644 --- a/src/geometry/LinesSet.cpp +++ b/src/geometry/LinesSet.cpp @@ -24,18 +24,18 @@ LinesSet::LinesSet(ClipperLib::Paths&& paths) } template -void LinesSet::push_back(const LineType& line, bool checkNonEmpty) +void LinesSet::push_back(const LineType& line, CheckNonEmptyParam checkNonEmpty) { - if (! checkNonEmpty || ! line.empty()) + if (checkNonEmpty == CheckNonEmptyParam::EvenIfEmpty || ! line.empty()) { lines_.push_back(line); } } template -void LinesSet::push_back(LineType&& line, bool checkNonEmpty) +void LinesSet::push_back(LineType&& line, CheckNonEmptyParam checkNonEmpty) { - if (! checkNonEmpty || ! line.empty()) + if (checkNonEmpty == CheckNonEmptyParam::EvenIfEmpty || ! line.empty()) { lines_.push_back(line); } @@ -327,8 +327,8 @@ template void LinesSet::translate(const Point2LL& delta); template void LinesSet::removeDegenerateVerts(); template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; template void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; -template void LinesSet::push_back(const OpenPolyline& line, bool checkNonEmpty); -template void LinesSet::push_back(OpenPolyline&& line, bool checkNonEmpty); +template void LinesSet::push_back(const OpenPolyline& line, CheckNonEmptyParam checkNonEmpty); +template void LinesSet::push_back(OpenPolyline&& line, CheckNonEmptyParam checkNonEmpty); template void LinesSet::push_back(LinesSet&& lines_set); template size_t LinesSet::pointCount() const; @@ -341,8 +341,8 @@ template void LinesSet::translate(const Point2LL& delta); template void LinesSet::removeDegenerateVerts(); template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; template void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; -template void LinesSet::push_back(const ClosedPolyline& line, bool checkNonEmpty); -template void LinesSet::push_back(ClosedPolyline&& line, bool checkNonEmpty); +template void LinesSet::push_back(const ClosedPolyline& line, CheckNonEmptyParam checkNonEmpty); +template void LinesSet::push_back(ClosedPolyline&& line, CheckNonEmptyParam checkNonEmpty); template void LinesSet::push_back(LinesSet&& lines_set); template void LinesSet::push_back(LinesSet&& lines_set); @@ -356,8 +356,8 @@ template void LinesSet::translate(const Point2LL& delta); template void LinesSet::removeDegenerateVerts(); template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; template void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; -template void LinesSet::push_back(const Polygon& line, bool checkNonEmpty); -template void LinesSet::push_back(Polygon&& line, bool checkNonEmpty); +template void LinesSet::push_back(const Polygon& line, CheckNonEmptyParam checkNonEmpty); +template void LinesSet::push_back(Polygon&& line, CheckNonEmptyParam checkNonEmpty); template void LinesSet::push_back(LinesSet&& lines_set); } // namespace cura diff --git a/src/slicer.cpp b/src/slicer.cpp index cb923c7c6e..579515a974 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -759,13 +759,13 @@ void SlicerLayer::makePolygons(const Mesh* mesh) { for (const OpenPolyline& polyline : open_polylines) { - polygons.push_back(Polygon(polyline.getPoints(), false), true); + polygons.push_back(Polygon(polyline.getPoints(), false), CheckNonEmptyParam::OnlyIfNotEmpty); } } for (const OpenPolyline& polyline : open_polylines) { - openPolylines.push_back(std::move(polyline), true); + openPolylines.push_back(std::move(polyline), CheckNonEmptyParam::OnlyIfNotEmpty); } // Remove all the tiny polygons, or polygons that are not closed. As they do not contribute to the actual print. diff --git a/src/utils/Simplify.cpp b/src/utils/Simplify.cpp index c31efa5abc..b684ccab3c 100644 --- a/src/utils/Simplify.cpp +++ b/src/utils/Simplify.cpp @@ -35,7 +35,7 @@ Shape Simplify::polygon(const Shape& polygons) const Shape result; for (size_t i = 0; i < polygons.size(); ++i) { - result.push_back(polygon(polygons[i]), true); + result.push_back(polygon(polygons[i]), CheckNonEmptyParam::OnlyIfNotEmpty); } return result; } From a3815d4e4a4476b19631e03d17c236177514a9bf Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 26 Apr 2024 14:52:48 +0200 Subject: [PATCH 061/135] Rename method with more explicit name CURA-9830 --- include/geometry/LinesSet.h | 2 +- src/LayerPlan.cpp | 2 +- src/TreeSupport.cpp | 2 +- src/geometry/LinesSet.cpp | 8 ++++---- src/support.cpp | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index 757505ff88..e41ba2c1a7 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -267,7 +267,7 @@ class LinesSet * kept, not the shape. \param outer_offset Offset relative to the original shape-outline towards the outside of the shape. Comparable to normal offset. \return The resulting * polygons. */ - Shape tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; + Shape createTubeShape(const coord_t inner_offset, const coord_t outer_offset) const; void translate(const Point2LL& delta); diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 29f50d71cb..4f749493af 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -1527,7 +1527,7 @@ void LayerPlan::addLinesMonotonic( const Ratio flow_ratio, const double fan_speed) { - const Shape exclude_areas = area.tubeShape(exclude_distance, exclude_distance); + const Shape exclude_areas = area.createTubeShape(exclude_distance, exclude_distance); const coord_t exclude_dist2 = exclude_distance * exclude_distance; const Point2LL last_position = getLastPlannedPositionOrStartingPosition(); diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 9358693b16..6ba49d7e3f 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -2025,7 +2025,7 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_storage) Shape outer_walls = TreeSupportUtils::toPolylines(support_layer_storage[layer_idx - 1].getOutsidePolygons()) - .tubeShape(closing_dist, 0); //.unionPolygons(volumes_.getCollision(0, layer_idx - 1, true).offset(-(config.support_line_width+config.xy_min_distance))); + .createTubeShape(closing_dist, 0); //.unionPolygons(volumes_.getCollision(0, layer_idx - 1, true).offset(-(config.support_line_width+config.xy_min_distance))); Shape holes_below; diff --git a/src/geometry/LinesSet.cpp b/src/geometry/LinesSet.cpp index 3d811eefa3..b24aac2009 100644 --- a/src/geometry/LinesSet.cpp +++ b/src/geometry/LinesSet.cpp @@ -123,7 +123,7 @@ coord_t LinesSet::length() const } template -Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const +Shape LinesSet::createTubeShape(const coord_t inner_offset, const coord_t outer_offset) const { return offset(outer_offset).difference(offset(-inner_offset)); } @@ -322,7 +322,7 @@ template void LinesSet::removeAt(size_t index); template void LinesSet::splitIntoSegments(OpenLinesSet& result) const; template OpenLinesSet LinesSet::splitIntoSegments() const; template coord_t LinesSet::length() const; -template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template Shape LinesSet::createTubeShape(const coord_t inner_offset, const coord_t outer_offset) const; template void LinesSet::translate(const Point2LL& delta); template void LinesSet::removeDegenerateVerts(); template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; @@ -336,7 +336,7 @@ template void LinesSet::removeAt(size_t index); template void LinesSet::splitIntoSegments(OpenLinesSet& result) const; template OpenLinesSet LinesSet::splitIntoSegments() const; template coord_t LinesSet::length() const; -template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template Shape LinesSet::createTubeShape(const coord_t inner_offset, const coord_t outer_offset) const; template void LinesSet::translate(const Point2LL& delta); template void LinesSet::removeDegenerateVerts(); template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; @@ -351,7 +351,7 @@ template void LinesSet::removeAt(size_t index); template void LinesSet::splitIntoSegments(OpenLinesSet& result) const; template OpenLinesSet LinesSet::splitIntoSegments() const; template coord_t LinesSet::length() const; -template Shape LinesSet::tubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template Shape LinesSet::createTubeShape(const coord_t inner_offset, const coord_t outer_offset) const; template void LinesSet::translate(const Point2LL& delta); template void LinesSet::removeDegenerateVerts(); template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; diff --git a/src/support.cpp b/src/support.cpp index c040f6dc6e..09146cd1f8 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -1043,10 +1043,10 @@ void AreaSupport::generateSupportAreasForMesh( sloped_areas_per_layer[layer_idx] = // Take the outer areas of the previous layer, where the outer areas are (mostly) just _inside_ the shape. storage.getLayerOutlines(layer_idx - 1, no_support, no_prime_tower) - .tubeShape(sloped_area_detection_width, 10) + .createTubeShape(sloped_area_detection_width, 10) // Intersect those with the outer areas of the current layer, where the outer areas are (mostly) _outside_ the shape. // This will detect every slope (and some/most vertical walls) between those two layers. - .intersection(outlines.tubeShape(10, sloped_area_detection_width)) + .intersection(outlines.createTubeShape(10, sloped_area_detection_width)) // Do an opening operation so we're not stuck with tiny patches. // The later offset is extended with the line-width, so all patches are merged together if there's less than a line-width between them. .offset(-10) From 645fa37f039fcb6f6d08337c0c91d0f83741c5cd Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 26 Apr 2024 14:54:13 +0200 Subject: [PATCH 062/135] Fix documentation CURA-9830 --- include/geometry/LinesSet.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index e41ba2c1a7..d307dbd328 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -263,9 +263,13 @@ class LinesSet /*! * Utility method for creating the tube (or 'donut') of a shape. - * \param inner_offset Offset relative to the original shape-outline towards the inside of the shape. Sort-of like a negative normal offset, except it's the offset part that's - * kept, not the shape. \param outer_offset Offset relative to the original shape-outline towards the outside of the shape. Comparable to normal offset. \return The resulting - * polygons. + * + * \param inner_offset Offset relative to the original shape-outline towards the inside of the + * shape. Sort-of like a negative normal offset, except it's the offset part that's kept, + * not the shape. + * \param outer_offset Offset relative to the original shape-outline towards the outside of the + * shape. Comparable to normal offset. + * \return The resulting polygons. */ Shape createTubeShape(const coord_t inner_offset, const coord_t outer_offset) const; From 9f39bf04196f2daa8d8c14cd4896a988f0edd6b1 Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Fri, 26 Apr 2024 15:45:54 +0200 Subject: [PATCH 063/135] writing debug.html in temp folder writing debug.html in the current folder (in case of build the program data) makes it read only and no write modifications are allowed, hence crash. Now it is written in temp foilder of the computer where writing the file is also allowed. --- src/utils/SVG.cpp | 2 +- src/utils/polygonUtils.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/utils/SVG.cpp b/src/utils/SVG.cpp index 4da036996a..96899b4a4e 100644 --- a/src/utils/SVG.cpp +++ b/src/utils/SVG.cpp @@ -87,7 +87,7 @@ SVG::SVG(std::string filename, AABB aabb, double scale, Point2LL canvas_size, Co out_ = fopen(filename.c_str(), "w"); if (! out_) { - spdlog::error("The file %s could not be opened for writing.", filename); + spdlog::error("The file {} could not be opened for writing.", filename); } if (output_is_html_) { diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index 7f7bc2466a..dba28c5324 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -15,12 +15,15 @@ #include "utils/linearAlg2D.h" #ifdef DEBUG +#include #include #include "utils/AABB.h" #include "utils/SVG.h" #endif +namespace fs = std::filesystem; + namespace cura { @@ -693,12 +696,13 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside( static bool has_run = false; if (! has_run) { + fs::path const debug_file_name = fs::temp_directory_path() / "debug.html"; try { int offset_performed = offset / 2; AABB aabb(polygons); aabb.expand(std::abs(preferred_dist_inside) * 2); - SVG svg("debug.html", aabb); + SVG svg(debug_file_name.string(), aabb); svg.writeComment("Original polygon in black"); svg.writePolygons(polygons, SVG::Color::BLACK); for (auto poly : polygons) @@ -729,7 +733,7 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside( catch (...) { } - spdlog::error("Clipper::offset failed. See generated debug.html! Black is original Blue is offsetted polygon"); + spdlog::error("Clipper::offset failed. See generated {}! Black is original Blue is offsetted polygon", debug_file_name.string()); has_run = true; } #endif From d4af3010a364be1f46ca11b8744438ee3c189cba Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Fri, 26 Apr 2024 13:46:37 +0000 Subject: [PATCH 064/135] Applied clang-format. --- src/utils/polygonUtils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index dba28c5324..9d18e82a95 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -16,6 +16,7 @@ #ifdef DEBUG #include + #include #include "utils/AABB.h" From eeee38d84bf854529cc65cdabfd781a127d0aa6b Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 26 Apr 2024 15:52:33 +0200 Subject: [PATCH 065/135] Use OpenLinesSet and ClosedLinesSet as much as possible CURA-9830 --- benchmark/infill_benchmark.h | 1 + include/TreeSupportTipGenerator.h | 6 +- include/TreeSupportUtils.h | 17 +++--- include/geometry/ClosedLinesSet.h | 7 ++- include/geometry/LinesSet.h | 5 +- include/geometry/MixedLinesSet.h | 11 ++-- include/geometry/OpenLinesSet.h | 7 ++- include/geometry/Polyline.h | 5 +- include/geometry/Shape.h | 2 +- include/infill.h | 38 ++++++------ include/infill/GyroidInfill.h | 7 +-- include/infill/LightningLayer.h | 2 +- include/infill/LightningTreeNode.h | 6 +- include/infill/NoZigZagConnectorProcessor.h | 2 +- include/infill/SubDivCube.h | 13 ++--- include/infill/ZigzagConnectorProcessor.h | 14 +---- include/plugins/converters.h | 2 +- include/plugins/slots.h | 2 +- include/sliceDataStorage.h | 2 +- include/utils/MixedPolylineStitcher.h | 2 +- src/FffGcodeWriter.cpp | 20 +++---- src/FffPolygonGenerator.cpp | 2 +- src/LayerPlan.cpp | 13 +++-- src/SkirtBrim.cpp | 3 +- src/TopSurface.cpp | 1 + src/TreeSupportTipGenerator.cpp | 17 +++--- src/bridge.cpp | 1 + src/geometry/LinesSet.cpp | 64 +++++++++++---------- src/geometry/MixedLinesSet.cpp | 6 +- src/geometry/Polyline.cpp | 2 + src/geometry/Shape.cpp | 9 +-- src/infill.cpp | 55 +++++++++--------- src/infill/GyroidInfill.cpp | 8 +-- src/infill/LightningLayer.cpp | 5 +- src/infill/LightningTreeNode.cpp | 8 +-- src/infill/SubDivCube.cpp | 11 ++-- src/layerPart.cpp | 1 + src/multiVolumes.cpp | 3 +- src/path_ordering.cpp | 1 + src/plugins/converters.cpp | 3 +- src/sliceDataStorage.cpp | 1 + src/slicer.cpp | 1 + src/utils/MixedPolylineStitcher.cpp | 3 +- src/utils/PolylineStitcher.cpp | 5 +- src/utils/Simplify.cpp | 4 +- src/utils/polygonUtils.cpp | 2 +- stress_benchmark/stress_benchmark.cpp | 1 + tests/InfillTest.cpp | 1 + tests/PathOrderMonotonicTest.cpp | 1 + tests/WallsComputationTest.cpp | 2 +- tests/integration/SlicePhaseTest.cpp | 1 + 51 files changed, 211 insertions(+), 195 deletions(-) diff --git a/benchmark/infill_benchmark.h b/benchmark/infill_benchmark.h index e95b9d9fc3..af05031656 100644 --- a/benchmark/infill_benchmark.h +++ b/benchmark/infill_benchmark.h @@ -7,6 +7,7 @@ #include #include "geometry/OpenLinesSet.h" +#include "geometry/OpenPolyline.h" #include "infill.h" namespace cura diff --git a/include/TreeSupportTipGenerator.h b/include/TreeSupportTipGenerator.h index c68e889319..adcc712a20 100644 --- a/include/TreeSupportTipGenerator.h +++ b/include/TreeSupportTipGenerator.h @@ -63,7 +63,7 @@ class TreeSupportTipGenerator * \param layer_idx[in] The current layer. * \return All lines of the \p polylines object, with information for each point regarding in which avoidance it is currently valid in. */ - std::vector convertLinesToInternal(const LinesSet& polylines, LayerIndex layer_idx); + std::vector convertLinesToInternal(const OpenLinesSet& polylines, LayerIndex layer_idx); /*! * \brief Converts lines in internal format into a Polygons object representing these lines. @@ -71,7 +71,7 @@ class TreeSupportTipGenerator * \param lines[in] The lines that will be converted. * \return All lines of the \p lines object as a Polygons object. */ - LinesSet convertInternalToLines(std::vector lines); + OpenLinesSet convertInternalToLines(std::vector lines); /*! * \brief Returns a function, evaluating if a point has to be added now. Required for a splitLines call in generateInitialAreas. @@ -102,7 +102,7 @@ class TreeSupportTipGenerator * \param enforce_distance[in] If points should not be added if they are closer than distance to other points. * \return A Polygons object containing the evenly spaced points. Does not represent an area, more a collection of points on lines. */ - LinesSet ensureMaximumDistancePolyline(const LinesSet& input, coord_t distance, size_t min_points, bool enforce_distance) const; + OpenLinesSet ensureMaximumDistancePolyline(const OpenLinesSet& input, coord_t distance, size_t min_points, bool enforce_distance) const; /*! * \brief Creates a valid CrossInfillProvider diff --git a/include/TreeSupportUtils.h b/include/TreeSupportUtils.h index a0c1b407f9..e880689ecd 100644 --- a/include/TreeSupportUtils.h +++ b/include/TreeSupportUtils.h @@ -12,6 +12,7 @@ #include "TreeSupportEnums.h" #include "TreeSupportSettings.h" #include "boost/functional/hash.hpp" // For combining hashes +#include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" #include "infill.h" #include "polyclipping/clipper.hpp" @@ -31,9 +32,9 @@ class TreeSupportUtils * \param poly[in] The Polygons object, of which its lines should be extended. * \return A Polygons object with explicit line from the last vertex of a Polygon to the first one added. */ - static LinesSet toPolylines(const Shape& poly) + static OpenLinesSet toPolylines(const Shape& poly) { - LinesSet result; + OpenLinesSet result; for (const auto& path : poly) { result.push_back(path.toPseudoOpenPolyline()); @@ -48,9 +49,9 @@ class TreeSupportUtils * \param toolpaths[in] The toolpaths. * \return A Polygons object. */ - [[nodiscard]] static LinesSet toPolylines(const std::vector toolpaths) + [[nodiscard]] static OpenLinesSet toPolylines(const std::vector toolpaths) { - LinesSet result; + OpenLinesSet result; for (const VariableWidthLines& lines : toolpaths) { for (const ExtrusionLine& line : lines) @@ -91,7 +92,7 @@ class TreeSupportUtils * todo doku * \return A Polygons object that represents the resulting infill lines. */ - [[nodiscard]] static LinesSet generateSupportInfillLines( + [[nodiscard]] static OpenLinesSet generateSupportInfillLines( const Shape& area, const TreeSupportSettings& config, bool roof, @@ -154,7 +155,7 @@ class TreeSupportUtils pocket_size); Shape areas; - LinesSet lines; + OpenLinesSet lines; roof_computation.generate(toolpaths, areas, lines, config.settings, layer_idx, SectionType::SUPPORT, cross_fill_provider); lines.push_back(toPolylines(areas)); lines.push_back(toPolylines(toolpaths)); @@ -286,9 +287,9 @@ class TreeSupportUtils * \param max_allowed_distance[in] The maximum distance a point may be moved. If not possible the point will be moved as far as possible in the direction of the outside of the * provided area. \return A Polyline object containing the moved points. */ - [[nodiscard]] static LinesSet movePointsOutside(const LinesSet& polylines, const Shape& area, coord_t max_allowed_distance) + [[nodiscard]] static OpenLinesSet movePointsOutside(const OpenLinesSet& polylines, const Shape& area, coord_t max_allowed_distance) { - LinesSet result; + OpenLinesSet result; for (const OpenPolyline& line : polylines) { diff --git a/include/geometry/ClosedLinesSet.h b/include/geometry/ClosedLinesSet.h index 405da85a79..381628f767 100644 --- a/include/geometry/ClosedLinesSet.h +++ b/include/geometry/ClosedLinesSet.h @@ -4,12 +4,13 @@ #ifndef GEOMETRY_CLOSED_LINES_SET_H #define GEOMETRY_CLOSED_LINES_SET_H -#include "geometry/ClosedPolyline.h" -#include "geometry/LinesSet.h" - namespace cura { +template +class LinesSet; +class ClosedPolyline; + /*! * \brief Convenience definition for a container that can hold only closed polylines. This makes it * explicit what the lines actually represent. diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index d307dbd328..50694e7fdc 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -8,6 +8,7 @@ #include +#include "geometry/OpenLinesSet.h" #include "geometry/Point2LL.h" namespace cura @@ -253,8 +254,8 @@ class LinesSet /*! \brief Get the total length of all the lines */ coord_t length() const; - void splitIntoSegments(LinesSet& result) const; - LinesSet splitIntoSegments() const; + void splitIntoSegments(OpenLinesSet& result) const; + OpenLinesSet splitIntoSegments() const; /*! \brief Removes overlapping consecutive line segments which don't delimit a positive area */ void removeDegenerateVerts(); diff --git a/include/geometry/MixedLinesSet.h b/include/geometry/MixedLinesSet.h index cf0c4f0e65..cf1cb19383 100644 --- a/include/geometry/MixedLinesSet.h +++ b/include/geometry/MixedLinesSet.h @@ -6,18 +6,17 @@ #include +#include "geometry/ClosedLinesSet.h" +#include "geometry/OpenLinesSet.h" #include "utils/Coord_t.h" namespace cura { class Polyline; -class OpenPolyline; class ClosedPolyline; class Polygon; class Shape; -template -class LinesSet; using PolylinePtr = std::shared_ptr; using OpenPolylinePtr = std::shared_ptr; @@ -93,20 +92,20 @@ class MixedLinesSet : public std::vector * @brief Adds a copy of all the polylines contained in the set * @note As we have to copy the whole points data, this is really not efficient */ - void push_back(const LinesSet& lines_set); + void push_back(const OpenLinesSet& lines_set); /*! * @brief Adds a copy of all the polylines contained in the set * @note As we can move the points data, this is much more efficient than the above methods, * but will clear the source data */ - void push_back(LinesSet&& lines_set); + void push_back(OpenLinesSet&& lines_set); /*! @brief Adds a copy of all the polylines contained in the set * @note As we can move the points data, this is much more efficient than the above methods, * but will clear the source data */ - void push_back(LinesSet&& lines_set); + void push_back(ClosedLinesSet&& lines_set); /*! \brief Computes the total lenght of all the polylines in the set */ coord_t length() const; diff --git a/include/geometry/OpenLinesSet.h b/include/geometry/OpenLinesSet.h index aefe77044a..d3e18902f5 100644 --- a/include/geometry/OpenLinesSet.h +++ b/include/geometry/OpenLinesSet.h @@ -4,12 +4,13 @@ #ifndef GEOMETRY_OPEN_LINES_SET_H #define GEOMETRY_OPEN_LINES_SET_H -#include "geometry/LinesSet.h" -#include "geometry/OpenPolyline.h" - namespace cura { +template +class LinesSet; +class OpenPolyline; + /*! * \brief Convenience definition for a container that can hold only open polylines. This makes it * explicit what the lines actually represent. diff --git a/include/geometry/Polyline.h b/include/geometry/Polyline.h index ae6b88cb6b..075a9d22d6 100644 --- a/include/geometry/Polyline.h +++ b/include/geometry/Polyline.h @@ -4,6 +4,7 @@ #ifndef GEOMETRY_POLYLINE_H #define GEOMETRY_POLYLINE_H +#include "geometry/OpenLinesSet.h" #include "geometry/PointsSet.h" #include "geometry/SegmentIterator.h" @@ -131,8 +132,8 @@ class Polyline : public PointsSet * Split these poly line objects into several line segment objects consisting of only two verts * and store them in the \p result */ - void splitIntoSegments(LinesSet& result) const; - LinesSet splitIntoSegments() const; + void splitIntoSegments(OpenLinesSet& result) const; + OpenLinesSet splitIntoSegments() const; /*! * On Y-axis positive upward displays, Orientation will return true if the polygon's orientation is counter-clockwise. diff --git a/include/geometry/Shape.h b/include/geometry/Shape.h index 6ed24d20d5..49b9991d05 100644 --- a/include/geometry/Shape.h +++ b/include/geometry/Shape.h @@ -106,7 +106,7 @@ class Shape : public LinesSet * \todo This should technically return a MixedLinesSet, because it can definitely contain open and closed polylines, but that is a heavy change */ template - LinesSet intersection(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; + OpenLinesSet intersection(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; Shape xorPolygons(const Shape& other, ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const; diff --git a/include/infill.h b/include/infill.h index 605516ab6c..610be628cf 100644 --- a/include/infill.h +++ b/include/infill.h @@ -203,7 +203,7 @@ class Infill void generate( std::vector& toolpaths, Shape& result_polygons, - LinesSet& result_lines, + OpenLinesSet& result_lines, const Settings& settings, int layer_idx, SectionType section_type, @@ -374,7 +374,7 @@ class Infill void _generate( std::vector& toolpaths, Shape& result_polygons, - LinesSet& result_lines, + OpenLinesSet& result_lines, const Settings& settings, const std::shared_ptr& cross_fill_pattern = nullptr, const std::shared_ptr& lightning_layer = nullptr, @@ -391,21 +391,21 @@ class Infill * \param[in,out] result_polygons The polygons to be multiplied (input and output) * \param[in,out] result_lines The lines to be multiplied (input and output) */ - void multiplyInfill(Shape& result_polygons, LinesSet& result_lines); + void multiplyInfill(Shape& result_polygons, OpenLinesSet& result_lines); /*! * Generate gyroid infill * \param result_polylines (output) The resulting polylines * \param result_polygons (output) The resulting polygons, if zigzagging accidentally happened to connect gyroid lines in a circle. */ - void generateGyroidInfill(LinesSet& result_polylines, Shape& result_polygons); + void generateGyroidInfill(OpenLinesSet& result_polylines, Shape& result_polygons); /*! * Generate lightning fill aka minfill aka 'Ribbed Support Vault Infill', see Tricard,Claux,Lefebvre/'Ribbed Support Vaults for 3D Printing of Hollowed Objects' * see https://hal.archives-ouvertes.fr/hal-02155929/document * \param result (output) The resulting polygons */ - void generateLightningInfill(const std::shared_ptr& lightning_layer, LinesSet& result_lines); + void generateLightningInfill(const std::shared_ptr& lightning_layer, OpenLinesSet& result_lines); /*! * Generate sparse concentric infill @@ -419,25 +419,25 @@ class Infill * Generate a rectangular grid of infill lines * \param[out] result (output) The resulting lines */ - void generateGridInfill(LinesSet& result); + void generateGridInfill(OpenLinesSet& result); /*! * Generate a shifting triangular grid of infill lines, which combine with consecutive layers into a cubic pattern * \param[out] result (output) The resulting lines */ - void generateCubicInfill(LinesSet& result); + void generateCubicInfill(OpenLinesSet& result); /*! * Generate a double shifting square grid of infill lines, which combine with consecutive layers into a tetrahedral pattern * \param[out] result (output) The resulting lines */ - void generateTetrahedralInfill(LinesSet& result); + void generateTetrahedralInfill(OpenLinesSet& result); /*! * Generate a double shifting square grid of infill lines, which combine with consecutive layers into a quarter cubic pattern * \param[out] result (output) The resulting lines */ - void generateQuarterCubicInfill(LinesSet& result); + void generateQuarterCubicInfill(OpenLinesSet& result); /*! * Generate a single shifting square grid of infill lines. @@ -447,26 +447,26 @@ class Infill * \param angle_shift The angle to add to the infill_angle * \param[out] result (output) The resulting lines */ - void generateHalfTetrahedralInfill(double pattern_z_shift, int angle_shift, LinesSet& result); + void generateHalfTetrahedralInfill(double pattern_z_shift, int angle_shift, OpenLinesSet& result); /*! * Generate a triangular grid of infill lines * \param[out] result (output) The resulting lines */ - void generateTriangleInfill(LinesSet& result); + void generateTriangleInfill(OpenLinesSet& result); /*! * Generate a triangular grid of infill lines * \param[out] result (output) The resulting lines */ - void generateTrihexagonInfill(LinesSet& result); + void generateTrihexagonInfill(OpenLinesSet& result); /*! * Generate a 3d pattern of subdivided cubes on their points * \param[out] result The resulting lines * \param[in] mesh Where the Cubic Subdivision Infill precomputation is stored */ - void generateCubicSubDivInfill(LinesSet& result, const SliceMeshStorage& mesh); + void generateCubicSubDivInfill(OpenLinesSet& result, const SliceMeshStorage& mesh); /*! * Generate a 3d pattern of subdivided cubes on their points @@ -474,7 +474,7 @@ class Infill * \param[out] result_polygons The resulting polygons * \param[out] result_lines The resulting lines */ - void generateCrossInfill(const SierpinskiFillProvider& cross_fill_provider, Shape& result_polygons, LinesSet& result_lines); + void generateCrossInfill(const SierpinskiFillProvider& cross_fill_provider, Shape& result_polygons, OpenLinesSet& result_lines); /*! * Convert a mapping from scanline to line_segment-scanline-intersections (\p cut_list) into line segments, using the even-odd rule @@ -487,7 +487,7 @@ class Infill * \param total_shift total shift of the scanlines in the direction perpendicular to the fill_angle. */ void addLineInfill( - LinesSet& result, + OpenLinesSet& result, const PointMatrix& rotation_matrix, const int scanline_min_idx, const int line_distance, @@ -506,7 +506,7 @@ class Infill * \param infill_rotation The angle of the generated lines * \param extra_shift extra shift of the scanlines in the direction perpendicular to the infill_rotation */ - void generateLineInfill(LinesSet& result, int line_distance, const double& infill_rotation, coord_t extra_shift); + void generateLineInfill(OpenLinesSet& result, int line_distance, const double& infill_rotation, coord_t extra_shift); /*! * Function for creating linear based infill types (Lines, ZigZag). @@ -524,7 +524,7 @@ class Infill * \param extra_shift extra shift of the scanlines in the direction perpendicular to the fill_angle */ void generateLinearBasedInfill( - LinesSet& result, + OpenLinesSet& result, const int line_distance, const PointMatrix& rotation_matrix, ZigzagConnectorProcessor& zigzag_connector_processor, @@ -578,7 +578,7 @@ class Infill * \param line_distance The distance between two lines which are in the same direction * \param infill_rotation The angle of the generated lines */ - void generateZigZagInfill(LinesSet& result, const coord_t line_distance, const double& infill_rotation); + void generateZigZagInfill(OpenLinesSet& result, const coord_t line_distance, const double& infill_rotation); /*! * determine how far the infill pattern should be shifted based on the values of infill_origin and \p infill_rotation @@ -620,7 +620,7 @@ class Infill * border of the infill area, similar to the zigzag pattern. * \param[in/out] result_lines The lines to connect together. */ - void connectLines(LinesSet& result_lines); + void connectLines(OpenLinesSet& result_lines); }; static_assert(concepts::semiregular, "Infill should be semiregular"); diff --git a/include/infill/GyroidInfill.h b/include/infill/GyroidInfill.h index de5117876e..2c4af661da 100644 --- a/include/infill/GyroidInfill.h +++ b/include/infill/GyroidInfill.h @@ -2,15 +2,12 @@ // CuraEngine is released under the terms of the AGPLv3 or higher. #include "../utils/Coord_t.h" +#include "geometry/OpenLinesSet.h" namespace cura { class Shape; -class OpenPolyline; - -template -class LinesSet; class GyroidInfill { @@ -37,7 +34,7 @@ class GyroidInfill * \param z The Z coordinate of this layer. Different Z coordinates cause the pattern to vary, producing a 3D * pattern. */ - static void generateTotalGyroidInfill(LinesSet& result_lines, bool zig_zaggify, coord_t line_distance, const Shape& in_outline, coord_t z); + static void generateTotalGyroidInfill(OpenLinesSet& result_lines, bool zig_zaggify, coord_t line_distance, const Shape& in_outline, coord_t z); private: }; diff --git a/include/infill/LightningLayer.h b/include/infill/LightningLayer.h index 76ab5eebbd..82cfc67a4a 100644 --- a/include/infill/LightningLayer.h +++ b/include/infill/LightningLayer.h @@ -68,7 +68,7 @@ class LightningLayer const coord_t supporting_radius, const coord_t wall_supporting_radius); - LinesSet convertToLines(const Shape& limit_to_outline, const coord_t line_width) const; + OpenLinesSet convertToLines(const Shape& limit_to_outline, const coord_t line_width) const; coord_t getWeightedDistance(const Point2LL& boundary_loc, const Point2LL& unsupported_location); diff --git a/include/infill/LightningTreeNode.h b/include/infill/LightningTreeNode.h index 877c55d8f9..3f18499a1e 100644 --- a/include/infill/LightningTreeNode.h +++ b/include/infill/LightningTreeNode.h @@ -240,7 +240,7 @@ class LightningTreeNode : public std::enable_shared_from_this * * \param output all branches in this tree connected into polylines */ - void convertToPolylines(LinesSet& output, const coord_t line_width) const; + void convertToPolylines(OpenLinesSet& output, const coord_t line_width) const; /*! If this was ever a direct child of the root, it'll have a previous grounding location. * @@ -259,9 +259,9 @@ class LightningTreeNode : public std::enable_shared_from_this * \param long_line a reference to a polyline in \p output which to continue building on in the recursion * \param output all branches in this tree connected into polylines */ - void convertToPolylines(size_t long_line_idx, LinesSet& output) const; + void convertToPolylines(size_t long_line_idx, OpenLinesSet& output) const; - void removeJunctionOverlap(LinesSet& polylines, const coord_t line_width) const; + void removeJunctionOverlap(OpenLinesSet& polylines, const coord_t line_width) const; bool is_root_; Point2LL p_; diff --git a/include/infill/NoZigZagConnectorProcessor.h b/include/infill/NoZigZagConnectorProcessor.h index 8279205763..041f491bae 100644 --- a/include/infill/NoZigZagConnectorProcessor.h +++ b/include/infill/NoZigZagConnectorProcessor.h @@ -20,7 +20,7 @@ class LinesSet; class NoZigZagConnectorProcessor : public ZigzagConnectorProcessor { public: - NoZigZagConnectorProcessor(const PointMatrix& rotation_matrix, LinesSet& result) + NoZigZagConnectorProcessor(const PointMatrix& rotation_matrix, OpenLinesSet& result) : ZigzagConnectorProcessor( rotation_matrix, result, diff --git a/include/infill/SubDivCube.h b/include/infill/SubDivCube.h index 0be7790c00..e16b4a2149 100644 --- a/include/infill/SubDivCube.h +++ b/include/infill/SubDivCube.h @@ -4,9 +4,10 @@ #ifndef INFILL_SUBDIVCUBE_H #define INFILL_SUBDIVCUBE_H +#include "geometry/OpenLinesSet.h" #include "geometry/Point2LL.h" -#include "geometry/Point3Matrix.h" #include "geometry/Point3LL.h" +#include "geometry/Point3Matrix.h" #include "geometry/PointMatrix.h" #include "settings/types/LayerIndex.h" #include "settings/types/Ratio.h" @@ -16,10 +17,6 @@ namespace cura class Polygon; class SliceMeshStorage; -class OpenPolyline; - -template -class LinesSet; class SubDivCube { @@ -43,7 +40,7 @@ class SubDivCube * \param z the specified layer height * \param result (output) The resulting lines */ - void generateSubdivisionLines(const coord_t z, LinesSet& result); + void generateSubdivisionLines(const coord_t z, OpenLinesSet& result); private: /*! @@ -52,7 +49,7 @@ class SubDivCube * \param result (output) The resulting lines * \param directional_line_groups Array of 3 times a polylines. Used to keep track of line segments that are all pointing the same direction for line segment combining */ - void generateSubdivisionLines(const coord_t z, LinesSet (&directional_line_groups)[3]); + void generateSubdivisionLines(const coord_t z, OpenLinesSet (&directional_line_groups)[3]); struct CubeProperties { @@ -98,7 +95,7 @@ class SubDivCube * Adds the defined line to the specified polygons. It assumes that the specified polygons are all parallel lines. Combines line segments with touching ends closer than * epsilon. \param[out] group the polygons to add the line to \param from the first endpoint of the line \param to the second endpoint of the line */ - void addLineAndCombine(LinesSet& group, Point2LL from, Point2LL to); + void addLineAndCombine(OpenLinesSet& group, Point2LL from, Point2LL to); size_t depth_; //!< the recursion depth of the cube (0 is most recursed) Point3LL center_; //!< center location of the cube in absolute coordinates diff --git a/include/infill/ZigzagConnectorProcessor.h b/include/infill/ZigzagConnectorProcessor.h index e0880778b8..2b5f683501 100644 --- a/include/infill/ZigzagConnectorProcessor.h +++ b/include/infill/ZigzagConnectorProcessor.h @@ -6,6 +6,7 @@ #include +#include "geometry/OpenLinesSet.h" #include "geometry/Point2LL.h" namespace cura @@ -14,9 +15,6 @@ namespace cura class Polygon; class Shape; class PointMatrix; -class OpenPolyline; -template -class LinesSet; /*! * Processor class for processing the connections between lines which makes the infill a zigzag pattern. @@ -117,13 +115,7 @@ class ZigzagConnectorProcessor * \param skip_some_zags Whether to skip some zags * \param zag_skip_count Skip 1 zag in every N zags */ - ZigzagConnectorProcessor( - const PointMatrix& rotation_matrix, - LinesSet& result, - bool use_endpieces, - bool connected_endpieces, - bool skip_some_zags, - int zag_skip_count) + ZigzagConnectorProcessor(const PointMatrix& rotation_matrix, OpenLinesSet& result, bool use_endpieces, bool connected_endpieces, bool skip_some_zags, int zag_skip_count) : rotation_matrix_(rotation_matrix) , result_(result) , use_endpieces_(use_endpieces) @@ -203,7 +195,7 @@ class ZigzagConnectorProcessor protected: const PointMatrix& rotation_matrix_; //!< The rotation matrix used to enforce the infill angle - LinesSet& result_; //!< The result of the computation + OpenLinesSet& result_; //!< The result of the computation const bool use_endpieces_; //!< Whether to include end pieces or not const bool connected_endpieces_; //!< Whether the end pieces should be connected with the rest part of the infill diff --git a/include/plugins/converters.h b/include/plugins/converters.h index ed0aac9e8a..e3eca0a663 100644 --- a/include/plugins/converters.h +++ b/include/plugins/converters.h @@ -108,7 +108,7 @@ struct infill_generate_request : public details::converter>, Shape, LinesSet>> + converter>, Shape, OpenLinesSet>> { native_value_type operator()(const value_type& message) const; }; diff --git a/include/plugins/slots.h b/include/plugins/slots.h index 3abef56cf1..28db123fc0 100644 --- a/include/plugins/slots.h +++ b/include/plugins/slots.h @@ -52,7 +52,7 @@ struct simplify_default struct infill_generate_default { - std::tuple, Shape, LinesSet> operator()([[maybe_unused]] auto&&... args) + std::tuple, Shape, OpenLinesSet> operator()([[maybe_unused]] auto&&... args) { // this code is only reachable when no slot is registered while the infill type is requested to be // generated by a plugin; this should not be possible to set up in the first place. Return an empty diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 5db2025df9..ddf0177e59 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -376,7 +376,7 @@ class SliceDataStorage : public NoCopy SupportStorage support; std::vector skirt_brim[MAX_EXTRUDERS]; //!< Skirt/brim polygons per extruder, ordered from inner to outer polygons. - LinesSet support_brim; //!< brim lines for support, going from the edge of the support inward. \note Not ordered by inset. + ClosedLinesSet support_brim; //!< brim lines for support, going from the edge of the support inward. \note Not ordered by inset. // Storage for the outline of the raft-parts. Will be filled with lines when the GCode is generated. Shape raftBaseOutline; diff --git a/include/utils/MixedPolylineStitcher.h b/include/utils/MixedPolylineStitcher.h index 5d511ec60a..b87e6799dd 100644 --- a/include/utils/MixedPolylineStitcher.h +++ b/include/utils/MixedPolylineStitcher.h @@ -16,7 +16,7 @@ class MixedLinesSet; class MixedPolylineStitcher : public PolylineStitcher { public: - static void stitch(const LinesSet& lines, MixedLinesSet& result, coord_t max_stitch_distance = MM2INT(0.1), coord_t snap_distance = 10); + static void stitch(const OpenLinesSet& lines, MixedLinesSet& result, coord_t max_stitch_distance = MM2INT(0.1), coord_t snap_distance = 10); }; } // namespace cura diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 10a03f2a70..c49a0e01a0 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -618,7 +618,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Application::getInstance().communication_->sendLayerComplete(layer_nr, z, layer_height); - LinesSet raft_lines; + OpenLinesSet raft_lines; AngleDegrees fill_angle = (num_surface_layers + num_interface_layers) % 2 ? 45 : 135; // 90 degrees rotated from the interface layer. constexpr bool zig_zaggify_infill = false; constexpr bool connect_polygons = true; // causes less jerks, so better adhesion @@ -805,7 +805,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_outline_path = storage.raftInterfaceOutline.offset(-small_offset); raft_outline_path = Simplify(interface_settings).polygon(raft_outline_path); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage_.raft_interface_config.getLineWidth(); - LinesSet raft_lines; + OpenLinesSet raft_lines; AngleDegrees fill_angle = (num_surface_layers + num_interface_layers - raft_interface_layer) % 2 ? 45 : 135; // 90 degrees rotated from the first top layer. constexpr bool zig_zaggify_infill = true; constexpr bool connect_polygons = true; // why not? @@ -976,7 +976,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_outline_path = storage.raftSurfaceOutline.offset(-small_offset); raft_outline_path = Simplify(interface_settings).polygon(raft_outline_path); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage_.raft_surface_config.getLineWidth(); - LinesSet raft_lines; + OpenLinesSet raft_lines; AngleDegrees fill_angle = (num_surface_layers - raft_surface_layer) % 2 ? 45 : 135; // Alternate between -45 and +45 degrees, ending up 90 degrees rotated from the default skin angle. constexpr bool zig_zaggify_infill = true; @@ -1910,7 +1910,7 @@ bool FffGcodeWriter::processMultiLayerInfill( const bool connect_polygons = mesh.settings.get("connect_infill_polygons"); const size_t infill_multiplier = mesh.settings.get("infill_multiplier"); Shape infill_polygons; - LinesSet infill_lines; + OpenLinesSet infill_lines; std::vector infill_paths = part.infill_wall_toolpaths; for (size_t density_idx = part.infill_area_per_combine_per_density.size() - 1; (int)density_idx >= 0; density_idx--) { // combine different density infill areas (for gradual infill) @@ -2031,7 +2031,7 @@ bool FffGcodeWriter::processSingleLayerInfill( // Combine the 1 layer thick infill with the top/bottom skin and print that as one thing. Shape infill_polygons; std::vector> wall_tool_paths; // All wall toolpaths binned by inset_idx (inner) and by density_idx (outer) - LinesSet infill_lines; + OpenLinesSet infill_lines; const auto pattern = mesh.settings.get("infill_pattern"); const bool zig_zaggify_infill = mesh.settings.get("zig_zaggify_infill") || pattern == EFillMethod::ZIG_ZAG; @@ -2084,7 +2084,7 @@ bool FffGcodeWriter::processSingleLayerInfill( continue; } - LinesSet infill_lines_here; + OpenLinesSet infill_lines_here; Shape infill_polygons_here; // the highest density infill combines with the next to create a grid with density_factor 1 @@ -3123,7 +3123,7 @@ void FffGcodeWriter::processSkinPrintFeature( double fan_speed) const { Shape skin_polygons; - LinesSet skin_lines; + OpenLinesSet skin_lines; std::vector skin_paths; constexpr int infill_multiplier = 1; @@ -3498,7 +3498,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer Shape support_polygons; std::vector wall_toolpaths_here; - LinesSet support_lines; + OpenLinesSet support_lines; const size_t max_density_idx = part.infill_area_per_combine_per_density_.size() - 1; for (size_t density_idx = max_density_idx; (density_idx + 1) > 0; --density_idx) { @@ -3754,7 +3754,7 @@ bool FffGcodeWriter::addSupportRoofsToGCode(const SliceDataStorage& storage, con pocket_size); Shape roof_polygons; std::vector roof_paths; - LinesSet roof_lines; + OpenLinesSet roof_lines; roof_computation.generate(roof_paths, roof_polygons, roof_lines, roof_extruder.settings_, gcode_layer.getLayerNr(), SectionType::SUPPORT); if ((gcode_layer.getLayerNr() == 0 && wall.empty()) || (gcode_layer.getLayerNr() > 0 && roof_paths.empty() && roof_polygons.empty() && roof_lines.empty())) { @@ -3871,7 +3871,7 @@ bool FffGcodeWriter::addSupportBottomsToGCode(const SliceDataStorage& storage, L pocket_size); Shape bottom_polygons; std::vector bottom_paths; - LinesSet bottom_lines; + OpenLinesSet bottom_lines; bottom_computation.generate(bottom_paths, bottom_polygons, bottom_lines, bottom_extruder.settings_, gcode_layer.getLayerNr(), SectionType::SUPPORT); if (bottom_paths.empty() && bottom_polygons.empty() && bottom_lines.empty()) { diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 3361ebaa45..6a7281617a 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -576,7 +576,7 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz } std::vector new_parts; - LinesSet new_polylines; + OpenLinesSet new_polylines; for (const size_t other_mesh_idx : mesh_order) { // limit the infill mesh's outline to within the infill of all meshes with lower order diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 4f749493af..da4b44ad89 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -18,6 +18,7 @@ #include "Slice.h" #include "WipeScriptConfig.h" #include "communication/Communication.h" +#include "geometry/OpenPolyline.h" #include "pathPlanning/Comb.h" #include "pathPlanning/CombPaths.h" #include "plugins/slots.h" @@ -804,7 +805,7 @@ void LayerPlan::addWallLine( // the default_config. Since the original line segment was straight we can simply print // to the first and last point of the intersected line segments alternating between // roofing and default_config's. - LinesSet line_polys; + OpenLinesSet line_polys; line_polys.addSegment(p0, p1); constexpr bool restitch = false; // only a single line doesn't need stitching auto roofing_line_segments = roofing_mask_.intersection(line_polys, restitch); @@ -877,7 +878,7 @@ void LayerPlan::addWallLine( // determine which segments of the line are bridges - LinesSet line_polys; + OpenLinesSet line_polys; line_polys.addSegment(p0, p1); constexpr bool restitch = false; // only a single line doesn't need stitching line_polys = bridge_wall_mask_.intersection(line_polys, restitch); @@ -1049,7 +1050,7 @@ void LayerPlan::addWall( // determine which segments of the line are bridges - LinesSet line_polys; + OpenLinesSet line_polys; line_polys.addSegment(p0.p_, p1.p_); constexpr bool restitch = false; // only a single line doesn't need stitching line_polys = bridge_wall_mask_.intersection(line_polys, restitch); @@ -1546,7 +1547,7 @@ void LayerPlan::addLinesMonotonic( // Order monotonically, except for line-segments which stay in the excluded areas (read: close to the walls) consecutively. PathOrderMonotonic order(monotonic_direction, max_adjacent_distance, last_position); - LinesSet left_over; + OpenLinesSet left_over; bool last_would_have_been_excluded = false; for (size_t line_idx = 0; line_idx < line_order.paths_.size(); ++line_idx) { @@ -2686,7 +2687,7 @@ void LayerPlan::setRoofingMask(const Shape& polys) } template void LayerPlan::addLinesByOptimizer( - const LinesSet& lines, + const OpenLinesSet& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const bool enable_travel_optimization, @@ -2698,7 +2699,7 @@ template void LayerPlan::addLinesByOptimizer( const std::unordered_multimap& order_requirements); template void LayerPlan::addLinesByOptimizer( - const LinesSet& lines, + const ClosedLinesSet& lines, const GCodePathConfig& config, const SpaceFillType space_fill_type, const bool enable_travel_optimization, diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index 9472471ab8..d6f32635e5 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -8,6 +8,7 @@ #include "Application.h" #include "ExtruderTrain.h" #include "Slice.h" +#include "geometry/OpenPolyline.h" #include "geometry/Shape.h" #include "settings/EnumSettings.h" #include "settings/types/Ratio.h" @@ -247,7 +248,7 @@ coord_t SkirtBrim::generateOffset(const Offset& offset, Shape& covered_area, std // limit brim lines to allowed areas, stitch them and store them in the result brim = Simplify(Application::getInstance().current_slice_->scene.extruders[offset.extruder_nr_].settings_).polygon(brim); - LinesSet brim_lines = allowed_areas_per_extruder[offset.extruder_nr_].intersection(brim, false); + OpenLinesSet brim_lines = allowed_areas_per_extruder[offset.extruder_nr_].intersection(brim, false); length_added = brim_lines.length(); Shape newly_covered = brim_lines.offset(extruder_config.line_width_ / 2 + 10, ClipperLib::jtRound); diff --git a/src/TopSurface.cpp b/src/TopSurface.cpp index 2bb57ce274..8203ccb2ce 100644 --- a/src/TopSurface.cpp +++ b/src/TopSurface.cpp @@ -5,6 +5,7 @@ #include "ExtruderTrain.h" #include "LayerPlan.h" +#include "geometry/OpenPolyline.h" #include "infill.h" #include "sliceDataStorage.h" diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 0ef1fd1fb8..95d5279598 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -16,6 +16,7 @@ #include "Application.h" //To get settings. #include "TreeSupportUtils.h" +#include "geometry/OpenPolyline.h" #include "infill/SierpinskiFillProvider.h" #include "settings/EnumSettings.h" #include "utils/Simplify.h" @@ -105,7 +106,7 @@ TreeSupportTipGenerator::TreeSupportTipGenerator(const SliceMeshStorage& mesh, T } -std::vector TreeSupportTipGenerator::convertLinesToInternal(const LinesSet& polylines, LayerIndex layer_idx) +std::vector TreeSupportTipGenerator::convertLinesToInternal(const OpenLinesSet& polylines, LayerIndex layer_idx) { // NOTE: The volumes below (on which '.inside(p, true)' is called each time below) are the same each time. The values being calculated here are strictly local as well. // So they could in theory be pre-calculated here (outside of the loop). However, when I refatored it to be that way, it seemed to cause deadlocks each time for some @@ -159,9 +160,9 @@ std::vector TreeSupportTipGenerator::c return result; } -LinesSet TreeSupportTipGenerator::convertInternalToLines(std::vector lines) +OpenLinesSet TreeSupportTipGenerator::convertInternalToLines(std::vector lines) { - LinesSet result; + OpenLinesSet result; for (const LineInformation& line : lines) { OpenPolyline path; @@ -251,9 +252,9 @@ std::pair, std::vector>>>(keep, set_free); } -LinesSet TreeSupportTipGenerator::ensureMaximumDistancePolyline(const LinesSet& input, coord_t distance, size_t min_points, bool enforce_distance) const +OpenLinesSet TreeSupportTipGenerator::ensureMaximumDistancePolyline(const OpenLinesSet& input, coord_t distance, size_t min_points, bool enforce_distance) const { - LinesSet result; + OpenLinesSet result; for (OpenPolyline part : input) { if (part.size() == 0) @@ -889,7 +890,7 @@ void TreeSupportTipGenerator::generateTips( = relevant_forbidden.offset(EPSILON) .unionPolygons(); // Prevent rounding errors down the line, points placed directly on the line of the forbidden area may not be added otherwise. - std::function(const Shape&, bool, LayerIndex)> generateLines = [&](const Shape& area, bool roof, LayerIndex generate_layer_idx) + std::function generateLines = [&](const Shape& area, bool roof, LayerIndex generate_layer_idx) { coord_t upper_line_distance = support_supporting_branch_distance_; coord_t line_distance = std::max(roof ? support_roof_line_distance_ : support_tree_branch_distance_, upper_line_distance); @@ -987,7 +988,7 @@ void TreeSupportTipGenerator::generateTips( } std::vector overhang_lines; - LinesSet polylines = ensureMaximumDistancePolyline(generateLines(remaining_overhang_part, false, layer_idx), config_.min_radius, 1, false); + OpenLinesSet polylines = ensureMaximumDistancePolyline(generateLines(remaining_overhang_part, false, layer_idx), config_.min_radius, 1, false); // ^^^ Support_line_width to form a line here as otherwise most will be unsupported. // Technically this violates branch distance, but not only is this the only reasonable choice, // but it ensures consistent behavior as some infill patterns generate each line segment as its own polyline part causing a similar line forming behavior. @@ -1070,7 +1071,7 @@ void TreeSupportTipGenerator::generateTips( // The tip positions are determined here. // todo can cause inconsistent support density if a line exactly aligns with the model - LinesSet polylines = ensureMaximumDistancePolyline( + OpenLinesSet polylines = ensureMaximumDistancePolyline( generateLines(overhang_outset, roof_allowed_for_this_part, layer_idx + roof_allowed_for_this_part), ! roof_allowed_for_this_part ? config_.min_radius * 2 : use_fake_roof_ ? support_supporting_branch_distance_ diff --git a/src/bridge.cpp b/src/bridge.cpp index 726eccdb4c..55b7b8e8cd 100644 --- a/src/bridge.cpp +++ b/src/bridge.cpp @@ -4,6 +4,7 @@ #include "bridge.h" #include "geometry/OpenLinesSet.h" +#include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" #include "settings/types/Ratio.h" #include "sliceDataStorage.h" diff --git a/src/geometry/LinesSet.cpp b/src/geometry/LinesSet.cpp index b24aac2009..c1fa4f8172 100644 --- a/src/geometry/LinesSet.cpp +++ b/src/geometry/LinesSet.cpp @@ -5,7 +5,9 @@ #include +#include "geometry/ClosedLinesSet.h" #include "geometry/OpenLinesSet.h" +#include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" #include "geometry/Shape.h" @@ -14,7 +16,7 @@ namespace cura template<> template<> -LinesSet::LinesSet(ClipperLib::Paths&& paths) +LinesSet::LinesSet(ClipperLib::Paths&& paths) { reserve(paths.size()); for (ClipperLib::Path& path : paths) @@ -66,7 +68,7 @@ size_t LinesSet::pointCount() const } template<> -void LinesSet::addSegment(const Point2LL& from, const Point2LL& to) +void OpenLinesSet::addSegment(const Point2LL& from, const Point2LL& to) { lines_.emplace_back(std::initializer_list{ from, to }); } @@ -190,7 +192,7 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType join_type } template<> -Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const +Shape OpenLinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const { if (empty() || distance == 0) { @@ -317,34 +319,34 @@ void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib } } -template size_t LinesSet::pointCount() const; -template void LinesSet::removeAt(size_t index); -template void LinesSet::splitIntoSegments(OpenLinesSet& result) const; -template OpenLinesSet LinesSet::splitIntoSegments() const; -template coord_t LinesSet::length() const; -template Shape LinesSet::createTubeShape(const coord_t inner_offset, const coord_t outer_offset) const; -template void LinesSet::translate(const Point2LL& delta); -template void LinesSet::removeDegenerateVerts(); -template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; -template void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; -template void LinesSet::push_back(const OpenPolyline& line, CheckNonEmptyParam checkNonEmpty); -template void LinesSet::push_back(OpenPolyline&& line, CheckNonEmptyParam checkNonEmpty); -template void LinesSet::push_back(LinesSet&& lines_set); - -template size_t LinesSet::pointCount() const; -template void LinesSet::removeAt(size_t index); -template void LinesSet::splitIntoSegments(OpenLinesSet& result) const; -template OpenLinesSet LinesSet::splitIntoSegments() const; -template coord_t LinesSet::length() const; -template Shape LinesSet::createTubeShape(const coord_t inner_offset, const coord_t outer_offset) const; -template void LinesSet::translate(const Point2LL& delta); -template void LinesSet::removeDegenerateVerts(); -template void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; -template void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; -template void LinesSet::push_back(const ClosedPolyline& line, CheckNonEmptyParam checkNonEmpty); -template void LinesSet::push_back(ClosedPolyline&& line, CheckNonEmptyParam checkNonEmpty); -template void LinesSet::push_back(LinesSet&& lines_set); -template void LinesSet::push_back(LinesSet&& lines_set); +template size_t OpenLinesSet::pointCount() const; +template void OpenLinesSet::removeAt(size_t index); +template void OpenLinesSet::splitIntoSegments(OpenLinesSet& result) const; +template OpenLinesSet OpenLinesSet::splitIntoSegments() const; +template coord_t OpenLinesSet::length() const; +template Shape OpenLinesSet::createTubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template void OpenLinesSet::translate(const Point2LL& delta); +template void OpenLinesSet::removeDegenerateVerts(); +template void OpenLinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; +template void OpenLinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; +template void OpenLinesSet::push_back(const OpenPolyline& line, CheckNonEmptyParam checkNonEmpty); +template void OpenLinesSet::push_back(OpenPolyline&& line, CheckNonEmptyParam checkNonEmpty); +template void OpenLinesSet::push_back(OpenLinesSet&& lines_set); + +template size_t ClosedLinesSet::pointCount() const; +template void ClosedLinesSet::removeAt(size_t index); +template void ClosedLinesSet::splitIntoSegments(OpenLinesSet& result) const; +template OpenLinesSet ClosedLinesSet::splitIntoSegments() const; +template coord_t ClosedLinesSet::length() const; +template Shape ClosedLinesSet::createTubeShape(const coord_t inner_offset, const coord_t outer_offset) const; +template void ClosedLinesSet::translate(const Point2LL& delta); +template void ClosedLinesSet::removeDegenerateVerts(); +template void ClosedLinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; +template void ClosedLinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; +template void ClosedLinesSet::push_back(const ClosedPolyline& line, CheckNonEmptyParam checkNonEmpty); +template void ClosedLinesSet::push_back(ClosedPolyline&& line, CheckNonEmptyParam checkNonEmpty); +template void ClosedLinesSet::push_back(ClosedLinesSet&& lines_set); +template void ClosedLinesSet::push_back(LinesSet&& lines_set); template size_t LinesSet::pointCount() const; template void LinesSet::removeAt(size_t index); diff --git a/src/geometry/MixedLinesSet.cpp b/src/geometry/MixedLinesSet.cpp index 88714178e7..0dc71ab943 100644 --- a/src/geometry/MixedLinesSet.cpp +++ b/src/geometry/MixedLinesSet.cpp @@ -111,7 +111,7 @@ void MixedLinesSet::push_back(const PolylinePtr& line) std::vector::push_back(line); } -void MixedLinesSet::push_back(LinesSet&& lines_set) +void MixedLinesSet::push_back(OpenLinesSet&& lines_set) { reserve(size() + lines_set.size()); for (OpenPolyline& line : lines_set) @@ -120,7 +120,7 @@ void MixedLinesSet::push_back(LinesSet&& lines_set) } } -void MixedLinesSet::push_back(const LinesSet& lines_set) +void MixedLinesSet::push_back(const OpenLinesSet& lines_set) { reserve(size() + lines_set.size()); for (const OpenPolyline& line : lines_set) @@ -129,7 +129,7 @@ void MixedLinesSet::push_back(const LinesSet& lines_set) } } -void MixedLinesSet::push_back(LinesSet&& lines_set) +void MixedLinesSet::push_back(ClosedLinesSet&& lines_set) { reserve(size() + lines_set.size()); for (ClosedPolyline& line : lines_set) diff --git a/src/geometry/Polyline.cpp b/src/geometry/Polyline.cpp index bd43c9c948..bf771b6846 100644 --- a/src/geometry/Polyline.cpp +++ b/src/geometry/Polyline.cpp @@ -5,7 +5,9 @@ #include +#include "geometry/LinesSet.h" #include "geometry/OpenLinesSet.h" +#include "geometry/OpenPolyline.h" #include "settings/types/Angle.h" #include "utils/linearAlg2D.h" diff --git a/src/geometry/Shape.cpp b/src/geometry/Shape.cpp index 412346b3ed..270047cbdc 100644 --- a/src/geometry/Shape.cpp +++ b/src/geometry/Shape.cpp @@ -24,6 +24,7 @@ #include #include "geometry/MixedLinesSet.h" +#include "geometry/OpenPolyline.h" #include "geometry/PartsView.h" #include "geometry/Polygon.h" #include "geometry/SingleShape.h" @@ -320,7 +321,7 @@ OpenLinesSet Shape::intersection(const LinesSet& polylines, bool resti return OpenLinesSet(); } - LinesSet split_polylines = polylines.splitIntoSegments(); + OpenLinesSet split_polylines = polylines.splitIntoSegments(); ClipperLib::PolyTree result; ClipperLib::Clipper clipper(clipper_init); @@ -972,8 +973,8 @@ void Shape::applyMatrix(const Point3Matrix& matrix) } #endif -template LinesSet Shape::intersection(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; -template LinesSet Shape::intersection(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; -template LinesSet Shape::intersection(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; +template OpenLinesSet Shape::intersection(const OpenLinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; +template OpenLinesSet Shape::intersection(const ClosedLinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; +template OpenLinesSet Shape::intersection(const LinesSet& polylines, bool restitch, const coord_t max_stitch_distance) const; } // namespace cura diff --git a/src/infill.cpp b/src/infill.cpp index 9cb7b8d7f6..1c3bfd2e71 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -11,6 +11,7 @@ #include #include "WallToolPaths.h" +#include "geometry/OpenPolyline.h" #include "geometry/PointMatrix.h" #include "infill/GyroidInfill.h" #include "infill/ImageBasedDensityProvider.h" @@ -84,7 +85,7 @@ Shape Infill::generateWallToolPaths( void Infill::generate( std::vector& toolpaths, Shape& result_polygons, - LinesSet& result_lines, + OpenLinesSet& result_lines, const Settings& settings, int layer_idx, SectionType section_type, @@ -180,7 +181,7 @@ void Infill::generate( zig_zaggify_ = false; } Shape generated_result_polygons; - LinesSet generated_result_lines; + OpenLinesSet generated_result_lines; _generate(toolpaths, generated_result_polygons, generated_result_lines, settings, cross_fill_provider, lightning_trees, mesh); @@ -194,7 +195,7 @@ void Infill::generate( //_generate may clear() the generated_result_lines, but this is an output variable that may contain data before we start. // So make sure we provide it with a Shape that is safe to clear and only add stuff to result_lines. Shape generated_result_polygons; - LinesSet generated_result_lines; + OpenLinesSet generated_result_lines; _generate(toolpaths, generated_result_polygons, generated_result_lines, settings, cross_fill_provider, lightning_trees, mesh); @@ -252,7 +253,7 @@ void Infill::generate( void Infill::_generate( std::vector& toolpaths, Shape& result_polygons, - LinesSet& result_lines, + OpenLinesSet& result_lines, const Settings& settings, const std::shared_ptr& cross_fill_provider, const std::shared_ptr& lightning_trees, @@ -349,14 +350,14 @@ void Infill::_generate( && (zig_zaggify_ || pattern_ == EFillMethod::CROSS || pattern_ == EFillMethod::CROSS_3D || pattern_ == EFillMethod::CUBICSUBDIV || pattern_ == EFillMethod::GYROID || pattern_ == EFillMethod::ZIG_ZAG)) { // don't stich for non-zig-zagged line infill types - LinesSet stitched_lines; + OpenLinesSet stitched_lines; OpenPolylineStitcher::stitch(result_lines, stitched_lines, result_polygons, infill_line_width_); result_lines = std::move(stitched_lines); } result_lines = simplifier.polyline(result_lines); } -void Infill::multiplyInfill(Shape& result_polygons, LinesSet& result_lines) +void Infill::multiplyInfill(Shape& result_polygons, OpenLinesSet& result_lines) { if (pattern_ == EFillMethod::CONCENTRIC) { @@ -412,20 +413,20 @@ void Infill::multiplyInfill(Shape& result_polygons, LinesSet& resu result_polygons.push_back(result); if (! zig_zaggify_) { - LinesSet polylines = inner_contour_.intersection(static_cast>(result_polygons)); + OpenLinesSet polylines = inner_contour_.intersection(static_cast>(result_polygons)); result_polygons.clear(); OpenPolylineStitcher::stitch(polylines, result_lines, result_polygons, infill_line_width_); } } -void Infill::generateGyroidInfill(LinesSet& result_lines, Shape& result_polygons) +void Infill::generateGyroidInfill(OpenLinesSet& result_lines, Shape& result_polygons) { - LinesSet line_segments; + OpenLinesSet line_segments; GyroidInfill::generateTotalGyroidInfill(line_segments, zig_zaggify_, line_distance_, inner_contour_, z_); OpenPolylineStitcher::stitch(line_segments, result_lines, result_polygons, infill_line_width_); } -void Infill::generateLightningInfill(const std::shared_ptr& trees, LinesSet& result_lines) +void Infill::generateLightningInfill(const std::shared_ptr& trees, OpenLinesSet& result_lines) { // Don't need to support areas smaller than line width, as they are always within radius: if (std::abs(inner_contour_.area()) < infill_line_width_ || ! trees) @@ -463,13 +464,13 @@ void Infill::generateConcentricInfill(std::vector& toolpaths } } -void Infill::generateGridInfill(LinesSet& result) +void Infill::generateGridInfill(OpenLinesSet& result) { generateLineInfill(result, line_distance_, fill_angle_, 0); generateLineInfill(result, line_distance_, fill_angle_ + 90, 0); } -void Infill::generateCubicInfill(LinesSet& result) +void Infill::generateCubicInfill(OpenLinesSet& result) { const coord_t shift = one_over_sqrt_2 * z_; generateLineInfill(result, line_distance_, fill_angle_, shift); @@ -477,19 +478,19 @@ void Infill::generateCubicInfill(LinesSet& result) generateLineInfill(result, line_distance_, fill_angle_ + 240, shift); } -void Infill::generateTetrahedralInfill(LinesSet& result) +void Infill::generateTetrahedralInfill(OpenLinesSet& result) { generateHalfTetrahedralInfill(0.0, 0, result); generateHalfTetrahedralInfill(0.0, 90, result); } -void Infill::generateQuarterCubicInfill(LinesSet& result) +void Infill::generateQuarterCubicInfill(OpenLinesSet& result) { generateHalfTetrahedralInfill(0.0, 0, result); generateHalfTetrahedralInfill(0.5, 90, result); } -void Infill::generateHalfTetrahedralInfill(double pattern_z_shift, int angle_shift, LinesSet& result) +void Infill::generateHalfTetrahedralInfill(double pattern_z_shift, int angle_shift, OpenLinesSet& result) { const coord_t period = line_distance_ * 2; coord_t shift = coord_t(one_over_sqrt_2 * (z_ + pattern_z_shift * period * 2)) % period; @@ -500,29 +501,29 @@ void Infill::generateHalfTetrahedralInfill(double pattern_z_shift, int angle_shi generateLineInfill(result, period, fill_angle_ + angle_shift, -shift); } -void Infill::generateTriangleInfill(LinesSet& result) +void Infill::generateTriangleInfill(OpenLinesSet& result) { generateLineInfill(result, line_distance_, fill_angle_, 0); generateLineInfill(result, line_distance_, fill_angle_ + 60, 0); generateLineInfill(result, line_distance_, fill_angle_ + 120, 0); } -void Infill::generateTrihexagonInfill(LinesSet& result) +void Infill::generateTrihexagonInfill(OpenLinesSet& result) { generateLineInfill(result, line_distance_, fill_angle_, 0); generateLineInfill(result, line_distance_, fill_angle_ + 60, 0); generateLineInfill(result, line_distance_, fill_angle_ + 120, line_distance_ / 2); } -void Infill::generateCubicSubDivInfill(LinesSet& result, const SliceMeshStorage& mesh) +void Infill::generateCubicSubDivInfill(OpenLinesSet& result, const SliceMeshStorage& mesh) { - LinesSet uncropped; + OpenLinesSet uncropped; mesh.base_subdiv_cube->generateSubdivisionLines(z_, uncropped); constexpr bool restitch = false; // cubic subdivision lines are always single line segments - not polylines consisting of multiple segments. result = outer_contour_.offset(infill_overlap_).intersection(uncropped, restitch); } -void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provider, Shape& result_polygons, LinesSet& result_lines) +void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provider, Shape& result_polygons, OpenLinesSet& result_lines) { Polygon cross_pattern_polygon = cross_fill_provider.generate(pattern_, z_, infill_line_width_, pocket_size_); @@ -540,15 +541,15 @@ void Infill::generateCrossInfill(const SierpinskiFillProvider& cross_fill_provid else { // make the polyline closed in order to handle cross_pattern_polygon as a polyline, rather than a closed polygon - LinesSet cross_pattern_polylines; + OpenLinesSet cross_pattern_polylines; cross_pattern_polylines.push_back(cross_pattern_polygon.toPseudoOpenPolyline()); - LinesSet poly_lines = inner_contour_.intersection(cross_pattern_polylines); + OpenLinesSet poly_lines = inner_contour_.intersection(cross_pattern_polylines); OpenPolylineStitcher::stitch(poly_lines, result_lines, result_polygons, infill_line_width_); } } void Infill::addLineInfill( - LinesSet& result, + OpenLinesSet& result, const PointMatrix& rotation_matrix, const int scanline_min_idx, const int line_distance, @@ -589,7 +590,7 @@ coord_t Infill::getShiftOffsetFromInfillOriginAndRotation(const double& infill_r return 0; } -void Infill::generateLineInfill(LinesSet& result, int line_distance, const double& infill_rotation, coord_t shift) +void Infill::generateLineInfill(OpenLinesSet& result, int line_distance, const double& infill_rotation, coord_t shift) { shift += getShiftOffsetFromInfillOriginAndRotation(infill_rotation); PointMatrix rotation_matrix(infill_rotation); @@ -599,7 +600,7 @@ void Infill::generateLineInfill(LinesSet& result, int line_distanc } -void Infill::generateZigZagInfill(LinesSet& result, const coord_t line_distance, const double& infill_rotation) +void Infill::generateZigZagInfill(OpenLinesSet& result, const coord_t line_distance, const double& infill_rotation) { const coord_t shift = getShiftOffsetFromInfillOriginAndRotation(infill_rotation); @@ -632,7 +633,7 @@ void Infill::generateZigZagInfill(LinesSet& result, const coord_t * while I also call a boundary segment leaving from an even scanline toward the right as belonging to an even scansegment. */ void Infill::generateLinearBasedInfill( - LinesSet& result, + OpenLinesSet& result, const int line_distance, const PointMatrix& rotation_matrix, ZigzagConnectorProcessor& zigzag_connector_processor, @@ -845,7 +846,7 @@ void Infill::resolveIntersection(const coord_t at_distance, const Point2LL& inte } } -void Infill::connectLines(LinesSet& result_lines) +void Infill::connectLines(OpenLinesSet& result_lines) { UnionFind connected_lines; // Keeps track of which lines are connected to which. for (const std::vector>& crossings_on_polygon : crossings_on_line_) diff --git a/src/infill/GyroidInfill.cpp b/src/infill/GyroidInfill.cpp index 8641e995ef..5ab658ff19 100644 --- a/src/infill/GyroidInfill.cpp +++ b/src/infill/GyroidInfill.cpp @@ -20,7 +20,7 @@ GyroidInfill::~GyroidInfill() { } -void GyroidInfill::generateTotalGyroidInfill(LinesSet& result_lines, bool zig_zaggify, coord_t line_distance, const Shape& in_outline, coord_t z) +void GyroidInfill::generateTotalGyroidInfill(OpenLinesSet& result_lines, bool zig_zaggify, coord_t line_distance, const Shape& in_outline, coord_t z) { // generate infill based on the gyroid equation: sin_x * cos_y + sin_y * cos_z + sin_z * cos_x = 0 // kudos to the author of the Slic3r implementation equation code, the equation code here is based on that @@ -41,7 +41,7 @@ void GyroidInfill::generateTotalGyroidInfill(LinesSet& result_line const double sin_z = std::sin(z_rads); std::vector odd_line_coords; std::vector even_line_coords; - LinesSet result; + OpenLinesSet result; std::vector chains[2]; // [start_points[], end_points[]] std::vector connected_to[2]; // [chain_indices[], chain_indices[]] std::vector line_numbers; // which row/column line a chain is part of @@ -87,7 +87,7 @@ void GyroidInfill::generateTotalGyroidInfill(LinesSet& result_line else if (last_inside != current_inside) { // line hits the boundary, add the part that's inside the boundary - LinesSet line; + OpenLinesSet line; line.addSegment(last, current); constexpr bool restitch = false; // only a single line doesn't need stitching line = in_outline.intersection(line, restitch); @@ -179,7 +179,7 @@ void GyroidInfill::generateTotalGyroidInfill(LinesSet& result_line else if (last_inside != current_inside) { // line hits the boundary, add the part that's inside the boundary - LinesSet line; + OpenLinesSet line; line.addSegment(last, current); constexpr bool restitch = false; // only a single line doesn't need stitching line = in_outline.intersection(line, restitch); diff --git a/src/infill/LightningLayer.cpp b/src/infill/LightningLayer.cpp index d7c575290a..9ecb401c41 100644 --- a/src/infill/LightningLayer.cpp +++ b/src/infill/LightningLayer.cpp @@ -5,6 +5,7 @@ #include // advance +#include "geometry/OpenPolyline.h" #include "infill/LightningDistanceField.h" #include "infill/LightningTreeNode.h" #include "sliceDataStorage.h" @@ -217,9 +218,9 @@ void LightningLayer::reconnectRoots( } // Returns 'added someting'. -LinesSet LightningLayer::convertToLines(const Shape& limit_to_outline, const coord_t line_width) const +OpenLinesSet LightningLayer::convertToLines(const Shape& limit_to_outline, const coord_t line_width) const { - LinesSet result_lines; + OpenLinesSet result_lines; if (tree_roots.empty()) { return result_lines; diff --git a/src/infill/LightningTreeNode.cpp b/src/infill/LightningTreeNode.cpp index 6fb978d895..76ef91dbe1 100644 --- a/src/infill/LightningTreeNode.cpp +++ b/src/infill/LightningTreeNode.cpp @@ -355,16 +355,16 @@ const std::optional& LightningTreeNode::getLastGroundingLocation() con return last_grounding_location_; } -void LightningTreeNode::convertToPolylines(LinesSet& output, const coord_t line_width) const +void LightningTreeNode::convertToPolylines(OpenLinesSet& output, const coord_t line_width) const { - LinesSet result; + OpenLinesSet result; result.emplace_back(); convertToPolylines(0, result); removeJunctionOverlap(result, line_width); output.push_back(result); } -void LightningTreeNode::convertToPolylines(size_t long_line_idx, LinesSet& output) const +void LightningTreeNode::convertToPolylines(size_t long_line_idx, OpenLinesSet& output) const { if (children_.empty()) { @@ -386,7 +386,7 @@ void LightningTreeNode::convertToPolylines(size_t long_line_idx, LinesSet& result_lines, const coord_t line_width) const +void LightningTreeNode::removeJunctionOverlap(OpenLinesSet& result_lines, const coord_t line_width) const { const coord_t reduction = line_width / 2; // TODO make configurable? for (auto poly_it = result_lines.begin(); poly_it != result_lines.end();) diff --git a/src/infill/SubDivCube.cpp b/src/infill/SubDivCube.cpp index 5fe15a2c7c..a3490a9add 100644 --- a/src/infill/SubDivCube.cpp +++ b/src/infill/SubDivCube.cpp @@ -5,6 +5,7 @@ #include +#include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" #include "geometry/Shape.h" #include "settings/types/Angle.h" //For the infill angle. @@ -85,19 +86,19 @@ void SubDivCube::precomputeOctree(SliceMeshStorage& mesh, const Point2LL& infill mesh.base_subdiv_cube = std::make_shared(mesh, center, curr_recursion_depth - 1); } -void SubDivCube::generateSubdivisionLines(const coord_t z, LinesSet& result) +void SubDivCube::generateSubdivisionLines(const coord_t z, OpenLinesSet& result) { if (cube_properties_per_recursion_step_.empty()) // Infill is set to 0%. { return; } - LinesSet directional_line_groups[3]; + OpenLinesSet directional_line_groups[3]; generateSubdivisionLines(z, directional_line_groups); for (int dir_idx = 0; dir_idx < 3; dir_idx++) { - LinesSet& line_group = directional_line_groups[dir_idx]; + OpenLinesSet& line_group = directional_line_groups[dir_idx]; for (unsigned int line_idx = 0; line_idx < line_group.size(); line_idx++) { result.addSegment(line_group[line_idx][0], line_group[line_idx][1]); @@ -105,7 +106,7 @@ void SubDivCube::generateSubdivisionLines(const coord_t z, LinesSet (&directional_line_groups)[3]) +void SubDivCube::generateSubdivisionLines(const coord_t z, OpenLinesSet (&directional_line_groups)[3]) { CubeProperties cube_properties = cube_properties_per_recursion_step_[depth_]; @@ -263,7 +264,7 @@ void SubDivCube::rotatePoint120(Point2LL& target) target.X = x; } -void SubDivCube::addLineAndCombine(LinesSet& group, Point2LL from, Point2LL to) +void SubDivCube::addLineAndCombine(OpenLinesSet& group, Point2LL from, Point2LL to) { int epsilon = 10; // the smallest distance of two points which are viewed as coincident (dist > 0 due to rounding errors) for (unsigned int idx = 0; idx < group.size(); idx++) diff --git a/src/layerPart.cpp b/src/layerPart.cpp index 7098411508..0be927a724 100644 --- a/src/layerPart.cpp +++ b/src/layerPart.cpp @@ -3,6 +3,7 @@ #include "layerPart.h" +#include "geometry/OpenPolyline.h" #include "progress/Progress.h" #include "settings/EnumSettings.h" //For ESurfaceMode. #include "settings/Settings.h" diff --git a/src/multiVolumes.cpp b/src/multiVolumes.cpp index 7e0e9eb838..774966b781 100644 --- a/src/multiVolumes.cpp +++ b/src/multiVolumes.cpp @@ -7,6 +7,7 @@ #include "Application.h" #include "Slice.h" +#include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" #include "settings/EnumSettings.h" #include "settings/types/LayerIndex.h" @@ -151,7 +152,7 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: } Shape new_outlines; - LinesSet new_polylines; + OpenLinesSet new_polylines; for (unsigned int carved_mesh_idx = 0; carved_mesh_idx < volumes.size(); carved_mesh_idx++) { const Mesh& carved_mesh = meshes[carved_mesh_idx]; diff --git a/src/path_ordering.cpp b/src/path_ordering.cpp index cbdf514467..63d4d47ef4 100644 --- a/src/path_ordering.cpp +++ b/src/path_ordering.cpp @@ -4,6 +4,7 @@ #include "path_ordering.h" //The definitions we're implementing here. #include "WallToolPaths.h" +#include "geometry/OpenPolyline.h" #include "sliceDataStorage.h" //For SliceLayerPart. namespace cura diff --git a/src/plugins/converters.cpp b/src/plugins/converters.cpp index de518aa9c2..f53d2cbc7c 100644 --- a/src/plugins/converters.cpp +++ b/src/plugins/converters.cpp @@ -11,6 +11,7 @@ #include "GCodePathConfig.h" #include "WallToolPaths.h" +#include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" #include "pathPlanning/GCodePath.h" #include "pathPlanning/SpeedDerivatives.h" @@ -212,7 +213,7 @@ infill_generate_response::native_value_type infill_generate_response::operator() { VariableWidthLines toolpaths; Shape result_polygons; - LinesSet result_lines; + OpenLinesSet result_lines; for (auto& tool_path : message.tool_paths().tool_paths()) { diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index 636f6ca0f7..f2ceebb72f 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -9,6 +9,7 @@ #include "ExtruderTrain.h" #include "FffProcessor.h" //To create a mesh group with if none is provided. #include "Slice.h" +#include "geometry/OpenPolyline.h" #include "infill/DensityProvider.h" // for destructor #include "infill/LightningGenerator.h" #include "infill/SierpinskiFillProvider.h" diff --git a/src/slicer.cpp b/src/slicer.cpp index 579515a974..adcfc615d9 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -12,6 +12,7 @@ #include "Application.h" #include "Slice.h" +#include "geometry/OpenPolyline.h" #include "plugins/slots.h" #include "raft.h" #include "settings/AdaptiveLayerHeights.h" diff --git a/src/utils/MixedPolylineStitcher.cpp b/src/utils/MixedPolylineStitcher.cpp index 3b2842a21d..50e49a9323 100644 --- a/src/utils/MixedPolylineStitcher.cpp +++ b/src/utils/MixedPolylineStitcher.cpp @@ -4,6 +4,7 @@ #include "utils/MixedPolylineStitcher.h" #include "geometry/MixedLinesSet.h" +#include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" #include "geometry/Shape.h" @@ -11,7 +12,7 @@ namespace cura { -void MixedPolylineStitcher::stitch(const LinesSet& lines, MixedLinesSet& result, coord_t max_stitch_distance, coord_t snap_distance) +void MixedPolylineStitcher::stitch(const OpenLinesSet& lines, MixedLinesSet& result, coord_t max_stitch_distance, coord_t snap_distance) { OpenLinesSet open_lines; ClosedLinesSet closed_lines; diff --git a/src/utils/PolylineStitcher.cpp b/src/utils/PolylineStitcher.cpp index 4be8805032..70ba6e849b 100644 --- a/src/utils/PolylineStitcher.cpp +++ b/src/utils/PolylineStitcher.cpp @@ -5,6 +5,7 @@ #include "geometry/ClosedLinesSet.h" #include "geometry/OpenLinesSet.h" +#include "geometry/OpenPolyline.h" #include "utils/ExtrusionLineStitcher.h" #include "utils/OpenPolylineStitcher.h" #include "utils/PolygonsPointIndex.h" @@ -228,13 +229,13 @@ template void PolylineStitcher -bool OpenPolylineStitcher::canReverse(const PathsPointIndex>&) +bool OpenPolylineStitcher::canReverse(const PathsPointIndex&) { return true; } template<> -bool PolylineStitcher::canReverse(const PathsPointIndex>&) +bool PolylineStitcher::canReverse(const PathsPointIndex&) { return true; } diff --git a/src/utils/Simplify.cpp b/src/utils/Simplify.cpp index b684ccab3c..3f8c3b7f1d 100644 --- a/src/utils/Simplify.cpp +++ b/src/utils/Simplify.cpp @@ -408,7 +408,7 @@ bool Simplify::remove(Polygonal& polygon, std::vector& to_delete, const si return false; } -template LinesSet Simplify::polyline(const LinesSet& polylines) const; -template LinesSet Simplify::polyline(const LinesSet& polylines) const; +template OpenLinesSet Simplify::polyline(const OpenLinesSet& polylines) const; +template ClosedLinesSet Simplify::polyline(const ClosedLinesSet& polylines) const; } // namespace cura diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index 07022274aa..0a97d52d31 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -106,7 +106,7 @@ std::vector PolygonUtils::spreadDotsArea(const Shape& polygons, Point2 Settings dummy_settings; Infill infill_gen(EFillMethod::LINES, false, false, polygons, 0, grid_size.X, 0, 1, 0, 0, 0, 0, 0); Shape result_polygons; - LinesSet result_lines; + OpenLinesSet result_lines; infill_gen.generate(dummy_toolpaths, result_polygons, result_lines, dummy_settings, 0, SectionType::DOTS); // FIXME: @jellespijker make sure the propper layer nr is used std::vector result; for (const OpenPolyline& line : result_lines) diff --git a/stress_benchmark/stress_benchmark.cpp b/stress_benchmark/stress_benchmark.cpp index 0fa07371a8..cd3cd4ce33 100644 --- a/stress_benchmark/stress_benchmark.cpp +++ b/stress_benchmark/stress_benchmark.cpp @@ -20,6 +20,7 @@ #include #include "WallsComputation.h" +#include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" #include "rapidjson/document.h" #include "rapidjson/stringbuffer.h" diff --git a/tests/InfillTest.cpp b/tests/InfillTest.cpp index dc2f20e2dd..ef6e730fdf 100644 --- a/tests/InfillTest.cpp +++ b/tests/InfillTest.cpp @@ -12,6 +12,7 @@ #include #include "ReadTestPolygons.h" +#include "geometry/OpenPolyline.h" #include "slicer.h" #include "utils/Coord_t.h" diff --git a/tests/PathOrderMonotonicTest.cpp b/tests/PathOrderMonotonicTest.cpp index d8c81186a1..8aa0168aa0 100644 --- a/tests/PathOrderMonotonicTest.cpp +++ b/tests/PathOrderMonotonicTest.cpp @@ -12,6 +12,7 @@ #include #include "ReadTestPolygons.h" +#include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" #include "infill.h" #include "slicer.h" diff --git a/tests/WallsComputationTest.cpp b/tests/WallsComputationTest.cpp index edbdfd35d9..98061d4cdc 100644 --- a/tests/WallsComputationTest.cpp +++ b/tests/WallsComputationTest.cpp @@ -11,6 +11,7 @@ #include #include "InsetOrderOptimizer.h" //Unit also under test. +#include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" //To create example polygons. #include "settings/Settings.h" //Settings to generate walls with. #include "sliceDataStorage.h" //Sl @@ -19,7 +20,6 @@ #ifdef WALLS_COMPUTATION_TEST_SVG_OUTPUT #include -#include "geometry/Polygon.h" #include "utils/SVG.h" #endif // WALLS_COMPUTATION_TEST_SVG_OUTPUT diff --git a/tests/integration/SlicePhaseTest.cpp b/tests/integration/SlicePhaseTest.cpp index a809d5e0f5..6145060cce 100644 --- a/tests/integration/SlicePhaseTest.cpp +++ b/tests/integration/SlicePhaseTest.cpp @@ -7,6 +7,7 @@ #include "Application.h" // To set up a slice with settings. #include "Slice.h" // To set up a scene to slice. +#include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" // Creating polygons to compare to sliced layers. #include "slicer.h" // Starts the slicing phase that we want to test. #include "utils/Coord_t.h" From 2b100798d806dde3527bd051b0f2c0974065aca3 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 26 Apr 2024 16:02:32 +0200 Subject: [PATCH 066/135] Removed extra documentation related to performance Those concerns are actually inherent to the language, so the developers should be aware of them. CURA-9830 --- include/geometry/ClosedPolyline.h | 35 ++----------------- include/geometry/LinesSet.h | 36 ++++--------------- include/geometry/MixedLinesSet.h | 58 ++++++------------------------- include/geometry/PointsSet.h | 27 +++----------- include/geometry/Polygon.h | 15 ++------ include/geometry/Polyline.h | 27 +++----------- include/geometry/Shape.h | 18 ++-------- 7 files changed, 34 insertions(+), 182 deletions(-) diff --git a/include/geometry/ClosedPolyline.h b/include/geometry/ClosedPolyline.h index 607ed4d6e7..12a60c0303 100644 --- a/include/geometry/ClosedPolyline.h +++ b/include/geometry/ClosedPolyline.h @@ -45,23 +45,15 @@ class ClosedPolyline : public Polyline { } - /*! - * \brief Creates a copy of the given polyline - * \warning A copy of the points list is made, so this constructor is somehow "slow" - */ + /*! \brief Creates a copy of the given polyline */ ClosedPolyline(const ClosedPolyline& other) = default; - /*! - * \brief Constructor that takes ownership of the inner points list from the given polyline - * \warning This constructor is fast because it does not allocate data, but it will clear - * the source object - */ + /*! \brief Constructor that takes ownership of the inner points list from the given polyline */ ClosedPolyline(ClosedPolyline&& other) = default; /*! * \brief Constructor with a points initializer list, provided for convenience * \param explicitely_closed Specify whether the given points form an explicitely closed line - * \warning A copy of the points list is made, so this constructor is somehow "slow" */ ClosedPolyline(const std::initializer_list& initializer, bool explicitely_closed) : Polyline(initializer) @@ -72,7 +64,6 @@ class ClosedPolyline : public Polyline /*! * \brief Constructor with an existing list of points * \param explicitely_closed Specify whether the given points form an explicitely closed line - * \warning A copy of the points list is made, so this constructor is somehow "slow" */ explicit ClosedPolyline(const ClipperLib::Path& points, bool explicitely_closed) : Polyline(points) @@ -83,8 +74,6 @@ class ClosedPolyline : public Polyline /*! * \brief Constructor that takes ownership of the given list of points * \param explicitely_closed Specify whether the given points form an explicitely closed line - * \warning This constructor is fast because it does not allocate data, but it will clear - * the source object */ explicit ClosedPolyline(ClipperLib::Path&& points, bool explicitely_closed) : Polyline(points) @@ -131,26 +120,6 @@ class ClosedPolyline : public Polyline explicitely_closed_ = explicitely_closed; } - /*! - * Check if we are inside the polygon. We do this by tracing from the point towards the positive X direction, - * every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon. - * Care needs to be taken, if p.Y exactly matches a vertex to the right of p, then we need to count 1 intersect if the - * outline passes vertically past; and 0 (or 2) intersections if that point on the outline is a 'top' or 'bottom' vertex. - * The easiest way to do this is to break out two cases for increasing and decreasing Y ( from p0 to p1 ). - * A segment is tested if pa.Y <= p.Y < pb.Y, where pa and pb are the points (from p0,p1) with smallest & largest Y. - * When both have the same Y, no intersections are counted but there is a special test to see if the point falls - * exactly on the line. - * - * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. - * - * \deprecated This function is no longer used, since the Clipper function is used by the function PolygonRef::inside(.) - * - * \param p The point for which to check if it is inside this polygon - * \param border_result What to return when the point is exactly on the border - * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) - */ - // bool _inside(Point2LL p, bool border_result = false) const; - /*! * Clipper function. * Returns false if outside, true if inside; if the point lies exactly on the border, will return 'border_result'. diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index 50694e7fdc..08f498a17f 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -43,33 +43,19 @@ class LinesSet /*! \brief Builds an empty set */ LinesSet() = default; - /*! - * \brief Creates a copy of the given lines set - * \warning A copy of the points list is made, so this constructor can be very slow - */ + /*! \brief Creates a copy of the given lines set */ LinesSet(const LinesSet& other) = default; - /*! - * \brief Constructor that takes the inner lines list from the given set - * \warning This constructor is fast because it does not allocate data, but it will clear - * the source object - */ + /*! \brief Constructor that takes the inner lines list from the given set */ LinesSet(LinesSet&& other) = default; - /*! - * \brief Constructor with an existing set of lines - * \warning A copy of the lines set is made, so this constructor can be very slow - */ + /*! \brief Constructor with an existing set of lines */ LinesSet(const std::vector& lines) : lines_(lines) { } - /*! - * \brief Constructor that takes ownership of the data from the given set of lines - * \warning This constructor is fast because it does not allocate data, but it will clear - * the source object - */ + /*! \brief Constructor that takes ownership of the data from the given set of lines */ LinesSet(std::vector&& lines) : lines_(std::move(lines)) { @@ -141,30 +127,20 @@ class LinesSet /*! * \brief Pushes the given line at the end of the set * \param checkNonEmpty Indicates whether we should check for the line to be non-empty before adding it - * \warning A copy of the line is made, so this method may be slow */ void push_back(const LineType& line, CheckNonEmptyParam checkNonEmpty = CheckNonEmptyParam::EvenIfEmpty); /*! * \brief Pushes the given line at the end of the set and takes ownership of the inner data * \param checkNonEmpty Indicates whether we should check for the line to be non-empty before adding it - * \warning This method is fast because it does not allocate data, but it will clear - * the source object */ void push_back(LineType&& line, CheckNonEmptyParam checkNonEmpty = CheckNonEmptyParam::EvenIfEmpty); - /*! - * \brief Pushes an entier set at the end and takes ownership of the inner data - * \warning This method is fast because it does not allocate data, but it will clear - * the source object - */ + /*! \brief Pushes an entier set at the end and takes ownership of the inner data */ template void push_back(LinesSet&& lines_set); - /*! - * \brief Pushes an entier set at the end - * \warning A copy of all the lines is made, so this method may be slow - */ + /*! \brief Pushes an entier set at the end */ void push_back(const LinesSet& other) { lines_.insert(lines_.end(), other.lines_.begin(), other.lines_.end()); diff --git a/include/geometry/MixedLinesSet.h b/include/geometry/MixedLinesSet.h index cf1cb19383..2017e87be8 100644 --- a/include/geometry/MixedLinesSet.h +++ b/include/geometry/MixedLinesSet.h @@ -38,73 +38,37 @@ class MixedLinesSet : public std::vector */ Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; - /*! - * @brief Adds a copy of the given polyline to the set - * @note As we have to copy the whole points data, this is not very efficient - */ + /*! @brief Adds a copy of the given polyline to the set */ void push_back(const OpenPolyline& line); - /*! - * @brief Adds a copy of the given polyline to the set - * @note As we have to copy the whole points data, this is not very efficient - */ + /*! @brief Adds a copy of the given polyline to the set */ void push_back(const Polygon& line); - /*! - * @brief Adds a copy of the given polyline to the set - * @note As we can move the points data, this is much more efficient than the above methods, - * but will clear the source data - */ + /*! @brief Adds a copy of the given polyline to the set */ void push_back(OpenPolyline&& line); - /*! - * @brief Adds a copy of the given polyline to the set - * @note As we can move the points data, this is much more efficient than the above methods, - * but will clear the source data - */ + /*! @brief Adds a copy of the given polyline to the set */ void push_back(ClosedPolyline&& line); - /*! - * @brief Adds the given shared pointer to the set. The pointer reference count will be incremeted but no data is actually copied. - * @note The is even more efficient than the above methods because it only involves copying a pointer - */ + /*! @brief Adds the given shared pointer to the set. The pointer reference count will be incremeted but no data is actually copied. */ void push_back(const OpenPolylinePtr& line); - /*! - * @brief Adds the given shared pointer to the set. The pointer reference count will be incremeted but no data is actually copied. - * @note The is even more efficient than the above methods because it only involves copying a pointer - */ + /*! @brief Adds the given shared pointer to the set. The pointer reference count will be incremeted but no data is actually copied. */ void push_back(const PolylinePtr& line); - /*! - * @brief Adds a copy of all the polygons contained in the shape - * @note As we have to copy the whole points data, this is really not efficient - */ + /*! @brief Adds a copy of all the polygons contained in the shape */ void push_back(const Shape& shape); - /*! - * @brief Adds a copy of all the polygons contained in the set - * @note As we have to copy the whole points data, this is really not efficient - */ + /*! @brief Adds a copy of all the polygons contained in the set */ void push_back(const LinesSet& lines_set); - /*! - * @brief Adds a copy of all the polylines contained in the set - * @note As we have to copy the whole points data, this is really not efficient - */ + /*! @brief Adds a copy of all the polylines contained in the set */ void push_back(const OpenLinesSet& lines_set); - /*! - * @brief Adds a copy of all the polylines contained in the set - * @note As we can move the points data, this is much more efficient than the above methods, - * but will clear the source data - */ + /*! @brief Adds a copy of all the polylines contained in the set */ void push_back(OpenLinesSet&& lines_set); - /*! @brief Adds a copy of all the polylines contained in the set - * @note As we can move the points data, this is much more efficient than the above methods, - * but will clear the source data - */ + /*! @brief Adds a copy of all the polylines contained in the set */ void push_back(ClosedLinesSet&& lines_set); /*! \brief Computes the total lenght of all the polylines in the set */ diff --git a/include/geometry/PointsSet.h b/include/geometry/PointsSet.h index ae084e61ce..f530613ba1 100644 --- a/include/geometry/PointsSet.h +++ b/include/geometry/PointsSet.h @@ -33,36 +33,19 @@ class PointsSet /*! \brief Builds an empty set */ PointsSet() = default; - /*! - * \brief Creates a copy of the given points set - * \warning A copy of the points set is made, so this constructor is somehow "slow" - */ + /*! \brief Creates a copy of the given points set */ PointsSet(const PointsSet& other) = default; - /*! - * \brief Constructor that takes ownership of the inner points from the given set - * \warning This constructor is fast because it does not allocate data, but it will clear - * the source object - */ + /*! \brief Constructor that takes ownership of the inner points from the given set */ PointsSet(PointsSet&& other) = default; - /*! - * \brief Constructor with a points initializer list, provided for convenience - * \warning A copy of the points list is made, so this constructor is somehow "slow" - */ + /*! \brief Constructor with a points initializer list, provided for convenience" */ PointsSet(const std::initializer_list& initializer); - /*! - * \brief Constructor with an existing list of points - * \warning A copy of the points list is made, so this constructor is somehow "slow" - */ + /*! \brief Constructor with an existing list of points */ PointsSet(const ClipperLib::Path& points); - /*! - * \brief Constructor that takes ownership of the given list of points - * \warning This constructor is fast because it does not allocate data, but it will clear - * the source object - */ + /*! \brief Constructor that takes ownership of the given list of points */ PointsSet(ClipperLib::Path&& points); const ClipperLib::Path& getPoints() const diff --git a/include/geometry/Polygon.h b/include/geometry/Polygon.h index 9a24abeaf0..fa2af370e9 100644 --- a/include/geometry/Polygon.h +++ b/include/geometry/Polygon.h @@ -33,23 +33,15 @@ class Polygon : public ClosedPolyline { } - /*! - * \brief Creates a copy of the given polygon - * \warning A copy of the points list is made, so this constructor is somehow "slow" - */ + /*! \brief Creates a copy of the given polygon */ Polygon(const Polygon& other) = default; - /*! - * \brief Constructor that takes ownership of the inner points list from the given polygon - * \warning This constructor is fast because it does not allocate data, but it will clear - * the source object - */ + /*! \brief Constructor that takes ownership of the inner points list from the given polygon */ Polygon(Polygon&& other) = default; /*! * \brief Constructor with a points initializer list, provided for convenience * \param explicitely_closed Specify whether the given points form an explicitely closed line - * \warning A copy of the points list is made, so this constructor is somehow "slow" */ Polygon(const std::initializer_list& initializer, bool explicitely_closed) : ClosedPolyline(initializer, explicitely_closed) @@ -59,7 +51,6 @@ class Polygon : public ClosedPolyline /*! * \brief Constructor with an existing list of points * \param explicitely_closed Specify whether the given points form an explicitely closed line - * \warning A copy of the points list is made, so this constructor is somehow "slow" */ explicit Polygon(const ClipperLib::Path& points, bool explicitely_closed) : ClosedPolyline(points, explicitely_closed) @@ -69,8 +60,6 @@ class Polygon : public ClosedPolyline /*! * \brief Constructor that takes ownership of the given list of points * \param explicitely_closed Specify whether the given points form an explicitely closed line - * \warning This constructor is fast because it does not allocate data, but it will clear - * the source object */ explicit Polygon(ClipperLib::Path&& points, bool explicitely_closed) : ClosedPolyline(points, explicitely_closed) diff --git a/include/geometry/Polyline.h b/include/geometry/Polyline.h index 075a9d22d6..765ac47b0f 100644 --- a/include/geometry/Polyline.h +++ b/include/geometry/Polyline.h @@ -41,42 +41,25 @@ class Polyline : public PointsSet /*! \brief Builds an empty polyline */ Polyline() = default; - /*! - * \brief Creates a copy of the given polyline - * \warning A copy of the points list is made, so this constructor is somehow "slow" - */ + /*! \brief Creates a copy of the given polyline */ Polyline(const Polyline& other) = default; - /*! - * \brief Constructor that takes ownership of the inner points list from the given polyline - * \warning This constructor is fast because it does not allocate data, but it will clear - * the source object - */ + /*! \brief Constructor that takes ownership of the inner points list from the given polyline */ Polyline(Polyline&& other) = default; - /*! - * \brief Constructor with a points initializer list, provided for convenience - * \warning A copy of the points list is made, so this constructor is somehow "slow" - */ + /*! \brief Constructor with a points initializer list, provided for convenience */ Polyline(const std::initializer_list& initializer) : PointsSet(initializer) { } - /*! - * \brief Constructor with an existing list of points - * \warning A copy of the points list is made, so this constructor is somehow "slow" - */ + /*! \brief Constructor with an existing list of points */ Polyline(const ClipperLib::Path& points) : PointsSet(points) { } - /*! - * \brief Constructor that takes ownership of the given list of points - * \warning This constructor is fast because it does not allocate data, but it will clear - * the source object - */ + /*! \brief Constructor that takes ownership of the given list of points */ Polyline(ClipperLib::Path&& points) : PointsSet(points) { diff --git a/include/geometry/Shape.h b/include/geometry/Shape.h index 49b9991d05..5e9e1d21d3 100644 --- a/include/geometry/Shape.h +++ b/include/geometry/Shape.h @@ -34,30 +34,18 @@ class Shape : public LinesSet /*! \brief Constructor of an empty shape */ Shape() = default; - /*! - * \brief Creates a copy of the given shape - * \warning A copy of the points list is made, so this constructor can be very slow - */ + /*! \brief Creates a copy of the given shape */ Shape(const Shape& other) = default; - /*! - * \brief Constructor that takes the inner polygons list from the given shape - * \warning This constructor is fast because it does not allocate data, but it will clear - * the source object - */ + /*! \brief Constructor that takes the inner polygons list from the given shape */ Shape(Shape&& other) = default; - /*! - * \brief Constructor with an existing set of polygons - * \warning A copy of the polygons set is made, so this constructor can be very slow - */ + /*! \brief Constructor with an existing set of polygons */ Shape(const std::vector& polygons); /*! * \brief Constructor that takes ownership of the given list of points * \param explicitely_closed Specify whether the given points form an explicitely closed line - * \warning This constructor is fast because it does not allocate data, but it will clear - * the source object */ explicit Shape(ClipperLib::Paths&& paths, bool explicitely_closed = clipper_explicitely_closed_); From f4ff0a30b06acadd776ac4786965e5fa0ebc7a03 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 26 Apr 2024 16:09:07 +0200 Subject: [PATCH 067/135] Clarify SegmentIterator CURA-9830 --- include/geometry/Polyline.h | 4 ++-- include/geometry/SegmentIterator.h | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/include/geometry/Polyline.h b/include/geometry/Polyline.h index 765ac47b0f..6f9dcba615 100644 --- a/include/geometry/Polyline.h +++ b/include/geometry/Polyline.h @@ -35,8 +35,8 @@ class OpenPolyline; class Polyline : public PointsSet { public: - using segments_iterator = SegmentIterator; - using const_segments_iterator = SegmentIterator; + using segments_iterator = SegmentIterator; + using const_segments_iterator = SegmentIterator; /*! \brief Builds an empty polyline */ Polyline() = default; diff --git a/include/geometry/SegmentIterator.h b/include/geometry/SegmentIterator.h index 764d15469e..9e0f70c932 100644 --- a/include/geometry/SegmentIterator.h +++ b/include/geometry/SegmentIterator.h @@ -9,14 +9,20 @@ namespace cura { -// Custom iterator to loop over the segments of a polyline -template +enum class ConstnessType +{ + Const, + Modifiable, +}; + +/*! @brief Custom iterator to loop over the segments of a polyline */ +template struct SegmentIterator { - // Transitory structure used to iterate over segments within a polyline + /*! @brief Transitory structure used to iterate over segments within a polyline */ struct Segment { - using PointType = typename std::conditional::type; + using PointType = typename std::conditional::type; PointType& start; PointType& end; @@ -28,7 +34,8 @@ struct SegmentIterator using difference_type = std::ptrdiff_t; using pointer = Segment*; using reference = Segment&; - using source_iterator_type = typename std::conditional::const_iterator, typename std::vector::iterator>::type; + using source_iterator_type = + typename std::conditional::const_iterator, typename std::vector::iterator>::type; private: source_iterator_type current_pos_; From 73644b1910dfd1a79205fc5191caa8e48db4b0ab Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 26 Apr 2024 16:15:33 +0200 Subject: [PATCH 068/135] Rename addClosingSegment method for clarity CURA-9830 --- include/geometry/ClosedPolyline.h | 4 ++-- include/geometry/OpenPolyline.h | 4 ++-- include/geometry/Polyline.h | 2 +- src/geometry/ClosedPolyline.cpp | 2 +- src/geometry/MixedLinesSet.cpp | 2 +- src/geometry/Polyline.cpp | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/geometry/ClosedPolyline.h b/include/geometry/ClosedPolyline.h index 12a60c0303..45b204dcd0 100644 --- a/include/geometry/ClosedPolyline.h +++ b/include/geometry/ClosedPolyline.h @@ -81,8 +81,8 @@ class ClosedPolyline : public Polyline { } - /*! @see Polyline::addClosingSegment() */ - virtual bool addClosingSegment() const + /*! @see Polyline::hasClosingSegment() */ + virtual bool hasClosingSegment() const { return ! explicitely_closed_; } diff --git a/include/geometry/OpenPolyline.h b/include/geometry/OpenPolyline.h index 849bc18c70..84c0cccdd0 100644 --- a/include/geometry/OpenPolyline.h +++ b/include/geometry/OpenPolyline.h @@ -64,8 +64,8 @@ class OpenPolyline : public Polyline { } - /*! @see Polyline::addClosingSegment() */ - virtual bool addClosingSegment() const override + /*! @see Polyline::hasClosingSegment() */ + virtual bool hasClosingSegment() const override { return false; // Definitely not } diff --git a/include/geometry/Polyline.h b/include/geometry/Polyline.h index 6f9dcba615..f151830e2a 100644 --- a/include/geometry/Polyline.h +++ b/include/geometry/Polyline.h @@ -72,7 +72,7 @@ class Polyline : public PointsSet * point in the set and the first one * \return True if a segment between the last and first point should be considered */ - virtual bool addClosingSegment() const = 0; + virtual bool hasClosingSegment() const = 0; /*! * \brief Gets the total number of "full" segments in the polyline. Calling this is also safe if diff --git a/src/geometry/ClosedPolyline.cpp b/src/geometry/ClosedPolyline.cpp index f9ae903ab5..0f7ab7e142 100644 --- a/src/geometry/ClosedPolyline.cpp +++ b/src/geometry/ClosedPolyline.cpp @@ -50,7 +50,7 @@ bool ClosedPolyline::inside(const ClipperLib::Path& polygon) const OpenPolyline ClosedPolyline::toPseudoOpenPolyline() const { OpenPolyline open_polyline(getPoints()); - if (addClosingSegment()) + if (hasClosingSegment()) { open_polyline.push_back(open_polyline.getPoints().front()); } diff --git a/src/geometry/MixedLinesSet.cpp b/src/geometry/MixedLinesSet.cpp index 0dc71ab943..d4923c3778 100644 --- a/src/geometry/MixedLinesSet.cpp +++ b/src/geometry/MixedLinesSet.cpp @@ -46,7 +46,7 @@ Shape MixedLinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, do { ClipperLib::EndType end_type; - if (line->addClosingSegment()) + if (line->hasClosingSegment()) { end_type = ClipperLib::etClosedLine; } diff --git a/src/geometry/Polyline.cpp b/src/geometry/Polyline.cpp index bf771b6846..24515b492a 100644 --- a/src/geometry/Polyline.cpp +++ b/src/geometry/Polyline.cpp @@ -99,7 +99,7 @@ Polyline::const_segments_iterator Polyline::beginSegments() const Polyline::const_segments_iterator Polyline::endSegments() const { - if (addClosingSegment()) + if (hasClosingSegment()) { return const_segments_iterator(end(), begin(), end()); } @@ -116,7 +116,7 @@ Polyline::segments_iterator Polyline::beginSegments() Polyline::segments_iterator Polyline::endSegments() { - if (addClosingSegment()) + if (hasClosingSegment()) { return segments_iterator(end(), begin(), end()); } From 338d57cd3e19debffb334a3cdae6eee784fb9ce5 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 26 Apr 2024 16:32:11 +0200 Subject: [PATCH 069/135] Code uniformization/cleaning CURA-9830 --- include/sliceDataStorage.h | 13 +++++------ include/slicer.h | 2 +- include/utils/AABB.h | 4 ++-- include/utils/ExtrusionSegment.h | 4 ++-- include/utils/ListPolyIt.h | 2 +- include/utils/Simplify.h | 2 +- src/ConicalOverhang.cpp | 26 ++++++++++----------- src/FffGcodeWriter.cpp | 40 +++++--------------------------- src/FffPolygonGenerator.cpp | 22 +++++++++--------- src/LayerPlan.cpp | 6 ++--- src/Mold.cpp | 4 ++-- src/SkirtBrim.cpp | 8 +++---- src/TreeModelVolumes.cpp | 2 +- src/layerPart.cpp | 6 ++--- src/multiVolumes.cpp | 2 +- src/raft.cpp | 32 ++++++++++++------------- src/sliceDataStorage.cpp | 10 ++++---- src/slicer.cpp | 10 ++++---- src/utils/AABB.cpp | 8 +++---- src/utils/ExtrusionSegment.cpp | 6 ++--- src/utils/ListPolyIt.cpp | 4 ++-- src/utils/Simplify.cpp | 4 ++-- src/utils/ToolpathVisualizer.cpp | 6 ++--- 23 files changed, 97 insertions(+), 126 deletions(-) diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index ddf0177e59..722c29064d 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -63,8 +63,7 @@ class SliceLayerPart //!< collision between different parts on different layers. It's an optimization used during //!< skin calculations. SingleShape outline; //!< The outline is the first member that is filled, and it's filled with polygons that match - //!< a cross-section of the 3D model. The first polygon is the outer boundary polygon and the - //!< rest are holes. + //!< a cross-section of the 3D model. Shape print_outline; //!< An approximation to the outline of what's actually printed, based on the outer wall. //!< Too small parts will be omitted compared to the outline. Shape spiral_wall; //!< The centerline of the wall used by spiralize mode. Only computed if spiralize mode is enabled. @@ -169,7 +168,7 @@ class SliceLayer coord_t printZ; //!< The height at which this layer needs to be printed. Can differ from sliceZ due to the raft. coord_t thickness; //!< The thickness of this layer. Can be different when using variable layer heights. std::vector parts; //!< An array of LayerParts which contain the actual data. The parts are printed one at a time to minimize travel outside of the 3D model. - OpenLinesSet openPolyLines; //!< A list of lines which were never hooked up into a 2D polygon. (Currently unused in normal operation) + OpenLinesSet open_polylines; //!< A list of lines which were never hooked up into a 2D polygon. (Currently unused in normal operation) /*! * \brief The parts of the model that are exposed at the very top of the @@ -379,9 +378,9 @@ class SliceDataStorage : public NoCopy ClosedLinesSet support_brim; //!< brim lines for support, going from the edge of the support inward. \note Not ordered by inset. // Storage for the outline of the raft-parts. Will be filled with lines when the GCode is generated. - Shape raftBaseOutline; - Shape raftInterfaceOutline; - Shape raftSurfaceOutline; + Shape raft_base_outline; + Shape raft_interface_outline; + Shape raft_surface_outline; int max_print_height_second_to_last_extruder; //!< Used in multi-extrusion: the layer number beyond which all models are printed with the same extruder std::vector max_print_height_per_extruder; //!< For each extruder the highest layer number at which it is used. @@ -392,7 +391,7 @@ class SliceDataStorage : public NoCopy PrimeTower primeTower; - std::vector oozeShield; // oozeShield per layer + std::vector ooze_shield; // oozeShield per layer Shape draft_protection_shield; //!< The polygons for a heightened skirt which protects from warping by gusts of wind and acts as a heated chamber. /*! diff --git a/include/slicer.h b/include/slicer.h index 290fe0d3d2..0f2f7a3d6b 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -62,7 +62,7 @@ class SlicerLayer int z = -1; Shape polygons; - OpenLinesSet openPolylines; + OpenLinesSet open_polylines; /*! * \brief Connect the segments into polygons for this layer of this \p mesh. diff --git a/include/utils/AABB.h b/include/utils/AABB.h index 4ef49afd37..e3a93c678b 100644 --- a/include/utils/AABB.h +++ b/include/utils/AABB.h @@ -20,10 +20,10 @@ class AABB AABB(); //!< initializes with invalid min and max AABB(const Point2LL& min, const Point2LL& max); //!< initializes with given min and max - AABB(const Shape& polys); //!< Computes the boundary box for the given polygons + AABB(const Shape& shape); //!< Computes the boundary box for the given shape AABB(const Polygon& poly); //!< Computes the boundary box for the given polygons - void calculate(const Shape& polys); //!< Calculates the aabb for the given polygons (throws away old min and max data of this aabb) + void calculate(const Shape& shape); //!< Calculates the aabb for the given shape (throws away old min and max data of this aabb) void calculate(const Polygon& poly); //!< Calculates the aabb for the given polygon (throws away old min and max data of this aabb) /*! diff --git a/include/utils/ExtrusionSegment.h b/include/utils/ExtrusionSegment.h index 55f62c6055..f16fab5ea8 100644 --- a/include/utils/ExtrusionSegment.h +++ b/include/utils/ExtrusionSegment.h @@ -55,7 +55,7 @@ class ExtrusionSegment * Converts this segment to an outline of the area that the segment covers. * \return The area that would be covered by this extrusion segment. */ - Shape toPolygons(); + Shape toShape(); /*! * Converts this segment to an outline of the area that the segment covers. @@ -63,7 +63,7 @@ class ExtrusionSegment * it will be included in the next extrusion move. Overrides class field * \ref is_reduced . */ - Shape toPolygons(bool reduced); + Shape toShape(bool reduced); /*! * Discretize a variable-line-width extrusion segment into multiple diff --git a/include/utils/ListPolyIt.h b/include/utils/ListPolyIt.h index ee990fd9a7..ed56a1825a 100644 --- a/include/utils/ListPolyIt.h +++ b/include/utils/ListPolyIt.h @@ -115,7 +115,7 @@ class ListPolyIt * \param polys The polygons to convert * \param result The converted polygons */ - static void convertPolygonsToLists(const Shape& polys, ListPolygons& result); + static void convertPolygonsToLists(const Shape& shape, ListPolygons& result); /*! * Convert Polygons to ListPolygons diff --git a/include/utils/Simplify.h b/include/utils/Simplify.h index 6968b7e7e4..d06c018568 100644 --- a/include/utils/Simplify.h +++ b/include/utils/Simplify.h @@ -276,7 +276,7 @@ class Simplify * \return An empty polygonal. */ template - Polygonal createEmpty(const Polygonal& original) const; + static Polygonal createEmpty(const Polygonal& original); template bool detectSmall(const Polygonal& polygon, const coord_t& min_size) const; diff --git a/src/ConicalOverhang.cpp b/src/ConicalOverhang.cpp index 3bba0c9b4c..f217af5a73 100644 --- a/src/ConicalOverhang.cpp +++ b/src/ConicalOverhang.cpp @@ -18,7 +18,7 @@ namespace cura void ConicalOverhang::apply(Slicer* slicer, const Mesh& mesh) { const AngleRadians angle = mesh.settings_.get("conical_overhang_angle"); - const double maxHoleArea = mesh.settings_.get("conical_overhang_hole_size"); + const double max_hole_area = mesh.settings_.get("conical_overhang_hole_size"); const double tan_angle = tan(angle); // the XY-component of the angle const coord_t layer_thickness = mesh.settings_.get("layer_height"); coord_t max_dist_from_lower_layer = std::llround(tan_angle * static_cast(layer_thickness)); // max dist which can be bridged @@ -41,31 +41,31 @@ void ConicalOverhang::apply(Slicer* slicer, const Mesh& mesh) else { // Get the current layer and split it into parts - std::vector layerParts = layer.polygons.splitIntoParts(); + std::vector layer_parts = layer.polygons.splitIntoParts(); // Get a copy of the layer above to prune away before we shrink it Shape above = layer_above.polygons; // Now go through all the holes in the current layer and check if they intersect anything in the layer above // If not, then they're the top of a hole and should be cut from the layer above before the union - for (unsigned int part = 0; part < layerParts.size(); part++) + for (unsigned int part = 0; part < layer_parts.size(); part++) { - if (layerParts[part].size() > 1) // first poly is the outer contour, 1..n are the holes + if (layer_parts[part].size() > 1) // first poly is the outer contour, 1..n are the holes { - for (unsigned int hole_nr = 1; hole_nr < layerParts[part].size(); ++hole_nr) + for (unsigned int hole_nr = 1; hole_nr < layer_parts[part].size(); ++hole_nr) { - Shape holePoly; - holePoly.push_back(layerParts[part][hole_nr]); - if (maxHoleArea > 0.0 && INT2MM2(std::abs(holePoly.area())) < maxHoleArea) + Shape hole_poly; + hole_poly.push_back(layer_parts[part][hole_nr]); + if (max_hole_area > 0.0 && INT2MM2(std::abs(hole_poly.area())) < max_hole_area) { - Shape holeWithAbove = holePoly.intersection(above); - if (! holeWithAbove.empty()) + Shape hole_with_above = hole_poly.intersection(above); + if (! hole_with_above.empty()) { // The hole had some intersection with the above layer, check if it's a complete overlap - Shape holeDifference = holePoly.xorPolygons(holeWithAbove); - if (holeDifference.empty()) + Shape hole_difference = hole_poly.xorPolygons(hole_with_above); + if (hole_difference.empty()) { // The hole was returned unchanged, so the layer above must completely cover it. Remove the hole from the layer above. - above = above.difference(holePoly); + above = above.difference(hole_poly); } } } diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index c49a0e01a0..d290dfba85 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -644,7 +644,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) }; std::vector raft_outline_paths; - raft_outline_paths.emplace_back(ParameterizedRaftPath{ line_spacing, storage.raftBaseOutline }); + raft_outline_paths.emplace_back(ParameterizedRaftPath{ line_spacing, storage.raft_base_outline }); if (storage.primeTower.enabled_) { const Shape& raft_outline_prime_tower = storage.primeTower.getOuterPoly(layer_nr); @@ -802,7 +802,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Shape raft_outline_path; const coord_t small_offset = gcode_layer.configs_storage_.raft_interface_config.getLineWidth() / 2; // Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. - raft_outline_path = storage.raftInterfaceOutline.offset(-small_offset); + raft_outline_path = storage.raft_interface_outline.offset(-small_offset); raft_outline_path = Simplify(interface_settings).polygon(raft_outline_path); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage_.raft_interface_config.getLineWidth(); OpenLinesSet raft_lines; @@ -973,7 +973,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) Shape raft_outline_path; const coord_t small_offset = gcode_layer.configs_storage_.raft_interface_config.getLineWidth() / 2; // Do this manually because of micron-movement created in corners when insetting a polygon that was offset with round joint type. - raft_outline_path = storage.raftSurfaceOutline.offset(-small_offset); + raft_outline_path = storage.raft_surface_outline.offset(-small_offset); raft_outline_path = Simplify(interface_settings).polygon(raft_outline_path); // Remove those micron-movements. const coord_t infill_outline_width = gcode_layer.configs_storage_.raft_surface_config.getLineWidth(); OpenLinesSet raft_lines; @@ -1366,33 +1366,6 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan for (size_t inset_idx = 0; inset_idx < storage.skirt_brim[extruder_nr].size(); inset_idx++) { const MixedLinesSet& offset = storage.skirt_brim[extruder_nr][inset_idx]; - /* - auto push_lines = [&all_brim_lines, &grid, &inset_idx](const LinesSet& lines) - { - for (const LineType& line : lines) - { - if (line.size() <= 1) - { - continue; - } - all_brim_lines.emplace_back(line); - if constexpr (LineType::type_ != PolylineType::Open) - { - // add closing segment - all_brim_lines.back().push_back(line.front()); - } - const OpenPolyline* pp = &all_brim_lines.back(); - for (const Point2LL& p : line) - { - grid.insert(p, BrimLineReference{ inset_idx, pp }); - } - } - }; - - push_lines(offset.closed_polygons); - push_lines(offset.open_polylines); - */ - for (const PolylinePtr& line : offset) { if (line->segmentsCount() > 0) @@ -1405,7 +1378,6 @@ void FffGcodeWriter::processSkirtBrim(const SliceDataStorage& storage, LayerPlan } } - // For layer_nr != 0 add only the innermost brim line (which is only the case if skirt_height > 1) if (layer_nr != 0) { @@ -1512,9 +1484,9 @@ void FffGcodeWriter::processOozeShield(const SliceDataStorage& storage, LayerPla { return; // ooze shield already generated by brim } - if (storage.oozeShield.size() > 0 && layer_nr < storage.oozeShield.size()) + if (storage.ooze_shield.size() > 0 && layer_nr < storage.ooze_shield.size()) { - gcode_layer.addPolygonsByOptimizer(storage.oozeShield[layer_nr], gcode_layer.configs_storage_.skirt_brim_config_per_extruder[0]); + gcode_layer.addPolygonsByOptimizer(storage.ooze_shield[layer_nr], gcode_layer.configs_storage_.skirt_brim_config_per_extruder[0]); } } @@ -1746,7 +1718,7 @@ void FffGcodeWriter::addMeshOpenPolyLinesToGCode(const SliceMeshStorage& mesh, c { const SliceLayer* layer = &mesh.layers[gcode_layer.getLayerNr()]; - gcode_layer.addLinesByOptimizer(layer->openPolyLines, mesh_config.inset0_config, SpaceFillType::PolyLines); + gcode_layer.addLinesByOptimizer(layer->open_polylines, mesh_config.inset0_config, SpaceFillType::PolyLines); } void FffGcodeWriter::addMeshLayerToGCode( diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index 6a7281617a..58e6ef5a9d 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -569,7 +569,7 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz { for (const Polygon& poly : part.outline) { - layer.openPolyLines.push_back(poly.toPseudoOpenPolyline()); + layer.open_polylines.push_back(poly.toPseudoOpenPolyline()); } } layer.parts.clear(); @@ -626,12 +626,12 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz if (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { const Shape& own_infill_area = other_part.getOwnInfillArea(); - OpenLinesSet cut_lines = own_infill_area.intersection(layer.openPolyLines); + OpenLinesSet cut_lines = own_infill_area.intersection(layer.open_polylines); new_polylines.push_back(cut_lines); // NOTE: closed polygons will be represented as polylines, which will be closed automatically in the PathOrderOptimizer if (! own_infill_area.empty()) { - other_part.infill_area_own = own_infill_area.difference(layer.openPolyLines.offset(surface_line_width / 2)); + other_part.infill_area_own = own_infill_area.difference(layer.open_polylines.offset(surface_line_width / 2)); } } } @@ -651,10 +651,10 @@ void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, const siz if (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { - layer.openPolyLines = new_polylines; + layer.open_polylines = new_polylines; } - if (layer.parts.size() > 0 || (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer.openPolyLines.size() > 0)) + if (layer.parts.size() > 0 || (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer.open_polylines.size() > 0)) { mesh.layer_nr_max_filled_layer = layer_idx; // last set by the highest non-empty layer } @@ -752,7 +752,7 @@ bool FffPolygonGenerator::isEmptyLayer(SliceDataStorage& storage, const LayerInd continue; } SliceLayer& layer = mesh.layers[layer_idx]; - if (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer.openPolyLines.size() > 0) + if (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer.open_polylines.size() > 0) { return false; } @@ -958,7 +958,7 @@ void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage) { constexpr bool around_support = true; constexpr bool around_prime_tower = false; - storage.oozeShield.push_back(storage.getLayerOutlines(layer_nr, around_support, around_prime_tower).offset(ooze_shield_dist, ClipperLib::jtRound).getOutsidePolygons()); + storage.ooze_shield.push_back(storage.getLayerOutlines(layer_nr, around_support, around_prime_tower).offset(ooze_shield_dist, ClipperLib::jtRound).getOutsidePolygons()); } const AngleDegrees angle = mesh_group_settings.get("ooze_shield_angle"); @@ -968,18 +968,18 @@ void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage) = tan(mesh_group_settings.get("ooze_shield_angle")) * mesh_group_settings.get("layer_height"); // Allow for a 60deg angle in the oozeShield. for (LayerIndex layer_nr = 1; layer_nr <= storage.max_print_height_second_to_last_extruder; layer_nr++) { - storage.oozeShield[layer_nr] = storage.oozeShield[layer_nr].unionPolygons(storage.oozeShield[layer_nr - 1].offset(-allowed_angle_offset)); + storage.ooze_shield[layer_nr] = storage.ooze_shield[layer_nr].unionPolygons(storage.ooze_shield[layer_nr - 1].offset(-allowed_angle_offset)); } for (LayerIndex layer_nr = storage.max_print_height_second_to_last_extruder; layer_nr > 0; layer_nr--) { - storage.oozeShield[layer_nr - 1] = storage.oozeShield[layer_nr - 1].unionPolygons(storage.oozeShield[layer_nr].offset(-allowed_angle_offset)); + storage.ooze_shield[layer_nr - 1] = storage.ooze_shield[layer_nr - 1].unionPolygons(storage.ooze_shield[layer_nr].offset(-allowed_angle_offset)); } } const double largest_printed_area = 1.0; // TODO: make var a parameter, and perhaps even a setting? for (LayerIndex layer_nr = 0; layer_nr <= storage.max_print_height_second_to_last_extruder; layer_nr++) { - storage.oozeShield[layer_nr].removeSmallAreas(largest_printed_area); + storage.ooze_shield[layer_nr].removeSmallAreas(largest_printed_area); } if (mesh_group_settings.get("prime_tower_enable")) { @@ -996,7 +996,7 @@ void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage) } for (LayerIndex layer_nr = 0; layer_nr <= storage.max_print_height_second_to_last_extruder; layer_nr++) { - storage.oozeShield[layer_nr] = storage.oozeShield[layer_nr].difference(storage.primeTower.getOuterPoly(layer_nr).offset(max_line_width / 2)); + storage.ooze_shield[layer_nr] = storage.ooze_shield[layer_nr].difference(storage.primeTower.getOuterPoly(layer_nr).offset(max_line_width / 2)); } } } diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index da4b44ad89..09daabc1f0 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -163,15 +163,15 @@ Shape LayerPlan::computeCombBoundary(const CombBoundary boundary_type) switch (layer_type_) { case Raft::LayerType::RaftBase: - comb_boundary = storage_.raftBaseOutline.offset(MM2INT(0.1)); + comb_boundary = storage_.raft_base_outline.offset(MM2INT(0.1)); break; case Raft::LayerType::RaftInterface: - comb_boundary = storage_.raftInterfaceOutline.offset(MM2INT(0.1)); + comb_boundary = storage_.raft_interface_outline.offset(MM2INT(0.1)); break; case Raft::LayerType::RaftSurface: - comb_boundary = storage_.raftSurfaceOutline.offset(MM2INT(0.1)); + comb_boundary = storage_.raft_surface_outline.offset(MM2INT(0.1)); break; case Raft::LayerType::Airgap: diff --git a/src/Mold.cpp b/src/Mold.cpp index 097690bf85..37ad953087 100644 --- a/src/Mold.cpp +++ b/src/Mold.cpp @@ -77,8 +77,8 @@ void Mold::process(std::vector& slicer_list) SlicerLayer& layer = slicer.layers[layer_nr]; - Shape model_outlines = layer.polygons.unionPolygons(layer.openPolylines.offset(open_polyline_width / 2)); - layer.openPolylines.clear(); + Shape model_outlines = layer.polygons.unionPolygons(layer.open_polylines.offset(open_polyline_width / 2)); + layer.open_polylines.clear(); all_original_mold_outlines.push_back(model_outlines); if (angle >= 90) diff --git a/src/SkirtBrim.cpp b/src/SkirtBrim.cpp index d6f32635e5..ba399fb721 100644 --- a/src/SkirtBrim.cpp +++ b/src/SkirtBrim.cpp @@ -23,7 +23,7 @@ namespace cura SkirtBrim::SkirtBrim(SliceDataStorage& storage) : storage_(storage) , adhesion_type_(Application::getInstance().current_slice_->scene.current_mesh_group->settings.get("adhesion_type")) - , has_ooze_shield_(storage.oozeShield.size() > 0 && storage.oozeShield[0].size() > 0) + , has_ooze_shield_(storage.ooze_shield.size() > 0 && storage.ooze_shield[0].size() > 0) , has_draft_shield_(storage.draft_protection_shield.size() > 0) , extruders_(Application::getInstance().current_slice_->scene.extruders) , extruder_count_(extruders_.size()) @@ -320,7 +320,7 @@ Shape SkirtBrim::getFirstLayerOutline(const int extruder_nr /* = -1 */) Shape shields; if (has_ooze_shield_) { - shields = storage_.oozeShield[0]; + shields = storage_.ooze_shield[0]; } if (has_draft_shield_) { @@ -442,7 +442,7 @@ void SkirtBrim::generateShieldBrim(Shape& brim_covered_area, std::vector& Shape shield_brim; if (has_ooze_shield_) { - shield_brim = storage_.oozeShield[0].difference(storage_.oozeShield[0].offset(-primary_skirt_brim_width - primary_extruder_skirt_brim_line_width)); + shield_brim = storage_.ooze_shield[0].difference(storage_.ooze_shield[0].offset(-primary_skirt_brim_width - primary_extruder_skirt_brim_line_width)); } if (has_draft_shield_) { @@ -472,7 +472,7 @@ void SkirtBrim::generateShieldBrim(Shape& brim_covered_area, std::vector& { if (has_ooze_shield_) { - const Shape covered_area = storage_.oozeShield[0].offset(extruder_config.line_width_ / 2); + const Shape covered_area = storage_.ooze_shield[0].offset(extruder_config.line_width_ / 2); brim_covered_area = brim_covered_area.unionPolygons(covered_area); allowed_areas_per_extruder[extruder_nr] = allowed_areas_per_extruder[extruder_nr].difference(covered_area); } diff --git a/src/TreeModelVolumes.cpp b/src/TreeModelVolumes.cpp index 8b9e0aa9bc..a6d12804a6 100644 --- a/src/TreeModelVolumes.cpp +++ b/src/TreeModelVolumes.cpp @@ -584,7 +584,7 @@ Shape TreeModelVolumes::extractOutlineFromMesh(const SliceMeshStorage& mesh, Lay layer.getOutlines(total, external_polys_only); if (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { - total = total.unionPolygons(layer.openPolyLines.offset(FUDGE_LENGTH * 2)); + total = total.unionPolygons(layer.open_polylines.offset(FUDGE_LENGTH * 2)); } const coord_t maximum_resolution = mesh.settings.get("meshfix_maximum_resolution"); const coord_t maximum_deviation = mesh.settings.get("meshfix_maximum_deviation"); diff --git a/src/layerPart.cpp b/src/layerPart.cpp index 0be927a724..5d3c7138c2 100644 --- a/src/layerPart.cpp +++ b/src/layerPart.cpp @@ -30,9 +30,9 @@ namespace cura void createLayerWithParts(const Settings& settings, SliceLayer& storageLayer, SlicerLayer* layer) { - OpenPolylineStitcher::stitch(layer->openPolylines, storageLayer.openPolyLines, layer->polygons, settings.get("wall_line_width_0")); + OpenPolylineStitcher::stitch(layer->open_polylines, storageLayer.open_polylines, layer->polygons, settings.get("wall_line_width_0")); - storageLayer.openPolyLines = Simplify(settings).polyline(storageLayer.openPolyLines); + storageLayer.open_polylines = Simplify(settings).polyline(storageLayer.open_polylines); const bool union_all_remove_holes = settings.get("meshfix_union_all_remove_holes"); if (union_all_remove_holes) @@ -99,7 +99,7 @@ void createLayerParts(SliceMeshStorage& mesh, Slicer* slicer) for (LayerIndex layer_nr = total_layers - 1; layer_nr >= 0; layer_nr--) { SliceLayer& layer_storage = mesh.layers[layer_nr]; - if (layer_storage.parts.size() > 0 || (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer_storage.openPolyLines.size() > 0)) + if (layer_storage.parts.size() > 0 || (mesh.settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer_storage.open_polylines.size() > 0)) { mesh.layer_nr_max_filled_layer = layer_nr; // last set by the highest non-empty layer break; diff --git a/src/multiVolumes.cpp b/src/multiVolumes.cpp index 774966b781..3ab392e358 100644 --- a/src/multiVolumes.cpp +++ b/src/multiVolumes.cpp @@ -121,7 +121,7 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: for (LayerIndex layer_nr = 0; layer_nr < cutting_mesh_volume.layers.size(); layer_nr++) { Shape& cutting_mesh_polygons = cutting_mesh_volume.layers[layer_nr].polygons; - OpenLinesSet& cutting_mesh_polylines = cutting_mesh_volume.layers[layer_nr].openPolylines; + OpenLinesSet& cutting_mesh_polylines = cutting_mesh_volume.layers[layer_nr].open_polylines; Shape cutting_mesh_area_recomputed; Shape* cutting_mesh_area; coord_t surface_line_width = cutting_mesh.settings_.get("wall_line_width_0"); diff --git a/src/raft.cpp b/src/raft.cpp index 4eb329964f..8bc54ec41e 100644 --- a/src/raft.cpp +++ b/src/raft.cpp @@ -20,7 +20,7 @@ namespace cura void Raft::generate(SliceDataStorage& storage) { assert( - storage.raftBaseOutline.size() == 0 && storage.raftInterfaceOutline.size() == 0 && storage.raftSurfaceOutline.size() == 0 + storage.raft_base_outline.size() == 0 && storage.raft_interface_outline.size() == 0 && storage.raft_surface_outline.size() == 0 && "Raft polygon isn't generated yet, so should be empty!"); const Settings& settings = Application::getInstance().current_slice_->scene.current_mesh_group->settings.get("raft_base_extruder_nr").settings_; constexpr bool include_support = true; @@ -29,10 +29,10 @@ void Raft::generate(SliceDataStorage& storage) const auto raft_interface_margin = settings.get("raft_interface_margin"); const auto raft_surface_margin = settings.get("raft_surface_margin"); - storage.raftBaseOutline = storage.raftSurfaceOutline = storage.raftInterfaceOutline = storage.getLayerOutlines(0, include_support, dont_include_prime_tower); - storage.raftBaseOutline = storage.raftBaseOutline.offset(raft_base_margin, ClipperLib::jtRound); - storage.raftInterfaceOutline = storage.raftInterfaceOutline.offset(raft_interface_margin, ClipperLib::jtRound); - storage.raftSurfaceOutline = storage.raftSurfaceOutline.offset(raft_surface_margin, ClipperLib::jtRound); + storage.raft_base_outline = storage.raft_surface_outline = storage.raft_interface_outline = storage.getLayerOutlines(0, include_support, dont_include_prime_tower); + storage.raft_base_outline = storage.raft_base_outline.offset(raft_base_margin, ClipperLib::jtRound); + storage.raft_interface_outline = storage.raft_interface_outline.offset(raft_interface_margin, ClipperLib::jtRound); + storage.raft_surface_outline = storage.raft_surface_outline.offset(raft_surface_margin, ClipperLib::jtRound); const coord_t shield_line_width_layer0 = settings.get("skirt_brim_line_width"); const coord_t max_raft_distance = std::max(std::max(raft_base_margin, raft_interface_margin), raft_surface_margin); @@ -42,19 +42,19 @@ void Raft::generate(SliceDataStorage& storage) = storage.draft_protection_shield .offset(shield_line_width_layer0) // start half a line width outside shield .difference(storage.draft_protection_shield.offset(-max_raft_distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield - storage.raftBaseOutline = storage.raftBaseOutline.unionPolygons(draft_shield_raft); - storage.raftSurfaceOutline = storage.raftSurfaceOutline.unionPolygons(draft_shield_raft); - storage.raftInterfaceOutline = storage.raftInterfaceOutline.unionPolygons(draft_shield_raft); + storage.raft_base_outline = storage.raft_base_outline.unionPolygons(draft_shield_raft); + storage.raft_surface_outline = storage.raft_surface_outline.unionPolygons(draft_shield_raft); + storage.raft_interface_outline = storage.raft_interface_outline.unionPolygons(draft_shield_raft); } - if (storage.oozeShield.size() > 0 && storage.oozeShield[0].size() > 0) + if (storage.ooze_shield.size() > 0 && storage.ooze_shield[0].size() > 0) { - const Shape& ooze_shield = storage.oozeShield[0]; + const Shape& ooze_shield = storage.ooze_shield[0]; Shape ooze_shield_raft = ooze_shield .offset(shield_line_width_layer0) // start half a line width outside shield .difference(ooze_shield.offset(-max_raft_distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield - storage.raftBaseOutline = storage.raftBaseOutline.unionPolygons(ooze_shield_raft); - storage.raftSurfaceOutline = storage.raftSurfaceOutline.unionPolygons(ooze_shield_raft); - storage.raftInterfaceOutline = storage.raftInterfaceOutline.unionPolygons(ooze_shield_raft); + storage.raft_base_outline = storage.raft_base_outline.unionPolygons(ooze_shield_raft); + storage.raft_surface_outline = storage.raft_surface_outline.unionPolygons(ooze_shield_raft); + storage.raft_interface_outline = storage.raft_interface_outline.unionPolygons(ooze_shield_raft); } const auto remove_inside_corners = [](Shape& outline, bool remove_inside_corners, coord_t smoothing, coord_t line_width) @@ -114,14 +114,14 @@ void Raft::generate(SliceDataStorage& storage) } }; const auto nominal_raft_line_width = settings.get("skirt_brim_line_width"); - remove_inside_corners(storage.raftBaseOutline, settings.get("raft_base_remove_inside_corners"), settings.get("raft_base_smoothing"), nominal_raft_line_width); + remove_inside_corners(storage.raft_base_outline, settings.get("raft_base_remove_inside_corners"), settings.get("raft_base_smoothing"), nominal_raft_line_width); remove_inside_corners( - storage.raftInterfaceOutline, + storage.raft_interface_outline, settings.get("raft_interface_remove_inside_corners"), settings.get("raft_interface_smoothing"), nominal_raft_line_width); remove_inside_corners( - storage.raftSurfaceOutline, + storage.raft_surface_outline, settings.get("raft_surface_remove_inside_corners"), settings.get("raft_surface_smoothing"), nominal_raft_line_width); diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index f2ceebb72f..677844d34d 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -173,7 +173,7 @@ bool SliceMeshStorage::getExtruderIsUsed(const size_t extruder_nr, const LayerIn } } if (settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && settings.get("wall_0_extruder_nr").extruder_nr_ == extruder_nr - && layer.openPolyLines.size() > 0) + && layer.open_polylines.size() > 0) { return true; } @@ -290,15 +290,15 @@ Shape SliceDataStorage::getLayerOutlines( switch (layer_type) { case Raft::LayerType::RaftBase: - raftOutline = &raftBaseOutline; + raftOutline = &raft_base_outline; use_current_extruder_for_raft |= extruder_nr == int(mesh_group_settings.get("raft_base_extruder_nr").extruder_nr_); break; case Raft::LayerType::RaftInterface: - raftOutline = &raftInterfaceOutline; + raftOutline = &raft_interface_outline; use_current_extruder_for_raft |= extruder_nr == int(mesh_group_settings.get("raft_interface_extruder_nr").extruder_nr_); break; case Raft::LayerType::RaftSurface: - raftOutline = &raftSurfaceOutline; + raftOutline = &raft_surface_outline; use_current_extruder_for_raft |= extruder_nr == int(mesh_group_settings.get("raft_surface_extruder_nr").extruder_nr_); break; default: @@ -346,7 +346,7 @@ Shape SliceDataStorage::getLayerOutlines( layer.getOutlines(total, external_polys_only); if (mesh->settings.get("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { - total = total.unionPolygons(layer.openPolyLines.offset(MM2INT(0.1))); + total = total.unionPolygons(layer.open_polylines.offset(MM2INT(0.1))); } } } diff --git a/src/slicer.cpp b/src/slicer.cpp index adcfc615d9..a7a694af28 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -766,7 +766,7 @@ void SlicerLayer::makePolygons(const Mesh* mesh) for (const OpenPolyline& polyline : open_polylines) { - openPolylines.push_back(std::move(polyline), CheckNonEmptyParam::OnlyIfNotEmpty); + open_polylines.push_back(std::move(polyline), CheckNonEmptyParam::OnlyIfNotEmpty); } // Remove all the tiny polygons, or polygons that are not closed. As they do not contribute to the actual print. @@ -786,15 +786,15 @@ void SlicerLayer::makePolygons(const Mesh* mesh) // Clean up polylines for Surface Mode printing auto itPolylines = std::remove_if( - openPolylines.begin(), - openPolylines.end(), + open_polylines.begin(), + open_polylines.end(), [snap_distance](const OpenPolyline& line) { return line.shorterThan(snap_distance); }); - openPolylines.erase(itPolylines, openPolylines.end()); + open_polylines.erase(itPolylines, open_polylines.end()); - openPolylines.removeDegenerateVerts(); + open_polylines.removeDegenerateVerts(); } Slicer::Slicer(Mesh* i_mesh, const coord_t thickness, const size_t slice_layer_count, bool use_variable_layer_heights, std::vector* adaptive_layers) diff --git a/src/utils/AABB.cpp b/src/utils/AABB.cpp index 3229852a30..6707775c3f 100644 --- a/src/utils/AABB.cpp +++ b/src/utils/AABB.cpp @@ -25,11 +25,11 @@ AABB::AABB(const Point2LL& min, const Point2LL& max) { } -AABB::AABB(const Shape& polys) +AABB::AABB(const Shape& shape) : min_(POINT_MAX, POINT_MAX) , max_(POINT_MIN, POINT_MIN) { - calculate(polys); + calculate(shape); } AABB::AABB(const Polygon& poly) @@ -69,11 +69,11 @@ coord_t AABB::distanceSquared(const AABB& other) const }); } -void AABB::calculate(const Shape& polys) +void AABB::calculate(const Shape& shape) { min_ = Point2LL(POINT_MAX, POINT_MAX); max_ = Point2LL(POINT_MIN, POINT_MIN); - for (const Polygon& poly : polys) + for (const Polygon& poly : shape) { for (const Point2LL& point : poly) { diff --git a/src/utils/ExtrusionSegment.cpp b/src/utils/ExtrusionSegment.cpp index 0d0a078d54..e43b962fce 100644 --- a/src/utils/ExtrusionSegment.cpp +++ b/src/utils/ExtrusionSegment.cpp @@ -10,12 +10,12 @@ namespace cura { -Shape ExtrusionSegment::toPolygons() +Shape ExtrusionSegment::toShape() { - return toPolygons(is_reduced_); + return toShape(is_reduced_); } -Shape ExtrusionSegment::toPolygons(bool reduced) +Shape ExtrusionSegment::toShape(bool reduced) { Shape ret; const Point2LL vec = to_.p_ - from_.p_; diff --git a/src/utils/ListPolyIt.cpp b/src/utils/ListPolyIt.cpp index 8eeb6887e6..f56159af5d 100644 --- a/src/utils/ListPolyIt.cpp +++ b/src/utils/ListPolyIt.cpp @@ -14,9 +14,9 @@ namespace cura { -void ListPolyIt::convertPolygonsToLists(const Shape& polys, ListPolygons& result) +void ListPolyIt::convertPolygonsToLists(const Shape& shape, ListPolygons& result) { - for (const Polygon& poly : polys) + for (const Polygon& poly : shape) { result.emplace_back(); convertPolygonToList(poly, result.back()); diff --git a/src/utils/Simplify.cpp b/src/utils/Simplify.cpp index 3f8c3b7f1d..e1802165ba 100644 --- a/src/utils/Simplify.cpp +++ b/src/utils/Simplify.cpp @@ -114,7 +114,7 @@ size_t Simplify::previousNotDeleted(size_t index, const std::vector& to_de } template<> -ExtrusionLine Simplify::createEmpty(const ExtrusionLine& original) const +ExtrusionLine Simplify::createEmpty(const ExtrusionLine& original) { ExtrusionLine result(original.inset_idx_, original.is_odd_); result.is_closed_ = original.is_closed_; @@ -122,7 +122,7 @@ ExtrusionLine Simplify::createEmpty(const ExtrusionLine& original) const } template -Polygonal Simplify::createEmpty(const Polygonal& /*original*/) const +Polygonal Simplify::createEmpty(const Polygonal& /*original*/) { return Polygonal(); } diff --git a/src/utils/ToolpathVisualizer.cpp b/src/utils/ToolpathVisualizer.cpp index 781ad724d3..88161c78c7 100644 --- a/src/utils/ToolpathVisualizer.cpp +++ b/src/utils/ToolpathVisualizer.cpp @@ -24,7 +24,7 @@ void ToolpathVisualizer::toolpaths(const std::vector& all_segm ExtrusionSegment s = all_segments[segment_idx]; s.from_.w_ *= w / .9; s.to_.w_ *= w / .9; - Shape covered = s.toPolygons(false); + Shape covered = s.toShape(false); polys.push_back(covered); } int c = 255 - 200 * (w - .25); @@ -71,7 +71,7 @@ void ToolpathVisualizer::width_legend(const Shape& input, coord_t nozzle_size, c legend_btm.p_ += (legend_mid.p_ - legend_btm.p_) / 4; legend_top.p_ += (legend_mid.p_ - legend_top.p_) / 4; ExtrusionSegment legend_segment(legend_btm, legend_top, true, false); - svg_.writeAreas(legend_segment.toPolygons(false), SVG::ColorObject(200, 200, 200), SVG::Color::NONE); // real outline + svg_.writeAreas(legend_segment.toShape(false), SVG::ColorObject(200, 200, 200), SVG::Color::NONE); // real outline std::vector all_segments_plus; all_segments_plus.emplace_back(legend_segment); // colored @@ -143,7 +143,7 @@ void ToolpathVisualizer::widths( // } s.from_.w_ *= w / .9; s.to_.w_ *= w / .9; - Shape covered = s.toPolygons(); + Shape covered = s.toShape(); svg_.writeAreas(covered, SVG::ColorObject(clr.x_, clr.y_, clr.z_), SVG::Color::NONE); } } From 74f008d4c373976a23f464f61664d944e43a9572 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 26 Apr 2024 16:37:47 +0200 Subject: [PATCH 070/135] Apply minor PR suggestions CURA-9830 --- include/geometry/SegmentIterator.h | 2 +- include/utils/ImplicitSharedDataContainer.h | 188 -------------------- 2 files changed, 1 insertion(+), 189 deletions(-) delete mode 100644 include/utils/ImplicitSharedDataContainer.h diff --git a/include/geometry/SegmentIterator.h b/include/geometry/SegmentIterator.h index 9e0f70c932..d56fd63dff 100644 --- a/include/geometry/SegmentIterator.h +++ b/include/geometry/SegmentIterator.h @@ -15,7 +15,7 @@ enum class ConstnessType Modifiable, }; -/*! @brief Custom iterator to loop over the segments of a polyline */ +/*! @brief Custom iterator to loop over the segments of a polyline/polygon */ template struct SegmentIterator { diff --git a/include/utils/ImplicitSharedDataContainer.h b/include/utils/ImplicitSharedDataContainer.h deleted file mode 100644 index ab706d7f0e..0000000000 --- a/include/utils/ImplicitSharedDataContainer.h +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright (c) 2024 UltiMaker -// CuraEngine is released under the terms of the AGPLv3 or higher - -#ifndef UTILS_IMPLICITSHAREDDATACONTAINER_H -#define UTILS_IMPLICITSHAREDDATACONTAINER_H - -namespace cura -{ - -template -class ImplicitSharedDataContainer -{ -public: - virtual ImplicitSharedDataContainer& operator=(const ImplicitSharedDataContainer& other) noexcept - { - data_ = other.data_; - return *this; - } - - virtual ImplicitSharedDataContainer& operator=(ImplicitSharedDataContainer&& other) noexcept - { - data_ = std::move(other.data_); - return *this; - } - -protected: - ImplicitSharedDataContainer() noexcept - : data_(std::make_shared()) - { - } - - ImplicitSharedDataContainer(const ImplicitSharedDataContainer& other) noexcept = default; - - ImplicitSharedDataContainer(ImplicitSharedDataContainer&& movable) noexcept = default; - - virtual ~ImplicitSharedDataContainer() = default; - - inline const DataType& getData() const noexcept - { - return *data_; - } - - DataType& getData() noexcept - { - if (! data_.unique()) - { - // Data is shared, make it unique so that we can modify it - data_ = std::make_shared(*data_); - } - - return *data_; - } - -private: - std::shared_ptr data_; -}; - -template -class ImplicitArraydDataContainer : public ImplicitSharedDataContainer -{ -public: - inline size_t size() const noexcept - { - return getData().size(); - } - - inline bool empty() const noexcept - { - return getData().empty(); - } - - DataType::const_reference operator[](size_t index) const - { - return getData()[index]; - } - - void reserve(size_t min_size) noexcept - { - getData().reserve(min_size); - } - - /*template - ClipperLib::Path::iterator insert(ClipperLib::Path::const_iterator pos, iterator first, iterator last) - { - return path_->insert(pos, first, last); - }*/ - - void add(const DataType::const_reference value) noexcept - { - getData().push_back(value); - } - - template - void emplace_back(Args&&... args) noexcept - { - getData().emplace_back(args...); - } - - void remove(size_t index) - { - DataType& data = getData(); - assert(index < data.size() && index <= static_cast(std::numeric_limits::max())); - data.erase(data.begin() + static_cast(index)); - } - - /*! - * Removes an element from the list and moves the last elements to its place. This is usually - * faster to process because it does only requires to resize the list. - * - * \warning The counterpart it that it changes the order of the elements ! - */ - void removeFast(size_t index) - { - DataType& data = getData(); - assert(index < data.size()); - if (index < data.size() - 1) - { - data[index] = std::move(data.back()); - } - data.resize(data.size() - 1); - } - - void insert(size_t index, DataType::const_reference value) - { - DataType& data = getData(); - assert(index < data.size() && index <= static_cast(std::numeric_limits::max())); - data.insert(std::next(), data.begin() + static_cast(index), value); - } - - void clear() noexcept - { - getData().clear(); - } - - void pop_back() - { - getData().pop_back(); - } - - void erase(DataType::iterator start, DataType::iterator end) - { - getData().erase(start, end); - } - - DataType::iterator begin() noexcept - { - return getData().begin(); - } - - DataType::const_iterator begin() const noexcept - { - return getData().begin(); - } - - DataType::iterator end() noexcept - { - return getData().end(); - } - - DataType::const_iterator end() const noexcept - { - return getData().end(); - } - - DataType::reference front() noexcept - { - return getData().front(); - } - - DataType::const_reference front() const noexcept - { - return getData().front(); - } - - DataType::reference back() noexcept - { - return getData().back(); - } - - DataType::const_reference back() const noexcept - { - return getData().back(); - } -}; - -} // namespace cura - -#endif // UTILS_IMPLICITSHAREDDATACONTAINER_H From 1f22f2c16eb6624182b2b6a633af4fa44e199f7e Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 26 Apr 2024 16:49:32 +0200 Subject: [PATCH 071/135] Minor code simplification CURA-9830 --- src/path_ordering.cpp | 41 +++++++++-------------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/src/path_ordering.cpp b/src/path_ordering.cpp index 63d4d47ef4..8d7cd91ad1 100644 --- a/src/path_ordering.cpp +++ b/src/path_ordering.cpp @@ -10,38 +10,8 @@ namespace cura { -template<> -const PointsSet& PathOrdering::getVertexData() -{ - return *vertices_; -} - -template<> -const PointsSet& PathOrdering::getVertexData() -{ - return *vertices_; -} - -template<> -const PointsSet& PathOrdering::getVertexData() -{ - return *vertices_; -} - -template<> -const PointsSet& PathOrdering::getVertexData() -{ - return *vertices_; -} - -template<> -const PointsSet& PathOrdering::getVertexData() -{ - return *vertices_; -} - -template<> -const PointsSet& PathOrdering::getVertexData() +template +const PointsSet& PathOrdering::getVertexData() { return *vertices_; } @@ -73,4 +43,11 @@ const PointsSet& PathOrdering::getVertexData() return *cached_vertices_; } +template const PointsSet& PathOrdering::getVertexData(); +template const PointsSet& PathOrdering::getVertexData(); +template const PointsSet& PathOrdering::getVertexData(); +template const PointsSet& PathOrdering::getVertexData(); +template const PointsSet& PathOrdering::getVertexData(); +template const PointsSet& PathOrdering::getVertexData(); + } // namespace cura From 5d4a4f0ebf0fc97fb9bf02289cf41ab7625849ab Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Fri, 26 Apr 2024 16:52:49 +0200 Subject: [PATCH 072/135] removing debug code as its executing in production Also this code contains svg generation, which is majorly used in debugging application --- src/utils/polygonUtils.cpp | 51 -------------------------------------- 1 file changed, 51 deletions(-) diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index 9d18e82a95..6266b73ce1 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -15,16 +15,10 @@ #include "utils/linearAlg2D.h" #ifdef DEBUG -#include - #include - #include "utils/AABB.h" -#include "utils/SVG.h" #endif -namespace fs = std::filesystem; - namespace cura { @@ -693,51 +687,6 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside( bool overall_is_inside = polygons.inside(overall_inside.location_); if (overall_is_inside != (preferred_dist_inside > 0)) { -#ifdef DEBUG - static bool has_run = false; - if (! has_run) - { - fs::path const debug_file_name = fs::temp_directory_path() / "debug.html"; - try - { - int offset_performed = offset / 2; - AABB aabb(polygons); - aabb.expand(std::abs(preferred_dist_inside) * 2); - SVG svg(debug_file_name.string(), aabb); - svg.writeComment("Original polygon in black"); - svg.writePolygons(polygons, SVG::Color::BLACK); - for (auto poly : polygons) - { - for (auto point : poly) - { - svg.writePoint(point, true, 2); - } - } - std::stringstream ss; - svg.writeComment("Reference polygon in yellow"); - svg.writePolygon(closest_poly, SVG::Color::YELLOW); - ss << "Offsetted polygon in blue with offset " << offset_performed; - svg.writeComment(ss.str()); - svg.writePolygons(insetted, SVG::Color::BLUE); - for (auto poly : insetted) - { - for (auto point : poly) - { - svg.writePoint(point, true, 2); - } - } - svg.writeComment("From location"); - svg.writePoint(from, true, 5, SVG::Color::GREEN); - svg.writeComment("Location computed to be inside the black polygon"); - svg.writePoint(inside.location_, true, 5, SVG::Color::RED); - } - catch (...) - { - } - spdlog::error("Clipper::offset failed. See generated {}! Black is original Blue is offsetted polygon", debug_file_name.string()); - has_run = true; - } -#endif return ClosestPolygonPoint(); } inside = overall_inside; From 38904ea4c533c4a9f6fb2af00a018432465d14c2 Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Fri, 26 Apr 2024 14:53:23 +0000 Subject: [PATCH 073/135] Applied clang-format. --- src/utils/polygonUtils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index 6266b73ce1..fff4f955ba 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -16,6 +16,7 @@ #ifdef DEBUG #include + #include "utils/AABB.h" #endif From 70e33aa13c2d81b109b6bee8a4d898f4d1659724 Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Wed, 1 May 2024 11:31:01 +0200 Subject: [PATCH 074/135] Removed SUPPORT type z seam and added isInDisallowedArea func. The code changes revolve around the functionality of the InsetOrderOptimizer and related path optimizers. These changes allow for better handling of support meshes by allowing the optimizer to consider if a layer part is supported or not. Furthermore, the type of paths used in path optimization was switched from 'ClipperLib::Paths' to 'Polygons' providing better performance and cleaner code. Also, the conditions for EZSeamType::SUPPORT in the seam configuration were removed. CURA-11227 --- include/InsetOrderOptimizer.h | 4 +- include/PathOrderOptimizer.h | 76 ++++++++--------------------------- src/FffGcodeWriter.cpp | 12 +----- src/InsetOrderOptimizer.cpp | 6 +-- src/settings/Settings.cpp | 2 - 5 files changed, 23 insertions(+), 77 deletions(-) diff --git a/include/InsetOrderOptimizer.h b/include/InsetOrderOptimizer.h index 3a09d460f4..8d3d9f3afa 100644 --- a/include/InsetOrderOptimizer.h +++ b/include/InsetOrderOptimizer.h @@ -64,7 +64,7 @@ class InsetOrderOptimizer * class, so this optimize function needs no additional information. * \return Whether anything was added to the layer plan. */ - bool addToLayer(); + bool addToLayer(const bool is_support = false); /*! * Get the order constraints of the insets when printing walls per region / hole. @@ -106,7 +106,7 @@ class InsetOrderOptimizer const ZSeamConfig& z_seam_config_; const std::vector& paths_; const LayerIndex layer_nr_; - std::vector mesh_paths_; + std::vector mesh_paths_; std::vector> inset_polys_; // vector of vectors holding the inset polygons Polygons retraction_region_; // After printing an outer wall, move into this region so that retractions do not leave visible blobs. Calculated lazily if needed (see diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index f25e3a1a96..22a986c19f 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -60,7 +60,7 @@ template class PathOrderOptimizer { private: - std::vector mesh_paths_{}; + std::vector mesh_paths_{}; size_t min_size_support_zeam_ = 0; public: @@ -137,11 +137,15 @@ class PathOrderOptimizer paths_.emplace_back(polygon, is_closed); } - void addMeshPathsinfo(const std::vector& polylines, const size_t min_distance) + void addMeshPathsinfo(const std::vector& mesh_polygons, const size_t min_distance) { constexpr bool is_closed = true; - mesh_paths_ = polylines; min_size_support_zeam_ = min_distance; + //offset polygon with th min_size_support z seam + for (auto& polygons :mesh_polygons) + { + mesh_paths_.push_back(polygons.offset(min_size_support_zeam_, ClipperLib::jtRound)); + } } /*! * Add a new polyline to be optimized. @@ -573,63 +577,15 @@ class PathOrderOptimizer return best_candidate->vertices_; } - /** - * @brief Checks if the given vertex is close to any polygon path defined by the front of the mesh_paths_. - * - * The function iteratively checks the shortest distance from the point to each line segment in the polygon. - * A line segment is defined by each pair of consecutive points in the polygon. - * If the shortest distance is less than or equal to min_size_support_zeam_, the function returns true. - * This implies that the vertex is considered "close" to the polygon path. - * The check is performed against all polygons in the front of the mesh_paths_. - * - * @param point Vertex of interest, provided as a 2D point in the LongLong (LL) coordinate space. - * @return Returns true if the vertex is close to any line segment in the polygon path, false otherwise. - * - * @note The closeness is judged based on the minimum Zeam support size. - * @note The distance check is performed on the squared distance to avoid costly square root operations. - */ - bool isVertexCloseToPolygonPath(Point2LL point) + + bool isInDisallowedPaths(Point2LL point, std::vector& paths) { - for (const auto& points : ranges::front(mesh_paths_)) - { - const int len = points.size(); - for (int i = 0; i < len; ++i) + for (const auto& polygons : paths) + { + if (polygons.inside(point, true)) { - const auto& polygon_point1 = points[i]; - const auto& polygon_point2 = points[(i + 1) % len]; // Ensures looping back to the first point to create the final segment - - // Definitions - double x = static_cast(point.X); - double y = static_cast(point.Y); - double x1 = static_cast(polygon_point1.X); - double y1 = static_cast(polygon_point1.Y); - double x2 = static_cast(polygon_point2.X); - double y2 = static_cast(polygon_point2.Y); - - // Calculate the shortest distance from the point to the line segment - double dx = x2 - x1; - double dy = y2 - y1; - - // Calculate the t parameter - double t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); - - // If t is outside bounds [0,1], point is closest to an endpoint of the segment - t = std::max(0.0, std::min(1.0, t)); - - // Compute the coordinates of the point on the line segment nearest to the external point - double nearestX = x1 + t * dx; - double nearestY = y1 + t * dy; - - // Calculate squared distance from external point to its nearest point on the line segment - double dx_nearest = x - nearestX; - double dy_nearest = y - nearestY; - double squared_distance = dx_nearest * dx_nearest + dy_nearest * dy_nearest; - - if (squared_distance <= min_size_support_zeam_ * min_size_support_zeam_) - { - return true; - } + return true; } } return false; @@ -706,7 +662,7 @@ class PathOrderOptimizer if (! mesh_paths_.empty()) { Point2LL current_candidate = (path.converted_)->at(best_pos); - if (isVertexCloseToPolygonPath(current_candidate)) + if (isInDisallowedPaths(current_candidate, mesh_paths_)) { size_t next_best_position = (path_size > best_pos + 1) ? best_pos + 1 : 0; number_of_paths_analysed += 1; @@ -795,7 +751,7 @@ class PathOrderOptimizer double corner_shift; - if ((seam_config_.type_ == EZSeamType::SHORTEST) || (seam_config_.type_ == EZSeamType::SUPPORT)) + if (seam_config_.type_ == EZSeamType::SHORTEST) { // the more a corner satisfies our criteria, the closer it appears to be // shift 10mm for a very acute corner @@ -861,7 +817,7 @@ class PathOrderOptimizer } } - if (seam_config_.type_ == EZSeamType::SUPPORT) + if (min_size_support_zeam_ != 0) { best_i = pathIfzeamSupportIsCloseToModel(best_i, path, 0); } diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index c9a858d8e4..524ecbc8e4 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3457,15 +3457,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer const GCodePathConfig& config = configs[0]; constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; - EZSeamType z_seam_type = EZSeamType::SHORTEST; - ZSeamConfig z_seam_config; - Point2LL start_pos = gcode_layer.getLastPlannedPositionOrStartingPosition(); - if (infill_extruder.settings_.get("support_z_seam_away_from_model")) - { - z_seam_type = EZSeamType::SUPPORT; - } - - z_seam_config = ZSeamConfig(z_seam_type, start_pos, EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); + ZSeamConfig z_seam_config = ZSeamConfig(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); InsetOrderOptimizer wall_orderer( @@ -3487,7 +3479,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer extruder_nr, z_seam_config, wall_toolpaths); - added_something |= wall_orderer.addToLayer(); + added_something |= wall_orderer.addToLayer(true); } if ((default_support_line_distance <= 0 && support_structure != ESupportStructure::TREE) || part.infill_area_per_combine_per_density_.empty()) diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 409900584d..94edd2bcd8 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -74,7 +74,7 @@ InsetOrderOptimizer::InsetOrderOptimizer( { } -bool InsetOrderOptimizer::addToLayer() +bool InsetOrderOptimizer::addToLayer(const bool is_support) { // Settings & configs: const auto pack_by_inset = ! settings_.get("optimize_wall_printing_order"); @@ -113,14 +113,14 @@ bool InsetOrderOptimizer::addToLayer() order_optimizer.addPolyline(&line); } } - if (z_seam_config_.type_ == EZSeamType::SUPPORT) + if (is_support && settings_.get("support_z_seam_away_from_model")) { for (std::shared_ptr mesh_ptr : storage_.meshes) { auto& mesh = *mesh_ptr; for (auto& part : mesh.layers[layer_nr_].parts) { - mesh_paths_.push_back(part.print_outline.paths); + mesh_paths_.push_back(part.print_outline); } } if (! mesh_paths_.empty()) diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index 9724281593..d946ec4496 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -513,8 +513,6 @@ EZSeamType Settings::get(const std::string& key) const return EZSeamType::SHARPEST_CORNER; case "plugin"_sw: return EZSeamType::PLUGIN; - case "support"_sw: - return EZSeamType::SUPPORT; default: return EZSeamType::SHORTEST; } From 744f417ad0e37a363a3a93c92e0451c3df5fcf6f Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Wed, 1 May 2024 09:31:36 +0000 Subject: [PATCH 075/135] Applied clang-format. --- include/PathOrderOptimizer.h | 7 +++---- src/FffGcodeWriter.cpp | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 22a986c19f..07acabedf1 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -141,8 +141,8 @@ class PathOrderOptimizer { constexpr bool is_closed = true; min_size_support_zeam_ = min_distance; - //offset polygon with th min_size_support z seam - for (auto& polygons :mesh_polygons) + // offset polygon with th min_size_support z seam + for (auto& polygons : mesh_polygons) { mesh_paths_.push_back(polygons.offset(min_size_support_zeam_, ClipperLib::jtRound)); } @@ -580,7 +580,6 @@ class PathOrderOptimizer bool isInDisallowedPaths(Point2LL point, std::vector& paths) { - for (const auto& polygons : paths) { if (polygons.inside(point, true)) @@ -817,7 +816,7 @@ class PathOrderOptimizer } } - if (min_size_support_zeam_ != 0) + if (min_size_support_zeam_ != 0) { best_i = pathIfzeamSupportIsCloseToModel(best_i, path, 0); } diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 524ecbc8e4..bf3c03dc96 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3457,7 +3457,8 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer const GCodePathConfig& config = configs[0]; constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; - ZSeamConfig z_seam_config = ZSeamConfig(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); + ZSeamConfig z_seam_config + = ZSeamConfig(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); InsetOrderOptimizer wall_orderer( From 8537117012f0800af85112921d774b680da6b1e2 Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Wed, 1 May 2024 11:39:28 +0200 Subject: [PATCH 076/135] remove z-seam support from enaum class as well CURA-11227 --- include/settings/EnumSettings.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/settings/EnumSettings.h b/include/settings/EnumSettings.h index 367b27d223..18bd091569 100644 --- a/include/settings/EnumSettings.h +++ b/include/settings/EnumSettings.h @@ -70,7 +70,6 @@ enum class EZSeamType SHORTEST, USER_SPECIFIED, SHARPEST_CORNER, - SUPPORT, /* The 'Skirt/brim' type behaves like shortest, except it doesn't try to do tie-breaking for similar locations to * the last attempt, as that gives a different result when the seams are next to each other instead of on top. From b8a4b17476a22b1928dcc4728ef1c46a19e7fc04 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Thu, 2 May 2024 11:00:47 +0200 Subject: [PATCH 077/135] use Shape instead of Polygons for the PrimeTowers This commit replaces instances of the Polygons data structure with Shape in the PrimeTower class, both in prime tower calculations and in storage data structures such as MovesByExtruder and MovesByLayer. This change streamlines the handling of geometric data and enables more robust manipulation of shapes in the prime tower generation process. Contribute to NP-9830 --- include/PrimeTower.h | 2 +- src/PrimeTower.cpp | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/PrimeTower.h b/include/PrimeTower.h index 03419f513a..c1f4927880 100644 --- a/include/PrimeTower.h +++ b/include/PrimeTower.h @@ -29,7 +29,7 @@ class PrimeTower { private: using MovesByExtruder = std::map; - using MovesByLayer = std::map>; + using MovesByLayer = std::map>; size_t extruder_count_; //!< Number of extruders diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index 16892ea790..b2f4fde0a5 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -186,7 +186,6 @@ void PrimeTower::generatePaths_denseInfill(std::vector& cumulative_inse } extra_radius = line_width * extra_rings; outer_poly_base_.push_back(outer_poly_.offset(extra_radius)); - base_extra_moves_[extruder_nr].push_back(PolygonUtils::generateOutset(outer_poly_, extra_rings, line_width)); } } @@ -448,7 +447,7 @@ void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const size_t ext { // Actual prime pattern const GCodePathConfig& config = gcode_layer.configs_storage_.prime_tower_config_per_extruder[extruder_nr]; - const Polygons& pattern = prime_moves_.at(extruder_nr); + const Shape& pattern = prime_moves_.at(extruder_nr); gcode_layer.addPolygonsByOptimizer(pattern, config); } } @@ -458,11 +457,11 @@ bool PrimeTower::addToGcode_base(LayerPlan& gcode_layer, const size_t extruder_n const size_t raft_total_extra_layers = Raft::getTotalExtraLayers(); LayerIndex absolute_layer_number = gcode_layer.getLayerNr() + raft_total_extra_layers; - const std::vector& pattern_extra_brim = base_extra_moves_.at(extruder_nr); + const auto& pattern_extra_brim = base_extra_moves_.at(extruder_nr); if (absolute_layer_number < pattern_extra_brim.size()) { // Extra rings for stronger base - const Shape& pattern = pattern_extra_brim[absolute_layer_number]; + const auto& pattern = pattern_extra_brim[absolute_layer_number]; if (! pattern.empty()) { const GCodePathConfig& config = gcode_layer.configs_storage_.prime_tower_config_per_extruder[extruder_nr]; @@ -481,7 +480,7 @@ bool PrimeTower::addToGcode_inset(LayerPlan& gcode_layer, const size_t extruder_ if (absolute_layer_number == 0) // Extra-adhesion on very first layer only { - const Polygons& pattern_extra_inset = inset_extra_moves_.at(extruder_nr); + const Shape& pattern_extra_inset = inset_extra_moves_.at(extruder_nr); if (! pattern_extra_inset.empty()) { const GCodePathConfig& config = gcode_layer.configs_storage_.prime_tower_config_per_extruder[extruder_nr]; From b05d0fd05f73c1573aae32bde6b46e0abb8c9dea Mon Sep 17 00:00:00 2001 From: jellespijker Date: Thu, 2 May 2024 09:01:22 +0000 Subject: [PATCH 078/135] Applied clang-format. --- include/plugins/converters.h | 3 +-- src/TreeSupport.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/plugins/converters.h b/include/plugins/converters.h index e3eca0a663..6748ca0be0 100644 --- a/include/plugins/converters.h +++ b/include/plugins/converters.h @@ -107,8 +107,7 @@ struct infill_generate_request : public details::converter>, Shape, OpenLinesSet>> + : public details::converter>, Shape, OpenLinesSet>> { native_value_type operator()(const value_type& message) const; }; diff --git a/src/TreeSupport.cpp b/src/TreeSupport.cpp index 6ba49d7e3f..21a34796de 100644 --- a/src/TreeSupport.cpp +++ b/src/TreeSupport.cpp @@ -2023,9 +2023,10 @@ void TreeSupport::filterFloatingLines(std::vector& support_layer_storage) return; } - Shape outer_walls - = TreeSupportUtils::toPolylines(support_layer_storage[layer_idx - 1].getOutsidePolygons()) - .createTubeShape(closing_dist, 0); //.unionPolygons(volumes_.getCollision(0, layer_idx - 1, true).offset(-(config.support_line_width+config.xy_min_distance))); + Shape outer_walls = TreeSupportUtils::toPolylines(support_layer_storage[layer_idx - 1].getOutsidePolygons()) + .createTubeShape( + closing_dist, + 0); //.unionPolygons(volumes_.getCollision(0, layer_idx - 1, true).offset(-(config.support_line_width+config.xy_min_distance))); Shape holes_below; From 76d32b8b7994f409d0eacc8150928bf80ed26608 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Thu, 2 May 2024 12:05:05 +0200 Subject: [PATCH 079/135] Add numbers library Updated the copyright year to 2024 across all files and included the 'numbers' library for use in various files. Also, made certain changes such as replacing 'stdio.h' with 'cstdio' and 'assert.h' with 'cassert' for better compatibility. Contribute to CURA-9830 --- src/FffGcodeWriter.cpp | 1 + src/Mold.cpp | 2 ++ src/PrimeTower.cpp | 1 + src/SkeletalTrapezoidation.cpp | 1 + src/TreeSupportTipGenerator.cpp | 1 + src/gcodeExport.cpp | 7 ++++--- src/infill.cpp | 1 + src/infill/GyroidInfill.cpp | 4 +++- src/mesh.cpp | 2 ++ src/settings/AdaptiveLayerHeights.cpp | 3 ++- src/settings/Settings.cpp | 5 +++-- src/sliceDataStorage.cpp | 5 +++-- src/slicer.cpp | 4 ++-- src/utils/ExtrusionSegment.cpp | 4 +++- tests/PathOrderMonotonicTest.cpp | 3 ++- tests/arcus/ArcusCommunicationTest.cpp | 3 ++- 16 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 2f8fd79234..89ba263f0c 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -7,6 +7,7 @@ #include // numeric_limits #include #include +#include #include #include #include diff --git a/src/Mold.cpp b/src/Mold.cpp index 37ad953087..6e8b501eae 100644 --- a/src/Mold.cpp +++ b/src/Mold.cpp @@ -13,6 +13,8 @@ #include "sliceDataStorage.h" #include "slicer.h" +#include + namespace cura { diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index b2f4fde0a5..cc56d71d4c 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -5,6 +5,7 @@ #include #include +#include #include diff --git a/src/SkeletalTrapezoidation.cpp b/src/SkeletalTrapezoidation.cpp index 9c578a185b..afe482c6f3 100644 --- a/src/SkeletalTrapezoidation.cpp +++ b/src/SkeletalTrapezoidation.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 95d5279598..0e10ca1971 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/src/gcodeExport.cpp b/src/gcodeExport.cpp index 8a3cc11538..f443bbc184 100644 --- a/src/gcodeExport.cpp +++ b/src/gcodeExport.cpp @@ -1,12 +1,13 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "gcodeExport.h" -#include +#include #include +#include #include -#include +#include #include diff --git a/src/infill.cpp b/src/infill.cpp index 592323ee52..705489ee18 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -5,6 +5,7 @@ #include //For std::sort. #include +#include #include #include diff --git a/src/infill/GyroidInfill.cpp b/src/infill/GyroidInfill.cpp index 5ab658ff19..59f85fbdf5 100644 --- a/src/infill/GyroidInfill.cpp +++ b/src/infill/GyroidInfill.cpp @@ -1,8 +1,10 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #include "infill/GyroidInfill.h" +#include + #include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" #include "geometry/Shape.h" diff --git a/src/mesh.cpp b/src/mesh.cpp index 740dc442c8..97c16800fd 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -3,6 +3,8 @@ #include "mesh.h" +#include + #include #include "utils/Point3D.h" diff --git a/src/settings/AdaptiveLayerHeights.cpp b/src/settings/AdaptiveLayerHeights.cpp index 14b37b8eaa..14e5e743c0 100644 --- a/src/settings/AdaptiveLayerHeights.cpp +++ b/src/settings/AdaptiveLayerHeights.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "settings/AdaptiveLayerHeights.h" @@ -6,6 +6,7 @@ #include #include #include +#include #include "Application.h" #include "Slice.h" diff --git a/src/settings/Settings.cpp b/src/settings/Settings.cpp index 36bd83d9f2..136606cde2 100644 --- a/src/settings/Settings.cpp +++ b/src/settings/Settings.cpp @@ -1,13 +1,14 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "settings/Settings.h" #include +#include #include +#include #include // regex parsing for temp flow graph #include // ostringstream -#include #include //Parsing strings (stod, stoul). #include diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index a5f6e25f59..d346d6df35 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -1,8 +1,10 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "sliceDataStorage.h" +#include + #include #include "Application.h" //To get settings. @@ -17,7 +19,6 @@ #include "raft.h" #include "utils/math.h" //For PI. - namespace cura { diff --git a/src/slicer.cpp b/src/slicer.cpp index a7a694af28..cb2e40339b 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -1,11 +1,11 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "slicer.h" #include // remove_if #include -#include +#include #include #include diff --git a/src/utils/ExtrusionSegment.cpp b/src/utils/ExtrusionSegment.cpp index e43b962fce..0327f333db 100644 --- a/src/utils/ExtrusionSegment.cpp +++ b/src/utils/ExtrusionSegment.cpp @@ -1,8 +1,10 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "utils/ExtrusionSegment.h" +#include + #include #include "utils/macros.h" diff --git a/tests/PathOrderMonotonicTest.cpp b/tests/PathOrderMonotonicTest.cpp index 8aa0168aa0..b344d58f48 100644 --- a/tests/PathOrderMonotonicTest.cpp +++ b/tests/PathOrderMonotonicTest.cpp @@ -1,9 +1,10 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "PathOrderMonotonic.h" #include +#include #include #include diff --git a/tests/arcus/ArcusCommunicationTest.cpp b/tests/arcus/ArcusCommunicationTest.cpp index 69434dd06d..cfd5f282c7 100644 --- a/tests/arcus/ArcusCommunicationTest.cpp +++ b/tests/arcus/ArcusCommunicationTest.cpp @@ -1,8 +1,9 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #include #include +#include #include From 5a2c2437138be45e513b627ce9210446b2b29f71 Mon Sep 17 00:00:00 2001 From: jellespijker Date: Thu, 2 May 2024 10:05:46 +0000 Subject: [PATCH 080/135] Applied clang-format. --- src/Mold.cpp | 4 ++-- src/SkeletalTrapezoidation.cpp | 2 +- src/TreeSupportTipGenerator.cpp | 2 +- src/slicer.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mold.cpp b/src/Mold.cpp index 6e8b501eae..4c2fa54a32 100644 --- a/src/Mold.cpp +++ b/src/Mold.cpp @@ -3,6 +3,8 @@ #include "Mold.h" +#include + #include "Application.h" //To get settings. #include "ExtruderTrain.h" #include "Scene.h" @@ -13,8 +15,6 @@ #include "sliceDataStorage.h" #include "slicer.h" -#include - namespace cura { diff --git a/src/SkeletalTrapezoidation.cpp b/src/SkeletalTrapezoidation.cpp index afe482c6f3..c233efe41c 100644 --- a/src/SkeletalTrapezoidation.cpp +++ b/src/SkeletalTrapezoidation.cpp @@ -4,11 +4,11 @@ #include "SkeletalTrapezoidation.h" #include +#include #include #include #include #include -#include #include #include diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 0e10ca1971..2e8ec5e5b6 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -5,9 +5,9 @@ #include #include +#include #include #include -#include #include #include diff --git a/src/slicer.cpp b/src/slicer.cpp index cb2e40339b..1b33bb37e2 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -4,8 +4,8 @@ #include "slicer.h" #include // remove_if -#include #include +#include #include #include From 9fc42e113f30b88543b344c1eff300fe2ec97b06 Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Thu, 2 May 2024 14:20:25 +0200 Subject: [PATCH 081/135] added disallowed area in PathOptimiser. Instead of specific case of support away from model, now it is given from Insetoptimiser as disallowed area. this can also be used for other features in future. CURA-11227 --- include/InsetOrderOptimizer.h | 2 +- include/PathOrderOptimizer.h | 43 ++++++++--------------------------- src/InsetOrderOptimizer.cpp | 5 ++-- 3 files changed, 13 insertions(+), 37 deletions(-) diff --git a/include/InsetOrderOptimizer.h b/include/InsetOrderOptimizer.h index 8d3d9f3afa..90097205ec 100644 --- a/include/InsetOrderOptimizer.h +++ b/include/InsetOrderOptimizer.h @@ -106,7 +106,7 @@ class InsetOrderOptimizer const ZSeamConfig& z_seam_config_; const std::vector& paths_; const LayerIndex layer_nr_; - std::vector mesh_paths_; + Polygons mesh_paths_; std::vector> inset_polys_; // vector of vectors holding the inset polygons Polygons retraction_region_; // After printing an outer wall, move into this region so that retractions do not leave visible blobs. Calculated lazily if needed (see diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 07acabedf1..1ff01a13ee 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -59,12 +59,10 @@ namespace cura template class PathOrderOptimizer { -private: - std::vector mesh_paths_{}; - size_t min_size_support_zeam_ = 0; - public: using OrderablePath = PathOrdering; + /* Areas defined here are not allowed to have the start the prints */ + Polygons disallowed_area {}; /*! * After optimizing, this contains the paths that need to be printed in the * correct order. @@ -122,7 +120,7 @@ class PathOrderOptimizer , reverse_direction_(reverse_direction) , _group_outer_walls(group_outer_walls) , order_requirements_(&order_requirements) - , mesh_paths_{} + , disallowed_area{} { } @@ -137,16 +135,6 @@ class PathOrderOptimizer paths_.emplace_back(polygon, is_closed); } - void addMeshPathsinfo(const std::vector& mesh_polygons, const size_t min_distance) - { - constexpr bool is_closed = true; - min_size_support_zeam_ = min_distance; - // offset polygon with th min_size_support z seam - for (auto& polygons : mesh_polygons) - { - mesh_paths_.push_back(polygons.offset(min_size_support_zeam_, ClipperLib::jtRound)); - } - } /*! * Add a new polyline to be optimized. * \param polyline The polyline to optimize. @@ -577,19 +565,6 @@ class PathOrderOptimizer return best_candidate->vertices_; } - - bool isInDisallowedPaths(Point2LL point, std::vector& paths) - { - for (const auto& polygons : paths) - { - if (polygons.inside(point, true)) - { - return true; - } - } - return false; - } - OrderablePath* findClosestPath(Point2LL start_position, std::vector candidate_paths) { coord_t best_distance2 = std::numeric_limits::max(); @@ -653,19 +628,19 @@ class PathOrderOptimizer * This typically happens when the distance of the support seam from the model is bigger than all the support wall points. */ - size_t pathIfzeamSupportIsCloseToModel(size_t best_pos, const OrderablePath& path, size_t number_of_paths_analysed) + size_t pathIfZseamIsInDisallowedArea(size_t best_pos, const OrderablePath& path, size_t number_of_paths_analysed) { size_t path_size = path.converted_->size(); if (path_size > number_of_paths_analysed) { - if (! mesh_paths_.empty()) + if (! disallowed_area.empty()) { Point2LL current_candidate = (path.converted_)->at(best_pos); - if (isInDisallowedPaths(current_candidate, mesh_paths_)) + if (disallowed_area.inside(current_candidate, true)) { size_t next_best_position = (path_size > best_pos + 1) ? best_pos + 1 : 0; number_of_paths_analysed += 1; - best_pos = pathIfzeamSupportIsCloseToModel(next_best_position, path, number_of_paths_analysed); + best_pos = pathIfZseamIsInDisallowedArea(next_best_position, path, number_of_paths_analysed); } } } @@ -816,9 +791,9 @@ class PathOrderOptimizer } } - if (min_size_support_zeam_ != 0) + if (!disallowed_area.empty()) { - best_i = pathIfzeamSupportIsCloseToModel(best_i, path, 0); + best_i = pathIfZseamIsInDisallowedArea(best_i, path, 0); } return best_i; } diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 94edd2bcd8..7e3eeb0ce0 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -120,12 +120,13 @@ bool InsetOrderOptimizer::addToLayer(const bool is_support) auto& mesh = *mesh_ptr; for (auto& part : mesh.layers[layer_nr_].parts) { - mesh_paths_.push_back(part.print_outline); + mesh_paths_.add(part.print_outline); } } if (! mesh_paths_.empty()) { - order_optimizer.addMeshPathsinfo(mesh_paths_, settings_.get("support_z_seam_min_distance")); + coord_t min_distance = settings_.get("support_z_seam_min_distance"); + order_optimizer.disallowed_area = mesh_paths_.offset(min_distance, ClipperLib::jtRound); } } From 6777aa0dd89d4689ff911561901201a3a627eab3 Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Thu, 2 May 2024 12:21:04 +0000 Subject: [PATCH 082/135] Applied clang-format. --- include/PathOrderOptimizer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 1ff01a13ee..c8a8b05421 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -62,7 +62,7 @@ class PathOrderOptimizer public: using OrderablePath = PathOrdering; /* Areas defined here are not allowed to have the start the prints */ - Polygons disallowed_area {}; + Polygons disallowed_area{}; /*! * After optimizing, this contains the paths that need to be printed in the * correct order. @@ -791,7 +791,7 @@ class PathOrderOptimizer } } - if (!disallowed_area.empty()) + if (! disallowed_area.empty()) { best_i = pathIfZseamIsInDisallowedArea(best_i, path, 0); } From 0ce98e61b0a2bfa10932bb293cca43e42db4f865 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Thu, 2 May 2024 15:02:19 +0200 Subject: [PATCH 083/135] Include numbers Contributes to CURA-9830 --- include/BeadingStrategy/BeadingStrategy.h | 11 ++-- .../BeadingStrategy/BeadingStrategyFactory.h | 6 +- include/PathOrderOptimizer.h | 11 ++-- include/TreeSupportSettings.h | 2 + include/geometry/Point2LL.h | 46 +++++++------- include/geometry/PointMatrix.h | 27 +++++---- include/settings/types/Angle.h | 31 +++++----- include/slicer.h | 3 +- include/utils/ExtrusionSegment.h | 5 +- include/utils/PolygonConnector.h | 3 +- include/utils/actions/smooth.h | 46 +++++++------- include/utils/math.h | 26 ++++---- include/utils/polygonUtils.h | 3 +- include/utils/types/generic.h | 8 ++- src/FffGcodeWriter.cpp | 3 - src/LayerPlan.cpp | 1 + src/PrimeTower.cpp | 3 +- src/SkeletalTrapezoidation.cpp | 1 - src/TreeSupportTipGenerator.cpp | 6 +- src/gcodeExport.cpp | 1 - src/geometry/Polygon.cpp | 2 + src/geometry/Polyline.cpp | 1 + src/utils/linearAlg2D.cpp | 3 +- src/utils/polygonUtils.cpp | 3 +- tests/integration/SlicePhaseTest.cpp | 4 +- tests/settings/SettingsTest.cpp | 5 +- tests/utils/LinearAlg2DTest.cpp | 3 +- tests/utils/PolygonTest.cpp | 4 +- tests/utils/SimplifyTest.cpp | 2 + tests/utils/SmoothTest.cpp | 60 +++++++++---------- 30 files changed, 175 insertions(+), 155 deletions(-) diff --git a/include/BeadingStrategy/BeadingStrategy.h b/include/BeadingStrategy/BeadingStrategy.h index 68d2c31be1..0a4b1d32f2 100644 --- a/include/BeadingStrategy/BeadingStrategy.h +++ b/include/BeadingStrategy/BeadingStrategy.h @@ -1,14 +1,15 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef BEADING_STRATEGY_H #define BEADING_STRATEGY_H #include +#include -#include "../settings/types/Angle.h" -#include "../settings/types/Ratio.h" //For the wall transition threshold. #include "geometry/Point2LL.h" +#include "settings/types/Angle.h" +#include "settings/types/Ratio.h" //For the wall transition threshold. namespace cura { @@ -45,9 +46,7 @@ class BeadingStrategy BeadingStrategy(const BeadingStrategy& other); - virtual ~BeadingStrategy() - { - } + virtual ~BeadingStrategy() = default; /*! * Retrieve the bead widths with which to cover a given thickness. diff --git a/include/BeadingStrategy/BeadingStrategyFactory.h b/include/BeadingStrategy/BeadingStrategyFactory.h index 2789fa4657..a2b5c1bd51 100644 --- a/include/BeadingStrategy/BeadingStrategyFactory.h +++ b/include/BeadingStrategy/BeadingStrategyFactory.h @@ -1,11 +1,13 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef BEADING_STRATEGY_FACTORY_H #define BEADING_STRATEGY_FACTORY_H -#include "../settings/types/Ratio.h" +#include + #include "BeadingStrategy.h" +#include "settings/types/Ratio.h" namespace cura { diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index fcdd21eec1..23dd12a305 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -1,9 +1,10 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef PATHORDEROPTIMIZER_H #define PATHORDEROPTIMIZER_H +#include #include #include @@ -15,7 +16,6 @@ #include #include -#include "InsetOrderOptimizer.h" // for makeOrderIncludeTransitive #include "pathPlanning/CombPath.h" //To calculate the combing distance if we want to use combing. #include "pathPlanning/LinePolygonsCrossings.h" //To prevent calculating combing distances if we don't cross the combing borders. #include "path_ordering.h" @@ -402,7 +402,7 @@ class PathOrderOptimizer } auto local_current_position = current_position; - while (candidates.size() != 0) + while (!candidates.empty()) { Path best_candidate = findClosestPathVertices(local_current_position, candidates); @@ -633,10 +633,7 @@ class PathOrderOptimizer { return path.converted_->size() - 1; // Back end is closer. } - else - { - return 0; // Front end is closer. - } + return 0; // Front end is closer. } // Rest of the function only deals with (closed) polygons. We need to be able to find the seam location of those polygons. diff --git a/include/TreeSupportSettings.h b/include/TreeSupportSettings.h index 26295fbd55..2e3162a71a 100644 --- a/include/TreeSupportSettings.h +++ b/include/TreeSupportSettings.h @@ -1,3 +1,4 @@ +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef TREESUPPORTSETTINGS_H @@ -13,6 +14,7 @@ #include "settings/types/Ratio.h" #include "utils/Coord_t.h" #include "utils/Simplify.h" +#include "utils/math.h" namespace cura diff --git a/include/geometry/Point2LL.h b/include/geometry/Point2LL.h index 0349b03bd5..4f76a70efe 100644 --- a/include/geometry/Point2LL.h +++ b/include/geometry/Point2LL.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef UTILS_INT_POINT_H @@ -10,11 +10,9 @@ Integer points are used to avoid floating point rounding errors, and because Cli */ #define INLINE static inline -//#include // for hash function object -//#include // auto-serialization / auto-toString() #include +#include #include -//#include #include "geometry/Point3LL.h" @@ -42,24 +40,24 @@ static Point2LL no_point(std::numeric_limits::min(), std::nume /* Extra operators to make it easier to do math with the 64bit Point objects */ INLINE Point2LL operator-(const Point2LL& p0) { - return Point2LL(-p0.X, -p0.Y); + return { -p0.X, -p0.Y }; } INLINE Point2LL operator+(const Point2LL& p0, const Point2LL& p1) { - return Point2LL(p0.X + p1.X, p0.Y + p1.Y); + return { p0.X + p1.X, p0.Y + p1.Y }; } INLINE Point2LL operator-(const Point2LL& p0, const Point2LL& p1) { - return Point2LL(p0.X - p1.X, p0.Y - p1.Y); + return { p0.X - p1.X, p0.Y - p1.Y }; } INLINE Point2LL operator*(const Point2LL& p0, const coord_t i) { - return Point2LL(p0.X * i, p0.Y * i); + return { p0.X * i, p0.Y * i }; } template::value, T>::type> // Use only for numeric types. INLINE Point2LL operator*(const Point2LL& p0, const T i) { - return Point2LL(std::llrint(static_cast(p0.X) * i), std::llrint(static_cast(p0.Y) * i)); + return { std::llrint(static_cast(p0.X) * i), std::llrint(static_cast(p0.Y) * i) }; } template::value, T>::type> // Use only for numeric types. INLINE Point2LL operator*(const T i, const Point2LL& p0) @@ -68,15 +66,15 @@ INLINE Point2LL operator*(const T i, const Point2LL& p0) } INLINE Point2LL operator/(const Point2LL& p0, const coord_t i) { - return Point2LL(p0.X / i, p0.Y / i); + return { p0.X / i, p0.Y / i }; } INLINE Point2LL operator/(const Point2LL& p0, const Point2LL& p1) { - return Point2LL(p0.X / p1.X, p0.Y / p1.Y); + return { p0.X / p1.X, p0.Y / p1.Y }; } INLINE Point2LL operator%(const Point2LL& p0, const coord_t i) { - return Point2LL(p0.X % i, p0.Y % i); + return { p0.X % i, p0.Y % i }; } INLINE Point2LL& operator+=(Point2LL& p0, const Point2LL& p1) @@ -150,24 +148,26 @@ INLINE double vSizeMM(const Point2LL& p0) INLINE Point2LL normal(const Point2LL& p0, coord_t len) { - coord_t _len = vSize(p0); + coord_t _len { vSize(p0) }; if (_len < 1) - return Point2LL(len, 0); + { + return { len, 0 }; + } return p0 * len / _len; } INLINE Point2LL turn90CCW(const Point2LL& p0) { - return Point2LL(-p0.Y, p0.X); + return { -p0.Y, p0.X }; } INLINE Point2LL rotate(const Point2LL& p0, double angle) { const double cos_component = std::cos(angle); const double sin_component = std::sin(angle); - const double x = static_cast(p0.X); - const double y = static_cast(p0.Y); - return Point2LL(std::llrint(cos_component * x - sin_component * y), std::llrint(sin_component * x + cos_component * y)); + const auto x = static_cast(p0.X); + const auto y = static_cast(p0.Y); + return { std::llrint(cos_component * x - sin_component * y), std::llrint(sin_component * x + cos_component * y) }; } INLINE coord_t dot(const Point2LL& p0, const Point2LL& p1) @@ -184,7 +184,9 @@ INLINE double angle(const Point2LL& p) { double angle = std::atan2(p.X, p.Y) / std::numbers::pi * 180.0; if (angle < 0.0) + { angle += 360.0; + } return angle; } @@ -196,7 +198,7 @@ INLINE const Point2LL& make_point(const Point2LL& p) inline Point3LL operator+(const Point3LL& p3, const Point2LL& p2) { - return Point3LL(p3.x_ + p2.X, p3.y_ + p2.Y, p3.z_); + return { p3.x_ + p2.X, p3.y_ + p2.Y, p3.z_ }; } inline Point3LL& operator+=(Point3LL& p3, const Point2LL& p2) { @@ -207,13 +209,13 @@ inline Point3LL& operator+=(Point3LL& p3, const Point2LL& p2) inline Point2LL operator+(const Point2LL& p2, const Point3LL& p3) { - return Point2LL(p3.x_ + p2.X, p3.y_ + p2.Y); + return { p3.x_ + p2.X, p3.y_ + p2.Y }; } inline Point3LL operator-(const Point3LL& p3, const Point2LL& p2) { - return Point3LL(p3.x_ - p2.X, p3.y_ - p2.Y, p3.z_); + return { p3.x_ - p2.X, p3.y_ - p2.Y, p3.z_ }; } inline Point3LL& operator-=(Point3LL& p3, const Point2LL& p2) { @@ -224,7 +226,7 @@ inline Point3LL& operator-=(Point3LL& p3, const Point2LL& p2) inline Point2LL operator-(const Point2LL& p2, const Point3LL& p3) { - return Point2LL(p2.X - p3.x_, p2.Y - p3.y_); + return { p2.X - p3.x_, p2.Y - p3.y_ }; } } // namespace cura diff --git a/include/geometry/PointMatrix.h b/include/geometry/PointMatrix.h index 10b04cbc6e..3cd0c24df9 100644 --- a/include/geometry/PointMatrix.h +++ b/include/geometry/PointMatrix.h @@ -4,6 +4,9 @@ #ifndef GEOMETRY_POINT_MATRIX_H #define GEOMETRY_POINT_MATRIX_H +#include +#include + #include "geometry/Point2LL.h" @@ -13,7 +16,7 @@ namespace cura class PointMatrix { public: - double matrix[4]; + std::array matrix{}; PointMatrix() { @@ -23,7 +26,7 @@ class PointMatrix matrix[3] = 1; } - PointMatrix(double rotation) + explicit PointMatrix(double rotation) { rotation = rotation / 180 * std::numbers::pi; matrix[0] = cos(rotation); @@ -32,7 +35,7 @@ class PointMatrix matrix[3] = matrix[0]; } - PointMatrix(const Point2LL& p) + explicit PointMatrix(const Point2LL& p) { matrix[0] = static_cast(p.X); matrix[1] = static_cast(p.Y); @@ -51,24 +54,24 @@ class PointMatrix return ret; } - Point2LL apply(const Point2LL& p) const + [[nodiscard]] Point2LL apply(const Point2LL& p) const { - const double x = static_cast(p.X); - const double y = static_cast(p.Y); - return Point2LL(std::llrint(x * matrix[0] + y * matrix[1]), std::llrint(x * matrix[2] + y * matrix[3])); + const auto x = static_cast(p.X); + const auto y = static_cast(p.Y); + return { std::llrint(x * matrix[0] + y * matrix[1]), std::llrint(x * matrix[2] + y * matrix[3]) }; } /*! * \warning only works on a rotation matrix! Output is incorrect for other types of matrix */ - Point2LL unapply(const Point2LL& p) const + [[nodiscard]] Point2LL unapply(const Point2LL& p) const { - const double x = static_cast(p.X); - const double y = static_cast(p.Y); - return Point2LL(std::llrint(x * matrix[0] + y * matrix[2]), std::llrint(x * matrix[1] + y * matrix[3])); + const auto x = static_cast(p.X); + const auto y = static_cast(p.Y); + return { std::llrint(x * matrix[0] + y * matrix[2]), std::llrint(x * matrix[1] + y * matrix[3]) }; } - PointMatrix inverse() const + [[nodiscard]] PointMatrix inverse() const { PointMatrix ret; double det = matrix[0] * matrix[3] - matrix[1] * matrix[2]; diff --git a/include/settings/types/Angle.h b/include/settings/types/Angle.h index f6a7665b00..f2814ee3c8 100644 --- a/include/settings/types/Angle.h +++ b/include/settings/types/Angle.h @@ -1,12 +1,11 @@ -// Copyright (c) 2021 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef ANGLE_H #define ANGLE_H #include //For fmod. - -#include "../../utils/math.h" //For PI. +#include #define TAU (2.0 * std::numbers::pi) @@ -27,10 +26,7 @@ class AngleDegrees /* * \brief Default constructor setting the angle to 0. */ - AngleDegrees() - : value_(0.0) - { - } + AngleDegrees() noexcept = default; /* * \brief Converts radians to degrees. @@ -41,7 +37,7 @@ class AngleDegrees * \brief Casts a double to an AngleDegrees instance. */ AngleDegrees(double value) - : value_(std::fmod(std::fmod(value, 360) + 360, 360)) + : value_{ std::fmod(std::fmod(value, 360) + 360, 360) } { } @@ -60,11 +56,13 @@ class AngleDegrees { return std::fmod(std::fmod(value_ + other.value_, 360) + 360, 360); } + template AngleDegrees operator+(const T& other) const { return operator+(AngleDegrees(static_cast(other))); } + AngleDegrees& operator+=(const AngleDegrees& other) { value_ = std::fmod(std::fmod(value_ + other.value_, 360) + 360, 360); @@ -74,11 +72,13 @@ class AngleDegrees { return std::fmod(std::fmod(value_ - other.value_, 360) + 360, 360); } + template AngleDegrees operator-(const T& other) const { return operator-(AngleDegrees(static_cast(other))); } + AngleDegrees& operator-=(const AngleDegrees& other) { value_ = std::fmod(std::fmod(value_ - other.value_, 360) + 360, 360); @@ -90,7 +90,7 @@ class AngleDegrees * * This value should always be between 0 and 360. */ - double value_ = 0; + double value_{ 0 }; }; /* @@ -105,10 +105,7 @@ class AngleRadians /* * \brief Default constructor setting the angle to 0. */ - AngleRadians() - : value_(0.0) - { - } + AngleRadians() noexcept = default; /*! * \brief Converts an angle from degrees into radians. @@ -138,15 +135,18 @@ class AngleRadians { return std::fmod(std::fmod(value_ + other.value_, TAU) + TAU, TAU); } + AngleRadians& operator+=(const AngleRadians& other) { value_ = std::fmod(std::fmod(value_ + other.value_, TAU) + TAU, TAU); return *this; } + AngleRadians operator-(const AngleRadians& other) const { return std::fmod(std::fmod(value_ - other.value_, TAU) + TAU, TAU); } + AngleRadians& operator-=(const AngleRadians& other) { value_ = std::fmod(std::fmod(value_ - other.value_, TAU) + TAU, TAU); @@ -158,15 +158,16 @@ class AngleRadians * * This value should always be between 0 and 2 * pi. */ - double value_ = 0; + double value_{ 0 }; }; inline AngleDegrees::AngleDegrees(const AngleRadians& value) : value_(value * 360 / TAU) { } + inline AngleRadians::AngleRadians(const AngleDegrees& value) - : value_(double(value) * TAU / 360.0) + : value_(static_cast(value) * TAU / 360.0) { } diff --git a/include/slicer.h b/include/slicer.h index 0f2f7a3d6b..ebb04185cb 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef SLICER_H @@ -9,6 +9,7 @@ #include #include "geometry/OpenLinesSet.h" +#include "geometry/OpenPolyline.h" #include "geometry/Shape.h" #include "settings/EnumSettings.h" diff --git a/include/utils/ExtrusionSegment.h b/include/utils/ExtrusionSegment.h index f16fab5ea8..87ca8176cf 100644 --- a/include/utils/ExtrusionSegment.h +++ b/include/utils/ExtrusionSegment.h @@ -1,14 +1,13 @@ -// Copyright (c) 2020 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef UTILS_EXTRUSION_SEGMENT_H #define UTILS_EXTRUSION_SEGMENT_H -#include +#include #include "ExtrusionJunction.h" -#include "geometry/Point2LL.h" #include "geometry/Polygon.h" #include "polygonUtils.h" diff --git a/include/utils/PolygonConnector.h b/include/utils/PolygonConnector.h index 39bb8c0373..38a3c1fe00 100644 --- a/include/utils/PolygonConnector.h +++ b/include/utils/PolygonConnector.h @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef UTILS_POLYGON_CONNECTOR_H @@ -14,6 +14,7 @@ #include "linearAlg2D.h" #include "polygonUtils.h" #include "settings/types/Ratio.h" +#include "utils/math.h" namespace cura { diff --git a/include/utils/actions/smooth.h b/include/utils/actions/smooth.h index a414d9850a..6cf1773e67 100644 --- a/include/utils/actions/smooth.h +++ b/include/utils/actions/smooth.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef UTILS_VIEWS_SMOOTH_H @@ -6,8 +6,6 @@ #include #include -#include -#include #include #include @@ -21,7 +19,9 @@ #include #include "settings/Settings.h" +#include "geometry/Point2LL.h" #include "settings/types/Angle.h" +#include "utils/Coord_t.h" #include "utils/types/arachne.h" #include "utils/types/generic.h" #include "utils/types/geometry.h" @@ -56,13 +56,13 @@ struct smooth_fn } template - requires ranges::forward_range && ranges::sized_range && ranges::erasable_range, ranges::sentinel_t> &&( - utils::point2d> || utils::junctions)constexpr auto - operator()( - Rng&& rng, - const utils::integral auto fluid_motion_shift_distance, - const utils::integral auto fluid_motion_small_distance, - const utils::floating_point auto fluid_motion_angle) const + requires ranges::forward_range && ranges::sized_range && ranges::erasable_range, ranges::sentinel_t> + && (utils::point2d> || utils::junctions) + constexpr auto operator()( + Rng&& rng, + const utils::integral auto fluid_motion_shift_distance, + const utils::integral auto fluid_motion_small_distance, + const utils::floating_point auto fluid_motion_angle) const { const auto size = ranges::distance(rng) - 1; if (size < 4) @@ -125,14 +125,14 @@ struct smooth_fn * */ template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto cosAngle(Point& a, Point& b, Point& c) const noexcept { return cosAngle(a, b, c, dist(a, b), dist(b, c)); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto cosAngle(Point& a, Point& b, Point& c, const utils::floating_point auto ab_magnitude, const utils::floating_point auto bc_magnitude) const noexcept { return cosAngle(a, b, b, c, ab_magnitude, bc_magnitude); @@ -156,14 +156,14 @@ struct smooth_fn * */ template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto cosAngle(Point& a, Point& b, Point& c, Point& d) const noexcept { return cosAngle(a, b, c, d, dist(a, b), dist(c, d)); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto cosAngle(Point& a, Point& b, Point& c, Point& d, const utils::floating_point auto ab_magnitude, const utils::floating_point auto bc_magnitude) const noexcept { @@ -183,14 +183,14 @@ struct smooth_fn * */ template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto cosAngle(Vector& a, Vector& b) const noexcept { return cosAngle(a, b, magnitude(a), magnitude(b)); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto cosAngle(Vector& a, Vector& b, const utils::floating_point auto a_magnitude, const utils::floating_point auto b_magnitude) const noexcept { if (a_magnitude <= std::numeric_limits::epsilon() || b_magnitude <= std::numeric_limits::epsilon()) @@ -201,14 +201,14 @@ struct smooth_fn } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr Point shiftPointTowards(Point& p0, Point& p1, const utils::numeric auto move_distance) const noexcept { return shiftPointTowards(p0, p1, move_distance, dist(p0, p1)); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr Point shiftPointTowards(Point& p0, Point& p1, const utils::numeric auto move_distance, const utils::floating_point auto p0p1_distance) const noexcept { using coord_type = std::remove_cvref_t(p0))>; @@ -220,7 +220,7 @@ struct smooth_fn } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr utils::floating_point auto dist(Point& point_0, Point& point_1) const noexcept { Point vector = { std::get<"X">(point_1) - std::get<"X">(point_0), std::get<"Y">(point_1) - std::get<"Y">(point_0) }; @@ -228,28 +228,28 @@ struct smooth_fn } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr utils::floating_point auto magnitude(Vector& v) const noexcept { return std::hypot(std::get<"X">(v), std::get<"Y">(v)); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto dotProduct(Vector& point_0, Vector& point_1) const noexcept { return std::get<"X">(point_0) * std::get<"X">(point_1) + std::get<"Y">(point_0) * std::get<"Y">(point_1); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction constexpr bool isSmooth(Point& a, Point& b, Point& c, Point& d, const utils::floating_point auto fluid_motion_angle) const noexcept { return isSmooth(a, b, c, d, fluid_motion_angle, dist(a, b), dist(b, c), dist(c, d)); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction constexpr bool isSmooth( Point& a, Point& b, diff --git a/include/utils/math.h b/include/utils/math.h index 23561cc86f..bb911f67b7 100644 --- a/include/utils/math.h +++ b/include/utils/math.h @@ -6,42 +6,44 @@ #include #include -#include + +#include "utils/types/generic.h" namespace cura { -template -inline T square(const T& a) +template +[[nodiscard]] T square(const T& a) { return a * a; } -inline int64_t round_divide_signed(const int64_t dividend, const int64_t divisor) //!< Return dividend divided by divisor rounded to the nearest integer +[[nodiscard]] inline int64_t round_divide_signed(const int64_t dividend, const int64_t divisor) //!< Return dividend divided by divisor rounded to the nearest integer { if ((dividend < 0) ^ (divisor < 0)) // Either the numerator or the denominator is negative, so the result must be negative. { return (dividend - divisor / 2) / divisor; // Flip the .5 offset to do proper rounding in the negatives too. } - else - { - return (dividend + divisor / 2) / divisor; - } + return (dividend + divisor / 2) / divisor; } -inline uint64_t ceil_divide_signed(const int64_t dividend, const int64_t divisor) //!< Return dividend divided by divisor rounded up towards positive infinity. + +[[nodiscard]] inline uint64_t ceil_divide_signed(const int64_t dividend, const int64_t divisor) //!< Return dividend divided by divisor rounded up towards positive infinity. { return static_cast((dividend / divisor) + (dividend * divisor > 0 ? 1 : 0)); } -inline uint64_t floor_divide_signed(const int64_t dividend, const int64_t divisor) //!< Return dividend divided by divisor rounded down towards negative infinity. + +[[nodiscard]] inline uint64_t floor_divide_signed(const int64_t dividend, const int64_t divisor) //!< Return dividend divided by divisor rounded down towards negative infinity. { return static_cast((dividend / divisor) + (dividend * divisor > 0 ? 0 : -1)); } -inline uint64_t round_divide(const uint64_t dividend, const uint64_t divisor) //!< Return dividend divided by divisor rounded to the nearest integer + +[[nodiscard]] inline uint64_t round_divide(const uint64_t dividend, const uint64_t divisor) //!< Return dividend divided by divisor rounded to the nearest integer { return (dividend + divisor / 2) / divisor; } -inline uint64_t round_up_divide(const uint64_t dividend, const uint64_t divisor) //!< Return dividend divided by divisor rounded to the nearest integer + +[[nodiscard]] inline uint64_t round_up_divide(const uint64_t dividend, const uint64_t divisor) //!< Return dividend divided by divisor rounded to the nearest integer { return (dividend + divisor - 1) / divisor; } diff --git a/include/utils/polygonUtils.h b/include/utils/polygonUtils.h index ef740a7def..825bc62e79 100644 --- a/include/utils/polygonUtils.h +++ b/include/utils/polygonUtils.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef UTILS_POLYGON_UTILS_H @@ -7,6 +7,7 @@ #include // function #include #include // unique_ptr +#include #include #include "PolygonsPointIndex.h" diff --git a/include/utils/types/generic.h b/include/utils/types/generic.h index 7d53dcfe86..237ac54cb4 100644 --- a/include/utils/types/generic.h +++ b/include/utils/types/generic.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef CURAENGINE_GENERIC_H @@ -9,6 +9,7 @@ #include #include #include +#include namespace cura::utils { @@ -63,6 +64,11 @@ concept floating_point = std::floating_point; template concept numeric = std::is_arithmetic_v>; + +template +concept multipliable = requires(T a, T b) { + { a * b }; +}; } // namespace cura::utils #endif // CURAENGINE_GENERIC_H diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 89ba263f0c..e798b15a8b 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -13,9 +13,6 @@ #include #include -#include -#include -#include #include #include "Application.h" diff --git a/src/LayerPlan.cpp b/src/LayerPlan.cpp index 09daabc1f0..7f923ef879 100644 --- a/src/LayerPlan.cpp +++ b/src/LayerPlan.cpp @@ -27,6 +27,7 @@ #include "sliceDataStorage.h" #include "utils/Simplify.h" #include "utils/linearAlg2D.h" +#include "utils/math.h" #include "utils/polygonUtils.h" #include "utils/section_type.h" diff --git a/src/PrimeTower.cpp b/src/PrimeTower.cpp index cc56d71d4c..ecde02dffe 100644 --- a/src/PrimeTower.cpp +++ b/src/PrimeTower.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #include "PrimeTower.h" @@ -12,7 +12,6 @@ #include "Application.h" //To get settings. #include "ExtruderTrain.h" #include "LayerPlan.h" -#include "PrintFeature.h" #include "Scene.h" #include "Slice.h" #include "gcodeExport.h" diff --git a/src/SkeletalTrapezoidation.cpp b/src/SkeletalTrapezoidation.cpp index c233efe41c..46454c3eb6 100644 --- a/src/SkeletalTrapezoidation.cpp +++ b/src/SkeletalTrapezoidation.cpp @@ -3,7 +3,6 @@ #include "SkeletalTrapezoidation.h" -#include #include #include #include diff --git a/src/TreeSupportTipGenerator.cpp b/src/TreeSupportTipGenerator.cpp index 2e8ec5e5b6..0a2af0e233 100644 --- a/src/TreeSupportTipGenerator.cpp +++ b/src/TreeSupportTipGenerator.cpp @@ -1,18 +1,17 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "TreeSupportTipGenerator.h" #include +#include #include #include -#include #include #include #include #include -#include #include #include "Application.h" //To get settings. @@ -20,7 +19,6 @@ #include "geometry/OpenPolyline.h" #include "infill/SierpinskiFillProvider.h" #include "settings/EnumSettings.h" -#include "utils/Simplify.h" #include "utils/ThreadPool.h" #include "utils/algorithm.h" #include "utils/math.h" //For round_up_divide and PI. diff --git a/src/gcodeExport.cpp b/src/gcodeExport.cpp index f443bbc184..37d758e629 100644 --- a/src/gcodeExport.cpp +++ b/src/gcodeExport.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/src/geometry/Polygon.cpp b/src/geometry/Polygon.cpp index cd75b3ecd7..431114b0e6 100644 --- a/src/geometry/Polygon.cpp +++ b/src/geometry/Polygon.cpp @@ -3,6 +3,8 @@ #include "geometry/Polygon.h" +#include + #include "geometry/Point3Matrix.h" #include "geometry/PointMatrix.h" #include "geometry/Shape.h" diff --git a/src/geometry/Polyline.cpp b/src/geometry/Polyline.cpp index 24515b492a..d64341eada 100644 --- a/src/geometry/Polyline.cpp +++ b/src/geometry/Polyline.cpp @@ -3,6 +3,7 @@ #include "geometry/Polyline.h" +#include #include #include "geometry/LinesSet.h" diff --git a/src/utils/linearAlg2D.cpp b/src/utils/linearAlg2D.cpp index 554dacdc65..64b50cee10 100644 --- a/src/utils/linearAlg2D.cpp +++ b/src/utils/linearAlg2D.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #include "utils/linearAlg2D.h" @@ -6,6 +6,7 @@ #include // swap #include #include // atan2 +#include #include "geometry/Point3Matrix.h" #include "geometry/PointMatrix.h" diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index 0a97d52d31..085bca049c 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -1,10 +1,11 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "utils/polygonUtils.h" #include #include +#include #include #include diff --git a/tests/integration/SlicePhaseTest.cpp b/tests/integration/SlicePhaseTest.cpp index 6145060cce..a746e0851b 100644 --- a/tests/integration/SlicePhaseTest.cpp +++ b/tests/integration/SlicePhaseTest.cpp @@ -1,13 +1,13 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include +#include #include #include "Application.h" // To set up a slice with settings. #include "Slice.h" // To set up a scene to slice. -#include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" // Creating polygons to compare to sliced layers. #include "slicer.h" // Starts the slicing phase that we want to test. #include "utils/Coord_t.h" diff --git a/tests/settings/SettingsTest.cpp b/tests/settings/SettingsTest.cpp index c8f7814db8..0c6c98f458 100644 --- a/tests/settings/SettingsTest.cpp +++ b/tests/settings/SettingsTest.cpp @@ -1,10 +1,11 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #include "settings/Settings.h" //The class under test. -#include //For std::numbers::pi. +#include #include //For shared_ptr. +#include #include diff --git a/tests/utils/LinearAlg2DTest.cpp b/tests/utils/LinearAlg2DTest.cpp index 6f61acae6d..afa754b9fb 100644 --- a/tests/utils/LinearAlg2DTest.cpp +++ b/tests/utils/LinearAlg2DTest.cpp @@ -1,9 +1,10 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #include "utils/linearAlg2D.h" #include +#include #include diff --git a/tests/utils/PolygonTest.cpp b/tests/utils/PolygonTest.cpp index cf39e89dab..fec93cad6b 100644 --- a/tests/utils/PolygonTest.cpp +++ b/tests/utils/PolygonTest.cpp @@ -1,8 +1,10 @@ -// Copyright (c) 2022 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. #include "geometry/Polygon.h" // The class under test. +#include + #include #include "geometry/OpenPolyline.h" diff --git a/tests/utils/SimplifyTest.cpp b/tests/utils/SimplifyTest.cpp index d6bec7c97a..00cb98f0b6 100644 --- a/tests/utils/SimplifyTest.cpp +++ b/tests/utils/SimplifyTest.cpp @@ -3,6 +3,8 @@ #include "utils/Simplify.h" // The unit under test. +#include + #include #include "utils/Coord_t.h" diff --git a/tests/utils/SmoothTest.cpp b/tests/utils/SmoothTest.cpp index d2b0be63bc..3fbcda11f1 100644 --- a/tests/utils/SmoothTest.cpp +++ b/tests/utils/SmoothTest.cpp @@ -1,14 +1,15 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher -#include +#include "utils/actions/smooth.h" -#include +#include #include +#include + #include "geometry/Point2LL.h" -#include "utils/actions/smooth.h" #include "geometry/Polygon.h" namespace cura @@ -30,10 +31,10 @@ TEST(SmoothTest, TestSmooth) * */ - auto A = cura::Point2LL { 0, 0 }; - auto B = cura::Point2LL { 0, 100 }; - auto C = cura::Point2LL { 1, 100 }; - auto D = cura::Point2LL { 1, 200 }; + auto A = cura::Point2LL{ 0, 0 }; + auto B = cura::Point2LL{ 0, 100 }; + auto C = cura::Point2LL{ 1, 100 }; + auto D = cura::Point2LL{ 1, 200 }; const auto is_smooth = smooth.isSmooth(A, B, C, D, COS_FLUID_ANGLE); EXPECT_EQ(is_smooth, false); @@ -51,10 +52,10 @@ TEST(SmoothTest, TestSmooth) * D * */ - auto A = cura::Point2LL { 0, 0 }; - auto B = cura::Point2LL { 100, 0 }; - auto C = cura::Point2LL { 101, 1 }; - auto D = cura::Point2LL { 101, 101 }; + auto A = cura::Point2LL{ 0, 0 }; + auto B = cura::Point2LL{ 100, 0 }; + auto C = cura::Point2LL{ 101, 1 }; + auto D = cura::Point2LL{ 101, 101 }; const auto is_smooth = smooth.isSmooth(A, B, C, D, COS_FLUID_ANGLE); EXPECT_EQ(is_smooth, true); @@ -66,10 +67,10 @@ TEST(SmoothTest, TestSmooth) * A ----------- B - C -------------D * */ - auto A = cura::Point2LL { 0, 0 }; - auto B = cura::Point2LL { 100, 0 }; - auto C = cura::Point2LL { 101, 0 }; - auto D = cura::Point2LL { 201, 0 }; + auto A = cura::Point2LL{ 0, 0 }; + auto B = cura::Point2LL{ 100, 0 }; + auto C = cura::Point2LL{ 101, 0 }; + auto D = cura::Point2LL{ 201, 0 }; const auto is_smooth = smooth.isSmooth(A, B, C, D, COS_FLUID_ANGLE); EXPECT_EQ(is_smooth, true); @@ -81,10 +82,10 @@ TEST(SmoothTest, TestSmooth) * D ----------- C - B -------------A * */ - auto A = cura::Point2LL { 201, 0 }; - auto B = cura::Point2LL { 101, 0 }; - auto C = cura::Point2LL { 100, 0 }; - auto D = cura::Point2LL { 0, 0 }; + auto A = cura::Point2LL{ 201, 0 }; + auto B = cura::Point2LL{ 101, 0 }; + auto C = cura::Point2LL{ 100, 0 }; + auto D = cura::Point2LL{ 0, 0 }; const auto is_smooth = smooth.isSmooth(A, B, C, D, COS_FLUID_ANGLE); EXPECT_EQ(is_smooth, true); @@ -105,10 +106,10 @@ TEST(SmoothTest, TestSmooth) * D * */ - auto A = cura::Point2LL { 0, 0 }; - auto B = cura::Point2LL { 100, 0 }; - auto C = cura::Point2LL { 99, -1 }; - auto D = cura::Point2LL { 199, 99 }; + auto A = cura::Point2LL{ 0, 0 }; + auto B = cura::Point2LL{ 100, 0 }; + auto C = cura::Point2LL{ 99, -1 }; + auto D = cura::Point2LL{ 199, 99 }; const auto is_smooth = smooth.isSmooth(A, B, C, D, COS_FLUID_ANGLE); EXPECT_EQ(is_smooth, false); @@ -127,10 +128,10 @@ TEST(SmoothTest, TestSmooth) * D * */ - auto A = cura::Point2LL { 0, 0 }; - auto B = cura::Point2LL { 100, 0 }; - auto C = cura::Point2LL { 101, 1 }; - auto D = cura::Point2LL { 201, 101 }; + auto A = cura::Point2LL{ 0, 0 }; + auto B = cura::Point2LL{ 100, 0 }; + auto C = cura::Point2LL{ 101, 1 }; + auto D = cura::Point2LL{ 201, 101 }; const auto is_smooth = smooth.isSmooth(A, B, C, D, COS_FLUID_ANGLE); EXPECT_EQ(is_smooth, true); @@ -166,6 +167,5 @@ TEST(SmoothTest, TestSmooth) const auto is_smooth = smooth.isSmooth(A, B, C, D, COS_FLUID_ANGLE); EXPECT_EQ(is_smooth, false); }; - } -} // namespace cura \ No newline at end of file +} // namespace cura From 4718d3d128586abed2e78fec4b61905745d87312 Mon Sep 17 00:00:00 2001 From: jellespijker Date: Thu, 2 May 2024 13:03:20 +0000 Subject: [PATCH 084/135] Applied clang-format. --- include/PathOrderOptimizer.h | 2 +- include/geometry/Point2LL.h | 2 +- include/utils/actions/smooth.h | 42 +++++++++++++++++----------------- include/utils/types/generic.h | 8 +++---- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 23dd12a305..cc5d6d08d8 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -402,7 +402,7 @@ class PathOrderOptimizer } auto local_current_position = current_position; - while (!candidates.empty()) + while (! candidates.empty()) { Path best_candidate = findClosestPathVertices(local_current_position, candidates); diff --git a/include/geometry/Point2LL.h b/include/geometry/Point2LL.h index 4f76a70efe..8217d7e797 100644 --- a/include/geometry/Point2LL.h +++ b/include/geometry/Point2LL.h @@ -148,7 +148,7 @@ INLINE double vSizeMM(const Point2LL& p0) INLINE Point2LL normal(const Point2LL& p0, coord_t len) { - coord_t _len { vSize(p0) }; + coord_t _len{ vSize(p0) }; if (_len < 1) { return { len, 0 }; diff --git a/include/utils/actions/smooth.h b/include/utils/actions/smooth.h index 6cf1773e67..338c47e391 100644 --- a/include/utils/actions/smooth.h +++ b/include/utils/actions/smooth.h @@ -18,8 +18,8 @@ #include #include -#include "settings/Settings.h" #include "geometry/Point2LL.h" +#include "settings/Settings.h" #include "settings/types/Angle.h" #include "utils/Coord_t.h" #include "utils/types/arachne.h" @@ -56,13 +56,13 @@ struct smooth_fn } template - requires ranges::forward_range && ranges::sized_range && ranges::erasable_range, ranges::sentinel_t> - && (utils::point2d> || utils::junctions) - constexpr auto operator()( - Rng&& rng, - const utils::integral auto fluid_motion_shift_distance, - const utils::integral auto fluid_motion_small_distance, - const utils::floating_point auto fluid_motion_angle) const + requires ranges::forward_range && ranges::sized_range && ranges::erasable_range, ranges::sentinel_t> &&( + utils::point2d> || utils::junctions)constexpr auto + operator()( + Rng&& rng, + const utils::integral auto fluid_motion_shift_distance, + const utils::integral auto fluid_motion_small_distance, + const utils::floating_point auto fluid_motion_angle) const { const auto size = ranges::distance(rng) - 1; if (size < 4) @@ -125,14 +125,14 @@ struct smooth_fn * */ template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto cosAngle(Point& a, Point& b, Point& c) const noexcept { return cosAngle(a, b, c, dist(a, b), dist(b, c)); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto cosAngle(Point& a, Point& b, Point& c, const utils::floating_point auto ab_magnitude, const utils::floating_point auto bc_magnitude) const noexcept { return cosAngle(a, b, b, c, ab_magnitude, bc_magnitude); @@ -156,14 +156,14 @@ struct smooth_fn * */ template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto cosAngle(Point& a, Point& b, Point& c, Point& d) const noexcept { return cosAngle(a, b, c, d, dist(a, b), dist(c, d)); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto cosAngle(Point& a, Point& b, Point& c, Point& d, const utils::floating_point auto ab_magnitude, const utils::floating_point auto bc_magnitude) const noexcept { @@ -183,14 +183,14 @@ struct smooth_fn * */ template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto cosAngle(Vector& a, Vector& b) const noexcept { return cosAngle(a, b, magnitude(a), magnitude(b)); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto cosAngle(Vector& a, Vector& b, const utils::floating_point auto a_magnitude, const utils::floating_point auto b_magnitude) const noexcept { if (a_magnitude <= std::numeric_limits::epsilon() || b_magnitude <= std::numeric_limits::epsilon()) @@ -201,14 +201,14 @@ struct smooth_fn } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr Point shiftPointTowards(Point& p0, Point& p1, const utils::numeric auto move_distance) const noexcept { return shiftPointTowards(p0, p1, move_distance, dist(p0, p1)); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr Point shiftPointTowards(Point& p0, Point& p1, const utils::numeric auto move_distance, const utils::floating_point auto p0p1_distance) const noexcept { using coord_type = std::remove_cvref_t(p0))>; @@ -220,7 +220,7 @@ struct smooth_fn } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr utils::floating_point auto dist(Point& point_0, Point& point_1) const noexcept { Point vector = { std::get<"X">(point_1) - std::get<"X">(point_0), std::get<"Y">(point_1) - std::get<"Y">(point_0) }; @@ -228,28 +228,28 @@ struct smooth_fn } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr utils::floating_point auto magnitude(Vector& v) const noexcept { return std::hypot(std::get<"X">(v), std::get<"Y">(v)); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction inline constexpr auto dotProduct(Vector& point_0, Vector& point_1) const noexcept { return std::get<"X">(point_0) * std::get<"X">(point_1) + std::get<"Y">(point_0) * std::get<"Y">(point_1); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction constexpr bool isSmooth(Point& a, Point& b, Point& c, Point& d, const utils::floating_point auto fluid_motion_angle) const noexcept { return isSmooth(a, b, c, d, fluid_motion_angle, dist(a, b), dist(b, c), dist(c, d)); } template - requires utils::point2d || utils::junction + requires utils::point2d || utils::junction constexpr bool isSmooth( Point& a, Point& b, diff --git a/include/utils/types/generic.h b/include/utils/types/generic.h index 237ac54cb4..4b4d6fc474 100644 --- a/include/utils/types/generic.h +++ b/include/utils/types/generic.h @@ -4,12 +4,11 @@ #ifndef CURAENGINE_GENERIC_H #define CURAENGINE_GENERIC_H -#include - #include #include #include -#include + +#include namespace cura::utils { @@ -66,7 +65,8 @@ template concept numeric = std::is_arithmetic_v>; template -concept multipliable = requires(T a, T b) { +concept multipliable = requires(T a, T b) +{ { a * b }; }; } // namespace cura::utils From 7229363746bcdb311fa023a3e92df8a9613ff751 Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Thu, 2 May 2024 17:15:37 +0200 Subject: [PATCH 085/135] Refactor "support away from model" to generic "disallowed areas" The specific "support away from model" case has been refactored to a more generic "disallowed areas" in the Insetoptimizer. This adjustment enhances flexibility and allows for potential future utilization in other features. Related to CURA-11227. --- include/InsetOrderOptimizer.h | 7 ++++--- include/PathOrderOptimizer.h | 7 ++++--- src/FffGcodeWriter.cpp | 23 ++++++++++++++++++++--- src/InsetOrderOptimizer.cpp | 25 +++++-------------------- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/include/InsetOrderOptimizer.h b/include/InsetOrderOptimizer.h index 90097205ec..47cd832fcb 100644 --- a/include/InsetOrderOptimizer.h +++ b/include/InsetOrderOptimizer.h @@ -55,7 +55,8 @@ class InsetOrderOptimizer const size_t wall_0_extruder_nr, const size_t wall_x_extruder_nr, const ZSeamConfig& z_seam_config, - const std::vector& paths); + const std::vector& paths, + const Polygons& disallowed_areas = {}); /*! * Adds the insets to the given layer plan. @@ -64,7 +65,7 @@ class InsetOrderOptimizer * class, so this optimize function needs no additional information. * \return Whether anything was added to the layer plan. */ - bool addToLayer(const bool is_support = false); + bool addToLayer(); /*! * Get the order constraints of the insets when printing walls per region / hole. @@ -106,7 +107,7 @@ class InsetOrderOptimizer const ZSeamConfig& z_seam_config_; const std::vector& paths_; const LayerIndex layer_nr_; - Polygons mesh_paths_; + Polygons disallowed_areas_; std::vector> inset_polys_; // vector of vectors holding the inset polygons Polygons retraction_region_; // After printing an outer wall, move into this region so that retractions do not leave visible blobs. Calculated lazily if needed (see diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index c8a8b05421..31eb58efb3 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -62,7 +62,7 @@ class PathOrderOptimizer public: using OrderablePath = PathOrdering; /* Areas defined here are not allowed to have the start the prints */ - Polygons disallowed_area{}; + Polygons disallowed_area; /*! * After optimizing, this contains the paths that need to be printed in the * correct order. @@ -112,7 +112,8 @@ class PathOrderOptimizer const Polygons* combing_boundary = nullptr, const bool reverse_direction = false, const std::unordered_multimap& order_requirements = no_order_requirements_, - const bool group_outer_walls = false) + const bool group_outer_walls = false, + const Polygons& disallowed_areas = {}) : start_point_(start_point) , seam_config_(seam_config) , combing_boundary_((combing_boundary != nullptr && ! combing_boundary->empty()) ? combing_boundary : nullptr) @@ -120,7 +121,7 @@ class PathOrderOptimizer , reverse_direction_(reverse_direction) , _group_outer_walls(group_outer_walls) , order_requirements_(&order_requirements) - , disallowed_area{} + , disallowed_area{disallowed_areas} { } diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index bf3c03dc96..2c1aac5858 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3459,7 +3459,23 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer constexpr coord_t wipe_dist = 0; ZSeamConfig z_seam_config = ZSeamConfig(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); - + Polygons disallowed_area {}; + if (infill_extruder.settings_.get("support_z_seam_away_from_model")) + { + for (std::shared_ptr mesh_ptr : storage.meshes) + { + auto& mesh = *mesh_ptr; + for (auto& part : mesh.layers[gcode_layer.getLayerNr()].parts) + { + disallowed_area.add(part.print_outline); + } + } + if (! disallowed_area.empty()) + { + coord_t min_distance = infill_extruder.settings_.get("support_z_seam_min_distance"); + disallowed_area = disallowed_area.offset(min_distance, ClipperLib::jtRound); + } + } InsetOrderOptimizer wall_orderer( *this, @@ -3479,8 +3495,9 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer extruder_nr, extruder_nr, z_seam_config, - wall_toolpaths); - added_something |= wall_orderer.addToLayer(true); + wall_toolpaths, + disallowed_area); + added_something |= wall_orderer.addToLayer(); } if ((default_support_line_distance <= 0 && support_structure != ESupportStructure::TREE) || part.infill_area_per_combine_per_density_.empty()) diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 7e3eeb0ce0..57cfd32201 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -50,7 +50,8 @@ InsetOrderOptimizer::InsetOrderOptimizer( const size_t wall_0_extruder_nr, const size_t wall_x_extruder_nr, const ZSeamConfig& z_seam_config, - const std::vector& paths) + const std::vector& paths, + const Polygons& disallowed_areas) : gcode_writer_(gcode_writer) , storage_(storage) , gcode_layer_(gcode_layer) @@ -70,11 +71,11 @@ InsetOrderOptimizer::InsetOrderOptimizer( , z_seam_config_(z_seam_config) , paths_(paths) , layer_nr_(gcode_layer.getLayerNr()) - , mesh_paths_{} + , disallowed_areas_{disallowed_areas} { } -bool InsetOrderOptimizer::addToLayer(const bool is_support) +bool InsetOrderOptimizer::addToLayer() { // Settings & configs: const auto pack_by_inset = ! settings_.get("optimize_wall_printing_order"); @@ -100,7 +101,7 @@ bool InsetOrderOptimizer::addToLayer(const bool is_support) // When we alternate walls, also alternate the direction at which the first wall starts in. // On even layers we start with normal direction, on odd layers with inverted direction. PathOrderOptimizer - order_optimizer(gcode_layer_.getLastPlannedPositionOrStartingPosition(), z_seam_config_, detect_loops, combing_boundary, reverse, order, group_outer_walls); + order_optimizer(gcode_layer_.getLastPlannedPositionOrStartingPosition(), z_seam_config_, detect_loops, combing_boundary, reverse, order, group_outer_walls, disallowed_areas_); for (const auto& line : walls_to_be_added) { @@ -113,22 +114,6 @@ bool InsetOrderOptimizer::addToLayer(const bool is_support) order_optimizer.addPolyline(&line); } } - if (is_support && settings_.get("support_z_seam_away_from_model")) - { - for (std::shared_ptr mesh_ptr : storage_.meshes) - { - auto& mesh = *mesh_ptr; - for (auto& part : mesh.layers[layer_nr_].parts) - { - mesh_paths_.add(part.print_outline); - } - } - if (! mesh_paths_.empty()) - { - coord_t min_distance = settings_.get("support_z_seam_min_distance"); - order_optimizer.disallowed_area = mesh_paths_.offset(min_distance, ClipperLib::jtRound); - } - } order_optimizer.optimize(); From c3d155d30c2e6355c0f418f9da2eac509fdf1a08 Mon Sep 17 00:00:00 2001 From: saumyaj3 Date: Thu, 2 May 2024 15:16:14 +0000 Subject: [PATCH 086/135] Applied clang-format. --- include/PathOrderOptimizer.h | 2 +- src/FffGcodeWriter.cpp | 2 +- src/InsetOrderOptimizer.cpp | 13 ++++++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 31eb58efb3..a709e22a2d 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -121,7 +121,7 @@ class PathOrderOptimizer , reverse_direction_(reverse_direction) , _group_outer_walls(group_outer_walls) , order_requirements_(&order_requirements) - , disallowed_area{disallowed_areas} + , disallowed_area{ disallowed_areas } { } diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 2c1aac5858..9063efa2f1 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3459,7 +3459,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer constexpr coord_t wipe_dist = 0; ZSeamConfig z_seam_config = ZSeamConfig(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); - Polygons disallowed_area {}; + Polygons disallowed_area{}; if (infill_extruder.settings_.get("support_z_seam_away_from_model")) { for (std::shared_ptr mesh_ptr : storage.meshes) diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 57cfd32201..81febedcfa 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -71,7 +71,7 @@ InsetOrderOptimizer::InsetOrderOptimizer( , z_seam_config_(z_seam_config) , paths_(paths) , layer_nr_(gcode_layer.getLayerNr()) - , disallowed_areas_{disallowed_areas} + , disallowed_areas_{ disallowed_areas } { } @@ -100,8 +100,15 @@ bool InsetOrderOptimizer::addToLayer() const auto group_outer_walls = settings_.get("group_outer_walls"); // When we alternate walls, also alternate the direction at which the first wall starts in. // On even layers we start with normal direction, on odd layers with inverted direction. - PathOrderOptimizer - order_optimizer(gcode_layer_.getLastPlannedPositionOrStartingPosition(), z_seam_config_, detect_loops, combing_boundary, reverse, order, group_outer_walls, disallowed_areas_); + PathOrderOptimizer order_optimizer( + gcode_layer_.getLastPlannedPositionOrStartingPosition(), + z_seam_config_, + detect_loops, + combing_boundary, + reverse, + order, + group_outer_walls, + disallowed_areas_); for (const auto& line : walls_to_be_added) { From 962a5a40bb5790117a784f8bbed3f7769ccef5e7 Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Fri, 3 May 2024 12:44:31 +0200 Subject: [PATCH 087/135] Refactor variable name to 'disallowed_areas_for_seams' Renamed the variable 'disallowed_area' to 'disallowed_areas_for_seams' in different files for more accurate representation. CURA-11227 --- include/InsetOrderOptimizer.h | 4 ++-- include/PathOrderOptimizer.h | 12 ++++++------ src/FffGcodeWriter.cpp | 10 +++++----- src/InsetOrderOptimizer.cpp | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/InsetOrderOptimizer.h b/include/InsetOrderOptimizer.h index 47cd832fcb..f23aae04bb 100644 --- a/include/InsetOrderOptimizer.h +++ b/include/InsetOrderOptimizer.h @@ -56,7 +56,7 @@ class InsetOrderOptimizer const size_t wall_x_extruder_nr, const ZSeamConfig& z_seam_config, const std::vector& paths, - const Polygons& disallowed_areas = {}); + const Polygons& disallowed_areas_for_seams = {}); /*! * Adds the insets to the given layer plan. @@ -107,7 +107,7 @@ class InsetOrderOptimizer const ZSeamConfig& z_seam_config_; const std::vector& paths_; const LayerIndex layer_nr_; - Polygons disallowed_areas_; + Polygons disallowed_areas_for_seams_; std::vector> inset_polys_; // vector of vectors holding the inset polygons Polygons retraction_region_; // After printing an outer wall, move into this region so that retractions do not leave visible blobs. Calculated lazily if needed (see diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index a709e22a2d..1a8c174cc7 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -62,7 +62,7 @@ class PathOrderOptimizer public: using OrderablePath = PathOrdering; /* Areas defined here are not allowed to have the start the prints */ - Polygons disallowed_area; + Polygons disallowed_area_for_seams; /*! * After optimizing, this contains the paths that need to be printed in the * correct order. @@ -113,7 +113,7 @@ class PathOrderOptimizer const bool reverse_direction = false, const std::unordered_multimap& order_requirements = no_order_requirements_, const bool group_outer_walls = false, - const Polygons& disallowed_areas = {}) + const Polygons& disallowed_areas_for_seams = {}) : start_point_(start_point) , seam_config_(seam_config) , combing_boundary_((combing_boundary != nullptr && ! combing_boundary->empty()) ? combing_boundary : nullptr) @@ -121,7 +121,7 @@ class PathOrderOptimizer , reverse_direction_(reverse_direction) , _group_outer_walls(group_outer_walls) , order_requirements_(&order_requirements) - , disallowed_area{ disallowed_areas } + , disallowed_area_for_seams{ disallowed_areas_for_seams } { } @@ -634,10 +634,10 @@ class PathOrderOptimizer size_t path_size = path.converted_->size(); if (path_size > number_of_paths_analysed) { - if (! disallowed_area.empty()) + if (! disallowed_area_for_seams.empty()) { Point2LL current_candidate = (path.converted_)->at(best_pos); - if (disallowed_area.inside(current_candidate, true)) + if (disallowed_area_for_seams.inside(current_candidate, true)) { size_t next_best_position = (path_size > best_pos + 1) ? best_pos + 1 : 0; number_of_paths_analysed += 1; @@ -792,7 +792,7 @@ class PathOrderOptimizer } } - if (! disallowed_area.empty()) + if (! disallowed_area_for_seams.empty()) { best_i = pathIfZseamIsInDisallowedArea(best_i, path, 0); } diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 9063efa2f1..bbfdaf47eb 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3459,7 +3459,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer constexpr coord_t wipe_dist = 0; ZSeamConfig z_seam_config = ZSeamConfig(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); - Polygons disallowed_area{}; + Polygons disallowed_area_for_seams{}; if (infill_extruder.settings_.get("support_z_seam_away_from_model")) { for (std::shared_ptr mesh_ptr : storage.meshes) @@ -3467,13 +3467,13 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer auto& mesh = *mesh_ptr; for (auto& part : mesh.layers[gcode_layer.getLayerNr()].parts) { - disallowed_area.add(part.print_outline); + disallowed_area_for_seams.add(part.print_outline); } } - if (! disallowed_area.empty()) + if (! disallowed_area_for_seams.empty()) { coord_t min_distance = infill_extruder.settings_.get("support_z_seam_min_distance"); - disallowed_area = disallowed_area.offset(min_distance, ClipperLib::jtRound); + disallowed_area_for_seams = disallowed_area_for_seams.offset(min_distance, ClipperLib::jtRound); } } @@ -3496,7 +3496,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer extruder_nr, z_seam_config, wall_toolpaths, - disallowed_area); + disallowed_area_for_seams); added_something |= wall_orderer.addToLayer(); } diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 81febedcfa..03ad5434cb 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -51,7 +51,7 @@ InsetOrderOptimizer::InsetOrderOptimizer( const size_t wall_x_extruder_nr, const ZSeamConfig& z_seam_config, const std::vector& paths, - const Polygons& disallowed_areas) + const Polygons& disallowed_areas_for_seams) : gcode_writer_(gcode_writer) , storage_(storage) , gcode_layer_(gcode_layer) @@ -71,7 +71,7 @@ InsetOrderOptimizer::InsetOrderOptimizer( , z_seam_config_(z_seam_config) , paths_(paths) , layer_nr_(gcode_layer.getLayerNr()) - , disallowed_areas_{ disallowed_areas } + , disallowed_areas_for_seams_{ disallowed_areas_for_seams } { } @@ -108,7 +108,7 @@ bool InsetOrderOptimizer::addToLayer() reverse, order, group_outer_walls, - disallowed_areas_); + disallowed_areas_for_seams_); for (const auto& line : walls_to_be_added) { From 96e4b5e5c89449fc3b81a25df2eb906615522286 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 3 May 2024 15:06:01 +0200 Subject: [PATCH 088/135] Modernized the code Improved the readability of the code by using modern C++ practices such as list initialization, return statement with braces, use of `std::move` and `[[maybe_unused]]`, auto-lambda type deduction, and range-based for loop. Removed unnecessary if-else blocks and simplified the syntax. Contribute to CURA-9830 --- include/geometry/LinesSet.h | 50 ++++--- include/geometry/Shape.h | 65 +++++---- include/geometry/SingleShape.h | 4 + include/settings/EnumSettings.h | 2 +- src/FffGcodeWriter.cpp | 6 +- src/WallsComputation.cpp | 2 +- src/geometry/LinesSet.cpp | 118 ++++++----------- src/geometry/Shape.cpp | 227 +++++++++++++++----------------- src/infill.cpp | 2 +- src/sliceDataStorage.cpp | 2 +- 10 files changed, 220 insertions(+), 258 deletions(-) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index 08f498a17f..212af90228 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -37,11 +37,14 @@ class LinesSet public: // Required for some std calls as a container - typedef LineType value_type; + using value_type = LineType; + using iterator = typename std::vector::iterator; + using const_iterator = typename std::vector::const_iterator; -public: /*! \brief Builds an empty set */ - LinesSet() = default; + LinesSet() noexcept = default; + + virtual ~LinesSet() = default; /*! \brief Creates a copy of the given lines set */ LinesSet(const LinesSet& other) = default; @@ -66,8 +69,16 @@ class LinesSet * \warning This constructor is actually only defined for a LinesSet containing OpenPolyline * objects, because closed ones require an additional argument */ - template::value>::type> - LinesSet(ClipperLib::Paths&& paths); + template + requires std::is_same_v + LinesSet(ClipperLib::Paths&& paths) + { + reserve(paths.size()); + for (ClipperLib::Path& path : paths) + { + lines_.emplace_back(std::move(path)); + } + } const std::vector& getLines() const { @@ -84,22 +95,22 @@ class LinesSet lines_ = lines; } - std::vector::const_iterator begin() const + const_iterator begin() const { return lines_.begin(); } - std::vector::iterator begin() + iterator begin() { return lines_.begin(); } - std::vector::const_iterator end() const + const_iterator end() const { return lines_.end(); } - std::vector::iterator end() + iterator end() { return lines_.end(); } @@ -126,15 +137,15 @@ class LinesSet /*! * \brief Pushes the given line at the end of the set - * \param checkNonEmpty Indicates whether we should check for the line to be non-empty before adding it + * \param check_non_empty Indicates whether we should check for the line to be non-empty before adding it */ - void push_back(const LineType& line, CheckNonEmptyParam checkNonEmpty = CheckNonEmptyParam::EvenIfEmpty); + void push_back(const LineType& line, CheckNonEmptyParam check_non_empty = CheckNonEmptyParam::EvenIfEmpty); /*! * \brief Pushes the given line at the end of the set and takes ownership of the inner data - * \param checkNonEmpty Indicates whether we should check for the line to be non-empty before adding it + * \param check_non_empty Indicates whether we should check for the line to be non-empty before adding it */ - void push_back(LineType&& line, CheckNonEmptyParam checkNonEmpty = CheckNonEmptyParam::EvenIfEmpty); + void push_back(LineType&& line, CheckNonEmptyParam check_non_empty = CheckNonEmptyParam::EvenIfEmpty); /*! \brief Pushes an entier set at the end and takes ownership of the inner data */ template @@ -151,12 +162,12 @@ class LinesSet lines_.pop_back(); } - size_t size() const + [[nodiscard]] size_t size() const { return lines_.size(); } - bool empty() const + [[nodiscard]] bool empty() const { return lines_.empty(); } @@ -176,13 +187,12 @@ class LinesSet lines_.clear(); } - template - void emplace_back(Args&&... args) + void emplace_back(auto&&... args) { - lines_.emplace_back(args...); + lines_.emplace_back(std::forward(args)...); } - std::vector::iterator erase(std::vector::const_iterator first, std::vector::const_iterator last) + iterator erase(const_iterator first, const_iterator last) { return lines_.erase(first, last); } @@ -193,7 +203,7 @@ class LinesSet return *this; } - LinesSet& operator=(LinesSet&& other) + LinesSet& operator=(LinesSet&& other) noexcept { lines_ = std::move(other.lines_); return *this; diff --git a/include/geometry/Shape.h b/include/geometry/Shape.h index 5e9e1d21d3..46091d49a3 100644 --- a/include/geometry/Shape.h +++ b/include/geometry/Shape.h @@ -30,7 +30,6 @@ class Shape : public LinesSet // Clipper expects and returns implicitely closed polygons static constexpr bool clipper_explicitely_closed_ = false; -public: /*! \brief Constructor of an empty shape */ Shape() = default; @@ -49,38 +48,38 @@ class Shape : public LinesSet */ explicit Shape(ClipperLib::Paths&& paths, bool explicitely_closed = clipper_explicitely_closed_); - Shape& operator=(const Shape& other); + Shape& operator=(const Shape& other) = default; + + Shape& operator=(Shape&& other) noexcept = default; - Shape& operator=(Shape&& other); + ~Shape() override = default; void emplace_back(ClipperLib::Paths&& paths, bool explicitely_closed = clipper_explicitely_closed_); void emplace_back(ClipperLib::Path&& path, bool explicitely_closed = clipper_explicitely_closed_); - template - void emplace_back(Args&&... args) + void emplace_back(auto&&... args) { - LinesSet::emplace_back(args...); + LinesSet::emplace_back(std::forward(args)...); } + [[nodiscard]] Shape difference(const Shape& other) const; - Shape difference(const Shape& other) const; - - Shape unionPolygons(const Shape& other, ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero) const; + [[nodiscard]] Shape unionPolygons(const Shape& other, ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero) const; /*! * Union all polygons with each other (When polygons.add(polygon) has been called for overlapping polygons) */ - Shape unionPolygons() const; + [[nodiscard]] Shape unionPolygons() const; - Shape intersection(const Shape& other) const; + [[nodiscard]] Shape intersection(const Shape& other) const; /*! * @brief Overridden definition of LinesSet::offset() * @note The behavior of this method is exactly the same, but it just exists because it allows * for a performance optimization */ - Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; + [[nodiscard]] Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; /*! * Intersect polylines with the area covered by the shape. @@ -96,9 +95,9 @@ class Shape : public LinesSet template OpenLinesSet intersection(const LinesSet& polylines, bool restitch = true, const coord_t max_stitch_distance = 10_mu) const; - Shape xorPolygons(const Shape& other, ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const; + [[nodiscard]] Shape xorPolygons(const Shape& other, ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const; - Shape execute(ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const; + [[nodiscard]] Shape execute(ClipperLib::PolyFillType pft = ClipperLib::pftEvenOdd) const; /*! * Check if we are inside the polygon. @@ -112,7 +111,7 @@ class Shape : public LinesSet * \param border_result What to return when the point is exactly on the border * \return Whether the point \p p is inside this polygon (or \p border_result when it is on the border) */ - bool inside(const Point2LL& p, bool border_result = false) const; + [[nodiscard]] bool inside(const Point2LL& p, bool border_result = false) const; /*! * Find the polygon inside which point \p p resides. @@ -127,7 +126,7 @@ class Shape : public LinesSet * \param border_result Whether a point exactly on a polygon counts as inside * \return The index of the polygon inside which the point \p p resides */ - size_t findInside(const Point2LL& p, bool border_result = false) const; + [[nodiscard]] size_t findInside(const Point2LL& p, bool border_result = false) const; /*! * \brief Approximates the convex hull of the polygons. @@ -135,7 +134,7 @@ class Shape : public LinesSet * \return the convex hull (approximately) * */ - Shape approxConvexHull(int extra_outset = 0) const; + [[nodiscard]] Shape approxConvexHull(int extra_outset = 0) const; /*! \brief Make each of the polygons convex */ void makeConvex(); @@ -145,7 +144,7 @@ class Shape : public LinesSet * * \return The area in square micron */ - double area() const; + [[nodiscard]] double area() const; /*! * Smooth out small perpendicular segments @@ -158,7 +157,7 @@ class Shape : public LinesSet * \param remove_length The length of the largest segment removed * \return The smoothed polygon */ - Shape smooth(int remove_length) const; + [[nodiscard]] Shape smooth(int remove_length) const; /*! * Smooth out sharp inner corners, by taking a shortcut which bypasses the corner @@ -167,9 +166,9 @@ class Shape : public LinesSet * \param shortcut_length The desired length of the shortcut line segment introduced (shorter shortcuts may be unavoidable) * \return The resulting polygons */ - Shape smooth_outward(const AngleDegrees angle, int shortcut_length) const; + [[nodiscard]] Shape smoothOutward(const AngleDegrees angle, int shortcut_length) const; - Shape smooth2(int remove_length, int min_area) const; //!< removes points connected to small lines + [[nodiscard]] Shape smooth2(int remove_length, int min_area) const; //!< removes points connected to small lines void removeColinearEdges(const AngleRadians max_deviation_angle = AngleRadians(0.0005)); @@ -178,20 +177,20 @@ class Shape : public LinesSet * Exclude holes and parts within holes. * \return the resulting polygons. */ - Shape getOutsidePolygons() const; + [[nodiscard]] Shape getOutsidePolygons() const; /*! * Split up the polygons into groups according to the even-odd rule. * Each SingleShape in the result has an outline as first polygon, whereas the rest are holes. */ - std::vector splitIntoParts(bool unionAll = false) const; + [[nodiscard]] std::vector splitIntoParts(bool union_all = false) const; /*! * Sort the polygons into bins where each bin has polygons which are contained within one of the polygons in the previous bin. * * \warning When polygons are crossing each other the result is undefined. */ - std::vector sortByNesting() const; + [[nodiscard]] std::vector sortByNesting() const; /*! * Split up the polygons into groups according to the even-odd rule. @@ -199,7 +198,7 @@ class Shape : public LinesSet * * \warning Note that this function reorders the polygons! */ - PartsView splitIntoPartsView(bool unionAll = false); + PartsView splitIntoPartsView(bool union_all = false); /*! * Removes polygons with area smaller than \p min_area_size (note that min_area_size is in mm^2, not in micron^2). @@ -212,9 +211,9 @@ class Shape : public LinesSet * Removes the same polygons from this set (and also empty polygons). * Shape are considered the same if all points lie within [same_distance] of their counterparts. */ - Shape removePolygon(const Shape& to_be_removed, int same_distance = 0) const; + [[nodiscard]] Shape removePolygon(const Shape& to_be_removed, int same_distance = 0) const; - Shape processEvenOdd(ClipperLib::PolyFillType poly_fill_type = ClipperLib::PolyFillType::pftEvenOdd) const; + [[nodiscard]] Shape processEvenOdd(ClipperLib::PolyFillType poly_fill_type = ClipperLib::PolyFillType::pftEvenOdd) const; /*! * Ensure the polygon is manifold, by removing small areas where the polygon touches itself. @@ -231,7 +230,7 @@ class Shape : public LinesSet void applyMatrix(const Point3Matrix& matrix); - Shape offsetMulti(const std::vector& offset_dists) const; + [[nodiscard]] Shape offsetMulti(const std::vector& offset_dists) const; /*! * @brief Remove self-intersections from the polygons @@ -242,7 +241,7 @@ class Shape : public LinesSet * * @return Polygons - the cleaned polygons */ - Shape removeNearSelfIntersections() const; + [[nodiscard]] Shape removeNearSelfIntersections() const; /*! * \brief Simplify the polygon lines using ClipperLib::SimplifyPolygons @@ -271,10 +270,10 @@ class Shape : public LinesSet * \param remove_holes Whether to remove empty holes or everything but the empty holes * \param ret Where to store polygons which are not empty holes */ - void removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Shape& ret) const; - void splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const; - void sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const; - void splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Shape& reordered, ClipperLib::PolyNode* node) const; + void removeEmptyHolesProcessPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Shape& ret) const; + void splitIntoPartsProcessPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const; + void sortByNestingProcessPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const; + void splitIntoPartsViewProcessPolyTreeNode(PartsView& parts_view, Shape& reordered, ClipperLib::PolyNode* node) const; }; } // namespace cura diff --git a/include/geometry/SingleShape.h b/include/geometry/SingleShape.h index a1a185c1df..f57309fdcc 100644 --- a/include/geometry/SingleShape.h +++ b/include/geometry/SingleShape.h @@ -21,6 +21,10 @@ class Polygon; class SingleShape : public Shape { public: + SingleShape() = default; + + explicit SingleShape(Shape&& shape) : Shape{ shape } {}; + Polygon& outerPolygon(); const Polygon& outerPolygon() const; diff --git a/include/settings/EnumSettings.h b/include/settings/EnumSettings.h index 18bd091569..bc6ea72cee 100644 --- a/include/settings/EnumSettings.h +++ b/include/settings/EnumSettings.h @@ -275,7 +275,7 @@ enum class BrimLocation /*! * Convenience binary operator to allow testing brim location easily, like (actual_location & BrimLocation::OUTSIDE) */ -static int operator&(BrimLocation location1, BrimLocation location2) +[[maybe_unused]] static int operator&(BrimLocation location1, BrimLocation location2) { return static_cast(location1) & static_cast(location2); } diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index e798b15a8b..ab8338d2c2 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -998,7 +998,7 @@ void FffGcodeWriter::processRaft(const SliceDataStorage& storage) raft_outline_path = raft_outline_path.difference(storage.primeTower.getOuterPoly(layer_nr)); } - for (const Shape raft_island : raft_outline_path.splitIntoParts()) + for (const Shape& raft_island : raft_outline_path.splitIntoParts()) { Infill infill_comp( EFillMethod::ZIG_ZAG, @@ -2689,7 +2689,7 @@ bool FffGcodeWriter::processInsets( gcode_layer.setOverhangMask(overhang_region); } - const auto roofing_mask = [&]() -> Shape + const auto roofing_mask_fn = [&]() -> Shape { const size_t roofing_layer_count = std::min(mesh.settings.get("roofing_layer_count"), mesh.settings.get("top_layers")); @@ -2711,7 +2711,7 @@ bool FffGcodeWriter::processInsets( return roofing_mask; }(); - gcode_layer.setRoofingMask(roofing_mask); + gcode_layer.setRoofingMask(roofing_mask_fn); } else { diff --git a/src/WallsComputation.cpp b/src/WallsComputation.cpp index 4f02bedc91..752d1cf0c9 100644 --- a/src/WallsComputation.cpp +++ b/src/WallsComputation.cpp @@ -85,7 +85,7 @@ void WallsComputation::generateWalls(SliceLayerPart* part, SectionType section_t part->inner_area = wall_tool_paths.getInnerContour(); } - part->outline = SingleShape({ Simplify(settings_).polygon(part->outline) }); + part->outline = SingleShape{ Simplify(settings_).polygon(part->outline) }; part->print_outline = part->outline; } diff --git a/src/geometry/LinesSet.cpp b/src/geometry/LinesSet.cpp index c1fa4f8172..3f116b41eb 100644 --- a/src/geometry/LinesSet.cpp +++ b/src/geometry/LinesSet.cpp @@ -14,32 +14,21 @@ namespace cura { -template<> -template<> -LinesSet::LinesSet(ClipperLib::Paths&& paths) -{ - reserve(paths.size()); - for (ClipperLib::Path& path : paths) - { - lines_.emplace_back(std::move(path)); - } -} - template -void LinesSet::push_back(const LineType& line, CheckNonEmptyParam checkNonEmpty) +void LinesSet::push_back(const LineType& line, CheckNonEmptyParam check_non_empty) { - if (checkNonEmpty == CheckNonEmptyParam::EvenIfEmpty || ! line.empty()) + if (check_non_empty == CheckNonEmptyParam::EvenIfEmpty || ! line.empty()) { lines_.push_back(line); } } template -void LinesSet::push_back(LineType&& line, CheckNonEmptyParam checkNonEmpty) +void LinesSet::push_back(LineType&& line, CheckNonEmptyParam check_non_empty) { - if (checkNonEmpty == CheckNonEmptyParam::EvenIfEmpty || ! line.empty()) + if (check_non_empty == CheckNonEmptyParam::EvenIfEmpty || ! line.empty()) { - lines_.push_back(line); + lines_.push_back(std::move(line)); } } @@ -60,7 +49,7 @@ size_t LinesSet::pointCount() const return std::accumulate( lines_.begin(), lines_.end(), - size_t(0), + 0ULL, [](size_t total, const LineType& line) { return total + line.size(); @@ -117,7 +106,7 @@ coord_t LinesSet::length() const return std::accumulate( lines_.begin(), lines_.end(), - 0, + 0LL, [](coord_t total, const LineType& line) { return total += line.length(); @@ -147,9 +136,9 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType jo { if (empty()) { - return Shape(); + return {}; } - else if (distance == 0) + if (distance == 0) { Shape result; for (const ClosedPolyline& line : getLines()) @@ -158,15 +147,12 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType jo } return result; } - else - { - ClipperLib::Paths ret; - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - addPaths(clipper, join_type, ClipperLib::etClosedLine); - clipper.MiterLimit = miter_limit; - clipper.Execute(ret, static_cast(distance)); - return Shape(std::move(ret)); - } + ClipperLib::Paths ret; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + addPaths(clipper, join_type, ClipperLib::etClosedLine); + clipper.MiterLimit = miter_limit; + clipper.Execute(ret, static_cast(distance)); + return Shape { std::move(ret) }; } template<> @@ -174,21 +160,18 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType join_type { if (empty()) { - return Shape(); - } - else if (distance == 0) - { - return Shape(getLines()); + return {}; } - else + if (distance == 0) { - ClipperLib::Paths ret; - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - Shape(getLines()).unionPolygons().addPaths(clipper, join_type, ClipperLib::etClosedPolygon); - clipper.MiterLimit = miter_limit; - clipper.Execute(ret, static_cast(distance)); - return Shape(std::move(ret)); + return { getLines() }; } + ClipperLib::Paths ret; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + Shape(getLines()).unionPolygons().addPaths(clipper, join_type, ClipperLib::etClosedPolygon); + clipper.MiterLimit = miter_limit; + clipper.Execute(ret, static_cast(distance)); + return Shape{ std::move(ret) }; } template<> @@ -196,32 +179,17 @@ Shape OpenLinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, dou { if (empty() || distance == 0) { - return Shape(); + return {}; } - else - { - Shape result; - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - ClipperLib::EndType end_type; - if (join_type == ClipperLib::jtMiter) - { - end_type = ClipperLib::etOpenSquare; - } - else - { - end_type = ClipperLib::etOpenRound; - } - - addPaths(clipper, join_type, end_type); - - clipper.MiterLimit = miter_limit; - ClipperLib::Paths result_paths; - clipper.Execute(result_paths, static_cast(distance)); - result = Shape(std::move(result_paths)); + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + const ClipperLib::EndType end_type{ join_type == ClipperLib::jtMiter ? ClipperLib::etOpenSquare : ClipperLib::etOpenRound }; + addPaths(clipper, join_type, end_type); + clipper.MiterLimit = miter_limit; + ClipperLib::Paths result_paths; + clipper.Execute(result_paths, static_cast(distance)); - return result; - } + return Shape{ std::move(result_paths) }; } template @@ -233,7 +201,7 @@ void LinesSet::removeDegenerateVerts() const bool for_polyline = (dynamic_cast(&poly) != nullptr); ClipperLib::Path result; - auto isDegenerate = [](const Point2LL& last, const Point2LL& now, const Point2LL& next) + auto is_degenerate = [](const Point2LL& last, const Point2LL& now, const Point2LL& next) { Point2LL last_line = now - last; Point2LL next_line = next - now; @@ -248,7 +216,7 @@ void LinesSet::removeDegenerateVerts() result.push_back(poly[i]); // Add everything before the start vertex. } - bool isChanged = false; + bool is_changed = false; for (size_t idx = start_vertex; idx < end_vertex; idx++) { const Point2LL& last = (result.size() == 0) ? poly.back() : result.back(); @@ -257,11 +225,11 @@ void LinesSet::removeDegenerateVerts() break; } const Point2LL& next = (idx + 1 >= poly.size()) ? result[0] : poly[idx + 1]; - if (isDegenerate(last, poly[idx], next)) + if (is_degenerate(last, poly[idx], next)) { // lines are in the opposite direction // don't add vert to the result - isChanged = true; - while (result.size() > 1 && isDegenerate(result[result.size() - 2], result.back(), next)) + is_changed = true; + while (result.size() > 1 && is_degenerate(result[result.size() - 2], result.back(), next)) { result.pop_back(); } @@ -277,7 +245,7 @@ void LinesSet::removeDegenerateVerts() result.push_back(poly[i]); // Add everything after the end vertex. } - if (isChanged) + if (is_changed) { if (for_polyline || result.size() > 2) { @@ -293,7 +261,7 @@ void LinesSet::removeDegenerateVerts() } template -void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const +void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType poly_typ) const { for (const LineType& line : getLines()) { @@ -301,21 +269,21 @@ void LinesSet::addPaths(ClipperLib::Clipper& clipper, ClipperLib::Poly // true for actual filled polygons. Closed polylines are to be treated as lines here. if constexpr (std::is_same::value) { - clipper.AddPath(line.getPoints(), PolyTyp, true); + clipper.AddPath(line.getPoints(), poly_typ, true); } else { - clipper.AddPath(line.getPoints(), PolyTyp, false); + clipper.AddPath(line.getPoints(), poly_typ, false); } } } template -void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const +void LinesSet::addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType joint_type, ClipperLib::EndType endType) const { for (const LineType& line : getLines()) { - clipper.AddPath(line.getPoints(), jointType, endType); + clipper.AddPath(line.getPoints(), joint_type, endType); } } diff --git a/src/geometry/Shape.cpp b/src/geometry/Shape.cpp index 270047cbdc..54440b2b80 100644 --- a/src/geometry/Shape.cpp +++ b/src/geometry/Shape.cpp @@ -3,6 +3,8 @@ #include "geometry/Shape.h" +#include +#include #include #include #include @@ -59,18 +61,6 @@ void Shape::emplace_back(ClipperLib::Path&& path, bool explicitely_closed) static_cast*>(this)->emplace_back(std::move(path), explicitely_closed); } -Shape& Shape::operator=(const Shape& other) -{ - LinesSet::operator=(other); - return *this; -} - -Shape& Shape::operator=(Shape&& other) -{ - LinesSet::operator=(std::move(other)); - return *this; -} - Shape Shape::approxConvexHull(int extra_outset) const { constexpr int overshoot = MM2INT(100); // 10cm (hard-coded value). @@ -141,53 +131,47 @@ void Shape::makeConvex() std::reverse(points.begin(), points.end()); make_sorted_poly_convex(points); - setLines({ std::move(convexified) }); + setLines({ convexified }); } Shape Shape::difference(const Shape& other) const { if (empty()) { - return Shape(); - } - else if (other.empty()) - { - return Shape(*this); + return {}; } - else + if (other.empty()) { - ClipperLib::Paths ret; - ClipperLib::Clipper clipper(clipper_init); - addPaths(clipper, ClipperLib::ptSubject); - other.addPaths(clipper, ClipperLib::ptClip); - clipper.Execute(ClipperLib::ctDifference, ret); - return Shape(std::move(ret)); + return *this; } + ClipperLib::Paths ret; + ClipperLib::Clipper clipper(clipper_init); + addPaths(clipper, ClipperLib::ptSubject); + other.addPaths(clipper, ClipperLib::ptClip); + clipper.Execute(ClipperLib::ctDifference, ret); + return Shape(std::move(ret)); } Shape Shape::unionPolygons(const Shape& other, ClipperLib::PolyFillType fill_type) const { if (empty() && other.empty()) { - return Shape(); + return {}; } - else if (empty() && other.size() <= 1) + if (empty() && other.size() <= 1) { return other; } - else if (other.empty() && size() <= 1) + if (other.empty() && size() <= 1) { return *this; } - else - { - ClipperLib::Paths ret; - ClipperLib::Clipper clipper(clipper_init); - addPaths(clipper, ClipperLib::ptSubject); - other.addPaths(clipper, ClipperLib::ptSubject); - clipper.Execute(ClipperLib::ctUnion, ret, fill_type, fill_type); - return Shape(std::move(ret)); - } + ClipperLib::Paths ret; + ClipperLib::Clipper clipper(clipper_init); + addPaths(clipper, ClipperLib::ptSubject); + other.addPaths(clipper, ClipperLib::ptSubject); + clipper.Execute(ClipperLib::ctUnion, ret, fill_type, fill_type); + return Shape{ std::move(ret) }; } Shape Shape::unionPolygons() const @@ -199,38 +183,33 @@ Shape Shape::intersection(const Shape& other) const { if (empty() || other.empty()) { - return Shape(); - } - else - { - ClipperLib::Paths ret; - ClipperLib::Clipper clipper(clipper_init); - addPaths(clipper, ClipperLib::ptSubject); - other.addPaths(clipper, ClipperLib::ptClip); - clipper.Execute(ClipperLib::ctIntersection, ret); - return Shape(std::move(ret)); + return {}; } + ClipperLib::Paths ret; + ClipperLib::Clipper clipper(clipper_init); + addPaths(clipper, ClipperLib::ptSubject); + other.addPaths(clipper, ClipperLib::ptClip); + clipper.Execute(ClipperLib::ctIntersection, ret); + return Shape{ std::move(ret) }; } Shape Shape::offset(coord_t distance, ClipperLib::JoinType join_type, double miter_limit) const { if (empty()) { - return Shape(); + return {}; } - else if (distance == 0) + if (distance == 0) { return *this; } - else - { - ClipperLib::Paths ret; - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - unionPolygons().addPaths(clipper, join_type, ClipperLib::etClosedPolygon); - clipper.MiterLimit = miter_limit; - clipper.Execute(ret, static_cast(distance)); - return Shape(std::move(ret)); - } + + ClipperLib::Paths ret; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + unionPolygons().addPaths(clipper, join_type, ClipperLib::etClosedPolygon); + clipper.MiterLimit = miter_limit; + clipper.Execute(ret, static_cast(distance)); + return Shape{ std::move(ret) }; } bool Shape::inside(const Point2LL& p, bool border_result) const @@ -250,9 +229,9 @@ bool Shape::inside(const Point2LL& p, bool border_result) const size_t Shape::findInside(const Point2LL& p, bool border_result) const { - if (size() < 1) + if (empty()) { - return false; + return 0; } // NOTE: Keep these vectors fixed-size, they replace an (non-standard, sized at runtime) arrays. @@ -278,10 +257,7 @@ size_t Shape::findInside(const Point2LL& p, bool border_result) const { x = p0.X + (p1.X - p0.X) * (p.Y - p0.Y) / (p1.Y - p0.Y); } - if (x < min_x[poly_idx]) - { - min_x[poly_idx] = x; - } + min_x[poly_idx] = std::min(x, min_x[poly_idx]); } else if (border_result && comp == 0) { @@ -318,7 +294,7 @@ OpenLinesSet Shape::intersection(const LinesSet& polylines, bool resti { if (empty() || polylines.empty()) { - return OpenLinesSet(); + return {}; } OpenLinesSet split_polylines = polylines.splitIntoSegments(); @@ -365,19 +341,16 @@ Shape Shape::xorPolygons(const Shape& other, ClipperLib::PolyFillType pft) const { return other; } - else if (other.empty()) + if (other.empty()) { return *this; } - else - { - ClipperLib::Paths ret; - ClipperLib::Clipper clipper(clipper_init); - addPaths(clipper, ClipperLib::ptSubject); - other.addPaths(clipper, ClipperLib::ptClip); - clipper.Execute(ClipperLib::ctXor, ret, pft); - return Shape(std::move(ret)); - } + ClipperLib::Paths ret; + ClipperLib::Clipper clipper(clipper_init); + addPaths(clipper, ClipperLib::ptSubject); + other.addPaths(clipper, ClipperLib::ptClip); + clipper.Execute(ClipperLib::ctXor, ret, pft); + return Shape{ std::move(ret) }; } Shape Shape::execute(ClipperLib::PolyFillType pft) const @@ -386,7 +359,7 @@ Shape Shape::execute(ClipperLib::PolyFillType pft) const ClipperLib::Clipper clipper(clipper_init); addPaths(clipper, ClipperLib::ptSubject); clipper.Execute(ClipperLib::ctXor, ret, pft); - return Shape(std::move(ret)); + return Shape{ std::move(ret) }; } Shape Shape::offsetMulti(const std::vector& offset_dists) const @@ -441,9 +414,9 @@ Shape Shape::getOutsidePolygons() const { if (empty()) { - return Shape(); + return {}; } - else if (size() == 1) + if (size() == 1) { return *this; } @@ -462,7 +435,7 @@ Shape Shape::getOutsidePolygons() const return ret; } -void Shape::removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Shape& ret) const +void Shape::removeEmptyHolesProcessPolyTreeNode(const ClipperLib::PolyNode& node, const bool remove_holes, Shape& ret) const { for (size_t outer_poly_idx = 0; outer_poly_idx < static_cast(node.ChildCount()); outer_poly_idx++) { @@ -477,7 +450,7 @@ void Shape::removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode& nod if ((hole_node.ChildCount() > 0) == remove_holes) { ret.emplace_back(std::move(hole_node.Contour)); - removeEmptyHoles_processPolyTreeNode(hole_node, remove_holes, ret); + removeEmptyHolesProcessPolyTreeNode(hole_node, remove_holes, ret); } } } @@ -516,15 +489,9 @@ void Shape::removeSmallAreas(const double min_area_size, const bool remove_holes std::swap(*new_end, *it); continue; } - else - { // Don't self-swap the last Path - break; - } - } - else - { - small_holes.push_back(&(*it)); + break; } + small_holes.push_back(&(*it)); } it++; // Skipped on removal such that the polygon just swaped in is checked next } @@ -554,34 +521,37 @@ Shape Shape::removePolygon(const Shape& to_be_removed, int same_distance) const { const Polygon& poly_keep = (*this)[poly_keep_idx]; bool should_be_removed = false; - if (poly_keep.size() > 0) - // for (int hole_poly_idx = 0; hole_poly_idx < to_be_removed.size(); hole_poly_idx++) + if (! poly_keep.empty()) + { for (const Polygon& poly_rem : to_be_removed) { - // PolygonRef poly_rem = to_be_removed[hole_poly_idx]; - if (poly_rem.size() != poly_keep.size() || poly_rem.size() == 0) + if (poly_rem.size() != poly_keep.size() || poly_rem.empty()) + { continue; + } // find closest point, supposing this point aligns the two shapes in the best way size_t closest_point_idx = 0; - coord_t smallestDist2 = -1; + coord_t smallest_dist2 = -1; for (size_t point_rem_idx = 0; point_rem_idx < poly_rem.size(); point_rem_idx++) { coord_t dist2 = vSize2(poly_rem[point_rem_idx] - poly_keep[0]); - if (dist2 < smallestDist2 || smallestDist2 < 0) + if (dist2 < smallest_dist2 || smallest_dist2 < 0) { - smallestDist2 = dist2; + smallest_dist2 = dist2; closest_point_idx = point_rem_idx; } } bool poly_rem_is_poly_keep = true; // compare the two polygons on all points - if (smallestDist2 > same_distance * same_distance) + if (smallest_dist2 > static_cast(same_distance * same_distance)) + { continue; + } for (size_t point_idx = 0; point_idx < poly_rem.size(); point_idx++) { coord_t dist2 = vSize2(poly_rem[(closest_point_idx + point_idx) % poly_rem.size()] - poly_keep[point_idx]); - if (dist2 > same_distance * same_distance) + if (dist2 > static_cast(same_distance * same_distance)) { poly_rem_is_poly_keep = false; break; @@ -593,8 +563,11 @@ Shape Shape::removePolygon(const Shape& to_be_removed, int same_distance) const break; } } + } if (! should_be_removed) + { result.push_back(poly_keep); + } } return result; } @@ -605,10 +578,10 @@ Shape Shape::processEvenOdd(ClipperLib::PolyFillType poly_fill_type) const ClipperLib::Clipper clipper(clipper_init); addPaths(clipper, ClipperLib::ptSubject); clipper.Execute(ClipperLib::ctUnion, ret, poly_fill_type); - return Shape(std::move(ret)); + return Shape{ std::move(ret) }; } -Shape Shape::smooth_outward(const AngleDegrees max_angle, int shortcut_length) const +Shape Shape::smoothOutward(const AngleDegrees max_angle, int shortcut_length) const { Shape ret; for (const Polygon& poly : (*this)) @@ -660,7 +633,7 @@ Shape Shape::smooth2(int remove_length, int min_area) const Shape ret; for (const Polygon& poly : (*this)) { - if (poly.size() == 0) + if (poly.empty()) { continue; } @@ -708,22 +681,26 @@ double Shape::area() const }); } -std::vector Shape::splitIntoParts(bool unionAll) const +std::vector Shape::splitIntoParts(bool union_all) const { std::vector ret; ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree resultPolyTree; + ClipperLib::PolyTree result_poly_tree; addPaths(clipper, ClipperLib::ptSubject); - if (unionAll) - clipper.Execute(ClipperLib::ctUnion, resultPolyTree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + if (union_all) + { + clipper.Execute(ClipperLib::ctUnion, result_poly_tree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + } else - clipper.Execute(ClipperLib::ctUnion, resultPolyTree); + { + clipper.Execute(ClipperLib::ctUnion, result_poly_tree); + } - splitIntoParts_processPolyTreeNode(&resultPolyTree, ret); + splitIntoPartsProcessPolyTreeNode(&result_poly_tree, ret); return ret; } -void Shape::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const +void Shape::splitIntoPartsProcessPolyTreeNode(ClipperLib::PolyNode* node, std::vector& ret) const { for (size_t n = 0; n < static_cast(node->ChildCount()); n++) { @@ -733,7 +710,7 @@ void Shape::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, std:: for (size_t i = 0; i < static_cast(child->ChildCount()); i++) { part.emplace_back(std::move(child->Childs[i]->Contour)); - splitIntoParts_processPolyTreeNode(child->Childs[i], ret); + splitIntoPartsProcessPolyTreeNode(child->Childs[i], ret); } ret.push_back(std::move(part)); } @@ -743,15 +720,15 @@ std::vector Shape::sortByNesting() const { std::vector ret; ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree resultPolyTree; + ClipperLib::PolyTree result_poly_tree; addPaths(clipper, ClipperLib::ptSubject); - clipper.Execute(ClipperLib::ctUnion, resultPolyTree); + clipper.Execute(ClipperLib::ctUnion, result_poly_tree); - sortByNesting_processPolyTreeNode(&resultPolyTree, 0, ret); + sortByNestingProcessPolyTreeNode(&result_poly_tree, 0, ret); return ret; } -void Shape::sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const +void Shape::sortByNestingProcessPolyTreeNode(ClipperLib::PolyNode* node, const size_t nesting_idx, std::vector& ret) const { for (size_t n = 0; n < static_cast(node->ChildCount()); n++) { @@ -761,29 +738,33 @@ void Shape::sortByNesting_processPolyTreeNode(ClipperLib::PolyNode* node, const ret.resize(nesting_idx + 1); } ret[nesting_idx].emplace_back(std::move(child->Contour)); - sortByNesting_processPolyTreeNode(child, nesting_idx + 1, ret); + sortByNestingProcessPolyTreeNode(child, nesting_idx + 1, ret); } } -PartsView Shape::splitIntoPartsView(bool unionAll) +PartsView Shape::splitIntoPartsView(bool union_all) { Shape reordered; - PartsView partsView(*this); + PartsView parts_view(*this); ClipperLib::Clipper clipper(clipper_init); - ClipperLib::PolyTree resultPolyTree; + ClipperLib::PolyTree result_poly_tree; addPaths(clipper, ClipperLib::ptSubject); - if (unionAll) - clipper.Execute(ClipperLib::ctUnion, resultPolyTree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + if (union_all) + { + clipper.Execute(ClipperLib::ctUnion, result_poly_tree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); + } else - clipper.Execute(ClipperLib::ctUnion, resultPolyTree); + { + clipper.Execute(ClipperLib::ctUnion, result_poly_tree); + } - splitIntoPartsView_processPolyTreeNode(partsView, reordered, &resultPolyTree); + splitIntoPartsViewProcessPolyTreeNode(parts_view, reordered, &result_poly_tree); (*this) = std::move(reordered); - return partsView; + return parts_view; } -void Shape::splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Shape& reordered, ClipperLib::PolyNode* node) const +void Shape::splitIntoPartsViewProcessPolyTreeNode(PartsView& partsView, Shape& reordered, ClipperLib::PolyNode* node) const { for (size_t n = 0; n < static_cast(node->ChildCount()); n++) { @@ -796,7 +777,7 @@ void Shape::splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Shape& { partsView[pos].push_back(reordered.size()); reordered.emplace_back(std::move(child->Childs[i]->Contour)); - splitIntoPartsView_processPolyTreeNode(partsView, reordered, child->Childs[i]); + splitIntoPartsViewProcessPolyTreeNode(partsView, reordered, child->Childs[i]); } } } diff --git a/src/infill.cpp b/src/infill.cpp index 705489ee18..a2d931d262 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -136,7 +136,7 @@ void Infill::generate( small_infill.push_back(small_infill_part); } } - inner_contour_.unionPolygons(); + inner_contour_ = inner_contour_.unionPolygons(); // Fill narrow area with walls. const size_t narrow_wall_count = small_area_width_ / infill_line_width_ + 1; diff --git a/src/sliceDataStorage.cpp b/src/sliceDataStorage.cpp index d346d6df35..2447ce356f 100644 --- a/src/sliceDataStorage.cpp +++ b/src/sliceDataStorage.cpp @@ -658,7 +658,7 @@ Shape SliceDataStorage::getMachineBorder(int checking_extruder_nr) const disallowed_all_extruders = disallowed_all_extruders.unionPolygons(extruder_border); } } - disallowed_all_extruders.processEvenOdd(ClipperLib::pftNonZero); // prevent overlapping disallowed areas from XORing + disallowed_all_extruders = disallowed_all_extruders.processEvenOdd(ClipperLib::pftNonZero); // prevent overlapping disallowed areas from XORing Shape border_all_extruders = border; // each extruders border areas must be limited to the global border, which is the union of all extruders borders if (mesh_group_settings.has("nozzle_offsetting_for_disallowed_areas") && mesh_group_settings.get("nozzle_offsetting_for_disallowed_areas")) From c271ad82a98f515350a3412d25d5f6d504cde705 Mon Sep 17 00:00:00 2001 From: jellespijker Date: Fri, 3 May 2024 13:06:42 +0000 Subject: [PATCH 089/135] Applied clang-format. --- include/geometry/LinesSet.h | 3 +-- include/geometry/SingleShape.h | 3 ++- src/geometry/LinesSet.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index 212af90228..10d327e2bc 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -70,8 +70,7 @@ class LinesSet * objects, because closed ones require an additional argument */ template - requires std::is_same_v - LinesSet(ClipperLib::Paths&& paths) + requires std::is_same_v LinesSet(ClipperLib::Paths&& paths) { reserve(paths.size()); for (ClipperLib::Path& path : paths) diff --git a/include/geometry/SingleShape.h b/include/geometry/SingleShape.h index f57309fdcc..f4f925e781 100644 --- a/include/geometry/SingleShape.h +++ b/include/geometry/SingleShape.h @@ -23,7 +23,8 @@ class SingleShape : public Shape public: SingleShape() = default; - explicit SingleShape(Shape&& shape) : Shape{ shape } {}; + explicit SingleShape(Shape&& shape) + : Shape{ shape } {}; Polygon& outerPolygon(); diff --git a/src/geometry/LinesSet.cpp b/src/geometry/LinesSet.cpp index 3f116b41eb..ae36f47f4d 100644 --- a/src/geometry/LinesSet.cpp +++ b/src/geometry/LinesSet.cpp @@ -152,7 +152,7 @@ Shape LinesSet::offset(coord_t distance, ClipperLib::JoinType jo addPaths(clipper, join_type, ClipperLib::etClosedLine); clipper.MiterLimit = miter_limit; clipper.Execute(ret, static_cast(distance)); - return Shape { std::move(ret) }; + return Shape{ std::move(ret) }; } template<> From f53362442b5dd9705ef73ef8eddf47fcecaaa2ad Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 3 May 2024 17:12:48 +0200 Subject: [PATCH 090/135] modernized geometry and utility classes Optimized the geometry and utility classes, enhancing the readability and maintenance of the code. Changes included the addition of explicit constructors, default and noexcept specifiers to methods, simplifying conditionals, and replaced old C++11 type traits with newer C++20 concepts where applicable. Contribute to CURA-9830 --- include/geometry/ClosedPolyline.h | 47 ++++++++---------- include/geometry/LinesSet.h | 32 +++++------- include/geometry/MixedLinesSet.h | 4 +- include/geometry/OpenPolyline.h | 30 +++++------ include/geometry/PartsView.h | 16 ++++-- include/geometry/Point2LL.h | 20 ++++++-- include/geometry/Point3LL.h | 82 ++++++++++++++++++++----------- include/geometry/PointsSet.h | 57 +++++++++++---------- include/geometry/Polygon.h | 32 ++++++------ src/geometry/ClosedPolyline.cpp | 19 +++---- src/geometry/MixedLinesSet.cpp | 68 +++++++++++-------------- src/infill/GyroidInfill.cpp | 6 +-- src/utils/Point3LL.cpp | 10 ---- 13 files changed, 212 insertions(+), 211 deletions(-) diff --git a/include/geometry/ClosedPolyline.h b/include/geometry/ClosedPolyline.h index 45b204dcd0..8f4bc3e753 100644 --- a/include/geometry/ClosedPolyline.h +++ b/include/geometry/ClosedPolyline.h @@ -32,6 +32,8 @@ class ClosedPolyline : public Polyline bool explicitely_closed_{ false }; public: + ClosedPolyline() = default; + /*! * \brief Builds an empty closed polyline * \param explicitely_closed Indicates whether the line will be explicitely closed @@ -39,9 +41,8 @@ class ClosedPolyline : public Polyline * constructor in various places, but be careful that the interpretation of the points * added later will depend on this. */ - ClosedPolyline(bool explicitely_closed = false) - : Polyline() - , explicitely_closed_(explicitely_closed) + explicit ClosedPolyline(const bool explicitely_closed) + : explicitely_closed_{ explicitely_closed } { } @@ -56,8 +57,8 @@ class ClosedPolyline : public Polyline * \param explicitely_closed Specify whether the given points form an explicitely closed line */ ClosedPolyline(const std::initializer_list& initializer, bool explicitely_closed) - : Polyline(initializer) - , explicitely_closed_(explicitely_closed) + : Polyline{ initializer } + , explicitely_closed_{ explicitely_closed } { } @@ -66,8 +67,8 @@ class ClosedPolyline : public Polyline * \param explicitely_closed Specify whether the given points form an explicitely closed line */ explicit ClosedPolyline(const ClipperLib::Path& points, bool explicitely_closed) - : Polyline(points) - , explicitely_closed_(explicitely_closed) + : Polyline{ points } + , explicitely_closed_{ explicitely_closed } { } @@ -76,36 +77,30 @@ class ClosedPolyline : public Polyline * \param explicitely_closed Specify whether the given points form an explicitely closed line */ explicit ClosedPolyline(ClipperLib::Path&& points, bool explicitely_closed) - : Polyline(points) - , explicitely_closed_(explicitely_closed) + : Polyline{ std::move(points) } + , explicitely_closed_{ explicitely_closed } { } + ~ClosedPolyline() override = default; + /*! @see Polyline::hasClosingSegment() */ - virtual bool hasClosingSegment() const + [[nodiscard]] bool hasClosingSegment() const override { return ! explicitely_closed_; } /*! @see Polyline::addClosingSegment() */ - virtual size_t segmentsCount() const override; + [[nodiscard]] size_t segmentsCount() const override; /*! @see Polyline::isValid() */ - virtual bool isValid() const override; + [[nodiscard]] bool isValid() const override; - ClosedPolyline& operator=(const ClosedPolyline& other) - { - Polyline::operator=(other); - return *this; - } + ClosedPolyline& operator=(const ClosedPolyline& other) = default; - ClosedPolyline& operator=(ClosedPolyline&& other) - { - Polyline::operator=(other); - return *this; - } + ClosedPolyline& operator=(ClosedPolyline&& other) = default; - bool isExplicitelyClosed() const + [[nodiscard]] bool isExplicitelyClosed() const { return explicitely_closed_; } @@ -126,9 +121,9 @@ class ClosedPolyline : public Polyline * * http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/PointInPolygon.htm */ - bool inside(const Point2LL& p, bool border_result = false) const; + [[nodiscard]] bool inside(const Point2LL& p, bool border_result = false) const; - bool inside(const ClipperLib::Path& polygon) const; + [[nodiscard]] bool inside(const ClipperLib::Path& polygon) const; /*! * \brief Converts the closed polyline to an open polyline which happens to have its end and start points at the same @@ -137,7 +132,7 @@ class ClosedPolyline : public Polyline * between open and closed polylines * \return An open polyline instance, with the end point at the same position of the start point */ - OpenPolyline toPseudoOpenPolyline() const; + [[nodiscard]] OpenPolyline toPseudoOpenPolyline() const; }; } // namespace cura diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index 10d327e2bc..3de08203a9 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -53,13 +53,13 @@ class LinesSet LinesSet(LinesSet&& other) = default; /*! \brief Constructor with an existing set of lines */ - LinesSet(const std::vector& lines) + explicit LinesSet(const std::vector& lines) : lines_(lines) { } /*! \brief Constructor that takes ownership of the data from the given set of lines */ - LinesSet(std::vector&& lines) + explicit LinesSet(std::vector&& lines) : lines_(std::move(lines)) { } @@ -70,7 +70,7 @@ class LinesSet * objects, because closed ones require an additional argument */ template - requires std::is_same_v LinesSet(ClipperLib::Paths&& paths) + requires std::is_same_v explicit LinesSet(ClipperLib::Paths&& paths) { reserve(paths.size()); for (ClipperLib::Path& path : paths) @@ -196,17 +196,9 @@ class LinesSet return lines_.erase(first, last); } - LinesSet& operator=(const LinesSet& other) - { - lines_ = other.lines_; - return *this; - } + LinesSet& operator=(const LinesSet& other) = default; - LinesSet& operator=(LinesSet&& other) noexcept - { - lines_ = std::move(other.lines_); - return *this; - } + LinesSet& operator=(LinesSet&& other) noexcept = default; LineType& operator[](size_t index) { @@ -225,7 +217,7 @@ class LinesSet } /*! \brief Return the amount of points in all lines */ - size_t pointCount() const; + [[nodiscard]] size_t pointCount() const; /*! * Remove a line from the list and move the last line to its place @@ -237,15 +229,15 @@ class LinesSet void addSegment(const Point2LL& from, const Point2LL& to); /*! \brief Get the total length of all the lines */ - coord_t length() const; + [[nodiscard]] coord_t length() const; void splitIntoSegments(OpenLinesSet& result) const; - OpenLinesSet splitIntoSegments() const; + [[nodiscard]] OpenLinesSet splitIntoSegments() const; /*! \brief Removes overlapping consecutive line segments which don't delimit a positive area */ void removeDegenerateVerts(); - Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; + [[nodiscard]] Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; /*! * Utility method for creating the tube (or 'donut') of a shape. @@ -257,7 +249,7 @@ class LinesSet * shape. Comparable to normal offset. * \return The resulting polygons. */ - Shape createTubeShape(const coord_t inner_offset, const coord_t outer_offset) const; + [[nodiscard]] Shape createTubeShape(const coord_t inner_offset, const coord_t outer_offset) const; void translate(const Point2LL& delta); @@ -265,13 +257,13 @@ class LinesSet * \brief Utility method to add all the lines to a ClipperLib::Clipper object * \note This method needs to be public but you shouldn't need to use it from outside */ - void addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType PolyTyp) const; + void addPaths(ClipperLib::Clipper& clipper, ClipperLib::PolyType poly_typ) const; /*! * \brief Utility method to add all the lines to a ClipperLib::ClipperOffset object * \note This method needs to be public but you shouldn't need to use it from outside */ - void addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType jointType, ClipperLib::EndType endType) const; + void addPaths(ClipperLib::ClipperOffset& clipper, ClipperLib::JoinType joint_type, ClipperLib::EndType end_type) const; /*! * \brief Display operator, useful for debugging/testing diff --git a/include/geometry/MixedLinesSet.h b/include/geometry/MixedLinesSet.h index 2017e87be8..f692f47661 100644 --- a/include/geometry/MixedLinesSet.h +++ b/include/geometry/MixedLinesSet.h @@ -36,7 +36,7 @@ class MixedLinesSet : public std::vector * \return A shape containing the offsetted polylines. This may contain many unjoined polygons, * but no overlapping ones. */ - Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; + [[nodiscard]] Shape offset(coord_t distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; /*! @brief Adds a copy of the given polyline to the set */ void push_back(const OpenPolyline& line); @@ -72,7 +72,7 @@ class MixedLinesSet : public std::vector void push_back(ClosedLinesSet&& lines_set); /*! \brief Computes the total lenght of all the polylines in the set */ - coord_t length() const; + [[nodiscard]] coord_t length() const; }; } // namespace cura diff --git a/include/geometry/OpenPolyline.h b/include/geometry/OpenPolyline.h index 84c0cccdd0..f9a3d1b62e 100644 --- a/include/geometry/OpenPolyline.h +++ b/include/geometry/OpenPolyline.h @@ -41,7 +41,7 @@ class OpenPolyline : public Polyline * \warning A copy of the points list is made, so this constructor is somehow "slow" */ OpenPolyline(const std::initializer_list& initializer) - : Polyline(initializer) + : Polyline{ initializer } { } @@ -49,8 +49,8 @@ class OpenPolyline : public Polyline * \brief Constructor with an existing list of points * \warning A copy of the points list is made, so this constructor is somehow "slow" */ - OpenPolyline(const ClipperLib::Path& points) - : Polyline(points) + explicit OpenPolyline(const ClipperLib::Path& points) + : Polyline{ points } { } @@ -59,40 +59,34 @@ class OpenPolyline : public Polyline * \warning This constructor is fast because it does not allocate data, but it will clear * the source object */ - OpenPolyline(ClipperLib::Path&& points) - : Polyline(std::move(points)) + explicit OpenPolyline(ClipperLib::Path&& points) + : Polyline{ std::move(points) } { } + ~OpenPolyline() override = default; + /*! @see Polyline::hasClosingSegment() */ - virtual bool hasClosingSegment() const override + [[nodiscard]] bool hasClosingSegment() const override { return false; // Definitely not } /*! @see Polyline::segmentsCount() */ - virtual size_t segmentsCount() const override + [[nodiscard]] size_t segmentsCount() const override { return size() > 1 ? size() - 1 : 0; } /*! @see Polyline::isValid() */ - virtual bool isValid() const override + [[nodiscard]] bool isValid() const override { return size() >= 2; } - OpenPolyline& operator=(OpenPolyline&& other) - { - Polyline::operator=(std::move(other)); - return *this; - } + OpenPolyline& operator=(OpenPolyline&& other) noexcept = default; - OpenPolyline& operator=(const OpenPolyline& other) - { - Polyline::operator=(other); - return *this; - } + OpenPolyline& operator=(const OpenPolyline& other) = default; }; } // namespace cura diff --git a/include/geometry/PartsView.h b/include/geometry/PartsView.h index f43c8c1d21..e8b6b59d31 100644 --- a/include/geometry/PartsView.h +++ b/include/geometry/PartsView.h @@ -21,11 +21,21 @@ class PartsView : public std::vector> public: Shape& polygons_; - PartsView(Shape& polygons) - : polygons_(polygons) + PartsView() = delete; + + explicit PartsView(Shape& polygons) + : polygons_{ polygons } { } + PartsView(PartsView&& parts_view) = default; + PartsView(const PartsView& parts_view) = default; + + ~PartsView() = default; + + PartsView& operator=(PartsView&& parts_view) = delete; + PartsView& operator=(const PartsView& parts_view) = delete; + /*! * Get the index of the SingleShape of which the polygon with index \p poly_idx is part. * @@ -50,7 +60,7 @@ class PartsView : public std::vector> * \param part_idx The index of the part * \return The SingleShape with index \p poly_idx */ - SingleShape assemblePart(size_t part_idx) const; + [[nodiscard]] SingleShape assemblePart(size_t part_idx) const; }; } // namespace cura diff --git a/include/geometry/Point2LL.h b/include/geometry/Point2LL.h index 8217d7e797..50781d49b6 100644 --- a/include/geometry/Point2LL.h +++ b/include/geometry/Point2LL.h @@ -42,36 +42,44 @@ INLINE Point2LL operator-(const Point2LL& p0) { return { -p0.X, -p0.Y }; } + INLINE Point2LL operator+(const Point2LL& p0, const Point2LL& p1) { return { p0.X + p1.X, p0.Y + p1.Y }; } + INLINE Point2LL operator-(const Point2LL& p0, const Point2LL& p1) { return { p0.X - p1.X, p0.Y - p1.Y }; } + INLINE Point2LL operator*(const Point2LL& p0, const coord_t i) { return { p0.X * i, p0.Y * i }; } + template::value, T>::type> // Use only for numeric types. INLINE Point2LL operator*(const Point2LL& p0, const T i) { return { std::llrint(static_cast(p0.X) * i), std::llrint(static_cast(p0.Y) * i) }; } + template::value, T>::type> // Use only for numeric types. INLINE Point2LL operator*(const T i, const Point2LL& p0) { return p0 * i; } + INLINE Point2LL operator/(const Point2LL& p0, const coord_t i) { return { p0.X / i, p0.Y / i }; } + INLINE Point2LL operator/(const Point2LL& p0, const Point2LL& p1) { return { p0.X / p1.X, p0.Y / p1.Y }; } + INLINE Point2LL operator%(const Point2LL& p0, const coord_t i) { return { p0.X % i, p0.Y % i }; @@ -83,6 +91,7 @@ INLINE Point2LL& operator+=(Point2LL& p0, const Point2LL& p1) p0.Y += p1.Y; return p0; } + INLINE Point2LL& operator-=(Point2LL& p0, const Point2LL& p1) { p0.X -= p1.X; @@ -111,6 +120,7 @@ INLINE coord_t vSize2(const Point2LL& p0) { return p0.X * p0.X + p0.Y * p0.Y; } + INLINE double vSize2f(const Point2LL& p0) { return static_cast(p0.X) * static_cast(p0.X) + static_cast(p0.Y) * static_cast(p0.Y); @@ -146,14 +156,14 @@ INLINE double vSizeMM(const Point2LL& p0) return sqrt(fx * fx + fy * fy); } -INLINE Point2LL normal(const Point2LL& p0, coord_t len) +INLINE Point2LL normal(const Point2LL& p0, coord_t length) { - coord_t _len{ vSize(p0) }; - if (_len < 1) + coord_t len{ vSize(p0) }; + if (len < 1) { - return { len, 0 }; + return { length, 0 }; } - return p0 * len / _len; + return p0 * length / len; } INLINE Point2LL turn90CCW(const Point2LL& p0) diff --git a/include/geometry/Point3LL.h b/include/geometry/Point3LL.h index 9dfb91c544..fd220b05ef 100644 --- a/include/geometry/Point3LL.h +++ b/include/geometry/Point3LL.h @@ -11,6 +11,7 @@ #include // for operations on any arithmetic number type #include "utils/Coord_t.h" +#include "utils/types/generic.h" namespace cura @@ -19,10 +20,12 @@ namespace cura class Point3LL { public: - coord_t x_, y_, z_; - Point3LL() - { - } + coord_t x_{}; + coord_t y_{}; + coord_t z_{}; + + Point3LL() = default; + Point3LL(const coord_t x, const coord_t y, const coord_t z) : x_(x) , y_(y) @@ -30,41 +33,53 @@ class Point3LL { } + Point3LL(Point3LL&& point) = default; + Point3LL(const Point3LL& point) = default; + Point3LL& operator=(const Point3LL& point) = default; + Point3LL& operator=(Point3LL&& point) = default; + + virtual ~Point3LL() = default; + Point3LL operator+(const Point3LL& p) const; Point3LL operator-() const; Point3LL operator-(const Point3LL& p) const; Point3LL operator*(const Point3LL& p) const; //!< Element-wise multiplication. For dot product, use .dot()! Point3LL operator/(const Point3LL& p) const; - template::value, num_t>::type> - Point3LL operator*(const num_t i) const + + template + Point3LL operator*(const T& i) const { - return Point3LL(std::llround(static_cast(x_) * i), std::llround(static_cast(y_) * i), std::llround(static_cast(z_) * i)); + return { std::llround(static_cast(x_) * i), std::llround(static_cast(y_) * i), std::llround(static_cast(z_) * i) }; } - template::value, num_t>::type> - Point3LL operator/(const num_t i) const + + template + Point3LL operator/(const T& i) const { - return Point3LL(x_ / i, y_ / i, z_ / i); + return { x_ / i, y_ / i, z_ / i }; } - template::value, num_t>::type> - Point3LL operator%(const num_t i) const + + template + Point3LL operator%(const T& i) const { - return Point3LL(x_ % i, y_ % i, z_ % i); + return { x_ % i, y_ % i, z_ % i }; } Point3LL& operator+=(const Point3LL& p); Point3LL& operator-=(const Point3LL& p); Point3LL& operator*=(const Point3LL& p); Point3LL& operator/=(const Point3LL& p); - template::value, num_t>::type> - Point3LL& operator*=(const num_t i) + + template + Point3LL& operator*=(const T i) { x_ *= i; y_ *= i; z_ *= i; return *this; } - template::value, num_t>::type> - Point3LL& operator/=(const num_t i) + + template + Point3LL& operator/=(const T i) { x_ /= i; y_ /= i; @@ -72,9 +87,7 @@ class Point3LL return *this; } - bool operator==(const Point3LL& p) const; - bool operator!=(const Point3LL& p) const; - + auto operator<=>(const Point3LL&) const = default; template friend std::basic_ostream& operator<<(std::basic_ostream& os, const Point3LL& p) @@ -82,38 +95,47 @@ class Point3LL return os << "(" << p.x_ << ", " << p.y_ << ", " << p.z_ << ")"; } - - coord_t max() const + [[nodiscard]] coord_t max() const { if (x_ > y_ && x_ > z_) + { return x_; + } if (y_ > z_) + { return y_; + } return z_; } - bool testLength(coord_t len) const + [[nodiscard]] bool testLength(coord_t len) const { if (x_ > len || x_ < -len) + { return false; + } if (y_ > len || y_ < -len) + { return false; + } if (z_ > len || z_ < -len) + { return false; + } return vSize2() <= len * len; } - coord_t vSize2() const + [[nodiscard]] coord_t vSize2() const { return x_ * x_ + y_ * y_ + z_ * z_; } - coord_t vSize() const + [[nodiscard]] coord_t vSize() const { return std::llrint(sqrt(static_cast(vSize2()))); } - double vSizeMM() const + [[nodiscard]] double vSizeMM() const { double fx = INT2MM(x_); double fy = INT2MM(y_); @@ -121,7 +143,7 @@ class Point3LL return sqrt(fx * fx + fy * fy + fz * fz); } - coord_t dot(const Point3LL& p) const + [[nodiscard]] coord_t dot(const Point3LL& p) const { return x_ * p.x_ + y_ * p.y_ + z_ * p.z_; } @@ -152,8 +174,8 @@ class Point3LL */ static Point3LL no_point3(std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min()); -template::value, num_t>::type> -inline Point3LL operator*(const num_t i, const Point3LL& rhs) +template +inline Point3LL operator*(const T i, const Point3LL& rhs) { return rhs * i; } @@ -166,7 +188,7 @@ namespace std template<> struct hash { - size_t operator()(const cura::Point3LL& pp) const + size_t operator()(const cura::Point3LL& pp) const noexcept { static int prime = 31; int result = 89; diff --git a/include/geometry/PointsSet.h b/include/geometry/PointsSet.h index f530613ba1..f61329929d 100644 --- a/include/geometry/PointsSet.h +++ b/include/geometry/PointsSet.h @@ -27,9 +27,12 @@ class PointsSet public: // Required for some std calls as a container - typedef Point2LL value_type; + using value_type = Point2LL; + using iterator = typename std::vector::iterator; + using const_iterator = typename std::vector::const_iterator; + using reverse_iterator = typename std::vector::reverse_iterator; + using const_reverse_iterator = typename std::vector::const_reverse_iterator; -public: /*! \brief Builds an empty set */ PointsSet() = default; @@ -42,13 +45,15 @@ class PointsSet /*! \brief Constructor with a points initializer list, provided for convenience" */ PointsSet(const std::initializer_list& initializer); + virtual ~PointsSet() = default; + /*! \brief Constructor with an existing list of points */ - PointsSet(const ClipperLib::Path& points); + explicit PointsSet(const ClipperLib::Path& points); /*! \brief Constructor that takes ownership of the given list of points */ - PointsSet(ClipperLib::Path&& points); + explicit PointsSet(ClipperLib::Path&& points); - const ClipperLib::Path& getPoints() const + [[nodiscard]] const ClipperLib::Path& getPoints() const { return points_; } @@ -63,7 +68,7 @@ class PointsSet points_ = points; } - size_t size() const + [[nodiscard]] size_t size() const { return points_.size(); } @@ -73,10 +78,9 @@ class PointsSet points_.push_back(point); } - template - void emplace_back(Args&&... args) + void emplace_back(auto&&... args) { - points_.emplace_back(args...); + points_.emplace_back(std::forward(args)...); } void pop_back() @@ -84,53 +88,52 @@ class PointsSet points_.pop_back(); } - template - void insert(Args&&... args) + void insert(auto&&... args) { - points_.insert(args...); + points_.insert(std::forward(args)...); } - std::vector::const_iterator begin() const + [[nodiscard]] const_iterator begin() const { return points_.begin(); } - std::vector::iterator begin() + iterator begin() { return points_.begin(); } - std::vector::const_iterator end() const + [[nodiscard]] const_iterator end() const { return points_.end(); } - std::vector::iterator end() + iterator end() { return points_.end(); } - std::vector::const_reverse_iterator rbegin() const + [[nodiscard]] const_reverse_iterator rbegin() const { return points_.rbegin(); } - std::vector::reverse_iterator rbegin() + reverse_iterator rbegin() { return points_.rbegin(); } - std::vector::const_reverse_iterator rend() const + [[nodiscard]] const_reverse_iterator rend() const { return points_.rend(); } - std::vector::reverse_iterator rend() + reverse_iterator rend() { return points_.rend(); } - const Point2LL& front() const + [[nodiscard]] const Point2LL& front() const { return points_.front(); } @@ -140,7 +143,7 @@ class PointsSet return points_.front(); } - const Point2LL& back() const + [[nodiscard]] const Point2LL& back() const { return points_.back(); } @@ -150,27 +153,27 @@ class PointsSet return points_.back(); } - const Point2LL& at(size_t pos) const + [[nodiscard]] const Point2LL& at(const size_t pos) const { return points_.at(pos); } - Point2LL& at(size_t pos) + Point2LL& at(const size_t pos) { return points_.at(pos); } - bool empty() const + [[nodiscard]] bool empty() const { return points_.empty(); } - void resize(size_t size) + void resize(const size_t size) { points_.resize(size); } - void reserve(size_t size) + void reserve(const size_t size) { points_.reserve(size); } diff --git a/include/geometry/Polygon.h b/include/geometry/Polygon.h index fa2af370e9..ddb6025794 100644 --- a/include/geometry/Polygon.h +++ b/include/geometry/Polygon.h @@ -21,6 +21,8 @@ class AngleDegrees; class Polygon : public ClosedPolyline { public: + Polygon() = default; + /*! * \brief Builds an empty polygon * \param explicitely_closed Indicates whether the contour line will be explicitely closed @@ -28,8 +30,8 @@ class Polygon : public ClosedPolyline * constructor in various places, but be careful that the interpretation of the points * added later will depend on this. */ - Polygon(bool explicitely_closed = false) - : ClosedPolyline(explicitely_closed) + explicit Polygon(const bool explicitely_closed) + : ClosedPolyline{ explicitely_closed } { } @@ -43,8 +45,8 @@ class Polygon : public ClosedPolyline * \brief Constructor with a points initializer list, provided for convenience * \param explicitely_closed Specify whether the given points form an explicitely closed line */ - Polygon(const std::initializer_list& initializer, bool explicitely_closed) - : ClosedPolyline(initializer, explicitely_closed) + Polygon(const std::initializer_list& initializer, const bool explicitely_closed) + : ClosedPolyline{ initializer, explicitely_closed } { } @@ -52,8 +54,8 @@ class Polygon : public ClosedPolyline * \brief Constructor with an existing list of points * \param explicitely_closed Specify whether the given points form an explicitely closed line */ - explicit Polygon(const ClipperLib::Path& points, bool explicitely_closed) - : ClosedPolyline(points, explicitely_closed) + explicit Polygon(const ClipperLib::Path& points, const bool explicitely_closed) + : ClosedPolyline{ points, explicitely_closed } { } @@ -61,22 +63,16 @@ class Polygon : public ClosedPolyline * \brief Constructor that takes ownership of the given list of points * \param explicitely_closed Specify whether the given points form an explicitely closed line */ - explicit Polygon(ClipperLib::Path&& points, bool explicitely_closed) - : ClosedPolyline(points, explicitely_closed) + explicit Polygon(ClipperLib::Path&& points, const bool explicitely_closed) + : ClosedPolyline{ std::move(points), explicitely_closed } { } - Polygon& operator=(const Polygon& other) - { - Polyline::operator=(other); - return *this; - } + ~Polygon() override = default; - Polygon& operator=(Polygon&& other) - { - Polyline::operator=(std::move(other)); - return *this; - } + Polygon& operator=(const Polygon& other) = default; + + Polygon& operator=(Polygon&& other) = default; /*! * \brief Compute the morphological intersection between this polygon and another. diff --git a/src/geometry/ClosedPolyline.cpp b/src/geometry/ClosedPolyline.cpp index 0f7ab7e142..c4890c48f1 100644 --- a/src/geometry/ClosedPolyline.cpp +++ b/src/geometry/ClosedPolyline.cpp @@ -3,6 +3,8 @@ #include "geometry/ClosedPolyline.h" +#include + #include "geometry/OpenPolyline.h" namespace cura @@ -14,10 +16,7 @@ size_t ClosedPolyline::segmentsCount() const { return size() >= 3 ? size() - 1 : 0; } - else - { - return size() >= 2 ? size() : 0; - } + return size() >= 2 ? size() : 0; } bool ClosedPolyline::isValid() const @@ -37,14 +36,12 @@ bool ClosedPolyline::inside(const Point2LL& p, bool border_result) const bool ClosedPolyline::inside(const ClipperLib::Path& polygon) const { - for (const auto& point : *this) - { - if (! ClipperLib::PointInPolygon(point, polygon)) + return ranges::all_of( + *this, + [&polygon](const auto& point) { - return false; - } - } - return true; + return ClipperLib::PointInPolygon(point, polygon); + }); } OpenPolyline ClosedPolyline::toPseudoOpenPolyline() const diff --git a/src/geometry/MixedLinesSet.cpp b/src/geometry/MixedLinesSet.cpp index d4923c3778..c080becf41 100644 --- a/src/geometry/MixedLinesSet.cpp +++ b/src/geometry/MixedLinesSet.cpp @@ -30,55 +30,47 @@ Shape MixedLinesSet::offset(coord_t distance, ClipperLib::JoinType join_type, do return result; } - else - { - Shape polygons; - ClipperLib::ClipperOffset clipper(miter_limit, 10.0); + Shape polygons; + ClipperLib::ClipperOffset clipper(miter_limit, 10.0); - for (const PolylinePtr& line : (*this)) + for (const PolylinePtr& line : (*this)) + { + if (const std::shared_ptr polygon = dynamic_pointer_cast(line)) { - if (const std::shared_ptr polygon = dynamic_pointer_cast(line)) - { - // Union all polygons first and add them later - polygons.push_back(*polygon); - } - else + // Union all polygons first and add them later + polygons.push_back(*polygon); + } + else + { + static auto end_type_fn = [&line, &join_type]() { - ClipperLib::EndType end_type; - if (line->hasClosingSegment()) { - end_type = ClipperLib::etClosedLine; - } - else if (join_type == ClipperLib::jtMiter) - { - end_type = ClipperLib::etOpenSquare; - } - else - { - end_type = ClipperLib::etOpenRound; + return ClipperLib::etClosedLine; } + return join_type == ClipperLib::jtMiter ? ClipperLib::etOpenSquare : ClipperLib::etOpenRound; + }; - clipper.AddPath(line->getPoints(), join_type, end_type); - } + const ClipperLib::EndType end_type{ end_type_fn() }; + clipper.AddPath(line->getPoints(), join_type, end_type); } + } - if (! polygons.empty()) - { - polygons = polygons.unionPolygons(); + if (! polygons.empty()) + { + polygons = polygons.unionPolygons(); - for (const Polygon& polygon : polygons) - { - clipper.AddPath(polygon.getPoints(), join_type, ClipperLib::etClosedPolygon); - } + for (const Polygon& polygon : polygons) + { + clipper.AddPath(polygon.getPoints(), join_type, ClipperLib::etClosedPolygon); } + } - clipper.MiterLimit = miter_limit; + clipper.MiterLimit = miter_limit; - ClipperLib::Paths result; - clipper.Execute(result, static_cast(distance)); - return Shape(std::move(result)); - } + ClipperLib::Paths result; + clipper.Execute(result, static_cast(distance)); + return Shape{ std::move(result) }; } void MixedLinesSet::push_back(const OpenPolyline& line) @@ -98,7 +90,7 @@ void MixedLinesSet::push_back(ClosedPolyline&& line) void MixedLinesSet::push_back(const Polygon& line) { - std::vector::push_back(std::make_shared(std::move(line))); + std::vector::push_back(std::make_shared(line)); } void MixedLinesSet::push_back(const std::shared_ptr& line) @@ -157,7 +149,7 @@ coord_t MixedLinesSet::length() const return std::accumulate( begin(), end(), - coord_t(0), + 0LL, [](coord_t value, const PolylinePtr& line) { return value + line->length(); diff --git a/src/infill/GyroidInfill.cpp b/src/infill/GyroidInfill.cpp index 59f85fbdf5..c085840a21 100644 --- a/src/infill/GyroidInfill.cpp +++ b/src/infill/GyroidInfill.cpp @@ -344,7 +344,7 @@ void GyroidInfill::generateTotalGyroidInfill(OpenLinesSet& result_lines, bool zi if (chain_index != connector_start_chain_index && connected_to[(point_index + 1) % 2][chain_index] != connector_start_chain_index) { - result.push_back(connector_points); + result.push_back(OpenPolyline{ connector_points }); drawing = false; connector_points.clear(); // remember the connection @@ -393,9 +393,9 @@ void GyroidInfill::generateTotalGyroidInfill(OpenLinesSet& result_lines, bool zi { // output the connector line segments from the last chain to the first point in the outline connector_points.push_back(outline_poly[0]); - result.push_back(connector_points); + result.push_back(OpenPolyline{ connector_points }); // output the connector line segments from the first point in the outline to the first chain - result.push_back(path_to_first_chain); + result.push_back(OpenPolyline{ path_to_first_chain }); } if (chain_ends_remaining < 1) diff --git a/src/utils/Point3LL.cpp b/src/utils/Point3LL.cpp index d12b31414f..bb8e7c6930 100644 --- a/src/utils/Point3LL.cpp +++ b/src/utils/Point3LL.cpp @@ -63,14 +63,4 @@ Point3LL& Point3LL::operator/=(const Point3LL& p) return *this; } -bool Point3LL::operator==(const Point3LL& p) const -{ - return x_ == p.x_ && y_ == p.y_ && z_ == p.z_; -} - -bool Point3LL::operator!=(const Point3LL& p) const -{ - return x_ != p.x_ || y_ != p.y_ || z_ != p.z_; -} - } // namespace cura From d4f04e5a83083b7fb611371a0ba83c20cb13db48 Mon Sep 17 00:00:00 2001 From: jellespijker Date: Fri, 3 May 2024 15:14:06 +0000 Subject: [PATCH 091/135] Applied clang-format. --- include/geometry/LinesSet.h | 3 ++- include/geometry/OpenPolyline.h | 2 +- include/geometry/PartsView.h | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index 3de08203a9..4d4cba8ad1 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -70,7 +70,8 @@ class LinesSet * objects, because closed ones require an additional argument */ template - requires std::is_same_v explicit LinesSet(ClipperLib::Paths&& paths) + requires std::is_same_v + explicit LinesSet(ClipperLib::Paths&& paths) { reserve(paths.size()); for (ClipperLib::Path& path : paths) diff --git a/include/geometry/OpenPolyline.h b/include/geometry/OpenPolyline.h index f9a3d1b62e..2a6b0faef2 100644 --- a/include/geometry/OpenPolyline.h +++ b/include/geometry/OpenPolyline.h @@ -84,7 +84,7 @@ class OpenPolyline : public Polyline return size() >= 2; } - OpenPolyline& operator=(OpenPolyline&& other) noexcept = default; + OpenPolyline& operator=(OpenPolyline&& other) noexcept = default; OpenPolyline& operator=(const OpenPolyline& other) = default; }; diff --git a/include/geometry/PartsView.h b/include/geometry/PartsView.h index e8b6b59d31..6cfb9bf4c6 100644 --- a/include/geometry/PartsView.h +++ b/include/geometry/PartsView.h @@ -33,8 +33,8 @@ class PartsView : public std::vector> ~PartsView() = default; - PartsView& operator=(PartsView&& parts_view) = delete; - PartsView& operator=(const PartsView& parts_view) = delete; + PartsView& operator=(PartsView&& parts_view) = delete; + PartsView& operator=(const PartsView& parts_view) = delete; /*! * Get the index of the SingleShape of which the polygon with index \p poly_idx is part. From 53cd4b070aa04fce054420a3899ff7b7952cc767 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 3 May 2024 18:23:57 +0200 Subject: [PATCH 092/135] Replace 'Polygons' with 'Shape' for 'disallowed_area_for_seams' The type of 'disallowed_area_for_seams' has been changed from 'Polygons' to 'Shape' in PathOrderOptimizer.h, FffGcodeWriter.cpp, InsetOrderOptimizer.cpp, and InsetOrderOptimizer.h. The change was made to increase code readability and maintainability. Also, the usage of 'disallowed_area_for_seams' has been adjusted accordingly in the respective files. Contribute to CURA-9830 --- include/InsetOrderOptimizer.h | 4 ++-- include/PathOrderOptimizer.h | 4 ++-- src/FffGcodeWriter.cpp | 4 ++-- src/InsetOrderOptimizer.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/InsetOrderOptimizer.h b/include/InsetOrderOptimizer.h index 67c97ec161..f03a7fc461 100644 --- a/include/InsetOrderOptimizer.h +++ b/include/InsetOrderOptimizer.h @@ -56,7 +56,7 @@ class InsetOrderOptimizer const size_t wall_x_extruder_nr, const ZSeamConfig& z_seam_config, const std::vector& paths, - const Polygons& disallowed_areas_for_seams = {}); + const Shape& disallowed_areas_for_seams = {}); /*! * Adds the insets to the given layer plan. @@ -107,7 +107,7 @@ class InsetOrderOptimizer const ZSeamConfig& z_seam_config_; const std::vector& paths_; const LayerIndex layer_nr_; - Polygons disallowed_areas_for_seams_; + Shape disallowed_areas_for_seams_; std::vector> inset_polys_; // vector of vectors holding the inset polygons Shape retraction_region_; // After printing an outer wall, move into this region so that retractions do not leave visible blobs. Calculated lazily if needed (see diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 2ee8589d83..cf54338a06 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -62,7 +62,7 @@ class PathOrderOptimizer public: using OrderablePath = PathOrdering; /* Areas defined here are not allowed to have the start the prints */ - Polygons disallowed_area_for_seams; + Shape disallowed_area_for_seams; /*! * After optimizing, this contains the paths that need to be printed in the * correct order. @@ -113,7 +113,7 @@ class PathOrderOptimizer const bool reverse_direction = false, const std::unordered_multimap& order_requirements = no_order_requirements_, const bool group_outer_walls = false, - const Polygons& disallowed_areas_for_seams = {}) + const Shape& disallowed_areas_for_seams = {}) : start_point_(start_point) , seam_config_(seam_config) , combing_boundary_((combing_boundary != nullptr && ! combing_boundary->empty()) ? combing_boundary : nullptr) diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index c146a2e7ec..dfba3f7ed8 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -3442,7 +3442,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer constexpr coord_t wipe_dist = 0; ZSeamConfig z_seam_config = ZSeamConfig(EZSeamType::SHORTEST, gcode_layer.getLastPlannedPositionOrStartingPosition(), EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); - Polygons disallowed_area_for_seams{}; + Shape disallowed_area_for_seams{}; if (infill_extruder.settings_.get("support_z_seam_away_from_model")) { for (std::shared_ptr mesh_ptr : storage.meshes) @@ -3450,7 +3450,7 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer auto& mesh = *mesh_ptr; for (auto& part : mesh.layers[gcode_layer.getLayerNr()].parts) { - disallowed_area_for_seams.add(part.print_outline); + disallowed_area_for_seams.push_back(part.print_outline); } } if (! disallowed_area_for_seams.empty()) diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index f2b3f5fc2d..7be4d8f6ba 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -51,7 +51,7 @@ InsetOrderOptimizer::InsetOrderOptimizer( const size_t wall_x_extruder_nr, const ZSeamConfig& z_seam_config, const std::vector& paths, - const Polygons& disallowed_areas_for_seams) + const Shape& disallowed_areas_for_seams) : gcode_writer_(gcode_writer) , storage_(storage) , gcode_layer_(gcode_layer) From 507c04a46feb1a1aa1c3b54405c9d70707a1f762 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 3 May 2024 18:30:43 +0200 Subject: [PATCH 093/135] Add Fuchsia default arguments check to .clang-tidy This commit includes the addition of the 'fuchsia-default-arguments' check in the .clang-tidy configuration file. It also fixes the newline at the end of file issue, ensuring the file meets the standard for text files on Unix-like systems. Contribute to CURA-9830 --- .clang-tidy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.clang-tidy b/.clang-tidy index e516426d03..ba5f3d47db 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -13,6 +13,7 @@ Checks: > -cppcoreguidelines-avoid-capturing-lambda-coroutines, -llvm-header-guard, -bugprone-easily-swappable-parameters + -fuchsia-default-arguments WarningsAsErrors: '-*' HeaderFilterRegex: '' FormatStyle: none @@ -52,4 +53,4 @@ CheckOptions: - key: readability-identifier-length.IgnoredVariableNames value: '_p|p0|p1|i|j|k|x|X|y|Y|z|Z|a|A|b|B|c|C|d|D|ab|AB|ba|BA|bc|BC|cb|CB|cd|CD|dc|DC|ad|AD|da|DA|ip|os' - key: readability-identifier-length.IgnoredLoopCounterNames - value: '_p|p0|p1|i|j|k|x|X|y|Y|z|Z|a|A|b|B|c|C|d|D|ab|AB|ba|BA|bc|BC|cb|CB|cd|CD|dc|DC|ad|AD|da|DA|ip|os' \ No newline at end of file + value: '_p|p0|p1|i|j|k|x|X|y|Y|z|Z|a|A|b|B|c|C|d|D|ab|AB|ba|BA|bc|BC|cb|CB|cd|CD|dc|DC|ad|AD|da|DA|ip|os' From 3a6ce96381b20eed9ddc9a934689450cfe453aeb Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 3 May 2024 19:18:32 +0200 Subject: [PATCH 094/135] Update .clang-tidy configuration The configuration rules in .clang-tidy have been modified. The rule `-fuchsia-default-arguments` has been replaced with `-*-default-arguments-declarations` and a comma has been added after `-bugprone-easily-swappable-parameters`. Contribute to CURA-9830 --- .clang-tidy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index ba5f3d47db..6ccf3b98db 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -12,8 +12,8 @@ Checks: > -fuchsia-overloaded-operator, -cppcoreguidelines-avoid-capturing-lambda-coroutines, -llvm-header-guard, - -bugprone-easily-swappable-parameters - -fuchsia-default-arguments + -bugprone-easily-swappable-parameters, + -*-default-arguments-declarations WarningsAsErrors: '-*' HeaderFilterRegex: '' FormatStyle: none From 0bef373966b199c2817ae533693674c323885ae6 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 3 May 2024 19:18:54 +0200 Subject: [PATCH 095/135] Refactor Polygon and PointMatrix classes, add nodiscard annotations The main revisions include making Polygon and PointMatrix classes noexcept by default, changing the function naming to camel case, and replacing index-based element access with '.at' function for safety. Also, 'nodiscard' annotations have been added to functions to ensure return values are not accidentally discarded. Contribute to CURA-9830 --- include/geometry/Point2LL.h | 14 ++-- include/geometry/Point3Matrix.h | 73 +++++++++--------- include/geometry/PointMatrix.h | 50 ++++++------ include/geometry/Polygon.h | 18 ++--- include/geometry/Polyline.h | 47 ++++-------- include/geometry/SegmentIterator.h | 9 +-- include/geometry/SingleShape.h | 6 +- src/geometry/Polygon.cpp | 117 +++++++++++++---------------- 8 files changed, 146 insertions(+), 188 deletions(-) diff --git a/include/geometry/Point2LL.h b/include/geometry/Point2LL.h index 50781d49b6..08a556a961 100644 --- a/include/geometry/Point2LL.h +++ b/include/geometry/Point2LL.h @@ -15,6 +15,7 @@ Integer points are used to avoid floating point rounding errors, and because Cli #include #include "geometry/Point3LL.h" +#include "utils/types/generic.h" #ifdef __GNUC__ #define DEPRECATED(func) func __attribute__((deprecated)) @@ -58,13 +59,13 @@ INLINE Point2LL operator*(const Point2LL& p0, const coord_t i) return { p0.X * i, p0.Y * i }; } -template::value, T>::type> // Use only for numeric types. +template // Use only for numeric types. INLINE Point2LL operator*(const Point2LL& p0, const T i) { return { std::llrint(static_cast(p0.X) * i), std::llrint(static_cast(p0.Y) * i) }; } -template::value, T>::type> // Use only for numeric types. +template INLINE Point2LL operator*(const T i, const Point2LL& p0) { return p0 * i; @@ -153,12 +154,12 @@ INLINE double vSizeMM(const Point2LL& p0) { double fx = INT2MM(p0.X); double fy = INT2MM(p0.Y); - return sqrt(fx * fx + fy * fy); + return std::sqrt(fx * fx + fy * fy); } INLINE Point2LL normal(const Point2LL& p0, coord_t length) { - coord_t len{ vSize(p0) }; + const coord_t len{ vSize(p0) }; if (len < 1) { return { length, 0 }; @@ -210,6 +211,7 @@ inline Point3LL operator+(const Point3LL& p3, const Point2LL& p2) { return { p3.x_ + p2.X, p3.y_ + p2.Y, p3.z_ }; } + inline Point3LL& operator+=(Point3LL& p3, const Point2LL& p2) { p3.x_ += p2.X; @@ -222,11 +224,11 @@ inline Point2LL operator+(const Point2LL& p2, const Point3LL& p3) return { p3.x_ + p2.X, p3.y_ + p2.Y }; } - inline Point3LL operator-(const Point3LL& p3, const Point2LL& p2) { return { p3.x_ - p2.X, p3.y_ - p2.Y, p3.z_ }; } + inline Point3LL& operator-=(Point3LL& p3, const Point2LL& p2) { p3.x_ -= p2.X; @@ -246,7 +248,7 @@ namespace std template<> struct hash { - size_t operator()(const cura::Point2LL& pp) const + size_t operator()(const cura::Point2LL& pp) const noexcept { static int prime = 31; int result = 89; diff --git a/include/geometry/Point3Matrix.h b/include/geometry/Point3Matrix.h index 0ff53ed6e5..bbe11d6918 100644 --- a/include/geometry/Point3Matrix.h +++ b/include/geometry/Point3Matrix.h @@ -4,6 +4,8 @@ #ifndef GEOMETRY_POINT3_MATRIX_H #define GEOMETRY_POINT3_MATRIX_H +#include + #include "geometry/Point3LL.h" #include "geometry/PointMatrix.h" @@ -13,77 +15,72 @@ namespace cura class Point3Matrix { public: - double matrix[9]; + std::array matrix{ 1, 0, 0, 0, 1, 0, 0, 0, 1 }; - Point3Matrix() - { - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 0; - matrix[4] = 1; - matrix[5] = 0; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 1; - } + Point3Matrix() noexcept = default; /*! * Initializes the top left corner with the values of \p b * and the rest as if it's a unit matrix */ - Point3Matrix(const PointMatrix& b) + explicit Point3Matrix(const PointMatrix& b) { - matrix[0] = b.matrix[0]; - matrix[1] = b.matrix[1]; - matrix[2] = 0; - matrix[3] = b.matrix[2]; - matrix[4] = b.matrix[3]; - matrix[5] = 0; - matrix[6] = 0; - matrix[7] = 0; - matrix[8] = 1; + matrix.at(0) = b.matrix.at(0); + matrix.at(1) = b.matrix.at(1); + matrix.at(2) = 0; + matrix.at(3) = b.matrix.at(2); + matrix.at(4) = b.matrix.at(3); + matrix.at(5) = 0; + matrix.at(6) = 0; + matrix.at(7) = 0; + matrix.at(8) = 1; } - Point3LL apply(const Point3LL& p) const + Point3Matrix(Point3Matrix&& point3_matrix) = default; + Point3Matrix(const Point3Matrix& point3_matrix) = default; + virtual ~Point3Matrix() = default; + + Point3Matrix& operator=(Point3Matrix&& point3_matrix) = default; + Point3Matrix& operator=(const Point3Matrix& point3_matrix) = default; + + [[nodiscard]] Point3LL apply(const Point3LL& p) const { - const double x = static_cast(p.x_); - const double y = static_cast(p.y_); - const double z = static_cast(p.z_); - return Point3LL( - std::llrint(x * matrix[0] + y * matrix[1] + z * matrix[2]), - std::llrint(x * matrix[3] + y * matrix[4] + z * matrix[5]), - std::llrint(x * matrix[6] + y * matrix[7] + z * matrix[8])); + const auto x = static_cast(p.x_); + const auto y = static_cast(p.y_); + const auto z = static_cast(p.z_); + return { std::llrint(x * matrix.at(0) + y * matrix.at(1) + z * matrix.at(2)), + std::llrint(x * matrix.at(3) + y * matrix.at(4) + z * matrix.at(5)), + std::llrint(x * matrix.at(6) + y * matrix.at(7) + z * matrix.at(8)) }; } /*! * Apply matrix to vector as homogeneous coordinates. */ - Point2LL apply(const Point2LL& p) const + [[nodiscard]] Point2LL apply(const Point2LL& p) const { Point3LL result = apply(Point3LL(p.X, p.Y, 1)); - return Point2LL(result.x_ / result.z_, result.y_ / result.z_); + return { result.x_ / result.z_, result.y_ / result.z_ }; } static Point3Matrix translate(const Point2LL& p) { Point3Matrix ret; // uniform matrix - ret.matrix[2] = static_cast(p.X); - ret.matrix[5] = static_cast(p.Y); + ret.matrix.at(2) = static_cast(p.X); + ret.matrix.at(5) = static_cast(p.Y); return ret; } - Point3Matrix compose(const Point3Matrix& b) + [[nodiscard]] Point3Matrix compose(const Point3Matrix& b) const { Point3Matrix ret; for (int outx = 0; outx < 3; outx++) { for (int outy = 0; outy < 3; outy++) { - ret.matrix[outy * 3 + outx] = 0; + ret.matrix.at(outy * 3 + outx) = 0; for (int in = 0; in < 3; in++) { - ret.matrix[outy * 3 + outx] += matrix[outy * 3 + in] * b.matrix[in * 3 + outx]; + ret.matrix.at(outy * 3 + outx) += matrix.at(outy * 3 + in) * b.matrix.at(in * 3 + outx); } } } diff --git a/include/geometry/PointMatrix.h b/include/geometry/PointMatrix.h index 3cd0c24df9..1a22a74f06 100644 --- a/include/geometry/PointMatrix.h +++ b/include/geometry/PointMatrix.h @@ -16,41 +16,35 @@ namespace cura class PointMatrix { public: - std::array matrix{}; + std::array matrix{ 1, 0, 0, 1 }; - PointMatrix() - { - matrix[0] = 1; - matrix[1] = 0; - matrix[2] = 0; - matrix[3] = 1; - } + PointMatrix() noexcept = default; explicit PointMatrix(double rotation) { rotation = rotation / 180 * std::numbers::pi; - matrix[0] = cos(rotation); - matrix[1] = -sin(rotation); - matrix[2] = -matrix[1]; - matrix[3] = matrix[0]; + matrix.at(0) = std::cos(rotation); + matrix.at(1) = -std::sin(rotation); + matrix.at(2) = -matrix.at(1); + matrix.at(3) = matrix.at(0); } explicit PointMatrix(const Point2LL& p) { - matrix[0] = static_cast(p.X); - matrix[1] = static_cast(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]; + matrix.at(0) = static_cast(p.X); + matrix.at(1) = static_cast(p.Y); + double f = std::sqrt((matrix.at(0) * matrix.at(0)) + (matrix.at(1) * matrix.at(1))); + matrix.at(0) /= f; + matrix.at(1) /= f; + matrix.at(2) = -matrix.at(1); + matrix.at(3) = matrix.at(0); } static PointMatrix scale(double s) { PointMatrix ret; - ret.matrix[0] = s; - ret.matrix[3] = s; + ret.matrix.at(0) = s; + ret.matrix.at(3) = s; return ret; } @@ -58,7 +52,7 @@ class PointMatrix { const auto x = static_cast(p.X); const auto y = static_cast(p.Y); - return { std::llrint(x * matrix[0] + y * matrix[1]), std::llrint(x * matrix[2] + y * matrix[3]) }; + return { std::llrint(x * matrix.at(0) + y * matrix.at(1)), std::llrint(x * matrix.at(2) + y * matrix.at(3)) }; } /*! @@ -68,17 +62,17 @@ class PointMatrix { const auto x = static_cast(p.X); const auto y = static_cast(p.Y); - return { std::llrint(x * matrix[0] + y * matrix[2]), std::llrint(x * matrix[1] + y * matrix[3]) }; + return { std::llrint(x * matrix.at(0) + y * matrix.at(2)), std::llrint(x * matrix.at(1) + y * matrix.at(3)) }; } [[nodiscard]] PointMatrix inverse() const { PointMatrix ret; - double det = matrix[0] * matrix[3] - matrix[1] * matrix[2]; - ret.matrix[0] = matrix[3] / det; - ret.matrix[1] = -matrix[1] / det; - ret.matrix[2] = -matrix[2] / det; - ret.matrix[3] = matrix[0] / det; + double det = matrix.at(0) * matrix.at(3) - matrix.at(1) * matrix.at(2); + ret.matrix.at(0) = matrix.at(3) / det; + ret.matrix.at(1) = -matrix.at(1) / det; + ret.matrix.at(2) = -matrix.at(2) / det; + ret.matrix.at(3) = matrix.at(0) / det; return ret; } }; diff --git a/include/geometry/Polygon.h b/include/geometry/Polygon.h index ddb6025794..ef26e72792 100644 --- a/include/geometry/Polygon.h +++ b/include/geometry/Polygon.h @@ -72,23 +72,23 @@ class Polygon : public ClosedPolyline Polygon& operator=(const Polygon& other) = default; - Polygon& operator=(Polygon&& other) = default; + Polygon& operator=(Polygon&& other) noexcept = default; /*! * \brief Compute the morphological intersection between this polygon and another. * \param other The polygon with which to intersect this polygon. * \note The result may consist of multiple polygons, if you have bad luck. */ - Shape intersection(const Polygon& other) const; + [[nodiscard]] Shape intersection(const Polygon& other) const; - double area() const + [[nodiscard]] double area() const { return ClipperLib::Area(getPoints()); } - Point2LL centerOfMass() const; + [[nodiscard]] Point2LL centerOfMass() const; - Shape offset(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const; + [[nodiscard]] Shape offset(int distance, ClipperLib::JoinType join_type = ClipperLib::jtMiter, double miter_limit = 1.2) const; /*! * Smooth out small perpendicular segments and store the result in \p result. @@ -110,7 +110,7 @@ class Polygon : public ClosedPolyline * \param shortcut_length The desired length of the shortcut line segment introduced (shorter shortcuts may be unavoidable) * \param result The resulting polygon */ - void smooth_outward(const AngleDegrees angle, int shortcut_length, Polygon& result) const; + void smoothOutward(const AngleDegrees angle, int shortcut_length, Polygon& result) const; /*! * Smooth out the polygon and store the result in \p result. @@ -138,7 +138,7 @@ class Polygon : public ClosedPolyline * \param shortcut_length The desired length ofthe shortcutting line * \param cos_angle The cosine on the angle in L 012 */ - static void smooth_corner_simple( + static void smoothCornerSimple( const Point2LL& p0, const Point2LL& p1, const Point2LL& p2, @@ -165,7 +165,7 @@ class Polygon : public ClosedPolyline * \param shortcut_length The desired length ofthe shortcutting line * \return Whether this whole polygon whould be removed by the smoothing */ - static bool smooth_corner_complex(const Point2LL& p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length); + static bool smoothCornerComplex(const Point2LL& p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length); /*! * Try to take a step away from the corner point in order to take a bigger shortcut. @@ -183,7 +183,7 @@ class Polygon : public ClosedPolyline * \param[in,out] forward_is_too_far Whether trying another step forward is blocked by the shortcut length condition. Updated for the next iteration. * \param[in,out] backward_is_too_far Whether trying another step backward is blocked by the shortcut length condition. Updated for the next iteration. */ - static void smooth_outward_step( + static void smoothOutwardStep( const Point2LL& p1, const int64_t shortcut_length2, ListPolyIt& p0_it, diff --git a/include/geometry/Polyline.h b/include/geometry/Polyline.h index f151830e2a..a26c942fcf 100644 --- a/include/geometry/Polyline.h +++ b/include/geometry/Polyline.h @@ -54,56 +54,48 @@ class Polyline : public PointsSet } /*! \brief Constructor with an existing list of points */ - Polyline(const ClipperLib::Path& points) + explicit Polyline(const ClipperLib::Path& points) : PointsSet(points) { } /*! \brief Constructor that takes ownership of the given list of points */ - Polyline(ClipperLib::Path&& points) - : PointsSet(points) + explicit Polyline(ClipperLib::Path&& points) + : PointsSet{ std::move(points) } { } - virtual ~Polyline() = default; + ~Polyline() override = default; /*! * \brief Indicates whether this polyline has an additional closing segment between the last * point in the set and the first one * \return True if a segment between the last and first point should be considered */ - virtual bool hasClosingSegment() const = 0; + [[nodiscard]] virtual bool hasClosingSegment() const = 0; /*! * \brief Gets the total number of "full" segments in the polyline. Calling this is also safe if * there are not enough points to make a valid polyline, so it can also be a good * indicator of a "valid" polyline. */ - virtual size_t segmentsCount() const = 0; + [[nodiscard]] virtual size_t segmentsCount() const = 0; /*! * \brief Indicates whether the points set form a valid polyline, i.e. if it has enough points * according to its type. */ - virtual bool isValid() const = 0; + [[nodiscard]] virtual bool isValid() const = 0; - Polyline& operator=(const Polyline& other) - { - PointsSet::operator=(other); - return *this; - } + Polyline& operator=(const Polyline& other) = default; - Polyline& operator=(Polyline&& other) - { - PointsSet::operator=(other); - return *this; - } + Polyline& operator=(Polyline&& other) = default; /*! \brief Provides a begin iterator to iterate over all the segments of the line */ - const_segments_iterator beginSegments() const; + [[nodiscard]] const_segments_iterator beginSegments() const; /*! \brief Provides an end iterator to iterate over all the segments of the line */ - const_segments_iterator endSegments() const; + [[nodiscard]] const_segments_iterator endSegments() const; /*! \brief Provides a begin iterator to iterate over all the segments of the line */ segments_iterator beginSegments(); @@ -116,21 +108,21 @@ class Polyline : public PointsSet * and store them in the \p result */ void splitIntoSegments(OpenLinesSet& result) const; - OpenLinesSet splitIntoSegments() const; + [[nodiscard]] OpenLinesSet splitIntoSegments() const; /*! * On Y-axis positive upward displays, Orientation will return true if the polygon's orientation is counter-clockwise. * * from http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/Orientation.htm */ - bool orientation() const + [[nodiscard]] bool orientation() const { return ClipperLib::Orientation(getPoints()); } - coord_t length() const; + [[nodiscard]] coord_t length() const; - bool shorterThan(const coord_t check_length) const; + [[nodiscard]] bool shorterThan(const coord_t check_length) const; void reverse() { @@ -161,15 +153,6 @@ class Polyline : public PointsSet removed */ void simplify(const coord_t smallest_line_segment_squared = MM2INT(0.01) * MM2INT(0.01), const coord_t allowed_error_distance_squared = 25); - - -private: - /*! - * Private implementation for both simplify and simplifyPolygons. - * - * Made private to avoid accidental use of the wrong function. - */ - void _simplify(const coord_t smallest_line_segment_squared = 100, const coord_t allowed_error_distance_squared = 25, bool processing_polylines = false); }; } // namespace cura diff --git a/include/geometry/SegmentIterator.h b/include/geometry/SegmentIterator.h index d56fd63dff..95e6bb0445 100644 --- a/include/geometry/SegmentIterator.h +++ b/include/geometry/SegmentIterator.h @@ -22,7 +22,7 @@ struct SegmentIterator /*! @brief Transitory structure used to iterate over segments within a polyline */ struct Segment { - using PointType = typename std::conditional::type; + using PointType = std::conditional_t; PointType& start; PointType& end; @@ -35,7 +35,7 @@ struct SegmentIterator using pointer = Segment*; using reference = Segment&; using source_iterator_type = - typename std::conditional::const_iterator, typename std::vector::iterator>::type; + std::conditional_t::const_iterator, typename std::vector::iterator>; private: source_iterator_type current_pos_; @@ -56,10 +56,7 @@ struct SegmentIterator { return Segment{ *current_pos_, *begin_ }; } - else - { - return Segment{ *current_pos_, *std::next(current_pos_) }; - } + return Segment{ *current_pos_, *std::next(current_pos_) }; } SegmentIterator& operator++() diff --git a/include/geometry/SingleShape.h b/include/geometry/SingleShape.h index f4f925e781..a962672a04 100644 --- a/include/geometry/SingleShape.h +++ b/include/geometry/SingleShape.h @@ -24,11 +24,11 @@ class SingleShape : public Shape SingleShape() = default; explicit SingleShape(Shape&& shape) - : Shape{ shape } {}; + : Shape{ std::move(shape) } {}; Polygon& outerPolygon(); - const Polygon& outerPolygon() const; + [[nodiscard]] const Polygon& outerPolygon() const; /*! * Tests whether the given point is inside this polygon part. @@ -36,7 +36,7 @@ class SingleShape : public Shape * \param border_result If the point is exactly on the border, this will be * returned instead. */ - bool inside(const Point2LL& p, bool border_result = false) const; + [[nodiscard]] bool inside(const Point2LL& p, bool border_result = false) const; }; } // namespace cura diff --git a/src/geometry/Polygon.cpp b/src/geometry/Polygon.cpp index 431114b0e6..83283b4000 100644 --- a/src/geometry/Polygon.cpp +++ b/src/geometry/Polygon.cpp @@ -3,10 +3,10 @@ #include "geometry/Polygon.h" +#include #include #include "geometry/Point3Matrix.h" -#include "geometry/PointMatrix.h" #include "geometry/Shape.h" #include "utils/ListPolyIt.h" #include "utils/linearAlg2D.h" @@ -21,12 +21,12 @@ Shape Polygon::intersection(const Polygon& other) const clipper.AddPath(getPoints(), ClipperLib::ptSubject, true); clipper.AddPath(other.getPoints(), ClipperLib::ptClip, true); clipper.Execute(ClipperLib::ctIntersection, ret_paths); - return Shape(std::move(ret_paths)); + return Shape{ std::move(ret_paths) }; } void Polygon::smooth2(int remove_length, Polygon& result) const { - if (size() > 0) + if (! empty()) { result.push_back(front()); } @@ -66,7 +66,7 @@ void Polygon::smooth(int remove_length, Polygon& result) const // | // | // 0 - if (size() > 0) + if (! empty()) { result.push_back(front()); } @@ -97,14 +97,14 @@ void Polygon::smooth(int remove_length, Polygon& result) const return true; }; Point2LL v02 = getPoints()[2] - getPoints()[0]; - Point2LL v02T = turn90CCW(v02); + Point2LL v02_t = turn90CCW(v02); int64_t v02_size = vSize(v02); bool force_push = false; for (unsigned int poly_idx = 1; poly_idx < size(); poly_idx++) { - const Point2LL& p1 = getPoints()[poly_idx]; - const Point2LL& p2 = getPoints()[(poly_idx + 1) % size()]; - const Point2LL& p3 = getPoints()[(poly_idx + 2) % size()]; + const Point2LL& p1 = getPoints().at(poly_idx); + const Point2LL& p2 = getPoints().at((poly_idx + 1) % size()); + const Point2LL& p3 = getPoints().at((poly_idx + 2) % size()); // v02 computed in last iteration // v02_size as well const Point2LL v12 = p2 - p1; @@ -113,9 +113,9 @@ void Polygon::smooth(int remove_length, Polygon& result) const const int64_t v13_size = vSize(v13); // v02T computed in last iteration - const int64_t dot1 = dot(v02T, v12); - const Point2LL v13T = turn90CCW(v13); - const int64_t dot2 = dot(v13T, v12); + const int64_t dot1 = dot(v02_t, v12); + const Point2LL v13_t = turn90CCW(v13); + const int64_t dot2 = dot(v13_t, v12); bool push_point = force_push || ! is_zigzag(v02_size, v12_size, v13_size, dot1, dot2); force_push = false; if (push_point) @@ -127,13 +127,13 @@ void Polygon::smooth(int remove_length, Polygon& result) const // do not add the current one to the result force_push = true; // ensure the next point is added; it cannot also be a zigzag } - v02T = v13T; + v02_t = v13_t; v02 = v13; v02_size = v13_size; } } -void Polygon::smooth_outward(const AngleDegrees min_angle, int shortcut_length, Polygon& result) const +void Polygon::smoothOutward(const AngleDegrees min_angle, int shortcut_length, Polygon& result) const { // example of smoothed out corner: // @@ -152,7 +152,7 @@ void Polygon::smooth_outward(const AngleDegrees min_angle, int shortcut_length, // 0 int shortcut_length2 = shortcut_length * shortcut_length; - double cos_min_angle = cos(min_angle / 180 * std::numbers::pi); + double cos_min_angle = std::cos(min_angle / 180 * std::numbers::pi); ListPolygon poly; ListPolyIt::convertPolygonToList(*this, poly); @@ -162,7 +162,7 @@ void Polygon::smooth_outward(const AngleDegrees min_angle, int shortcut_length, do { ListPolyIt next = p1_it.next(); - if (vSize2(p1_it.p() - next.p()) < 10 * 10) + if (vSize2(p1_it.p() - next.p()) < 100LL) { p1_it.remove(); } @@ -189,11 +189,11 @@ void Polygon::smooth_outward(const AngleDegrees min_angle, int shortcut_length, Point2LL v02 = p2_it.p() - p0_it.p(); if (vSize2(v02) >= shortcut_length2) { - smooth_corner_simple(p0, p1, p2, p0_it, p1_it, p2_it, v10, v12, v02, shortcut_length, cos_angle); + smoothCornerSimple(p0, p1, p2, p0_it, p1_it, p2_it, v10, v12, v02, shortcut_length, cos_angle); } else { - bool remove_poly = smooth_corner_complex(p1, p0_it, p2_it, shortcut_length); // edits p0_it and p2_it! + bool remove_poly = smoothCornerComplex(p1, p0_it, p2_it, shortcut_length); // edits p0_it and p2_it! if (remove_poly) { // don't convert ListPolygon into result @@ -212,7 +212,7 @@ void Polygon::smooth_outward(const AngleDegrees min_angle, int shortcut_length, ListPolyIt::convertListPolygonToPolygon(poly, result); } -void Polygon::smooth_corner_simple( +void Polygon::smoothCornerSimple( const Point2LL& p0, const Point2LL& p1, const Point2LL& p2, @@ -253,7 +253,7 @@ void Polygon::smooth_corner_simple( // m // use trigonometry on the right-angled triangle am1 double a1m_angle = acos(cos_angle) / 2; - const int64_t a1_size = shortcut_length / 2 / sin(a1m_angle); + const int64_t a1_size = shortcut_length / 2 / std::sin(a1m_angle); if (a1_size * a1_size < vSize2(v10) && a1_size * a1_size < vSize2(v12)) { Point2LL a = p1 + normal(v10, a1_size); @@ -313,7 +313,7 @@ void Polygon::smooth_corner_simple( } } -void Polygon::smooth_outward_step( +void Polygon::smoothOutwardStep( const Point2LL& p1, const int64_t shortcut_length2, ListPolyIt& p0_it, @@ -353,32 +353,28 @@ void Polygon::smooth_outward_step( backward_is_too_far = false; return; } - else + const ListPolyIt p0_2_it = p0_it.prev(); + const Point2LL p0_2 = p0_2_it.p(); + bool p0_is_left = LinearAlg2D::pointIsLeftOfLine(p0, p0_2, p2) >= 0; + if (! p0_is_left) { - const ListPolyIt p0_2_it = p0_it.prev(); - const Point2LL p0_2 = p0_2_it.p(); - bool p0_is_left = LinearAlg2D::pointIsLeftOfLine(p0, p0_2, p2) >= 0; - if (! p0_is_left) - { - backward_is_blocked = true; - return; - } - - const Point2LL v02_2 = p2_it.p() - p0_2; - if (vSize2(v02_2) > shortcut_length2) - { - backward_is_too_far = true; - return; - } + backward_is_blocked = true; + return; + } - p0_it = p0_2_it; // make one step in the backward direction - forward_is_blocked = false; // invalidate data about forward walking - forward_is_too_far = false; + const Point2LL v02_2 = p2_it.p() - p0_2; + if (vSize2(v02_2) > shortcut_length2) + { + backward_is_too_far = true; return; } + + p0_it = p0_2_it; // make one step in the backward direction + forward_is_blocked = false; // invalidate data about forward walking + forward_is_too_far = false; } -bool Polygon::smooth_corner_complex(const Point2LL& p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length) +bool Polygon::smoothCornerComplex(const Point2LL& p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length) { // walk away from the corner until the shortcut > shortcut_length or it would smooth a piece inward // - walk in both directions untill shortcut > shortcut_length @@ -414,12 +410,9 @@ bool Polygon::smooth_corner_complex(const Point2LL& p1, ListPolyIt& p0_it, ListP backward_is_too_far = false; // invalidate data continue; } - else - { - break; - } + break; } - smooth_outward_step(p1, shortcut_length2, p0_it, p2_it, forward_is_blocked, backward_is_blocked, forward_is_too_far, backward_is_too_far); + smoothOutwardStep(p1, shortcut_length2, p0_it, p2_it, forward_is_blocked, backward_is_blocked, forward_is_too_far, backward_is_too_far); if (p0_it.prev() == p2_it || p0_it == p2_it) { // stop if we went all the way around the polygon // this should only be the case for hole polygons (?) @@ -438,11 +431,8 @@ bool Polygon::smooth_corner_complex(const Point2LL& p1, ListPolyIt& p0_it, ListP // \ . break; } - else - { - // this whole polygon can be removed - return true; - } + // this whole polygon can be removed + return true; } } @@ -466,7 +456,7 @@ bool Polygon::smooth_corner_complex(const Point2LL& p1, ListPolyIt& p0_it, ListP // |a // | // 0 - const int64_t v02_size = sqrt(v02_size2); + const auto v02_size = static_cast(std::sqrt(v02_size2)); const ListPolyIt p0_2_it = p0_it.prev(); const ListPolyIt p2_2_it = p2_it.next(); @@ -563,19 +553,20 @@ bool Polygon::smooth_corner_complex(const Point2LL& p1, ListPolyIt& p0_it, ListP Point2LL Polygon::centerOfMass() const { - if (size() > 0) + if (! empty()) { Point2LL p0 = getPoints()[0]; if (size() > 1) { - double x = 0, y = 0; + double x{ 0 }; + double y{ 0 }; for (size_t n = 1; n <= size(); n++) { Point2LL p1 = getPoints()[n % size()]; - double second_factor = static_cast((p0.X * p1.Y) - (p1.X * p0.Y)); + auto second_factor = static_cast((p0.X * p1.Y) - (p1.X * p0.Y)); - x += double(p0.X + p1.X) * second_factor; - y += double(p0.Y + p1.Y) * second_factor; + x += static_cast(p0.X + p1.X) * second_factor; + y += static_cast(p0.Y + p1.Y) * second_factor; p0 = p1; } @@ -584,17 +575,11 @@ Point2LL Polygon::centerOfMass() const x = x / 6 / current_area; y = y / 6 / current_area; - return Point2LL(std::llrint(x), std::llrint(y)); - } - else - { - return p0; + return { std::llrint(x), std::llrint(y) }; } + return p0; } - else - { - return Point2LL(); - } + return {}; } Shape Polygon::offset(int distance, ClipperLib::JoinType join_type, double miter_limit) const @@ -608,7 +593,7 @@ Shape Polygon::offset(int distance, ClipperLib::JoinType join_type, double miter clipper.AddPath(getPoints(), join_type, ClipperLib::etClosedPolygon); clipper.MiterLimit = miter_limit; clipper.Execute(ret, distance); - return Shape(std::move(ret)); + return Shape{ std::move(ret) }; } } // namespace cura From 4faab9e26b8cf165aaf2f0f6ea4335955adbf254 Mon Sep 17 00:00:00 2001 From: jellespijker Date: Fri, 3 May 2024 17:20:34 +0000 Subject: [PATCH 096/135] Applied clang-format. --- include/geometry/Polygon.h | 2 +- include/geometry/SegmentIterator.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/geometry/Polygon.h b/include/geometry/Polygon.h index ef26e72792..987851ab8d 100644 --- a/include/geometry/Polygon.h +++ b/include/geometry/Polygon.h @@ -72,7 +72,7 @@ class Polygon : public ClosedPolyline Polygon& operator=(const Polygon& other) = default; - Polygon& operator=(Polygon&& other) noexcept = default; + Polygon& operator=(Polygon&& other) noexcept = default; /*! * \brief Compute the morphological intersection between this polygon and another. diff --git a/include/geometry/SegmentIterator.h b/include/geometry/SegmentIterator.h index 95e6bb0445..5164c7d32f 100644 --- a/include/geometry/SegmentIterator.h +++ b/include/geometry/SegmentIterator.h @@ -34,8 +34,7 @@ struct SegmentIterator using difference_type = std::ptrdiff_t; using pointer = Segment*; using reference = Segment&; - using source_iterator_type = - std::conditional_t::const_iterator, typename std::vector::iterator>; + using source_iterator_type = std::conditional_t::const_iterator, typename std::vector::iterator>; private: source_iterator_type current_pos_; From fdeb5651fecdd56ee09fbdab3a111bf4d5404c8c Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 3 May 2024 19:39:48 +0200 Subject: [PATCH 097/135] Refactor method name `smooth_outward` in Shape class The method 'smooth_outward' in the Shape class has been renamed to 'smoothOutward' for better readability and consistency with general coding standards. This change only affects the naming of the function and not its functionality or usage. Contribute to CURA-9830 --- src/geometry/Shape.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/geometry/Shape.cpp b/src/geometry/Shape.cpp index 54440b2b80..2145ec5d70 100644 --- a/src/geometry/Shape.cpp +++ b/src/geometry/Shape.cpp @@ -595,7 +595,7 @@ Shape Shape::smoothOutward(const AngleDegrees max_angle, int shortcut_length) co ret.push_back(poly); continue; } - poly.smooth_outward(max_angle, shortcut_length, ret.newLine()); + poly.smoothOutward(max_angle, shortcut_length, ret.newLine()); if (ret.back().size() < 3) { ret.resize(ret.size() - 1); From f8bc7097fb8d7c3adec3167a42d9ef8710c38da4 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 6 May 2024 10:43:41 +0200 Subject: [PATCH 098/135] Include geometry/LinesSet.h in multiple source files The necessary header geometry/LinesSet.h has been included into multiple files across the project. This marks an important step for functionality expansion as the new header file has updated geometrical methods that are crucial for the application to function optimally. Copyright years in certain files were also updated. Contribute to CURA-9830 --- benchmark/infill_benchmark.h | 3 ++- include/LayerPlan.h | 2 ++ include/TreeSupportTipGenerator.h | 2 ++ include/TreeSupportUtils.h | 2 ++ include/infill.h | 2 ++ include/infill/GyroidInfill.h | 7 +++---- include/infill/LightningLayer.h | 9 +++++---- include/infill/LightningTreeNode.h | 4 +++- include/infill/NoZigZagConnectorProcessor.h | 13 +++++++------ include/plugins/converters.h | 2 ++ include/plugins/slots.h | 2 ++ include/slicer.h | 1 + include/utils/MixedPolylineStitcher.h | 1 + include/utils/OpenPolylineStitcher.h | 1 + src/FffGcodeWriter.cpp | 1 + 15 files changed, 36 insertions(+), 16 deletions(-) diff --git a/benchmark/infill_benchmark.h b/benchmark/infill_benchmark.h index af05031656..29423a1b70 100644 --- a/benchmark/infill_benchmark.h +++ b/benchmark/infill_benchmark.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef CURAENGINE_INFILL_BENCHMARK_H @@ -8,6 +8,7 @@ #include "geometry/OpenLinesSet.h" #include "geometry/OpenPolyline.h" +#include "geometry/LinesSet.h" #include "infill.h" namespace cura diff --git a/include/LayerPlan.h b/include/LayerPlan.h index dda622b603..b1377d4f3d 100644 --- a/include/LayerPlan.h +++ b/include/LayerPlan.h @@ -10,6 +10,8 @@ #include "PathOrderOptimizer.h" #include "SpaceFillType.h" #include "gcodeExport.h" +#include "geometry/LinesSet.h" +#include "geometry/OpenLinesSet.h" #include "geometry/Polygon.h" #include "pathPlanning/GCodePath.h" #include "pathPlanning/NozzleTempInsert.h" diff --git a/include/TreeSupportTipGenerator.h b/include/TreeSupportTipGenerator.h index adcc712a20..e483500ea0 100644 --- a/include/TreeSupportTipGenerator.h +++ b/include/TreeSupportTipGenerator.h @@ -11,6 +11,8 @@ #include "TreeSupportEnums.h" #include "TreeSupportSettings.h" #include "boost/functional/hash.hpp" // For combining hashes +#include "geometry/LinesSet.h" +#include "geometry/OpenLinesSet.h" #include "geometry/Polygon.h" #include "polyclipping/clipper.hpp" #include "settings/EnumSettings.h" diff --git a/include/TreeSupportUtils.h b/include/TreeSupportUtils.h index e880689ecd..d11364fd2d 100644 --- a/include/TreeSupportUtils.h +++ b/include/TreeSupportUtils.h @@ -12,6 +12,8 @@ #include "TreeSupportEnums.h" #include "TreeSupportSettings.h" #include "boost/functional/hash.hpp" // For combining hashes +#include "geometry/LinesSet.h" +#include "geometry/OpenLinesSet.h" #include "geometry/OpenPolyline.h" #include "geometry/Polygon.h" #include "infill.h" diff --git a/include/infill.h b/include/infill.h index 610be628cf..081652d68f 100644 --- a/include/infill.h +++ b/include/infill.h @@ -8,6 +8,8 @@ #include +#include "geometry/LinesSet.h" +#include "geometry/OpenLinesSet.h" #include "geometry/Point2LL.h" #include "infill/LightningGenerator.h" #include "infill/ZigzagConnectorProcessor.h" diff --git a/include/infill/GyroidInfill.h b/include/infill/GyroidInfill.h index 2c4af661da..00c2e3b273 100644 --- a/include/infill/GyroidInfill.h +++ b/include/infill/GyroidInfill.h @@ -1,12 +1,12 @@ -// Copyright (c) 2020 Ultimaker B.V. +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher. -#include "../utils/Coord_t.h" +#include "geometry/LinesSet.h" #include "geometry/OpenLinesSet.h" +#include "utils/Coord_t.h" namespace cura { - class Shape; class GyroidInfill @@ -38,5 +38,4 @@ class GyroidInfill private: }; - } // namespace cura diff --git a/include/infill/LightningLayer.h b/include/infill/LightningLayer.h index 82cfc67a4a..d62b5267a4 100644 --- a/include/infill/LightningLayer.h +++ b/include/infill/LightningLayer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 UltiMaker +// Copyright (c) 2024 UltiMaker // CuraEngine is released under the terms of the AGPLv3 or higher #ifndef LIGHTNING_LAYER_H @@ -9,9 +9,11 @@ #include #include -#include "../utils/SquareGrid.h" -#include "../utils/polygonUtils.h" +#include "geometry/LinesSet.h" +#include "geometry/OpenLinesSet.h" #include "infill/LightningTreeNode.h" +#include "utils/SquareGrid.h" +#include "utils/polygonUtils.h" namespace cura { @@ -74,7 +76,6 @@ class LightningLayer void fillLocator(SparseLightningTreeNodeGrid& tree_node_locator); }; - } // namespace cura #endif // LIGHTNING_LAYER_H diff --git a/include/infill/LightningTreeNode.h b/include/infill/LightningTreeNode.h index 3f18499a1e..fa73e10fb9 100644 --- a/include/infill/LightningTreeNode.h +++ b/include/infill/LightningTreeNode.h @@ -9,9 +9,11 @@ #include #include -#include "../utils/polygonUtils.h" +#include "geometry/LinesSet.h" +#include "geometry/OpenLinesSet.h" #include "geometry/Polygon.h" #include "geometry/Shape.h" +#include "utils/polygonUtils.h" namespace cura { diff --git a/include/infill/NoZigZagConnectorProcessor.h b/include/infill/NoZigZagConnectorProcessor.h index f60a221d73..b52bf3ed9f 100644 --- a/include/infill/NoZigZagConnectorProcessor.h +++ b/include/infill/NoZigZagConnectorProcessor.h @@ -5,6 +5,7 @@ #define INFILL_NO_ZIGZAG_CONNECTOR_PROCESSOR_H #include "ZigzagConnectorProcessor.h" +#include "geometry/OpenLinesSet.h" namespace cura { @@ -22,12 +23,12 @@ class NoZigZagConnectorProcessor : public ZigzagConnectorProcessor public: NoZigZagConnectorProcessor(const PointMatrix& rotation_matrix, OpenLinesSet& result) : ZigzagConnectorProcessor( - rotation_matrix, - result, - false, - false, // settings for zig-zag end pieces, no use here - false, - 0) // settings for skipping some zags, no use here + rotation_matrix, + result, + false, + false, // settings for zig-zag end pieces, no use here + false, + 0) // settings for skipping some zags, no use here { } diff --git a/include/plugins/converters.h b/include/plugins/converters.h index 6748ca0be0..de947a850c 100644 --- a/include/plugins/converters.h +++ b/include/plugins/converters.h @@ -27,6 +27,8 @@ #include "cura/plugins/slots/postprocess/v0/modify.pb.h" #include "cura/plugins/slots/simplify/v0/modify.grpc.pb.h" #include "cura/plugins/slots/simplify/v0/modify.pb.h" +#include "geometry/LinesSet.h" +#include "geometry/OpenLinesSet.h" #include "geometry/Polygon.h" #include "pathPlanning/GCodePath.h" #include "pathPlanning/SpeedDerivatives.h" diff --git a/include/plugins/slots.h b/include/plugins/slots.h index 28db123fc0..8cf14dec69 100644 --- a/include/plugins/slots.h +++ b/include/plugins/slots.h @@ -17,6 +17,8 @@ #include "cura/plugins/slots/postprocess/v0/modify.grpc.pb.h" #include "cura/plugins/slots/simplify/v0/modify.grpc.pb.h" #include "cura/plugins/v0/slot_id.pb.h" +#include "geometry/LinesSet.h" +#include "geometry/OpenLinesSet.h" #include "geometry/Point2LL.h" #include "geometry/Polygon.h" #include "infill.h" diff --git a/include/slicer.h b/include/slicer.h index ebb04185cb..5cb3d77a4f 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -8,6 +8,7 @@ #include #include +#include "geometry/LinesSet.h" #include "geometry/OpenLinesSet.h" #include "geometry/OpenPolyline.h" #include "geometry/Shape.h" diff --git a/include/utils/MixedPolylineStitcher.h b/include/utils/MixedPolylineStitcher.h index b87e6799dd..9c092e1bcd 100644 --- a/include/utils/MixedPolylineStitcher.h +++ b/include/utils/MixedPolylineStitcher.h @@ -6,6 +6,7 @@ #include "PolylineStitcher.h" #include "geometry/ClosedLinesSet.h" +#include "geometry/LinesSet.h" #include "geometry/OpenLinesSet.h" namespace cura diff --git a/include/utils/OpenPolylineStitcher.h b/include/utils/OpenPolylineStitcher.h index b99cd91c41..fb2a532f0b 100644 --- a/include/utils/OpenPolylineStitcher.h +++ b/include/utils/OpenPolylineStitcher.h @@ -5,6 +5,7 @@ #define UTILS_OPEN_POLYLINE_STITCHER_H #include "PolylineStitcher.h" +#include "geometry/LinesSet.h" #include "geometry/OpenLinesSet.h" #include "geometry/Shape.h" diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index dfba3f7ed8..255747a3f6 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -26,6 +26,7 @@ #include "bridge.h" #include "communication/Communication.h" //To send layer view data. #include "geometry/OpenPolyline.h" +#include "geometry/LinesSet.h" #include "geometry/PointMatrix.h" #include "infill.h" #include "progress/Progress.h" From 619b344f155d91bdc5492f3e21c4c1833979e7c4 Mon Sep 17 00:00:00 2001 From: jellespijker Date: Mon, 6 May 2024 08:44:25 +0000 Subject: [PATCH 099/135] Applied clang-format. --- include/infill/NoZigZagConnectorProcessor.h | 12 ++++++------ src/FffGcodeWriter.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/infill/NoZigZagConnectorProcessor.h b/include/infill/NoZigZagConnectorProcessor.h index b52bf3ed9f..c456297223 100644 --- a/include/infill/NoZigZagConnectorProcessor.h +++ b/include/infill/NoZigZagConnectorProcessor.h @@ -23,12 +23,12 @@ class NoZigZagConnectorProcessor : public ZigzagConnectorProcessor public: NoZigZagConnectorProcessor(const PointMatrix& rotation_matrix, OpenLinesSet& result) : ZigzagConnectorProcessor( - rotation_matrix, - result, - false, - false, // settings for zig-zag end pieces, no use here - false, - 0) // settings for skipping some zags, no use here + rotation_matrix, + result, + false, + false, // settings for zig-zag end pieces, no use here + false, + 0) // settings for skipping some zags, no use here { } diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index 255747a3f6..5154971d39 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -25,8 +25,8 @@ #include "WallToolPaths.h" #include "bridge.h" #include "communication/Communication.h" //To send layer view data. -#include "geometry/OpenPolyline.h" #include "geometry/LinesSet.h" +#include "geometry/OpenPolyline.h" #include "geometry/PointMatrix.h" #include "infill.h" #include "progress/Progress.h" From 0e5f382e0ecee08dcd12b3127e894842bd97afa9 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 6 May 2024 13:50:37 +0200 Subject: [PATCH 100/135] Remove useless headers inclusions CURA-9830 --- include/plugins/slots.h | 6 ------ include/plugins/types.h | 2 -- src/Application.cpp | 1 - 3 files changed, 9 deletions(-) diff --git a/include/plugins/slots.h b/include/plugins/slots.h index 8cf14dec69..9e38b29547 100644 --- a/include/plugins/slots.h +++ b/include/plugins/slots.h @@ -17,17 +17,11 @@ #include "cura/plugins/slots/postprocess/v0/modify.grpc.pb.h" #include "cura/plugins/slots/simplify/v0/modify.grpc.pb.h" #include "cura/plugins/v0/slot_id.pb.h" -#include "geometry/LinesSet.h" -#include "geometry/OpenLinesSet.h" -#include "geometry/Point2LL.h" -#include "geometry/Polygon.h" -#include "infill.h" #include "plugins/converters.h" #include "plugins/slotproxy.h" #include "plugins/types.h" #include "plugins/validator.h" #include "utils/Simplify.h" // TODO: Remove once the simplify slot has been removed -#include "utils/types/char_range_literal.h" namespace cura { diff --git a/include/plugins/types.h b/include/plugins/types.h index f3abfc9ad1..a8fa18fad9 100644 --- a/include/plugins/types.h +++ b/include/plugins/types.h @@ -11,8 +11,6 @@ #include #include "cura/plugins/v0/slot_id.pb.h" -#include "geometry/Point2LL.h" -#include "geometry/Polygon.h" namespace fmt { diff --git a/src/Application.cpp b/src/Application.cpp index 897b4c89eb..f6277f8afa 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -18,7 +18,6 @@ #include #include -#include "FffProcessor.h" #include "communication/ArcusCommunication.h" //To connect via Arcus to the front-end. #include "communication/CommandLine.h" //To use the command line to slice stuff. #include "plugins/slots.h" From 2f9fc5f9eee4c83ac17205882b4ed47507c8def5 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 6 May 2024 14:10:02 +0200 Subject: [PATCH 101/135] Remove one more useless header include CURA-9830 --- include/plugins/slots.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/plugins/slots.h b/include/plugins/slots.h index 9e38b29547..b123879ab6 100644 --- a/include/plugins/slots.h +++ b/include/plugins/slots.h @@ -10,7 +10,6 @@ #include #include -#include "WallToolPaths.h" #include "cura/plugins/slots/broadcast/v0/broadcast.grpc.pb.h" #include "cura/plugins/slots/gcode_paths/v0/modify.grpc.pb.h" #include "cura/plugins/slots/infill/v0/generate.grpc.pb.h" From e5a0d4bbb76884bc015f1d265f603dfd1bdba314 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 6 May 2024 14:35:45 +0200 Subject: [PATCH 102/135] Remove one more useless header include CURA-9830 --- src/Application.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Application.cpp b/src/Application.cpp index f6277f8afa..14f5a1bf7d 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -20,7 +20,6 @@ #include "communication/ArcusCommunication.h" //To connect via Arcus to the front-end. #include "communication/CommandLine.h" //To use the command line to slice stuff. -#include "plugins/slots.h" #include "progress/Progress.h" #include "utils/ThreadPool.h" #include "utils/string.h" //For stringcasecompare. From 2e6bfa7047052223bbb2774443203f05377a7131 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 6 May 2024 15:00:08 +0200 Subject: [PATCH 103/135] Make more use of forward-declaration CURA-9830 --- include/FffGcodeWriter.h | 5 ++--- include/LayerPlanBuffer.h | 6 ++---- include/gcodeExport.h | 2 +- include/plugins/slotproxy.h | 15 +++++++-------- include/plugins/slots.h | 1 - include/sliceDataStorage.h | 2 ++ src/gcodeExport.cpp | 1 + 7 files changed, 15 insertions(+), 17 deletions(-) diff --git a/include/FffGcodeWriter.h b/include/FffGcodeWriter.h index fa7e975a6c..9c2482a937 100644 --- a/include/FffGcodeWriter.h +++ b/include/FffGcodeWriter.h @@ -9,11 +9,9 @@ #include "ExtruderUse.h" #include "FanSpeedLayerTime.h" +#include "GCodePathConfig.h" #include "LayerPlanBuffer.h" #include "gcodeExport.h" -#include "settings/MeshPathConfigs.h" -#include "settings/PathConfigStorage.h" //For the MeshPathConfigs subclass. -#include "utils/ExtrusionLine.h" //Processing variable-width paths. #include "utils/NoCopy.h" #include "utils/gettime.h" @@ -27,6 +25,7 @@ class SliceDataStorage; class SliceMeshStorage; class SliceLayer; class SliceLayerPart; +struct MeshPathConfigs; /*! * Secondary stage in Fused Filament Fabrication processing: The generated polygons are used in the gcode generation. diff --git a/include/LayerPlanBuffer.h b/include/LayerPlanBuffer.h index 1fb0ef56a7..3916321729 100644 --- a/include/LayerPlanBuffer.h +++ b/include/LayerPlanBuffer.h @@ -7,17 +7,15 @@ #include #include -#include "ExtruderPlan.h" -#include "LayerPlan.h" #include "Preheat.h" -#include "gcodeExport.h" #include "settings/Settings.h" #include "settings/types/Duration.h" namespace cura { - +class LayerPlan; +class ExtruderPlan; class GCodeExport; /*! diff --git a/include/gcodeExport.h b/include/gcodeExport.h index 052fa85582..9d91325d97 100644 --- a/include/gcodeExport.h +++ b/include/gcodeExport.h @@ -17,7 +17,6 @@ #include "settings/types/LayerIndex.h" #include "settings/types/Temperature.h" //Bed temperature. #include "settings/types/Velocity.h" -#include "sliceDataStorage.h" #include "timeEstimate.h" #include "utils/AABB3D.h" //To track the used build volume for the Griffin header. #include "utils/NoCopy.h" @@ -26,6 +25,7 @@ namespace cura { class RetractionConfig; +class SliceDataStorage; struct WipeScriptConfig; // The GCodeExport class writes the actual GCode. This is the only class that knows how GCode looks and feels. diff --git a/include/plugins/slotproxy.h b/include/plugins/slotproxy.h index 037db10a19..82dd57d2a5 100644 --- a/include/plugins/slotproxy.h +++ b/include/plugins/slotproxy.h @@ -4,20 +4,19 @@ #ifndef PLUGINS_SLOTPROXY_H #define PLUGINS_SLOTPROXY_H -#include "plugins/converters.h" -#include "plugins/pluginproxy.h" -#include "plugins/types.h" -#include "plugins/validator.h" -#include "utils/types/char_range_literal.h" - -#include - #include #include #include #include #include +#include + +#include "plugins/pluginproxy.h" +#include "plugins/types.h" +#include "plugins/validator.h" +#include "utils/types/char_range_literal.h" + namespace cura::plugins { diff --git a/include/plugins/slots.h b/include/plugins/slots.h index b123879ab6..30740be3c4 100644 --- a/include/plugins/slots.h +++ b/include/plugins/slots.h @@ -16,7 +16,6 @@ #include "cura/plugins/slots/postprocess/v0/modify.grpc.pb.h" #include "cura/plugins/slots/simplify/v0/modify.grpc.pb.h" #include "cura/plugins/v0/slot_id.pb.h" -#include "plugins/converters.h" #include "plugins/slotproxy.h" #include "plugins/types.h" #include "plugins/validator.h" diff --git a/include/sliceDataStorage.h b/include/sliceDataStorage.h index 722c29064d..669e6829d0 100644 --- a/include/sliceDataStorage.h +++ b/include/sliceDataStorage.h @@ -13,8 +13,10 @@ #include "SupportInfillPart.h" #include "TopSurface.h" #include "WipeScriptConfig.h" +#include "geometry/LinesSet.h" #include "geometry/MixedLinesSet.h" #include "geometry/OpenLinesSet.h" +#include "geometry/OpenPolyline.h" #include "geometry/Point2LL.h" #include "geometry/Polygon.h" #include "geometry/SingleShape.h" diff --git a/src/gcodeExport.cpp b/src/gcodeExport.cpp index 37d758e629..98d95d3f07 100644 --- a/src/gcodeExport.cpp +++ b/src/gcodeExport.cpp @@ -18,6 +18,7 @@ #include "WipeScriptConfig.h" #include "communication/Communication.h" //To send layer view data. #include "settings/types/LayerIndex.h" +#include "sliceDataStorage.h" #include "utils/Date.h" #include "utils/string.h" // MMtoStream, PrecisionedDouble From 19ead34e075e7aec14b88823b790aca30d2bbb00 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 6 May 2024 15:11:00 +0200 Subject: [PATCH 104/135] Reorder template methods specialization instantiations This should help fixing Mac build CURA-9830 --- src/utils/PolylineStitcher.cpp | 132 ++++++++++++++++----------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/src/utils/PolylineStitcher.cpp b/src/utils/PolylineStitcher.cpp index 70ba6e849b..6e67797c62 100644 --- a/src/utils/PolylineStitcher.cpp +++ b/src/utils/PolylineStitcher.cpp @@ -26,6 +26,72 @@ bool ExtrusionLineStitcher::canReverse(const PathsPointIndex } } +template<> +bool OpenPolylineStitcher::canReverse(const PathsPointIndex&) +{ + return true; +} + +template<> +bool PolylineStitcher::canReverse(const PathsPointIndex&) +{ + return true; +} + +template<> +bool ExtrusionLineStitcher::canConnect(const ExtrusionLine& a, const ExtrusionLine& b) +{ + return a.is_odd_ == b.is_odd_; +} + +template<> +bool OpenPolylineStitcher::canConnect(const OpenPolyline&, const OpenPolyline&) +{ + return true; +} + +template<> +bool PolylineStitcher::canConnect(const OpenPolyline&, const OpenPolyline&) +{ + return true; +} + +template<> +bool ExtrusionLineStitcher::isOdd(const ExtrusionLine& line) +{ + return line.is_odd_; +} + +template<> +bool OpenPolylineStitcher::isOdd(const OpenPolyline&) +{ + return false; +} + +template<> +bool PolylineStitcher::isOdd(const OpenPolyline&) +{ + return false; +} + +template<> +void ExtrusionLineStitcher::pushToClosedResult(VariableWidthLines& result_polygons, const ExtrusionLine& polyline) +{ + result_polygons.push_back(polyline); +} + +template<> +void OpenPolylineStitcher::pushToClosedResult(Shape& result_polygons, const OpenPolyline& polyline) +{ + result_polygons.emplace_back(polyline.getPoints(), true); +} + +template<> +void PolylineStitcher::pushToClosedResult(ClosedLinesSet& result_polygons, const OpenPolyline& polyline) +{ + result_polygons.emplace_back(polyline.getPoints(), true); +} + template void PolylineStitcher::stitch( const InputPaths& lines, @@ -228,70 +294,4 @@ template void PolylineStitcher -bool OpenPolylineStitcher::canReverse(const PathsPointIndex&) -{ - return true; -} - -template<> -bool PolylineStitcher::canReverse(const PathsPointIndex&) -{ - return true; -} - -template<> -bool ExtrusionLineStitcher::canConnect(const ExtrusionLine& a, const ExtrusionLine& b) -{ - return a.is_odd_ == b.is_odd_; -} - -template<> -bool OpenPolylineStitcher::canConnect(const OpenPolyline&, const OpenPolyline&) -{ - return true; -} - -template<> -bool PolylineStitcher::canConnect(const OpenPolyline&, const OpenPolyline&) -{ - return true; -} - -template<> -bool ExtrusionLineStitcher::isOdd(const ExtrusionLine& line) -{ - return line.is_odd_; -} - -template<> -bool OpenPolylineStitcher::isOdd(const OpenPolyline&) -{ - return false; -} - -template<> -bool PolylineStitcher::isOdd(const OpenPolyline&) -{ - return false; -} - -template<> -void ExtrusionLineStitcher::pushToClosedResult(VariableWidthLines& result_polygons, const ExtrusionLine& polyline) -{ - result_polygons.push_back(polyline); -} - -template<> -void OpenPolylineStitcher::pushToClosedResult(Shape& result_polygons, const OpenPolyline& polyline) -{ - result_polygons.emplace_back(polyline.getPoints(), true); -} - -template<> -void PolylineStitcher::pushToClosedResult(ClosedLinesSet& result_polygons, const OpenPolyline& polyline) -{ - result_polygons.emplace_back(polyline.getPoints(), true); -} - } // namespace cura From 08f30ec375cd6e64b9a90aa3830dcec813cb2a73 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Mon, 6 May 2024 15:46:04 +0200 Subject: [PATCH 105/135] Fix unit tests CURA-9830 --- tests/arcus/ArcusCommunicationTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/arcus/ArcusCommunicationTest.cpp b/tests/arcus/ArcusCommunicationTest.cpp index cfd5f282c7..a05b88d98d 100644 --- a/tests/arcus/ArcusCommunicationTest.cpp +++ b/tests/arcus/ArcusCommunicationTest.cpp @@ -11,6 +11,7 @@ #include "MockSocket.h" //To mock out the communication with the front-end. #include "communication/ArcusCommunicationPrivate.h" //To access the private fields of this communication class. #include "geometry/Polygon.h" //Create test shapes to send over the socket. +#include "geometry/Shape.h" #include "settings/types/LayerIndex.h" #include "utils/Coord_t.h" From 3050787393018cd0c56f0cdc93f520b45ae07aca Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 7 May 2024 15:29:04 +0200 Subject: [PATCH 106/135] Fix missing open polylines A class variable and a local variable were renamed to the same name. Add a suffix to the class variable to differentiate them. CURA-9830 --- include/slicer.h | 2 +- src/Mold.cpp | 4 ++-- src/layerPart.cpp | 2 +- src/multiVolumes.cpp | 2 +- src/slicer.cpp | 10 +++++----- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/slicer.h b/include/slicer.h index 5cb3d77a4f..dc247bfcb7 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -64,7 +64,7 @@ class SlicerLayer int z = -1; Shape polygons; - OpenLinesSet open_polylines; + OpenLinesSet open_polylines_; /*! * \brief Connect the segments into polygons for this layer of this \p mesh. diff --git a/src/Mold.cpp b/src/Mold.cpp index 4c2fa54a32..8d3c20e582 100644 --- a/src/Mold.cpp +++ b/src/Mold.cpp @@ -79,8 +79,8 @@ void Mold::process(std::vector& slicer_list) SlicerLayer& layer = slicer.layers[layer_nr]; - Shape model_outlines = layer.polygons.unionPolygons(layer.open_polylines.offset(open_polyline_width / 2)); - layer.open_polylines.clear(); + Shape model_outlines = layer.polygons.unionPolygons(layer.open_polylines_.offset(open_polyline_width / 2)); + layer.open_polylines_.clear(); all_original_mold_outlines.push_back(model_outlines); if (angle >= 90) diff --git a/src/layerPart.cpp b/src/layerPart.cpp index 5d3c7138c2..a6960fc5ec 100644 --- a/src/layerPart.cpp +++ b/src/layerPart.cpp @@ -30,7 +30,7 @@ namespace cura void createLayerWithParts(const Settings& settings, SliceLayer& storageLayer, SlicerLayer* layer) { - OpenPolylineStitcher::stitch(layer->open_polylines, storageLayer.open_polylines, layer->polygons, settings.get("wall_line_width_0")); + OpenPolylineStitcher::stitch(layer->open_polylines_, storageLayer.open_polylines, layer->polygons, settings.get("wall_line_width_0")); storageLayer.open_polylines = Simplify(settings).polyline(storageLayer.open_polylines); diff --git a/src/multiVolumes.cpp b/src/multiVolumes.cpp index 3ab392e358..9296644ae9 100644 --- a/src/multiVolumes.cpp +++ b/src/multiVolumes.cpp @@ -121,7 +121,7 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: for (LayerIndex layer_nr = 0; layer_nr < cutting_mesh_volume.layers.size(); layer_nr++) { Shape& cutting_mesh_polygons = cutting_mesh_volume.layers[layer_nr].polygons; - OpenLinesSet& cutting_mesh_polylines = cutting_mesh_volume.layers[layer_nr].open_polylines; + OpenLinesSet& cutting_mesh_polylines = cutting_mesh_volume.layers[layer_nr].open_polylines_; Shape cutting_mesh_area_recomputed; Shape* cutting_mesh_area; coord_t surface_line_width = cutting_mesh.settings_.get("wall_line_width_0"); diff --git a/src/slicer.cpp b/src/slicer.cpp index 1b33bb37e2..d0f4c2f009 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -766,7 +766,7 @@ void SlicerLayer::makePolygons(const Mesh* mesh) for (const OpenPolyline& polyline : open_polylines) { - open_polylines.push_back(std::move(polyline), CheckNonEmptyParam::OnlyIfNotEmpty); + open_polylines_.push_back(std::move(polyline), CheckNonEmptyParam::OnlyIfNotEmpty); } // Remove all the tiny polygons, or polygons that are not closed. As they do not contribute to the actual print. @@ -786,15 +786,15 @@ void SlicerLayer::makePolygons(const Mesh* mesh) // Clean up polylines for Surface Mode printing auto itPolylines = std::remove_if( - open_polylines.begin(), - open_polylines.end(), + open_polylines_.begin(), + open_polylines_.end(), [snap_distance](const OpenPolyline& line) { return line.shorterThan(snap_distance); }); - open_polylines.erase(itPolylines, open_polylines.end()); + open_polylines_.erase(itPolylines, open_polylines_.end()); - open_polylines.removeDegenerateVerts(); + open_polylines_.removeDegenerateVerts(); } Slicer::Slicer(Mesh* i_mesh, const coord_t thickness, const size_t slice_layer_count, bool use_variable_layer_heights, std::vector* adaptive_layers) From 6425ef17051440eb3826934918e0e8ab0a47c858 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 7 May 2024 15:35:44 +0200 Subject: [PATCH 107/135] Make SlicerLayer member variable naming consistent CURA-9830 --- include/slicer.h | 8 +- src/ConicalOverhang.cpp | 14 ++-- src/InterlockingGenerator.cpp | 14 ++-- src/Mold.cpp | 14 ++-- src/layerPart.cpp | 16 ++-- src/multiVolumes.cpp | 12 +-- src/slicer.cpp | 114 +++++++++++++-------------- src/support.cpp | 6 +- tests/integration/SlicePhaseTest.cpp | 16 ++-- 9 files changed, 107 insertions(+), 107 deletions(-) diff --git a/include/slicer.h b/include/slicer.h index dc247bfcb7..ddafd67ca3 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -59,11 +59,11 @@ class GapCloserResult class SlicerLayer { public: - std::vector segments; - std::unordered_map face_idx_to_segment_idx; // topology + std::vector segments_; + std::unordered_map face_idx_to_segment_idx_; // topology - int z = -1; - Shape polygons; + int z_ = -1; + Shape polygons_; OpenLinesSet open_polylines_; /*! diff --git a/src/ConicalOverhang.cpp b/src/ConicalOverhang.cpp index f217af5a73..699d9697d7 100644 --- a/src/ConicalOverhang.cpp +++ b/src/ConicalOverhang.cpp @@ -31,19 +31,19 @@ void ConicalOverhang::apply(Slicer* slicer, const Mesh& mesh) { // magically nothing happens when max_dist_from_lower_layer == 0 // below magic code solves that constexpr coord_t safe_dist = 20; - Shape diff = layer_above.polygons.difference(layer.polygons.offset(-safe_dist)); - layer.polygons = layer.polygons.unionPolygons(diff); - layer.polygons = layer.polygons.smooth(safe_dist); - layer.polygons = Simplify(safe_dist, safe_dist / 2, 0).polygon(layer.polygons); + Shape diff = layer_above.polygons_.difference(layer.polygons_.offset(-safe_dist)); + layer.polygons_ = layer.polygons_.unionPolygons(diff); + layer.polygons_ = layer.polygons_.smooth(safe_dist); + layer.polygons_ = Simplify(safe_dist, safe_dist / 2, 0).polygon(layer.polygons_); // somehow layer.polygons get really jagged lines with a lot of vertices // without the above steps slicing goes really slow } else { // Get the current layer and split it into parts - std::vector layer_parts = layer.polygons.splitIntoParts(); + std::vector layer_parts = layer.polygons_.splitIntoParts(); // Get a copy of the layer above to prune away before we shrink it - Shape above = layer_above.polygons; + Shape above = layer_above.polygons_; // Now go through all the holes in the current layer and check if they intersect anything in the layer above // If not, then they're the top of a hole and should be cut from the layer above before the union @@ -73,7 +73,7 @@ void ConicalOverhang::apply(Slicer* slicer, const Mesh& mesh) } } // And now union with offset of the resulting above layer - layer.polygons = layer.polygons.unionPolygons(above.offset(-max_dist_from_lower_layer)); + layer.polygons_ = layer.polygons_.unionPolygons(above.offset(-max_dist_from_lower_layer)); } } } diff --git a/src/InterlockingGenerator.cpp b/src/InterlockingGenerator.cpp index ccbf6fa374..abfab67ae7 100644 --- a/src/InterlockingGenerator.cpp +++ b/src/InterlockingGenerator.cpp @@ -124,8 +124,8 @@ void InterlockingGenerator::handleThinAreas(const std::unordered_set // Only alter layers when they are present in both meshes, zip should take care if that. for (auto [layer_nr, layer] : ranges::views::zip(mesh_a_.layers, mesh_b_.layers) | ranges::views::enumerate) { - Shape& polys_a = std::get<0>(layer).polygons; - Shape& polys_b = std::get<1>(layer).polygons; + Shape& polys_a = std::get<0>(layer).polygons_; + Shape& polys_b = std::get<1>(layer).polygons_; const auto [from_border_a, from_border_b] = growBorderAreasPerpendicular(polys_a, polys_b, detect); @@ -188,7 +188,7 @@ std::vector> InterlockingGenerator::getShellVoxel for (size_t layer_nr = 0; layer_nr < mesh->layers.size(); layer_nr++) { SlicerLayer& layer = mesh->layers[layer_nr]; - rotated_polygons_per_layer[layer_nr] = layer.polygons; + rotated_polygons_per_layer[layer_nr] = layer.polygons_; rotated_polygons_per_layer[layer_nr].applyMatrix(rotation_); } @@ -235,7 +235,7 @@ std::vector InterlockingGenerator::computeUnionedVolumeRegions() const break; } const SlicerLayer& layer = mesh->layers[static_cast(layer_nr)]; - layer_region.push_back(layer.polygons); + layer_region.push_back(layer.polygons_); } layer_region = layer_region.offset(ignored_gap_).offset(-ignored_gap_); // Morphological close to merge meshes into single volume layer_region.applyMatrix(rotation_); @@ -334,9 +334,9 @@ void InterlockingGenerator::applyMicrostructureToOutlines(const std::unordered_s const Shape& areas_other = structure_per_layer[! mesh_idx][layer_nr / static_cast(beam_layer_count_)]; SlicerLayer& layer = mesh->layers[layer_nr]; - layer.polygons = layer.polygons - .difference(areas_other) // reduce layer areas inward with beams from other mesh - .unionPolygons(areas_here); // extend layer areas outward with newly added beams + layer.polygons_ = layer.polygons_ + .difference(areas_other) // reduce layer areas inward with beams from other mesh + .unionPolygons(areas_here); // extend layer areas outward with newly added beams } } } diff --git a/src/Mold.cpp b/src/Mold.cpp index 8d3c20e582..48b4fba93c 100644 --- a/src/Mold.cpp +++ b/src/Mold.cpp @@ -79,29 +79,29 @@ void Mold::process(std::vector& slicer_list) SlicerLayer& layer = slicer.layers[layer_nr]; - Shape model_outlines = layer.polygons.unionPolygons(layer.open_polylines_.offset(open_polyline_width / 2)); + Shape model_outlines = layer.polygons_.unionPolygons(layer.open_polylines_.offset(open_polyline_width / 2)); layer.open_polylines_.clear(); all_original_mold_outlines.push_back(model_outlines); if (angle >= 90) { - layer.polygons = model_outlines.offset(width, ClipperLib::jtRound); + layer.polygons_ = model_outlines.offset(width, ClipperLib::jtRound); } else { Shape& mold_outline_above = mold_outline_above_per_mesh[mesh_idx]; // the outside of the mold on the layer above - layer.polygons = mold_outline_above.offset(-inset).unionPolygons(model_outlines.offset(width, ClipperLib::jtRound)); + layer.polygons_ = mold_outline_above.offset(-inset).unionPolygons(model_outlines.offset(width, ClipperLib::jtRound)); } // add roofs if (roof_layer_count > 0 && layer_nr > 0) { LayerIndex layer_nr_below = std::max(0, static_cast(layer_nr - roof_layer_count)); - Shape roofs = slicer.layers[layer_nr_below].polygons.offset(width, ClipperLib::jtRound); // TODO: don't compute offset twice! - layer.polygons = layer.polygons.unionPolygons(roofs); + Shape roofs = slicer.layers[layer_nr_below].polygons_.offset(width, ClipperLib::jtRound); // TODO: don't compute offset twice! + layer.polygons_ = layer.polygons_.unionPolygons(roofs); } - mold_outline_above_per_mesh[mesh_idx] = layer.polygons; + mold_outline_above_per_mesh[mesh_idx] = layer.polygons_; } all_original_mold_outlines = all_original_mold_outlines.unionPolygons(); @@ -117,7 +117,7 @@ void Mold::process(std::vector& slicer_list) } Slicer& slicer = *slicer_list[mesh_idx]; SlicerLayer& layer = slicer.layers[layer_nr]; - layer.polygons = layer.polygons.difference(all_original_mold_outlines); + layer.polygons_ = layer.polygons_.difference(all_original_mold_outlines); } } } diff --git a/src/layerPart.cpp b/src/layerPart.cpp index a6960fc5ec..e1754b73fe 100644 --- a/src/layerPart.cpp +++ b/src/layerPart.cpp @@ -15,7 +15,7 @@ /* The layer-part creation step is the first step in creating actual useful data for 3D printing. -It takes the result of the Slice step, which is an unordered list of polygons, and makes groups of polygons, +It takes the result of the Slice step, which is an unordered list of polygons_, and makes groups of polygons_, each of these groups is called a "part", which sometimes are also known as "islands". These parts represent isolated areas in the 2D layer with possible holes. @@ -30,17 +30,17 @@ namespace cura void createLayerWithParts(const Settings& settings, SliceLayer& storageLayer, SlicerLayer* layer) { - OpenPolylineStitcher::stitch(layer->open_polylines_, storageLayer.open_polylines, layer->polygons, settings.get("wall_line_width_0")); + OpenPolylineStitcher::stitch(layer->open_polylines_, storageLayer.open_polylines, layer->polygons_, settings.get("wall_line_width_0")); storageLayer.open_polylines = Simplify(settings).polyline(storageLayer.open_polylines); const bool union_all_remove_holes = settings.get("meshfix_union_all_remove_holes"); if (union_all_remove_holes) { - for (unsigned int i = 0; i < layer->polygons.size(); i++) + for (unsigned int i = 0; i < layer->polygons_.size(); i++) { - if (layer->polygons[i].orientation()) - layer->polygons[i].reverse(); + if (layer->polygons_[i].orientation()) + layer->polygons_[i].reverse(); } } @@ -49,8 +49,8 @@ void createLayerWithParts(const Settings& settings, SliceLayer& storageLayer, Sl const ESurfaceMode surface_only = settings.get("magic_mesh_surface_mode"); if (surface_only == ESurfaceMode::SURFACE && ! union_layers) { // Don't do anything with overlapping areas; no union nor xor - result.reserve(layer->polygons.size()); - for (const Polygon& poly : layer->polygons) + result.reserve(layer->polygons_.size()); + for (const Polygon& poly : layer->polygons_) { if (poly.empty()) { @@ -62,7 +62,7 @@ void createLayerWithParts(const Settings& settings, SliceLayer& storageLayer, Sl } else { - result = layer->polygons.splitIntoParts(union_layers || union_all_remove_holes); + result = layer->polygons_.splitIntoParts(union_layers || union_all_remove_holes); } for (auto& part : result) diff --git a/src/multiVolumes.cpp b/src/multiVolumes.cpp index 9296644ae9..68c7231522 100644 --- a/src/multiVolumes.cpp +++ b/src/multiVolumes.cpp @@ -55,11 +55,11 @@ void carveMultipleVolumes(std::vector& volumes) SlicerLayer& layer2 = volume_2.layers[layerNr]; if (alternate_carve_order && layerNr % 2 == 0 && volume_1.mesh->settings_.get("infill_mesh_order") == volume_2.mesh->settings_.get("infill_mesh_order")) { - layer2.polygons = layer2.polygons.difference(layer1.polygons); + layer2.polygons_ = layer2.polygons_.difference(layer1.polygons_); } else { - layer1.polygons = layer1.polygons.difference(layer2.polygons); + layer1.polygons_ = layer1.polygons_.difference(layer2.polygons_); } } } @@ -99,11 +99,11 @@ void generateMultipleVolumesOverlap(std::vector& volumes) continue; } SlicerLayer& other_volume_layer = other_volume->layers[layer_nr]; - all_other_volumes = all_other_volumes.unionPolygons(other_volume_layer.polygons.offset(offset_to_merge_other_merged_volumes), fill_type); + all_other_volumes = all_other_volumes.unionPolygons(other_volume_layer.polygons_.offset(offset_to_merge_other_merged_volumes), fill_type); } SlicerLayer& volume_layer = volume->layers[layer_nr]; - volume_layer.polygons = volume_layer.polygons.unionPolygons(all_other_volumes.intersection(volume_layer.polygons.offset(overlap / 2)), fill_type); + volume_layer.polygons_ = volume_layer.polygons_.unionPolygons(all_other_volumes.intersection(volume_layer.polygons_.offset(overlap / 2)), fill_type); } } } @@ -120,7 +120,7 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: Slicer& cutting_mesh_volume = *volumes[carving_mesh_idx]; for (LayerIndex layer_nr = 0; layer_nr < cutting_mesh_volume.layers.size(); layer_nr++) { - Shape& cutting_mesh_polygons = cutting_mesh_volume.layers[layer_nr].polygons; + Shape& cutting_mesh_polygons = cutting_mesh_volume.layers[layer_nr].polygons_; OpenLinesSet& cutting_mesh_polylines = cutting_mesh_volume.layers[layer_nr].open_polylines_; Shape cutting_mesh_area_recomputed; Shape* cutting_mesh_area; @@ -162,7 +162,7 @@ void MultiVolumes::carveCuttingMeshes(std::vector& volumes, const std:: continue; } Slicer& carved_volume = *volumes[carved_mesh_idx]; - Shape& carved_mesh_layer = carved_volume.layers[layer_nr].polygons; + Shape& carved_mesh_layer = carved_volume.layers[layer_nr].polygons_; Shape intersection = cutting_mesh_polygons.intersection(carved_mesh_layer); new_outlines.push_back(intersection); diff --git a/src/slicer.cpp b/src/slicer.cpp index d0f4c2f009..fa8fded180 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -33,31 +33,31 @@ constexpr int max_stitch1 = MM2INT(10.0); //!< maximal distance stitched between void SlicerLayer::makeBasicPolygonLoops(OpenLinesSet& open_polylines) { - for (size_t start_segment_idx = 0; start_segment_idx < segments.size(); start_segment_idx++) + for (size_t start_segment_idx = 0; start_segment_idx < segments_.size(); start_segment_idx++) { - if (! segments[start_segment_idx].addedToPolygon) + if (! segments_[start_segment_idx].addedToPolygon) { makeBasicPolygonLoop(open_polylines, start_segment_idx); } } // Clear the segmentList to save memory, it is no longer needed after this point. - segments.clear(); + segments_.clear(); } void SlicerLayer::makeBasicPolygonLoop(OpenLinesSet& open_polylines, const size_t start_segment_idx) { Polygon poly(true); - poly.push_back(segments[start_segment_idx].start); + poly.push_back(segments_[start_segment_idx].start); for (int segment_idx = start_segment_idx; segment_idx != -1;) { - SlicerSegment& segment = segments[segment_idx]; + SlicerSegment& segment = segments_[segment_idx]; poly.push_back(segment.end); segment.addedToPolygon = true; segment_idx = getNextSegmentIdx(segment, start_segment_idx); if (segment_idx == static_cast(start_segment_idx)) { // polyon is closed - polygons.push_back(std::move(poly)); + polygons_.push_back(std::move(poly)); return; } } @@ -67,13 +67,13 @@ void SlicerLayer::makeBasicPolygonLoop(OpenLinesSet& open_polylines, const size_ int SlicerLayer::tryFaceNextSegmentIdx(const SlicerSegment& segment, const int face_idx, const size_t start_segment_idx) const { - decltype(face_idx_to_segment_idx.begin()) it; - auto it_end = face_idx_to_segment_idx.end(); - it = face_idx_to_segment_idx.find(face_idx); + decltype(face_idx_to_segment_idx_.begin()) it; + auto it_end = face_idx_to_segment_idx_.end(); + it = face_idx_to_segment_idx_.find(face_idx); if (it != it_end) { const int segment_idx = (*it).second; - Point2LL p1 = segments[segment_idx].start; + Point2LL p1 = segments_[segment_idx].start; Point2LL diff = segment.end - p1; if (shorterThen(diff, largest_neglected_gap_first_phase)) { @@ -81,7 +81,7 @@ int SlicerLayer::tryFaceNextSegmentIdx(const SlicerSegment& segment, const int f { return start_segment_idx; } - if (segments[segment_idx].addedToPolygon) + if (segments_[segment_idx].addedToPolygon) { return -1; } @@ -494,7 +494,7 @@ void SlicerLayer::connectOpenPolylinesImpl(OpenLinesSet& open_polylines, coord_t { // finished polygon OpenPolyline& polyline_0 = open_polylines[best_polyline_0_idx]; - polygons.push_back(Polygon(std::move(polyline_0.getPoints()), true)); // Will also clear the polyline + polygons_.push_back(Polygon(std::move(polyline_0.getPoints()), true)); // Will also clear the polyline Terminus cur_terms[2] = { { best_polyline_0_idx, false }, { best_polyline_0_idx, true } }; for (size_t idx = 0U; idx != 2U; ++idx) { @@ -586,24 +586,24 @@ void SlicerLayer::stitch_extensive(OpenLinesSet& open_polylines) { if (best_result->pointIdxA == best_result->pointIdxB) { - polygons.push_back(Polygon(open_polylines[best_polyline_1_idx].getPoints(), true)); + polygons_.push_back(Polygon(open_polylines[best_polyline_1_idx].getPoints(), true)); open_polylines[best_polyline_1_idx].clear(); } else if (best_result->AtoB) { - Polygon& poly = polygons.newLine(); - for (unsigned int j = best_result->pointIdxA; j != best_result->pointIdxB; j = (j + 1) % polygons[best_result->polygonIdx].size()) - poly.push_back(polygons[best_result->polygonIdx][j]); + Polygon& poly = polygons_.newLine(); + for (unsigned int j = best_result->pointIdxA; j != best_result->pointIdxB; j = (j + 1) % polygons_[best_result->polygonIdx].size()) + poly.push_back(polygons_[best_result->polygonIdx][j]); for (unsigned int j = open_polylines[best_polyline_1_idx].size() - 1; int(j) >= 0; j--) poly.push_back(open_polylines[best_polyline_1_idx][j]); open_polylines[best_polyline_1_idx].clear(); } else { - unsigned int n = polygons.size(); - polygons.push_back(Polygon(open_polylines[best_polyline_1_idx].getPoints(), true)); - for (unsigned int j = best_result->pointIdxB; j != best_result->pointIdxA; j = (j + 1) % polygons[best_result->polygonIdx].size()) - polygons[n].push_back(polygons[best_result->polygonIdx][j]); + unsigned int n = polygons_.size(); + polygons_.push_back(Polygon(open_polylines[best_polyline_1_idx].getPoints(), true)); + for (unsigned int j = best_result->pointIdxB; j != best_result->pointIdxA; j = (j + 1) % polygons_[best_result->polygonIdx].size()) + polygons_[n].push_back(polygons_[best_result->polygonIdx][j]); open_polylines[best_polyline_1_idx].clear(); } } @@ -618,8 +618,8 @@ void SlicerLayer::stitch_extensive(OpenLinesSet& open_polylines) else if (best_result->AtoB) { Polygon poly; - for (unsigned int n = best_result->pointIdxA; n != best_result->pointIdxB; n = (n + 1) % polygons[best_result->polygonIdx].size()) - poly.push_back(polygons[best_result->polygonIdx][n]); + for (unsigned int n = best_result->pointIdxA; n != best_result->pointIdxB; n = (n + 1) % polygons_[best_result->polygonIdx].size()) + poly.push_back(polygons_[best_result->polygonIdx][n]); for (unsigned int n = poly.size() - 1; int(n) >= 0; n--) open_polylines[best_polyline_2_idx].push_back(poly[n]); for (unsigned int n = 0; n < open_polylines[best_polyline_1_idx].size(); n++) @@ -628,8 +628,8 @@ void SlicerLayer::stitch_extensive(OpenLinesSet& open_polylines) } else { - for (unsigned int n = best_result->pointIdxB; n != best_result->pointIdxA; n = (n + 1) % polygons[best_result->polygonIdx].size()) - open_polylines[best_polyline_2_idx].push_back(polygons[best_result->polygonIdx][n]); + for (unsigned int n = best_result->pointIdxB; n != best_result->pointIdxA; n = (n + 1) % polygons_[best_result->polygonIdx].size()) + open_polylines[best_polyline_2_idx].push_back(polygons_[best_result->polygonIdx][n]); for (unsigned int n = open_polylines[best_polyline_1_idx].size() - 1; int(n) >= 0; n--) open_polylines[best_polyline_2_idx].push_back(open_polylines[best_polyline_1_idx][n]); open_polylines[best_polyline_1_idx].clear(); @@ -666,21 +666,21 @@ std::optional SlicerLayer::findPolygonGapCloser(Point2LL ip0, P else { // Find out if we have should go from A to B or the other way around. - Point2LL p0 = polygons[ret.polygonIdx][ret.pointIdxA]; + Point2LL p0 = polygons_[ret.polygonIdx][ret.pointIdxA]; int64_t lenA = vSize(p0 - ip0); - for (unsigned int i = ret.pointIdxA; i != ret.pointIdxB; i = (i + 1) % polygons[ret.polygonIdx].size()) + for (unsigned int i = ret.pointIdxA; i != ret.pointIdxB; i = (i + 1) % polygons_[ret.polygonIdx].size()) { - Point2LL p1 = polygons[ret.polygonIdx][i]; + Point2LL p1 = polygons_[ret.polygonIdx][i]; lenA += vSize(p0 - p1); p0 = p1; } lenA += vSize(p0 - ip1); - p0 = polygons[ret.polygonIdx][ret.pointIdxB]; + p0 = polygons_[ret.polygonIdx][ret.pointIdxB]; int64_t lenB = vSize(p0 - ip1); - for (unsigned int i = ret.pointIdxB; i != ret.pointIdxA; i = (i + 1) % polygons[ret.polygonIdx].size()) + for (unsigned int i = ret.pointIdxB; i != ret.pointIdxA; i = (i + 1) % polygons_[ret.polygonIdx].size()) { - Point2LL p1 = polygons[ret.polygonIdx][i]; + Point2LL p1 = polygons_[ret.polygonIdx][i]; lenB += vSize(p0 - p1); p0 = p1; } @@ -702,12 +702,12 @@ std::optional SlicerLayer::findPolygonGapCloser(Point2LL ip0, P std::optional SlicerLayer::findPolygonPointClosestTo(Point2LL input) { - for (size_t n = 0; n < polygons.size(); n++) + for (size_t n = 0; n < polygons_.size(); n++) { - Point2LL p0 = polygons[n][polygons[n].size() - 1]; - for (size_t i = 0; i < polygons[n].size(); i++) + Point2LL p0 = polygons_[n][polygons_[n].size() - 1]; + for (size_t i = 0; i < polygons_[n].size(); i++) { - Point2LL p1 = polygons[n][i]; + Point2LL p1 = polygons_[n][i]; // Q = A + Normal( B - A ) * ((( B - A ) dot ( P - A )) / VSize( A - B )); Point2LL pDiff = p1 - p0; @@ -760,7 +760,7 @@ void SlicerLayer::makePolygons(const Mesh* mesh) { for (const OpenPolyline& polyline : open_polylines) { - polygons.push_back(Polygon(polyline.getPoints(), false), CheckNonEmptyParam::OnlyIfNotEmpty); + polygons_.push_back(Polygon(polyline.getPoints(), false), CheckNonEmptyParam::OnlyIfNotEmpty); } } @@ -772,17 +772,17 @@ void SlicerLayer::makePolygons(const Mesh* mesh) // Remove all the tiny polygons, or polygons that are not closed. As they do not contribute to the actual print. const coord_t snap_distance = std::max(mesh->settings_.get("minimum_polygon_circumference"), static_cast(1)); auto itPolygons = std::remove_if( - polygons.begin(), - polygons.end(), + polygons_.begin(), + polygons_.end(), [snap_distance](const Polygon& poly) { return poly.shorterThan(snap_distance); }); - polygons.erase(itPolygons, polygons.end()); + polygons_.erase(itPolygons, polygons_.end()); // Finally optimize all the polygons. Every point removed saves time in the long run. - polygons = Simplify(mesh->settings_).polygon(polygons); - polygons.removeDegenerateVerts(); // remove verts connected to overlapping line segments + polygons_ = Simplify(mesh->settings_).polygon(polygons_); + polygons_.removeDegenerateVerts(); // remove verts connected to overlapping line segments // Clean up polylines for Surface Mode printing auto itPolylines = std::remove_if( @@ -838,8 +838,8 @@ void Slicer::buildSegments(const Mesh& mesh, const std::vector Slicer::buildLayersWithHeight( layers_res.resize(slice_layer_count); // set (and initialize compensation for) initial layer, depending on slicing mode - layers_res[0].z = slicing_tolerance == SlicingTolerance::INCLUSIVE ? 0 : std::max(0LL, initial_layer_thickness - thickness); + layers_res[0].z_ = slicing_tolerance == SlicingTolerance::INCLUSIVE ? 0 : std::max(0LL, initial_layer_thickness - thickness); coord_t adjusted_layer_offset = initial_layer_thickness; if (use_variable_layer_heights) { - layers_res[0].z = (*adaptive_layers)[0].z_position_; + layers_res[0].z_ = (*adaptive_layers)[0].z_position_; } else if (slicing_tolerance == SlicingTolerance::MIDDLE) { - layers_res[0].z = initial_layer_thickness / 2; + layers_res[0].z_ = initial_layer_thickness / 2; adjusted_layer_offset = initial_layer_thickness + (thickness / 2); } @@ -993,11 +993,11 @@ std::vector Slicer::buildLayersWithHeight( { if (use_variable_layer_heights) { - layers_res[layer_nr].z = (*adaptive_layers)[layer_nr].z_position_; + layers_res[layer_nr].z_ = (*adaptive_layers)[layer_nr].z_position_; } else { - layers_res[layer_nr].z = adjusted_layer_offset + (thickness * (layer_nr - 1)); + layers_res[layer_nr].z_ = adjusted_layer_offset + (thickness * (layer_nr - 1)); } } @@ -1018,15 +1018,15 @@ void Slicer::makePolygons(Mesh& mesh, SlicingTolerance slicing_tolerance, std::v case SlicingTolerance::INCLUSIVE: for (LayerIndex layer_nr = 0; layer_nr + 1 < layers.size(); layer_nr++) { - layers[layer_nr].polygons = layers[layer_nr].polygons.unionPolygons(layers[layer_nr + 1].polygons); + layers[layer_nr].polygons_ = layers[layer_nr].polygons_.unionPolygons(layers[layer_nr + 1].polygons_); } break; case SlicingTolerance::EXCLUSIVE: for (LayerIndex layer_nr = 0; layer_nr + 1 < layers.size(); layer_nr++) { - layers[layer_nr].polygons = layers[layer_nr].polygons.intersection(layers[layer_nr + 1].polygons); + layers[layer_nr].polygons_ = layers[layer_nr].polygons_.intersection(layers[layer_nr + 1].polygons_); } - layers.back().polygons.clear(); + layers.back().polygons_.clear(); break; case SlicingTolerance::MIDDLE: default: @@ -1035,7 +1035,7 @@ void Slicer::makePolygons(Mesh& mesh, SlicingTolerance slicing_tolerance, std::v } size_t layer_apply_initial_xy_offset = 0; - if (layers.size() > 0 && layers[0].polygons.size() == 0 && ! mesh.settings_.get("support_mesh") && ! mesh.settings_.get("anti_overhang_mesh") + if (layers.size() > 0 && layers[0].polygons_.size() == 0 && ! mesh.settings_.get("support_mesh") && ! mesh.settings_.get("anti_overhang_mesh") && ! mesh.settings_.get("cutting_mesh") && ! mesh.settings_.get("infill_mesh")) { layer_apply_initial_xy_offset = 1; @@ -1057,12 +1057,12 @@ void Slicer::makePolygons(Mesh& mesh, SlicingTolerance slicing_tolerance, std::v const auto xy_offset_local = (layer_nr <= layer_apply_initial_xy_offset) ? xy_offset_0 : xy_offset; if (xy_offset_local != 0) { - layers[layer_nr].polygons = layers[layer_nr].polygons.offset(xy_offset_local, ClipperLib::JoinType::jtRound); + layers[layer_nr].polygons_ = layers[layer_nr].polygons_.offset(xy_offset_local, ClipperLib::JoinType::jtRound); } if (xy_offset_hole != 0) { - const auto parts = layers[layer_nr].polygons.splitIntoParts(); - layers[layer_nr].polygons.clear(); + const auto parts = layers[layer_nr].polygons_.splitIntoParts(); + layers[layer_nr].polygons_.clear(); for (const auto& part : parts) { @@ -1095,7 +1095,7 @@ void Slicer::makePolygons(Mesh& mesh, SlicingTolerance slicing_tolerance, std::v } } - layers[layer_nr].polygons.push_back(outline.difference(holes.unionPolygons())); + layers[layer_nr].polygons_.push_back(outline.difference(holes.unionPolygons())); } } }); diff --git a/src/support.cpp b/src/support.cpp index eec1dc2c3e..a432da3d58 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -62,13 +62,13 @@ bool AreaSupport::handleSupportModifierMesh(SliceDataStorage& storage, const Set switch (modifier_type) { case ANTI_OVERHANG: - support_layer.anti_overhang.push_back(slicer_layer.polygons); + support_layer.anti_overhang.push_back(slicer_layer.polygons_); break; case SUPPORT_DROP_DOWN: - support_layer.support_mesh_drop_down.push_back(slicer_layer.polygons); + support_layer.support_mesh_drop_down.push_back(slicer_layer.polygons_); break; case SUPPORT_VANILLA: - support_layer.support_mesh.push_back(slicer_layer.polygons); + support_layer.support_mesh.push_back(slicer_layer.polygons_); break; } } diff --git a/tests/integration/SlicePhaseTest.cpp b/tests/integration/SlicePhaseTest.cpp index a746e0851b..cfb9557024 100644 --- a/tests/integration/SlicePhaseTest.cpp +++ b/tests/integration/SlicePhaseTest.cpp @@ -12,7 +12,7 @@ #include "slicer.h" // Starts the slicing phase that we want to test. #include "utils/Coord_t.h" #include "utils/Matrix4x3D.h" // To load STL files. -#include "utils/polygonUtils.h" // Comparing similarity of polygons. +#include "utils/polygonUtils.h" // Comparing similarity of polygons_. namespace cura { @@ -96,10 +96,10 @@ TEST_F(SlicePhaseTest, Cube) for (size_t layer_nr = 0; layer_nr < num_layers; layer_nr++) { const SlicerLayer& layer = slicer.layers[layer_nr]; - EXPECT_EQ(layer.polygons.size(), 1); - if (layer.polygons.size() == 1) + EXPECT_EQ(layer.polygons_.size(), 1); + if (layer.polygons_.size() == 1) { - Polygon sliced_polygon = layer.polygons[0]; + Polygon sliced_polygon = layer.polygons_[0]; EXPECT_EQ(sliced_polygon.size(), square.size()); if (sliced_polygon.size() == square.size()) { @@ -164,13 +164,13 @@ TEST_F(SlicePhaseTest, Cylinder1000) for (size_t layer_nr = 0; layer_nr < num_layers; layer_nr++) { const SlicerLayer& layer = slicer.layers[layer_nr]; - EXPECT_EQ(layer.polygons.size(), 1); - if (layer.polygons.size() == 1) + EXPECT_EQ(layer.polygons_.size(), 1); + if (layer.polygons_.size() == 1) { - Polygon sliced_polygon = layer.polygons[0]; + Polygon sliced_polygon = layer.polygons_[0]; // Due to the reduction in resolution, the final slice will not have the same vertices as the input. // Let's say that are allowed to be up to 1/500th of the surface area off. - EXPECT_LE(PolygonUtils::relativeHammingDistance(layer.polygons, circles), 0.002); + EXPECT_LE(PolygonUtils::relativeHammingDistance(layer.polygons_, circles), 0.002); } } } From 7d0b21e6d797a3e2b769106e40cf9c7479e7cfbc Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 8 May 2024 12:41:52 +0200 Subject: [PATCH 108/135] Add a new option to append a line to a set Now it is possible to check for global validity of a polyline, based on number of points. CURA-9830 --- include/geometry/LinesSet.h | 4 ++++ src/geometry/LinesSet.cpp | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index 4d4cba8ad1..1e885cb89c 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -21,6 +21,7 @@ class OpenPolyline; enum class CheckNonEmptyParam { + OnlyIfValid, OnlyIfNotEmpty, EvenIfEmpty }; @@ -288,6 +289,9 @@ class LinesSet os << "]"; return os; } + +private: + bool checkAdd(const LineType& line, CheckNonEmptyParam check_non_empty); }; } // namespace cura diff --git a/src/geometry/LinesSet.cpp b/src/geometry/LinesSet.cpp index ae36f47f4d..039931812a 100644 --- a/src/geometry/LinesSet.cpp +++ b/src/geometry/LinesSet.cpp @@ -14,10 +14,26 @@ namespace cura { +template +bool LinesSet::checkAdd(const LineType& line, CheckNonEmptyParam check_non_empty) +{ + switch (check_non_empty) + { + case CheckNonEmptyParam::EvenIfEmpty: + return true; + case CheckNonEmptyParam::OnlyIfNotEmpty: + return ! line.empty(); + case CheckNonEmptyParam::OnlyIfValid: + return line.isValid(); + } + + return false; +} + template void LinesSet::push_back(const LineType& line, CheckNonEmptyParam check_non_empty) { - if (check_non_empty == CheckNonEmptyParam::EvenIfEmpty || ! line.empty()) + if (checkAdd(line, check_non_empty)) { lines_.push_back(line); } @@ -26,7 +42,7 @@ void LinesSet::push_back(const LineType& line, CheckNonEmptyParam chec template void LinesSet::push_back(LineType&& line, CheckNonEmptyParam check_non_empty) { - if (check_non_empty == CheckNonEmptyParam::EvenIfEmpty || ! line.empty()) + if (checkAdd(line, check_non_empty)) { lines_.push_back(std::move(line)); } From 42ad7560af678c890d65d0b24d6ca33b2de2fe30 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 8 May 2024 12:42:58 +0200 Subject: [PATCH 109/135] Restore line emptyness check when symplifying This was a regression of the behavior compared to before the geometry classes refactoring. Just restoring this behavior. CURA-9830 --- src/utils/Simplify.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/Simplify.cpp b/src/utils/Simplify.cpp index e1802165ba..a7c38d496c 100644 --- a/src/utils/Simplify.cpp +++ b/src/utils/Simplify.cpp @@ -58,7 +58,7 @@ LinesSet Simplify::polyline(const LinesSet& polylines) const LinesSet result; for (size_t i = 0; i < polylines.size(); ++i) { - result.push_back(polyline(polylines[i])); + result.push_back(polyline(polylines[i]), CheckNonEmptyParam::OnlyIfNotEmpty); } return result; } From 64e94c086ccbf31c59f1de333f0d30dc0543596f Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 8 May 2024 17:09:30 +0200 Subject: [PATCH 110/135] Fix missing polygons when using simplify When simplifying polygons, more polygons could be returned than initially. The new simplify implementation didn't handle this case, and polygons could be lost. We now resize the list to the proper polygons count. CURA-9830 --- src/geometry/Shape.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/geometry/Shape.cpp b/src/geometry/Shape.cpp index 2145ec5d70..8156bb5fa2 100644 --- a/src/geometry/Shape.cpp +++ b/src/geometry/Shape.cpp @@ -842,16 +842,20 @@ void Shape::simplify(ClipperLib::PolyFillType fill_type) } // This is the actual content from clipper.cpp::SimplifyPolygons, but rewritten here in order - // to avoid a list copy + // to avoid having to put all the polygons in a transitory list ClipperLib::Clipper clipper; ClipperLib::Paths ret; clipper.StrictlySimple(true); addPaths(clipper, ClipperLib::ptSubject); clipper.Execute(ClipperLib::ctUnion, ret, fill_type, fill_type); - for (size_t i = 0; i < size(); ++i) + resize(ret.size()); + + for (size_t i = 0; i < ret.size(); i++) { - getLines()[i].setPoints(std::move(ret[i])); + Polygon& polygon = getLines()[i]; + polygon.setExplicitelyClosed(clipper_explicitely_closed_); // Required for polygon newly created by resize() + polygon.setPoints(std::move(ret[i])); } } From b847f92fa5d5ed90bbd401a300297ef0622f4a65 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 10 May 2024 10:09:59 +0200 Subject: [PATCH 111/135] Add cura resources as optional Conan dependency This update adds an optional dependency to 'cura_resources' in the 'conandata.yml' and 'conanfile.py'. Another significant change is in the 'gcodeanalyzer.yml' where the steps to checkout Cura and the associated environment variables have been removed in favor of adding the Cura resources directly to the Conan install command. Contribute to NP-186 --- .github/workflows/gcodeanalyzer.yml | 25 +------------------------ conandata.yml | 2 ++ conanfile.py | 5 +++++ 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/.github/workflows/gcodeanalyzer.yml b/.github/workflows/gcodeanalyzer.yml index 29c83817de..8bcc738422 100644 --- a/.github/workflows/gcodeanalyzer.yml +++ b/.github/workflows/gcodeanalyzer.yml @@ -81,28 +81,6 @@ jobs: fetch-depth: 1 token: ${{ secrets.GITHUB_TOKEN }} - - name: Determine the corresponding Cura branch - id: curabranch - run: | - status_code=$(curl -s -o /dev/null -w "%{http_code}" "https://api.github.com/repos/ultimaker/cura/branches/${{ github.head_ref }}") - if [ "$status_code" -eq 200 ]; then - echo "The branch exists in Cura" - echo "branch=${{ github.head_ref }}" >> $GITHUB_OUTPUT - else - echo "branch=main" >> $GITHUB_OUTPUT - fi - - - name: Checkout Cura - uses: actions/checkout@v3 - with: - repository: 'Ultimaker/Cura' - ref: ${{ steps.curabranch.outputs.branch}} - path: 'Cura' - fetch-depth: 1 - sparse-checkout: | - resources/definitions - resources/extruders - - name: Sync pip requirements run: curl -O https://raw.githubusercontent.com/Ultimaker/cura-workflows/main/.github/workflows/requirements-runner.txt working-directory: CuraEngine/.github/workflows @@ -159,7 +137,7 @@ jobs: ${{ runner.os }}-conan-downloads- - name: Install dependencies - run: conan install . ${{ needs.conan-recipe-version.outputs.recipe_id_full }} -s build_type=Release --build=missing --update -g GitHubActionsRunEnv -g GitHubActionsBuildEnv -c tools.build:skip_test=True + run: conan install . ${{ needs.conan-recipe-version.outputs.recipe_id_full }} -s build_type=Release --build=missing --update -g GitHubActionsRunEnv -g GitHubActionsBuildEnv -c tools.build:skip_test=True -o with_cura_resources=True working-directory: CuraEngine - name: Set Environment variables from Conan install (bash) @@ -167,7 +145,6 @@ jobs: run: | . ./activate_github_actions_runenv.sh . ./activate_github_actions_buildenv.sh - echo "CURA_ENGINE_SEARCH_PATH=$GITHUB_WORKSPACE/Cura/resources/definitions:$GITHUB_WORKSPACE/Cura/resources/extruders" >> $GITHUB_ENV working-directory: CuraEngine/build/Release/generators - name: Build CuraEngine and tests diff --git a/conandata.yml b/conandata.yml index 858634c9a0..38e20233f1 100644 --- a/conandata.yml +++ b/conandata.yml @@ -5,3 +5,5 @@ requirements_arcus: - "arcus/5.3.1" requirements_plugins: - "curaengine_grpc_definitions/(latest)@ultimaker/testing" +requirements_cura_resources: + - "cura_resources/(latest)@ultimaker/testing" diff --git a/conanfile.py b/conanfile.py index a696e03a1c..127a23576f 100644 --- a/conanfile.py +++ b/conanfile.py @@ -32,6 +32,7 @@ class CuraEngineConan(ConanFile): "enable_plugins": [True, False], "enable_sentry": [True, False], "enable_remote_plugins": [True, False], + "with_cura_resources": [True, False], } default_options = { "enable_arcus": True, @@ -40,6 +41,7 @@ class CuraEngineConan(ConanFile): "enable_plugins": True, "enable_sentry": False, "enable_remote_plugins": False, + "with_cura_resources": False, } def set_version(self): @@ -116,6 +118,9 @@ def requirements(self): self.requires("grpc/1.50.1") for req in self.conan_data["requirements_plugins"]: self.requires(req) + if self.options.with_cura_resources: + for req in self.conan_data["requirements_cura_resources"]: + self.requires(req) if self.options.enable_arcus or self.options.enable_plugins: self.requires("protobuf/3.21.12") self.requires("clipper/6.4.2@ultimaker/stable") From bf3442f4f644ffd1731a0870c3fce434a34ddedf Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 10 May 2024 11:21:28 +0200 Subject: [PATCH 112/135] Use current branch Contribute to NP-186 --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index 38e20233f1..124b6af3d3 100644 --- a/conandata.yml +++ b/conandata.yml @@ -6,4 +6,4 @@ requirements_arcus: requirements_plugins: - "curaengine_grpc_definitions/(latest)@ultimaker/testing" requirements_cura_resources: - - "cura_resources/(latest)@ultimaker/testing" + - "cura_resources/(latest)@ultimaker/np_186" From cd2a5af11fc15f885930ac4de247fe472a0c2fb8 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 10 May 2024 11:43:58 +0200 Subject: [PATCH 113/135] Use `CURA_RESOURCES` variable Contribute to NP-186 --- .github/workflows/gcodeanalyzer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gcodeanalyzer.yml b/.github/workflows/gcodeanalyzer.yml index 8bcc738422..0b85fb75aa 100644 --- a/.github/workflows/gcodeanalyzer.yml +++ b/.github/workflows/gcodeanalyzer.yml @@ -157,7 +157,7 @@ jobs: run: | for file in `ls ../NightlyTestModels/*.stl`; do - ( time ./build/Release/CuraEngine slice --force-read-parent --force-read-nondefault -v -p -j ../Cura/resources/definitions/ultimaker_s3.def.json -l $file -o ../`basename $file .stl`.gcode ) 2> ../`basename $file .stl`.time + ( time ./build/Release/CuraEngine slice --force-read-parent --force-read-nondefault -v -p -j $CURA_RESOURCES/definitions/ultimaker_s3.def.json -l $file -o ../`basename $file .stl`.gcode ) 2> ../`basename $file .stl`.time done working-directory: CuraEngine From 33701fecec0879fcb19a57837cfba79bb8ef0eed Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Fri, 10 May 2024 13:31:48 +0200 Subject: [PATCH 114/135] Use `testing` for cura_resources Contribute to NP-186 --- conandata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conandata.yml b/conandata.yml index 124b6af3d3..38e20233f1 100644 --- a/conandata.yml +++ b/conandata.yml @@ -6,4 +6,4 @@ requirements_arcus: requirements_plugins: - "curaengine_grpc_definitions/(latest)@ultimaker/testing" requirements_cura_resources: - - "cura_resources/(latest)@ultimaker/np_186" + - "cura_resources/(latest)@ultimaker/testing" From 0792ef37010e251caabbaab5bab85681faa27a71 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 13 May 2024 11:29:49 +0200 Subject: [PATCH 115/135] Update Conan package workflow to run on PR events This commit modifies the Conan package GitHub action to also be triggered by pull request events, in addition to the existing push events. The action will now run whenever a PR is opened, reopened, or updated, and it's limited to changes in specific paths like 'include/**', 'src/**', etc. on the main branch. This will ensure that the package creation is verified on relevant pull requests. Contribute to CURA-9830 --- .github/workflows/conan-package.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/conan-package.yml b/.github/workflows/conan-package.yml index 0acc07d220..4e3f3c18bf 100644 --- a/.github/workflows/conan-package.yml +++ b/.github/workflows/conan-package.yml @@ -20,6 +20,18 @@ on: tags: - '[0-9]+.[0-9]+.[0-9]*' - '[0-9]+.[0-9]+.[0-9]' + pull_request: + types: [opened, reopened, synchronize] + paths: + - 'include/**' + - 'src/**' + - 'test_package/**' + - 'conanfile.py' + - 'conandata.yml' + - 'CMakeLists.txt' + - '.github/workflows/conan-package.yml' + branches: + - main jobs: conan-recipe-version: @@ -37,7 +49,7 @@ jobs: conan-package-create-macos: needs: [ conan-recipe-version, conan-package-export ] - if: ${{ (github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }} + if: ${{ ((github.event_name == 'push' || github.event_name == 'pull_request') && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }} uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-macos.yml@main with: recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} @@ -45,7 +57,7 @@ jobs: conan-package-create-windows: needs: [ conan-recipe-version, conan-package-export ] - if: ${{ (github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }} + if: ${{ ((github.event_name == 'push' || github.event_name == 'pull_request') && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }} uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-windows.yml@main with: recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} @@ -53,7 +65,7 @@ jobs: conan-package-create-linux: needs: [ conan-recipe-version, conan-package-export ] - if: ${{ (github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }} + if: ${{ ((github.event_name == 'push' || github.event_name == 'pull_request') && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }} uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-linux.yml@main with: recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} From 40ed0cdb8a0ba1a7b0c154a2c0de6fda0b784202 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 13 May 2024 11:35:26 +0200 Subject: [PATCH 116/135] Always run on PR Contribute to CURA-9830 --- .github/workflows/conan-package.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/conan-package.yml b/.github/workflows/conan-package.yml index 4e3f3c18bf..64ab6141b3 100644 --- a/.github/workflows/conan-package.yml +++ b/.github/workflows/conan-package.yml @@ -32,6 +32,11 @@ on: - '.github/workflows/conan-package.yml' branches: - main + - 'CURA-*' + - 'PP-*' + - 'NP-*' + - '[0-9].[0-9]*' + - '[0-9].[0-9][0-9]*' jobs: conan-recipe-version: @@ -49,7 +54,7 @@ jobs: conan-package-create-macos: needs: [ conan-recipe-version, conan-package-export ] - if: ${{ ((github.event_name == 'push' || github.event_name == 'pull_request') && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }} + if: ${{ ((github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) || github.event_name == 'pull_request') }} uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-macos.yml@main with: recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} @@ -57,7 +62,7 @@ jobs: conan-package-create-windows: needs: [ conan-recipe-version, conan-package-export ] - if: ${{ ((github.event_name == 'push' || github.event_name == 'pull_request') && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }} + if: ${{ ((github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) || github.event_name == 'pull_request') }} uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-windows.yml@main with: recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} @@ -65,7 +70,7 @@ jobs: conan-package-create-linux: needs: [ conan-recipe-version, conan-package-export ] - if: ${{ ((github.event_name == 'push' || github.event_name == 'pull_request') && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }} + if: ${{ ((github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) || github.event_name == 'pull_request') }} uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-linux.yml@main with: recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} From bab08d12f843f22a0d401eaaedaa8b6211ddffbe Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Fri, 17 May 2024 10:02:13 +0200 Subject: [PATCH 117/135] Fix wrong class name which causes a build fail CURA-9830 --- src/utils/polygonUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/polygonUtils.cpp b/src/utils/polygonUtils.cpp index bdcf0f799f..84f367c586 100644 --- a/src/utils/polygonUtils.cpp +++ b/src/utils/polygonUtils.cpp @@ -693,7 +693,7 @@ ClosestPointPolygon PolygonUtils::ensureInsideOrOutside( bool overall_is_inside = polygons.inside(overall_inside.location_); if (overall_is_inside != (preferred_dist_inside > 0)) { - return ClosestPolygonPoint(); + return ClosestPointPolygon(); } inside = overall_inside; } From ed10d7d2e67613da835cf8454dfb419c56cd64f7 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 23 May 2024 13:09:25 +0200 Subject: [PATCH 118/135] Add some missing imports NP-205 --- include/geometry/LinesSet.h | 1 + include/settings/types/LayerIndex.h | 1 + include/slicer.h | 1 + 3 files changed, 3 insertions(+) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index 1e885cb89c..a344e763b5 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -9,6 +9,7 @@ #include #include "geometry/OpenLinesSet.h" +#include "geometry/Polygon.h" #include "geometry/Point2LL.h" namespace cura diff --git a/include/settings/types/LayerIndex.h b/include/settings/types/LayerIndex.h index 9e2100da87..a4de451913 100644 --- a/include/settings/types/LayerIndex.h +++ b/include/settings/types/LayerIndex.h @@ -9,6 +9,7 @@ #include #include "utils/types/generic.h" +#include "geometry/Polygon.h" namespace cura { diff --git a/include/slicer.h b/include/slicer.h index ddafd67ca3..e3d3500fe1 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -11,6 +11,7 @@ #include "geometry/LinesSet.h" #include "geometry/OpenLinesSet.h" #include "geometry/OpenPolyline.h" +#include "geometry/Polygon.h" #include "geometry/Shape.h" #include "settings/EnumSettings.h" From 0b161852a0d197dbbc6f0fe47d4566777dc5d046 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 23 May 2024 13:10:14 +0200 Subject: [PATCH 119/135] Don't use `NoCopy` class to prevent copying But delete copy operator/assignment instead NP-205 --- include/MeshGroup.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/MeshGroup.h b/include/MeshGroup.h index 232bf08662..6f20523f4a 100644 --- a/include/MeshGroup.h +++ b/include/MeshGroup.h @@ -18,9 +18,21 @@ class Matrix4x3D; * One MeshGroup is a whole which is printed at once. * Generally there is one single MeshGroup, though when using one-at-a-time printing, multiple MeshGroups are processed consecutively. */ -class MeshGroup : public NoCopy +class MeshGroup { public: + MeshGroup() = default; + + ~MeshGroup() = default; + + MeshGroup(MeshGroup&& other) noexcept = default; + + MeshGroup& operator=(MeshGroup&& other) noexcept = default; + + /* Copying a MeshGroup is not allowed */ + MeshGroup(const MeshGroup& other) = delete; + MeshGroup& operator=(const MeshGroup& other) = delete; + std::vector meshes; Settings settings; From f1ad7840f777896cdf45003add0fec85b203904c Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 23 May 2024 15:21:42 +0200 Subject: [PATCH 120/135] Add command line option to parse json's NP-205 --- include/communication/CommandLine.h | 15 +++ src/Application.cpp | 1 + src/MeshGroup.cpp | 5 + src/communication/CommandLine.cpp | 155 ++++++++++++++++++++++++++++ 4 files changed, 176 insertions(+) diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index 47b27f6586..5f70994517 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -5,6 +5,7 @@ #define COMMANDLINE_H #include +#include #include //Loading JSON documents to get settings from them. #include //To store the command line arguments. #include //To store the command line arguments. @@ -212,6 +213,20 @@ class CommandLine : public Communication * \return The first definition file that matches the definition ID. */ static std::string findDefinitionFile(const std::string& definition_id, const std::vector& search_directories); + + /* + * \brief Read the resolved JSON values from a file. + * \param element The path to the file to read the JSON values from. + * \return The resolved JSON values. + */ + static std::optional>> readResolvedJsonValues(const std::filesystem::path& element); + + /* + * \brief Read the resolved JSON values from a document. + * \param document The document to read the JSON values from. + * \return The resolved JSON values. + */ + static std::optional>> readResolvedJsonValues(const rapidjson::Document& document); }; } // namespace cura diff --git a/src/Application.cpp b/src/Application.cpp index 14f5a1bf7d..cb0f17b297 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -131,6 +131,7 @@ void Application::printHelp() const fmt::print(" -p\n\tLog progress information.\n"); fmt::print(" -d Add definition search paths seperated by a `:` (Unix) or `;` (Windows)\n"); fmt::print(" -j\n\tLoad settings.def.json file to register all settings and their defaults.\n"); + fmt::print(" -r\n\tLoad a json file containing resolved setting values.\n"); fmt::print(" -s =\n\tSet a setting to a value for the last supplied object, \n\textruder train, or general settings.\n"); fmt::print(" -l \n\tLoad an STL model. \n"); fmt::print(" -g\n\tSwitch setting focus to the current mesh group only.\n\tUsed for one-at-a-time printing.\n"); diff --git a/src/MeshGroup.cpp b/src/MeshGroup.cpp index f71b2f7bd5..b518d77328 100644 --- a/src/MeshGroup.cpp +++ b/src/MeshGroup.cpp @@ -293,6 +293,11 @@ bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, const Mat spdlog::info("loading '{}' took {:03.3f} seconds", filename, load_timer.restart()); return true; } + else + { + spdlog::warn("loading '{}' failed", filename); + return false; + } } spdlog::warn("Unable to recognize the extension of the file. Currently only .stl and .STL are supported."); return false; diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index de88960fbf..fb078b0df7 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -8,12 +8,16 @@ #include #include //To check if files exist. #include //For std::accumulate. +#include #include //Loading JSON documents to get settings from them. #include #include #include #include +#include +#include #include +#include #include #include @@ -22,6 +26,7 @@ #include "Application.h" //To get the extruders for material estimates. #include "ExtruderTrain.h" #include "FffProcessor.h" //To start a slice and get time estimates. +#include "MeshGroup.h" #include "Slice.h" #include "utils/Matrix4x3D.h" //For the mesh_rotation_matrix setting. #include "utils/format/filesystem_path.h" @@ -354,6 +359,107 @@ void CommandLine::sliceNext() last_settings->add(key, value); break; } + case 'r': + { + // read in resolved values + + argument_index++; + if (argument_index >= arguments_.size()) + { + spdlog::error("Missing setting name and value with -s argument."); + exit(1); + } + argument = arguments_[argument_index]; + const auto settings = readResolvedJsonValues(std::filesystem::path{ argument }); + + if (! settings.has_value()) + { + spdlog::error("Failed to load JSON file: {}", argument); + exit(1); + } + + constexpr std::string_view global_identifier = "global"; + constexpr std::string_view extruder_identifier = "extruder."; + constexpr std::string_view model_identifier = "model."; + constexpr std::string_view limit_to_extruder_identifier = "limit_to_extruder"; + + // Split the settings into global, extruder and model settings. This is needed since the order in which the settings are applied is important. + // first global settings, then extruder settings, then model settings. The order of these stacks is not enforced in the JSON files. + std::unordered_map global_settings; + std::unordered_map> extruder_settings; + std::unordered_map> model_settings; + std::unordered_map limit_to_extruder; + + for (const auto& [key, values] : settings.value()) + { + if (key == global_identifier) + { + global_settings = values; + } + else if (key.starts_with(extruder_identifier)) + { + extruder_settings[key] = values; + } + else if (key == limit_to_extruder_identifier) + { + limit_to_extruder = values; + } + else + { + model_settings[key] = values; + } + } + + for (const auto& [setting_key, setting_value] : global_settings) + { + slice.scene.settings.add(setting_key, setting_value); + } + + for (const auto& [key, values] : extruder_settings) + { + const auto extruder_nr = std::stoi(key.substr(extruder_identifier.size())); + while (slice.scene.extruders.size() <= static_cast(extruder_nr)) + { + slice.scene.extruders.emplace_back(extruder_nr, &slice.scene.settings); + } + for (const auto& [setting_key, setting_value] : values) + { + slice.scene.extruders[extruder_nr].settings_.add(setting_key, setting_value); + } + } + + for (const auto& [key, values] : model_settings) + { + const auto model_name = key; + + cura::MeshGroup mesh_group; + for (const auto& [setting_key, setting_value] : values) + { + mesh_group.settings.add(setting_key, setting_value); + } + + const auto transformation = mesh_group.settings.get("mesh_rotation_matrix"); + const auto extruder_nr = mesh_group.settings.get("extruder_nr"); + + if (! loadMeshIntoMeshGroup(&mesh_group, model_name.c_str(), transformation, slice.scene.extruders[extruder_nr].settings_)) + { + spdlog::error("Failed to load model: {}. (error number {})", model_name, errno); + exit(1); + } + + slice.scene.mesh_groups.push_back(std::move(mesh_group)); + } + for (const auto& [key, value] : limit_to_extruder) + { + const auto extruder_nr = std::stoi(value.substr(extruder_identifier.size())); + if (extruder_nr >= 0) + { + slice.scene.limit_to_extruder[key] = &slice.scene.extruders[extruder_nr]; + } + } + + break; + } default: { spdlog::error("Unknown option: -{}", argument[1]); @@ -586,6 +692,55 @@ void CommandLine::loadJSONSettings(const rapidjson::Value& element, Settings& se } } +std::optional>> CommandLine::readResolvedJsonValues(const std::filesystem::path& json_filename) +{ + std::ifstream file(json_filename, std::ios::binary); + if (! file) + { + spdlog::error("Couldn't open JSON file: {}", json_filename); + return std::nullopt; + } + + std::vector read_buffer(std::istreambuf_iterator(file), {}); + rapidjson::MemoryStream memory_stream(read_buffer.data(), read_buffer.size()); + + rapidjson::Document json_document; + json_document.ParseStream(memory_stream); + if (json_document.HasParseError()) + { + spdlog::error("Error parsing JSON (offset {}): {}", json_document.GetErrorOffset(), GetParseError_En(json_document.GetParseError())); + return std::nullopt; + } + + return readResolvedJsonValues(json_document); +} + +std::optional>> CommandLine::readResolvedJsonValues(const rapidjson::Document& document) +{ + if (! document.IsObject()) + { + return std::nullopt; + } + + std::unordered_map> result; + for (rapidjson::Value::ConstMemberIterator resolved_key = document.MemberBegin(); resolved_key != document.MemberEnd(); resolved_key++) + { + std::unordered_map values; + for (rapidjson::Value::ConstMemberIterator resolved_value = resolved_key->value.MemberBegin(); resolved_value != resolved_key->value.MemberEnd(); resolved_value++) + { + std::string value_string; + if (! jsonValue2Str(resolved_value->value, value_string)) + { + spdlog::warn("Unrecognized data type in JSON setting {}", resolved_value->name.GetString()); + continue; + } + values.emplace(resolved_value->name.GetString(), value_string); + } + result.emplace(resolved_key->name.GetString(), std::move(values)); + } + return result; +} + std::string CommandLine::findDefinitionFile(const std::string& definition_id, const std::vector& search_directories) { for (const auto& search_directory : search_directories) From 1f66d0ee584321118957825b065dc863822a920f Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Thu, 23 May 2024 13:49:08 +0000 Subject: [PATCH 121/135] Applied clang-format. --- include/geometry/LinesSet.h | 2 +- include/settings/types/LayerIndex.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index a344e763b5..e76a1a77c7 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -9,8 +9,8 @@ #include #include "geometry/OpenLinesSet.h" -#include "geometry/Polygon.h" #include "geometry/Point2LL.h" +#include "geometry/Polygon.h" namespace cura { diff --git a/include/settings/types/LayerIndex.h b/include/settings/types/LayerIndex.h index a4de451913..d707c1eca2 100644 --- a/include/settings/types/LayerIndex.h +++ b/include/settings/types/LayerIndex.h @@ -8,8 +8,8 @@ #include -#include "utils/types/generic.h" #include "geometry/Polygon.h" +#include "utils/types/generic.h" namespace cura { From 7991a2d8714ef067a1e6a5385ea944c5f9f365ed Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 23 May 2024 17:02:18 +0200 Subject: [PATCH 122/135] Add missing import NP-205 --- include/communication/CommandLine.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index 5f70994517..f09f64cee2 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -6,6 +6,7 @@ #include #include +#include #include //Loading JSON documents to get settings from them. #include //To store the command line arguments. #include //To store the command line arguments. @@ -219,7 +220,7 @@ class CommandLine : public Communication * \param element The path to the file to read the JSON values from. * \return The resolved JSON values. */ - static std::optional>> readResolvedJsonValues(const std::filesystem::path& element); + static std::optional>> readResolvedJsonValues(const std::filesystem::path& json_filename); /* * \brief Read the resolved JSON values from a document. From 2977386be1323aaa64d1c93018480cd4c9244d03 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Thu, 23 May 2024 15:03:01 +0000 Subject: [PATCH 123/135] Applied clang-format. --- include/communication/CommandLine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index f09f64cee2..c277f61614 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -6,9 +6,9 @@ #include #include -#include #include //Loading JSON documents to get settings from them. #include //To store the command line arguments. +#include #include //To store the command line arguments. #include "Communication.h" //The class we're implementing. From ed9004ae312aaf32bef5b2ff71ca0bfe412364cd Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 23 May 2024 17:14:53 +0200 Subject: [PATCH 124/135] Add documentation regarding the format of the resolved json file NP-205 --- src/communication/CommandLine.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index fb078b0df7..040948c5b5 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -361,7 +361,27 @@ void CommandLine::sliceNext() } case 'r': { - // read in resolved values + /* + * read in resolved values from a json file. The json format of the file resolved settings is the following: + * + * ``` + * { + * "global": [SETTINGS], + * "extruder.0": [SETTINGS], + * "extruder.1": [SETTINGS], + * "model.stl": [SETTINGS] + * } + * ``` + * where `[SETTINGS]` follow the schema + * ``` + * { + * [key: string]: bool | string | number | number[] | number[][] + * } + * ``` + * There can be any number of extruders (denoted with `extruder.n`) and any number of models (denoted with `[modelname].stl`). + * The key of the model values will also be the filename of the relevant model, when running CuraEngine with this option the + * model file with that same name _must_ be in the same folder as the resolved settings json. + */ argument_index++; if (argument_index >= arguments_.size()) From d30480b4122f257a3d87569b73fb8db7b15805e2 Mon Sep 17 00:00:00 2001 From: Casper Lamboo Date: Thu, 23 May 2024 19:15:17 +0200 Subject: [PATCH 125/135] Remove redundant else Co-authored-by: Jelle Spijker --- src/MeshGroup.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/MeshGroup.cpp b/src/MeshGroup.cpp index b518d77328..91fae7ae5c 100644 --- a/src/MeshGroup.cpp +++ b/src/MeshGroup.cpp @@ -293,11 +293,8 @@ bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, const Mat spdlog::info("loading '{}' took {:03.3f} seconds", filename, load_timer.restart()); return true; } - else - { - spdlog::warn("loading '{}' failed", filename); - return false; - } + spdlog::warn("loading '{}' failed", filename); + return false; } spdlog::warn("Unable to recognize the extension of the file. Currently only .stl and .STL are supported."); return false; From 57d357d497f7e824cb0c8526799b5ed1978fb1d5 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 24 May 2024 10:16:59 +0200 Subject: [PATCH 126/135] Fix polygon imports NP-205 --- include/geometry/LinesSet.h | 1 - include/geometry/Shape.h | 1 + include/settings/types/LayerIndex.h | 1 - include/slicer.h | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/geometry/LinesSet.h b/include/geometry/LinesSet.h index e76a1a77c7..1e885cb89c 100644 --- a/include/geometry/LinesSet.h +++ b/include/geometry/LinesSet.h @@ -10,7 +10,6 @@ #include "geometry/OpenLinesSet.h" #include "geometry/Point2LL.h" -#include "geometry/Polygon.h" namespace cura { diff --git a/include/geometry/Shape.h b/include/geometry/Shape.h index 46091d49a3..f2edf6c79c 100644 --- a/include/geometry/Shape.h +++ b/include/geometry/Shape.h @@ -6,6 +6,7 @@ #include "geometry/LinesSet.h" #include "settings/types/Angle.h" +#include "geometry/Polygon.h" namespace cura { diff --git a/include/settings/types/LayerIndex.h b/include/settings/types/LayerIndex.h index d707c1eca2..9e2100da87 100644 --- a/include/settings/types/LayerIndex.h +++ b/include/settings/types/LayerIndex.h @@ -8,7 +8,6 @@ #include -#include "geometry/Polygon.h" #include "utils/types/generic.h" namespace cura diff --git a/include/slicer.h b/include/slicer.h index e3d3500fe1..ddafd67ca3 100644 --- a/include/slicer.h +++ b/include/slicer.h @@ -11,7 +11,6 @@ #include "geometry/LinesSet.h" #include "geometry/OpenLinesSet.h" #include "geometry/OpenPolyline.h" -#include "geometry/Polygon.h" #include "geometry/Shape.h" #include "settings/EnumSettings.h" From 5c2dcea607f993186a96a33cd643066d14df9e28 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Fri, 24 May 2024 08:17:36 +0000 Subject: [PATCH 127/135] Applied clang-format. --- include/geometry/Shape.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/geometry/Shape.h b/include/geometry/Shape.h index f2edf6c79c..aaa373f4e1 100644 --- a/include/geometry/Shape.h +++ b/include/geometry/Shape.h @@ -5,8 +5,8 @@ #define GEOMETRY_SHAPE_H #include "geometry/LinesSet.h" -#include "settings/types/Angle.h" #include "geometry/Polygon.h" +#include "settings/types/Angle.h" namespace cura { From 549f4a9fa8bf5b42bcf935138962c8319687f7b4 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 24 May 2024 12:48:19 +0200 Subject: [PATCH 128/135] Add type aliases NP-205 --- include/communication/CommandLine.h | 7 +++++-- src/communication/CommandLine.cpp | 14 +++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/communication/CommandLine.h b/include/communication/CommandLine.h index c277f61614..55c742871a 100644 --- a/include/communication/CommandLine.h +++ b/include/communication/CommandLine.h @@ -17,6 +17,9 @@ namespace cura { class Settings; +using setting_map = std::unordered_map; +using container_setting_map = std::unordered_map; + /* * \brief When slicing via the command line, interprets the command line * arguments to initiate a slice. @@ -220,14 +223,14 @@ class CommandLine : public Communication * \param element The path to the file to read the JSON values from. * \return The resolved JSON values. */ - static std::optional>> readResolvedJsonValues(const std::filesystem::path& json_filename); + static std::optional readResolvedJsonValues(const std::filesystem::path& json_filename); /* * \brief Read the resolved JSON values from a document. * \param document The document to read the JSON values from. * \return The resolved JSON values. */ - static std::optional>> readResolvedJsonValues(const rapidjson::Document& document); + static std::optional readResolvedJsonValues(const rapidjson::Document& document); }; } // namespace cura diff --git a/src/communication/CommandLine.cpp b/src/communication/CommandLine.cpp index 040948c5b5..12e04adc13 100644 --- a/src/communication/CommandLine.cpp +++ b/src/communication/CommandLine.cpp @@ -386,7 +386,7 @@ void CommandLine::sliceNext() argument_index++; if (argument_index >= arguments_.size()) { - spdlog::error("Missing setting name and value with -s argument."); + spdlog::error("Missing setting name and value with -r argument."); exit(1); } argument = arguments_[argument_index]; @@ -406,8 +406,8 @@ void CommandLine::sliceNext() // Split the settings into global, extruder and model settings. This is needed since the order in which the settings are applied is important. // first global settings, then extruder settings, then model settings. The order of these stacks is not enforced in the JSON files. std::unordered_map global_settings; - std::unordered_map> extruder_settings; - std::unordered_map> model_settings; + container_setting_map extruder_settings; + container_setting_map model_settings; std::unordered_map limit_to_extruder; for (const auto& [key, values] : settings.value()) @@ -450,7 +450,7 @@ void CommandLine::sliceNext() for (const auto& [key, values] : model_settings) { - const auto model_name = key; + const auto& model_name = key; cura::MeshGroup mesh_group; for (const auto& [setting_key, setting_value] : values) @@ -712,7 +712,7 @@ void CommandLine::loadJSONSettings(const rapidjson::Value& element, Settings& se } } -std::optional>> CommandLine::readResolvedJsonValues(const std::filesystem::path& json_filename) +std::optional CommandLine::readResolvedJsonValues(const std::filesystem::path& json_filename) { std::ifstream file(json_filename, std::ios::binary); if (! file) @@ -735,14 +735,14 @@ std::optional>> CommandLine::readResolvedJsonValues(const rapidjson::Document& document) +std::optional CommandLine::readResolvedJsonValues(const rapidjson::Document& document) { if (! document.IsObject()) { return std::nullopt; } - std::unordered_map> result; + container_setting_map result; for (rapidjson::Value::ConstMemberIterator resolved_key = document.MemberBegin(); resolved_key != document.MemberEnd(); resolved_key++) { std::unordered_map values; From f5d4bcf0d2cd03569b1575f2ddf10b3701edb312 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 28 May 2024 08:25:28 +0200 Subject: [PATCH 129/135] Added wasm package creation Modified conditions for the creation of conan packages in 'conan-package.yml' to exclude 'master' branch. Also added a new package creation workflow for WebAssembly (wasm). This change is temporary for the 'NP-202_conan_wasm_package' branch, needs to be reverted once the related PR is merged to main. Contribute to NP-202 --- .github/workflows/conan-package.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/conan-package.yml b/.github/workflows/conan-package.yml index 64ab6141b3..9a9d46c1fe 100644 --- a/.github/workflows/conan-package.yml +++ b/.github/workflows/conan-package.yml @@ -54,7 +54,7 @@ jobs: conan-package-create-macos: needs: [ conan-recipe-version, conan-package-export ] - if: ${{ ((github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) || github.event_name == 'pull_request') }} + if: ${{ ((github.event_name == 'push' && (github.ref_name == 'main' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) || github.event_name == 'pull_request') }} uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-macos.yml@main with: recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} @@ -62,7 +62,7 @@ jobs: conan-package-create-windows: needs: [ conan-recipe-version, conan-package-export ] - if: ${{ ((github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) || github.event_name == 'pull_request') }} + if: ${{ ((github.event_name == 'push' && (github.ref_name == 'main' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) || github.event_name == 'pull_request') }} uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-windows.yml@main with: recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} @@ -70,8 +70,17 @@ jobs: conan-package-create-linux: needs: [ conan-recipe-version, conan-package-export ] - if: ${{ ((github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'master' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) || github.event_name == 'pull_request') }} + if: ${{ ((github.event_name == 'push' && (github.ref_name == 'main' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) || github.event_name == 'pull_request') }} uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-linux.yml@main with: recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} secrets: inherit + +# FIXME: Remove the references to the NP-202_conan_wasm_package branch once https://github.com/Ultimaker/cura-workflows/pull/19 is merged to main + conan-package-create-wasm: + needs: [ conan-recipe-version, conan-package-export ] + if: ${{ (github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'NP-202_conan_wasm_package' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }} + uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-wasm.yml@NP-202_conan_wasm_package + with: + recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} + secrets: inherit From 51cc6a306bad9fe60b99ae3b72816620a29de9b0 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 28 May 2024 09:48:04 +0200 Subject: [PATCH 130/135] Add SingleShape include in slicer.cpp A necessary inclusion of "geometry/SingleShape.h" has been added to the slicer.cpp file. This is needed for our implementation of the splitIntoParts() function. Contribute to NP-202 --- src/slicer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slicer.cpp b/src/slicer.cpp index fa8fded180..1e12d21018 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -13,6 +13,7 @@ #include "Application.h" #include "Slice.h" #include "geometry/OpenPolyline.h" +#include "geometry/SingleShape.h" // Needed to our call of splitIntoParts() #include "plugins/slots.h" #include "raft.h" #include "settings/AdaptiveLayerHeights.h" From 55aa0770cfac2e5437c90298018ef82e00004397 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Tue, 28 May 2024 09:53:55 +0200 Subject: [PATCH 131/135] Refactor method overrides and use std::move The virtual keyword was removed from override methods in various BeadingStrategy classes to improve clarity. The std::move function was also used in the BeadingStrategyFactory.cpp file to transfer ownership of a unique_ptr, improving efficiency and semantic accuracy. Contribute to NP-202 --- include/BeadingStrategy/LimitedBeadingStrategy.h | 2 +- .../OuterWallInsetBeadingStrategy.h | 2 +- .../RedistributeBeadingStrategy.h | 2 +- .../BeadingStrategy/WideningBeadingStrategy.h | 16 ++++++++-------- src/BeadingStrategy/BeadingStrategyFactory.cpp | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/BeadingStrategy/LimitedBeadingStrategy.h b/include/BeadingStrategy/LimitedBeadingStrategy.h index 42d34f86a4..3e15eefec2 100644 --- a/include/BeadingStrategy/LimitedBeadingStrategy.h +++ b/include/BeadingStrategy/LimitedBeadingStrategy.h @@ -35,7 +35,7 @@ class LimitedBeadingStrategy : public BeadingStrategy coord_t getOptimalThickness(coord_t bead_count) const override; coord_t getTransitionThickness(coord_t lower_bead_count) const override; coord_t getOptimalBeadCount(coord_t thickness) const override; - virtual std::string toString() const override; + std::string toString() const override; coord_t getTransitioningLength(coord_t lower_bead_count) const override; diff --git a/include/BeadingStrategy/OuterWallInsetBeadingStrategy.h b/include/BeadingStrategy/OuterWallInsetBeadingStrategy.h index c8c6eae31d..840c04f888 100644 --- a/include/BeadingStrategy/OuterWallInsetBeadingStrategy.h +++ b/include/BeadingStrategy/OuterWallInsetBeadingStrategy.h @@ -25,7 +25,7 @@ class OuterWallInsetBeadingStrategy : public BeadingStrategy coord_t getOptimalBeadCount(coord_t thickness) const override; coord_t getTransitioningLength(coord_t lower_bead_count) const override; - virtual std::string toString() const; + std::string toString() const override; private: BeadingStrategyPtr parent_; diff --git a/include/BeadingStrategy/RedistributeBeadingStrategy.h b/include/BeadingStrategy/RedistributeBeadingStrategy.h index 2f8304bf39..52d41e1a93 100644 --- a/include/BeadingStrategy/RedistributeBeadingStrategy.h +++ b/include/BeadingStrategy/RedistributeBeadingStrategy.h @@ -45,7 +45,7 @@ class RedistributeBeadingStrategy : public BeadingStrategy coord_t getTransitioningLength(coord_t lower_bead_count) const override; double getTransitionAnchorPos(coord_t lower_bead_count) const override; - virtual std::string toString() const; + std::string toString() const override; protected: /*! diff --git a/include/BeadingStrategy/WideningBeadingStrategy.h b/include/BeadingStrategy/WideningBeadingStrategy.h index bda69f345d..cd0f00c406 100644 --- a/include/BeadingStrategy/WideningBeadingStrategy.h +++ b/include/BeadingStrategy/WideningBeadingStrategy.h @@ -27,14 +27,14 @@ class WideningBeadingStrategy : public BeadingStrategy virtual ~WideningBeadingStrategy() override = default; - virtual Beading compute(coord_t thickness, coord_t bead_count) const override; - virtual coord_t getOptimalThickness(coord_t bead_count) const override; - virtual coord_t getTransitionThickness(coord_t lower_bead_count) const override; - virtual coord_t getOptimalBeadCount(coord_t thickness) const override; - virtual coord_t getTransitioningLength(coord_t lower_bead_count) const override; - virtual double getTransitionAnchorPos(coord_t lower_bead_count) const override; - virtual std::vector getNonlinearThicknesses(coord_t lower_bead_count) const override; - virtual std::string toString() const override; + Beading compute(coord_t thickness, coord_t bead_count) const override; + coord_t getOptimalThickness(coord_t bead_count) const override; + coord_t getTransitionThickness(coord_t lower_bead_count) const override; + coord_t getOptimalBeadCount(coord_t thickness) const override; + coord_t getTransitioningLength(coord_t lower_bead_count) const override; + double getTransitionAnchorPos(coord_t lower_bead_count) const override; + std::vector getNonlinearThicknesses(coord_t lower_bead_count) const override; + std::string toString() const override; protected: BeadingStrategyPtr parent_; diff --git a/src/BeadingStrategy/BeadingStrategyFactory.cpp b/src/BeadingStrategy/BeadingStrategyFactory.cpp index c929bd5d9f..8b2d289449 100644 --- a/src/BeadingStrategy/BeadingStrategyFactory.cpp +++ b/src/BeadingStrategy/BeadingStrategyFactory.cpp @@ -41,22 +41,22 @@ BeadingStrategyPtr BeadingStrategyFactory::makeStrategy( wall_add_middle_threshold, inward_distributed_center_wall_count); spdlog::debug("Applying the Redistribute meta-strategy with outer-wall width = {}, inner-wall width = {}", preferred_bead_width_outer, preferred_bead_width_inner); - ret = make_unique(preferred_bead_width_outer, minimum_variable_line_ratio, move(ret)); + ret = make_unique(preferred_bead_width_outer, minimum_variable_line_ratio, std::move(ret)); if (print_thin_walls) { spdlog::debug("Applying the Widening Beading meta-strategy with minimum input width {} and minimum output width {}.", min_feature_size, min_bead_width); - ret = make_unique(move(ret), min_feature_size, min_bead_width); + ret = make_unique(std::move(ret), min_feature_size, min_bead_width); } if (outer_wall_offset > 0) { spdlog::debug("Applying the OuterWallOffset meta-strategy with offset = {}", outer_wall_offset); - ret = make_unique(outer_wall_offset, move(ret)); + ret = make_unique(outer_wall_offset, std::move(ret)); } // Apply the LimitedBeadingStrategy last, since that adds a 0-width marker wall which other beading strategies shouldn't touch. spdlog::debug("Applying the Limited Beading meta-strategy with maximum bead count = {}", max_bead_count); - ret = make_unique(max_bead_count, move(ret)); + ret = make_unique(max_bead_count, std::move(ret)); return ret; } } // namespace cura From 8d6517607272d69c1e7862da4d44223228740a2c Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Tue, 28 May 2024 11:13:08 +0200 Subject: [PATCH 132/135] Apply same fix as for Cura to avoid variable injection --- .github/workflows/lint-poster.yml | 58 ++++++++++++++++++++----------- .github/workflows/lint-tidier.yml | 2 +- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/.github/workflows/lint-poster.yml b/.github/workflows/lint-poster.yml index a016599fec..3ea00c6572 100644 --- a/.github/workflows/lint-poster.yml +++ b/.github/workflows/lint-poster.yml @@ -10,72 +10,88 @@ jobs: # Trigger the job only if the previous (insecure) workflow completed successfully if: ${{ github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-latest + permissions: + pull-requests: write steps: - name: Download analysis results - uses: actions/github-script@v3.1.0 + uses: actions/github-script@v7 with: script: | - let artifacts = await github.actions.listWorkflowRunArtifacts({ + const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ owner: context.repo.owner, repo: context.repo.repo, run_id: ${{github.event.workflow_run.id }}, }); - let matchArtifact = artifacts.data.artifacts.filter((artifact) => { + const matchArtifact = artifacts.data.artifacts.filter((artifact) => { return artifact.name == "linter-result" })[0]; - let download = await github.actions.downloadArtifact({ + const download = await github.rest.actions.downloadArtifact({ owner: context.repo.owner, repo: context.repo.repo, artifact_id: matchArtifact.id, archive_format: "zip", }); - let fs = require("fs"); + const fs = require("fs"); fs.writeFileSync("${{github.workspace}}/linter-result.zip", Buffer.from(download.data)); - - name: Set environment variables + - name: Extract analysis results run: | mkdir linter-result - unzip linter-result.zip -d linter-result - echo "pr_id=$(cat linter-result/pr-id.txt)" >> $GITHUB_ENV - echo "pr_head_repo=$(cat linter-result/pr-head-repo.txt)" >> $GITHUB_ENV - echo "pr_head_ref=$(cat linter-result/pr-head-ref.txt)" >> $GITHUB_ENV + unzip -j linter-result.zip -d linter-result + + - name: Set PR details environment variables + uses: actions/github-script@v7 + with: + script: | + const assert = require("node:assert").strict; + const fs = require("fs"); + function exportVar(varName, fileName, regEx) { + const val = fs.readFileSync("${{ github.workspace }}/linter-result/" + fileName, { + encoding: "ascii" + }).trimEnd(); + assert.ok(regEx.test(val), "Invalid value format for " + varName); + core.exportVariable(varName, val); + } + exportVar("PR_ID", "pr-id.txt", /^[0-9]+$/); + exportVar("PR_HEAD_REPO", "pr-head-repo.txt", /^[-./0-9A-Z_a-z]+$/); + exportVar("PR_HEAD_SHA", "pr-head-sha.txt", /^[0-9A-Fa-f]+$/); - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: - repository: ${{ env.pr_head_repo }} - ref: ${{ env.pr_head_ref }} + repository: ${{ env.PR_HEAD_REPO }} + ref: ${{ env.PR_HEAD_SHA }} persist-credentials: false - name: Redownload analysis results - uses: actions/github-script@v3.1.0 + uses: actions/github-script@v7 with: script: | - let artifacts = await github.actions.listWorkflowRunArtifacts({ + const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ owner: context.repo.owner, repo: context.repo.repo, run_id: ${{github.event.workflow_run.id }}, }); - let matchArtifact = artifacts.data.artifacts.filter((artifact) => { + const matchArtifact = artifacts.data.artifacts.filter((artifact) => { return artifact.name == "linter-result" })[0]; - let download = await github.actions.downloadArtifact({ + const download = await github.rest.actions.downloadArtifact({ owner: context.repo.owner, repo: context.repo.repo, artifact_id: matchArtifact.id, archive_format: "zip", }); - let fs = require("fs"); + const fs = require("fs"); fs.writeFileSync("${{github.workspace}}/linter-result.zip", Buffer.from(download.data)); - name: Extract analysis results run: | mkdir linter-result - unzip linter-result.zip -d linter-result + unzip -j linter-result.zip -d linter-result - name: Run clang-tidy-pr-comments action - uses: platisd/clang-tidy-pr-comments + uses: platisd/clang-tidy-pr-comments@v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} clang_tidy_fixes: linter-result/fixes.yml - pull_request_id: ${{ env.pr_id }} + pull_request_id: ${{ env.PR_ID }} request_changes: true diff --git a/.github/workflows/lint-tidier.yml b/.github/workflows/lint-tidier.yml index d178f52f3a..a4bdf1b9d6 100644 --- a/.github/workflows/lint-tidier.yml +++ b/.github/workflows/lint-tidier.yml @@ -91,7 +91,7 @@ jobs: run: | echo ${{ github.event.number }} > linter-result/pr-id.txt echo ${{ github.event.pull_request.head.repo.full_name }} > linter-result/pr-head-repo.txt - echo ${{ github.event.pull_request.head.ref }} > linter-result/pr-head-ref.txt + echo ${{ github.event.pull_request.head.sha }} > linter-result/pr-head-sha.txt - uses: actions/upload-artifact@v2 with: From 58aaaf0c669beadb836a7b8e1bd2269759d75e82 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Wed, 29 May 2024 08:59:50 +0200 Subject: [PATCH 133/135] Add deploy method in conanfile.py Added a new deploy method in conanfile.py that copies CuraEngine files from the package_folder/bin directory to the installation folder. This change is intended to provide additional deployment capabilities to the script. Contribute to NP-207 --- conanfile.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conanfile.py b/conanfile.py index 127a23576f..8e325411cd 100644 --- a/conanfile.py +++ b/conanfile.py @@ -217,6 +217,9 @@ def build(self): self.run(f"sentry-cli --auth-token {os.environ['SENTRY_TOKEN']} releases set-commits -o {sentry_org} -p {sentry_project} --commit \"Ultimaker/CuraEngine@{self.conan_data['commit']}\" {self.version}") self.run(f"sentry-cli --auth-token {os.environ['SENTRY_TOKEN']} releases finalize -o {sentry_org} -p {sentry_project} {self.version}") + def deploy(self): + copy(self, "CuraEngine*", src=os.path.join(self.package_folder, "bin"), dst=self.install_folder) + def package(self): match self.settings.os: case "Windows": From 40e0b5b54edc80e022525cbdba267bca40c24fe3 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Wed, 5 Jun 2024 17:48:51 +0200 Subject: [PATCH 134/135] fix grammar Contribute to NP-207 and NP-206 --- src/slicer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slicer.cpp b/src/slicer.cpp index 1e12d21018..f66e2d40ec 100644 --- a/src/slicer.cpp +++ b/src/slicer.cpp @@ -13,7 +13,7 @@ #include "Application.h" #include "Slice.h" #include "geometry/OpenPolyline.h" -#include "geometry/SingleShape.h" // Needed to our call of splitIntoParts() +#include "geometry/SingleShape.h" // Needed in order to call splitIntoParts() #include "plugins/slots.h" #include "raft.h" #include "settings/AdaptiveLayerHeights.h" From 793e742451911113764ad443e1311d46f05798d7 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Wed, 5 Jun 2024 17:49:20 +0200 Subject: [PATCH 135/135] Use `main` conan-package-create workflow Contribute to NP-207 and NP-206 --- .github/workflows/conan-package.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/conan-package.yml b/.github/workflows/conan-package.yml index 9a9d46c1fe..eb5829a6a7 100644 --- a/.github/workflows/conan-package.yml +++ b/.github/workflows/conan-package.yml @@ -76,11 +76,10 @@ jobs: recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} secrets: inherit -# FIXME: Remove the references to the NP-202_conan_wasm_package branch once https://github.com/Ultimaker/cura-workflows/pull/19 is merged to main conan-package-create-wasm: needs: [ conan-recipe-version, conan-package-export ] - if: ${{ (github.event_name == 'push' && (github.ref_name == 'main' || github.ref_name == 'NP-202_conan_wasm_package' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }} - uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-wasm.yml@NP-202_conan_wasm_package + if: ${{ (github.event_name == 'push' && (github.ref_name == 'main' || needs.conan-recipe-version.outputs.is_release_branch == 'true')) }} + uses: ultimaker/cura-workflows/.github/workflows/conan-package-create-wasm.yml@main with: recipe_id_full: ${{ needs.conan-recipe-version.outputs.recipe_id_full }} secrets: inherit