2013-07-14 13:53:53 +00:00
|
|
|
#ifndef slic3r_Polygon_hpp_
|
|
|
|
#define slic3r_Polygon_hpp_
|
|
|
|
|
2015-12-07 23:39:54 +00:00
|
|
|
#include "libslic3r.h"
|
2013-07-15 18:31:43 +00:00
|
|
|
#include <vector>
|
2014-11-15 22:06:15 +00:00
|
|
|
#include <string>
|
2013-07-16 19:04:14 +00:00
|
|
|
#include "Line.hpp"
|
|
|
|
#include "MultiPoint.hpp"
|
2013-07-14 14:09:54 +00:00
|
|
|
#include "Polyline.hpp"
|
2013-07-14 13:53:53 +00:00
|
|
|
|
|
|
|
namespace Slic3r {
|
|
|
|
|
2013-11-22 01:16:10 +00:00
|
|
|
class Polygon;
|
2021-04-13 11:28:21 +00:00
|
|
|
using Polygons = std::vector<Polygon>;
|
|
|
|
using PolygonPtrs = std::vector<Polygon*>;
|
|
|
|
using ConstPolygonPtrs = std::vector<const Polygon*>;
|
2013-11-22 01:16:10 +00:00
|
|
|
|
2019-09-27 16:17:21 +00:00
|
|
|
class Polygon : public MultiPoint
|
|
|
|
{
|
2017-01-19 12:43:29 +00:00
|
|
|
public:
|
2020-11-16 12:11:58 +00:00
|
|
|
Polygon() = default;
|
2022-01-28 13:51:08 +00:00
|
|
|
~Polygon() override = default;
|
2019-10-25 15:07:55 +00:00
|
|
|
explicit Polygon(const Points &points) : MultiPoint(points) {}
|
|
|
|
Polygon(std::initializer_list<Point> points) : MultiPoint(points) {}
|
2017-01-19 12:43:29 +00:00
|
|
|
Polygon(const Polygon &other) : MultiPoint(other.points) {}
|
|
|
|
Polygon(Polygon &&other) : MultiPoint(std::move(other.points)) {}
|
2018-08-21 19:05:24 +00:00
|
|
|
static Polygon new_scale(const std::vector<Vec2d> &points) {
|
2018-08-21 18:34:45 +00:00
|
|
|
Polygon pgn;
|
|
|
|
pgn.points.reserve(points.size());
|
2018-08-21 19:05:24 +00:00
|
|
|
for (const Vec2d &pt : points)
|
2018-08-21 18:34:45 +00:00
|
|
|
pgn.points.emplace_back(Point::new_scale(pt(0), pt(1)));
|
|
|
|
return pgn;
|
2018-01-25 12:46:04 +00:00
|
|
|
}
|
2017-01-19 12:43:29 +00:00
|
|
|
Polygon& operator=(const Polygon &other) { points = other.points; return *this; }
|
|
|
|
Polygon& operator=(Polygon &&other) { points = std::move(other.points); return *this; }
|
|
|
|
|
2021-09-13 13:13:05 +00:00
|
|
|
Point& operator[](Points::size_type idx) { return this->points[idx]; }
|
|
|
|
const Point& operator[](Points::size_type idx) const { return this->points[idx]; }
|
|
|
|
|
2019-09-27 16:17:21 +00:00
|
|
|
// last point == first point for polygons
|
|
|
|
const Point& last_point() const override { return this->points.front(); }
|
|
|
|
|
2020-03-04 11:48:04 +00:00
|
|
|
Lines lines() const override;
|
2015-01-19 17:53:04 +00:00
|
|
|
Polyline split_at_vertex(const Point &point) const;
|
2016-09-13 11:30:00 +00:00
|
|
|
// Split a closed polygon into an open polyline, with the split point duplicated at both ends.
|
2015-01-19 17:53:04 +00:00
|
|
|
Polyline split_at_index(int index) const;
|
2016-09-13 11:30:00 +00:00
|
|
|
// Split a closed polygon into an open polyline, with the split point duplicated at both ends.
|
2019-09-27 16:17:21 +00:00
|
|
|
Polyline split_at_first_point() const { return this->split_at_index(0); }
|
|
|
|
Points equally_spaced_points(double distance) const { return this->split_at_first_point().equally_spaced_points(distance); }
|
2020-04-23 16:19:03 +00:00
|
|
|
|
|
|
|
static double area(const Points &pts);
|
2013-08-26 20:50:26 +00:00
|
|
|
double area() const;
|
|
|
|
bool is_counter_clockwise() const;
|
2013-08-26 23:26:44 +00:00
|
|
|
bool is_clockwise() const;
|
2013-07-16 19:09:29 +00:00
|
|
|
bool make_counter_clockwise();
|
|
|
|
bool make_clockwise();
|
2019-09-27 16:17:21 +00:00
|
|
|
bool is_valid() const { return this->points.size() >= 3; }
|
2021-02-03 14:12:53 +00:00
|
|
|
void douglas_peucker(double tolerance);
|
2019-09-27 16:17:21 +00:00
|
|
|
|
2016-09-13 11:30:00 +00:00
|
|
|
// Does an unoriented polygon contain a point?
|
|
|
|
// Tested by counting intersections along a horizontal line.
|
2014-11-23 19:14:13 +00:00
|
|
|
bool contains(const Point &point) const;
|
2013-11-21 19:25:24 +00:00
|
|
|
Polygons simplify(double tolerance) const;
|
|
|
|
void simplify(double tolerance, Polygons &polygons) const;
|
2020-08-31 05:25:24 +00:00
|
|
|
void densify(float min_length, std::vector<float>* lengths = nullptr);
|
2014-04-24 14:59:36 +00:00
|
|
|
void triangulate_convex(Polygons* polygons) const;
|
2014-05-22 17:34:49 +00:00
|
|
|
Point centroid() const;
|
2015-01-19 17:53:04 +00:00
|
|
|
Points concave_points(double angle = PI) const;
|
|
|
|
Points convex_points(double angle = PI) const;
|
2017-06-08 09:02:29 +00:00
|
|
|
// Projection of a point onto the polygon.
|
|
|
|
Point point_projection(const Point &point) const;
|
2020-08-31 05:25:24 +00:00
|
|
|
std::vector<float> parameter_by_length() const;
|
2021-04-21 14:02:25 +00:00
|
|
|
|
|
|
|
using iterator = Points::iterator;
|
|
|
|
using const_iterator = Points::const_iterator;
|
2013-07-15 21:28:23 +00:00
|
|
|
};
|
2013-07-15 14:21:09 +00:00
|
|
|
|
2019-10-25 15:07:55 +00:00
|
|
|
inline bool operator==(const Polygon &lhs, const Polygon &rhs) { return lhs.points == rhs.points; }
|
|
|
|
inline bool operator!=(const Polygon &lhs, const Polygon &rhs) { return lhs.points != rhs.points; }
|
|
|
|
|
2021-09-24 12:07:46 +00:00
|
|
|
BoundingBox get_extents(const Polygon &poly);
|
|
|
|
BoundingBox get_extents(const Polygons &polygons);
|
|
|
|
BoundingBox get_extents_rotated(const Polygon &poly, double angle);
|
|
|
|
BoundingBox get_extents_rotated(const Polygons &polygons, double angle);
|
|
|
|
std::vector<BoundingBox> get_extents_vector(const Polygons &polygons);
|
|
|
|
|
New BuildVolume class was created, which detects build volume type (rectangular,
circular, convex, concave) and performs efficient collision detection agains these build
volumes. As of now, collision detection is performed against a convex
hull of a concave build volume for efficency.
GCodeProcessor::Result renamed out of GCodeProcessor to GCodeProcessorResult,
so it could be forward declared.
Plater newly exports BuildVolume, not Bed3D. Bed3D is a rendering class,
while BuildVolume is a purely geometric class.
Reduced usage of global wxGetApp, the Bed3D is passed as a parameter
to View3D/Preview/GLCanvas.
Convex hull code was extracted from Geometry.cpp/hpp to Geometry/ConvexHulll.cpp,hpp.
New test inside_convex_polygon().
New efficent point inside polygon test: Decompose convex hull
to bottom / top parts and use the decomposition to detect point inside
a convex polygon in O(log n). decompose_convex_polygon_top_bottom(),
inside_convex_polygon().
New Circle constructing functions: circle_ransac() and circle_taubin_newton().
New polygon_is_convex() test with unit tests.
2021-11-16 09:15:51 +00:00
|
|
|
// Polygon must be valid (at least three points), collinear points and duplicate points removed.
|
|
|
|
bool polygon_is_convex(const Points &poly);
|
|
|
|
inline bool polygon_is_convex(const Polygon &poly) { return polygon_is_convex(poly.points); }
|
|
|
|
|
2021-09-24 12:07:46 +00:00
|
|
|
// Test for duplicate points. The points are copied, sorted and checked for duplicates globally.
|
|
|
|
inline bool has_duplicate_points(Polygon &&poly) { return has_duplicate_points(std::move(poly.points)); }
|
|
|
|
inline bool has_duplicate_points(const Polygon &poly) { return has_duplicate_points(poly.points); }
|
|
|
|
bool has_duplicate_points(const Polygons &polys);
|
2016-09-13 11:30:00 +00:00
|
|
|
|
2017-02-02 15:03:32 +00:00
|
|
|
inline double total_length(const Polygons &polylines) {
|
|
|
|
double total = 0;
|
|
|
|
for (Polygons::const_iterator it = polylines.begin(); it != polylines.end(); ++it)
|
|
|
|
total += it->length();
|
|
|
|
return total;
|
|
|
|
}
|
|
|
|
|
2021-04-21 14:02:25 +00:00
|
|
|
inline double area(const Polygon &poly) { return poly.area(); }
|
|
|
|
|
2020-08-25 11:40:06 +00:00
|
|
|
inline double area(const Polygons &polys)
|
|
|
|
{
|
|
|
|
double s = 0.;
|
|
|
|
for (auto &p : polys) s += p.area();
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2016-10-20 11:04:23 +00:00
|
|
|
// Remove sticks (tentacles with zero area) from the polygon.
|
2021-09-24 12:07:46 +00:00
|
|
|
bool remove_sticks(Polygon &poly);
|
|
|
|
bool remove_sticks(Polygons &polys);
|
2016-10-20 11:04:23 +00:00
|
|
|
|
|
|
|
// Remove polygons with less than 3 edges.
|
2021-09-24 12:07:46 +00:00
|
|
|
bool remove_degenerate(Polygons &polys);
|
|
|
|
bool remove_small(Polygons &polys, double min_area);
|
|
|
|
void remove_collinear(Polygon &poly);
|
|
|
|
void remove_collinear(Polygons &polys);
|
2016-11-02 09:47:00 +00:00
|
|
|
|
|
|
|
// Append a vector of polygons at the end of another vector of polygons.
|
2021-09-24 12:07:46 +00:00
|
|
|
inline void polygons_append(Polygons &dst, const Polygons &src) { dst.insert(dst.end(), src.begin(), src.end()); }
|
2017-01-20 13:39:44 +00:00
|
|
|
|
2021-09-24 12:07:46 +00:00
|
|
|
inline void polygons_append(Polygons &dst, Polygons &&src)
|
2016-11-02 09:47:00 +00:00
|
|
|
{
|
2017-01-20 13:39:44 +00:00
|
|
|
if (dst.empty()) {
|
2016-11-02 09:47:00 +00:00
|
|
|
dst = std::move(src);
|
2017-01-20 13:39:44 +00:00
|
|
|
} else {
|
2016-11-02 09:47:00 +00:00
|
|
|
std::move(std::begin(src), std::end(src), std::back_inserter(dst));
|
2017-01-20 13:39:44 +00:00
|
|
|
src.clear();
|
|
|
|
}
|
2016-11-02 09:47:00 +00:00
|
|
|
}
|
2016-11-07 21:49:11 +00:00
|
|
|
|
2019-10-25 11:34:37 +00:00
|
|
|
inline Polygons polygons_simplify(const Polygons &polys, double tolerance)
|
|
|
|
{
|
|
|
|
Polygons out;
|
|
|
|
out.reserve(polys.size());
|
|
|
|
for (const Polygon &p : polys)
|
|
|
|
polygons_append(out, p.simplify(tolerance));
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2016-11-07 21:49:11 +00:00
|
|
|
inline void polygons_rotate(Polygons &polys, double angle)
|
|
|
|
{
|
2017-06-08 12:02:37 +00:00
|
|
|
const double cos_angle = cos(angle);
|
|
|
|
const double sin_angle = sin(angle);
|
|
|
|
for (Polygon &p : polys)
|
|
|
|
p.rotate(cos_angle, sin_angle);
|
2016-11-07 21:49:11 +00:00
|
|
|
}
|
|
|
|
|
2018-09-17 13:12:13 +00:00
|
|
|
inline void polygons_reverse(Polygons &polys)
|
|
|
|
{
|
|
|
|
for (Polygon &p : polys)
|
|
|
|
p.reverse();
|
|
|
|
}
|
|
|
|
|
2017-05-03 16:28:22 +00:00
|
|
|
inline Points to_points(const Polygon &poly)
|
|
|
|
{
|
|
|
|
return poly.points;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Points to_points(const Polygons &polys)
|
|
|
|
{
|
|
|
|
size_t n_points = 0;
|
|
|
|
for (size_t i = 0; i < polys.size(); ++ i)
|
|
|
|
n_points += polys[i].points.size();
|
|
|
|
Points points;
|
|
|
|
points.reserve(n_points);
|
|
|
|
for (const Polygon &poly : polys)
|
|
|
|
append(points, poly.points);
|
|
|
|
return points;
|
|
|
|
}
|
|
|
|
|
2016-11-07 21:49:11 +00:00
|
|
|
inline Lines to_lines(const Polygon &poly)
|
|
|
|
{
|
|
|
|
Lines lines;
|
|
|
|
lines.reserve(poly.points.size());
|
2020-06-16 11:13:51 +00:00
|
|
|
if (poly.points.size() > 2) {
|
|
|
|
for (Points::const_iterator it = poly.points.begin(); it != poly.points.end()-1; ++it)
|
|
|
|
lines.push_back(Line(*it, *(it + 1)));
|
|
|
|
lines.push_back(Line(poly.points.back(), poly.points.front()));
|
|
|
|
}
|
2016-11-07 21:49:11 +00:00
|
|
|
return lines;
|
2013-07-14 13:53:53 +00:00
|
|
|
}
|
|
|
|
|
2016-11-07 21:49:11 +00:00
|
|
|
inline Lines to_lines(const Polygons &polys)
|
|
|
|
{
|
|
|
|
size_t n_lines = 0;
|
|
|
|
for (size_t i = 0; i < polys.size(); ++ i)
|
|
|
|
n_lines += polys[i].points.size();
|
|
|
|
Lines lines;
|
|
|
|
lines.reserve(n_lines);
|
|
|
|
for (size_t i = 0; i < polys.size(); ++ i) {
|
|
|
|
const Polygon &poly = polys[i];
|
|
|
|
for (Points::const_iterator it = poly.points.begin(); it != poly.points.end()-1; ++it)
|
|
|
|
lines.push_back(Line(*it, *(it + 1)));
|
|
|
|
lines.push_back(Line(poly.points.back(), poly.points.front()));
|
|
|
|
}
|
|
|
|
return lines;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Polylines to_polylines(const Polygons &polys)
|
|
|
|
{
|
|
|
|
Polylines polylines;
|
|
|
|
polylines.assign(polys.size(), Polyline());
|
|
|
|
size_t idx = 0;
|
|
|
|
for (Polygons::const_iterator it = polys.begin(); it != polys.end(); ++ it) {
|
|
|
|
Polyline &pl = polylines[idx ++];
|
|
|
|
pl.points = it->points;
|
|
|
|
pl.points.push_back(it->points.front());
|
|
|
|
}
|
|
|
|
assert(idx == polylines.size());
|
|
|
|
return polylines;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Polylines to_polylines(Polygons &&polys)
|
|
|
|
{
|
|
|
|
Polylines polylines;
|
|
|
|
polylines.assign(polys.size(), Polyline());
|
|
|
|
size_t idx = 0;
|
|
|
|
for (Polygons::const_iterator it = polys.begin(); it != polys.end(); ++ it) {
|
|
|
|
Polyline &pl = polylines[idx ++];
|
|
|
|
pl.points = std::move(it->points);
|
|
|
|
pl.points.push_back(it->points.front());
|
|
|
|
}
|
|
|
|
assert(idx == polylines.size());
|
|
|
|
return polylines;
|
|
|
|
}
|
|
|
|
|
2021-04-30 09:49:57 +00:00
|
|
|
inline Polygons to_polygons(const std::vector<Points> &paths)
|
|
|
|
{
|
|
|
|
Polygons out;
|
|
|
|
out.reserve(paths.size());
|
|
|
|
for (const Points &path : paths)
|
|
|
|
out.emplace_back(path);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Polygons to_polygons(std::vector<Points> &&paths)
|
|
|
|
{
|
|
|
|
Polygons out;
|
|
|
|
out.reserve(paths.size());
|
|
|
|
for (const Points &path : paths)
|
|
|
|
out.emplace_back(std::move(path));
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2016-11-07 21:49:11 +00:00
|
|
|
} // Slic3r
|
|
|
|
|
2014-04-24 11:43:24 +00:00
|
|
|
// start Boost
|
|
|
|
#include <boost/polygon/polygon.hpp>
|
|
|
|
namespace boost { namespace polygon {
|
|
|
|
template <>
|
2016-12-08 14:16:09 +00:00
|
|
|
struct geometry_concept<Slic3r::Polygon>{ typedef polygon_concept type; };
|
2014-04-24 11:43:24 +00:00
|
|
|
|
|
|
|
template <>
|
2016-12-08 14:16:09 +00:00
|
|
|
struct polygon_traits<Slic3r::Polygon> {
|
2014-04-24 11:43:24 +00:00
|
|
|
typedef coord_t coordinate_type;
|
2016-12-08 14:16:09 +00:00
|
|
|
typedef Slic3r::Points::const_iterator iterator_type;
|
|
|
|
typedef Slic3r::Point point_type;
|
2014-04-24 11:43:24 +00:00
|
|
|
|
|
|
|
// Get the begin iterator
|
2016-12-08 14:16:09 +00:00
|
|
|
static inline iterator_type begin_points(const Slic3r::Polygon& t) {
|
2014-04-24 11:43:24 +00:00
|
|
|
return t.points.begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the end iterator
|
2016-12-08 14:16:09 +00:00
|
|
|
static inline iterator_type end_points(const Slic3r::Polygon& t) {
|
2014-04-24 11:43:24 +00:00
|
|
|
return t.points.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the number of sides of the polygon
|
2016-12-08 14:16:09 +00:00
|
|
|
static inline std::size_t size(const Slic3r::Polygon& t) {
|
2014-04-24 11:43:24 +00:00
|
|
|
return t.points.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the winding direction of the polygon
|
2017-05-03 16:28:22 +00:00
|
|
|
static inline winding_direction winding(const Slic3r::Polygon& /* t */) {
|
2014-04-24 11:43:24 +00:00
|
|
|
return unknown_winding;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
2016-12-08 14:16:09 +00:00
|
|
|
struct polygon_mutable_traits<Slic3r::Polygon> {
|
2014-04-24 11:43:24 +00:00
|
|
|
// expects stl style iterators
|
|
|
|
template <typename iT>
|
2016-12-08 14:16:09 +00:00
|
|
|
static inline Slic3r::Polygon& set_points(Slic3r::Polygon& polygon, iT input_begin, iT input_end) {
|
2014-04-24 11:43:24 +00:00
|
|
|
polygon.points.clear();
|
|
|
|
while (input_begin != input_end) {
|
2016-12-08 18:02:16 +00:00
|
|
|
polygon.points.push_back(Slic3r::Point());
|
2014-04-24 11:43:24 +00:00
|
|
|
boost::polygon::assign(polygon.points.back(), *input_begin);
|
|
|
|
++input_begin;
|
|
|
|
}
|
|
|
|
// skip last point since Boost will set last point = first point
|
|
|
|
polygon.points.pop_back();
|
|
|
|
return polygon;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
2016-12-08 14:16:09 +00:00
|
|
|
struct geometry_concept<Slic3r::Polygons> { typedef polygon_set_concept type; };
|
2014-04-24 11:43:24 +00:00
|
|
|
|
|
|
|
//next we map to the concept through traits
|
|
|
|
template <>
|
2016-12-08 14:16:09 +00:00
|
|
|
struct polygon_set_traits<Slic3r::Polygons> {
|
2014-04-24 11:43:24 +00:00
|
|
|
typedef coord_t coordinate_type;
|
2016-12-08 14:16:09 +00:00
|
|
|
typedef Slic3r::Polygons::const_iterator iterator_type;
|
|
|
|
typedef Slic3r::Polygons operator_arg_type;
|
2014-04-24 11:43:24 +00:00
|
|
|
|
2016-12-08 14:16:09 +00:00
|
|
|
static inline iterator_type begin(const Slic3r::Polygons& polygon_set) {
|
2014-04-24 11:43:24 +00:00
|
|
|
return polygon_set.begin();
|
|
|
|
}
|
|
|
|
|
2016-12-08 14:16:09 +00:00
|
|
|
static inline iterator_type end(const Slic3r::Polygons& polygon_set) {
|
2014-04-24 11:43:24 +00:00
|
|
|
return polygon_set.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
//don't worry about these, just return false from them
|
2017-05-03 16:28:22 +00:00
|
|
|
static inline bool clean(const Slic3r::Polygons& /* polygon_set */) { return false; }
|
|
|
|
static inline bool sorted(const Slic3r::Polygons& /* polygon_set */) { return false; }
|
2014-04-24 11:43:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
2016-12-08 14:16:09 +00:00
|
|
|
struct polygon_set_mutable_traits<Slic3r::Polygons> {
|
2014-04-24 11:43:24 +00:00
|
|
|
template <typename input_iterator_type>
|
2016-12-08 14:16:09 +00:00
|
|
|
static inline void set(Slic3r::Polygons& polygons, input_iterator_type input_begin, input_iterator_type input_end) {
|
2014-04-24 11:43:24 +00:00
|
|
|
polygons.assign(input_begin, input_end);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} }
|
|
|
|
// end Boost
|
|
|
|
|
2013-07-14 13:53:53 +00:00
|
|
|
#endif
|