1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
#ifndef slic3r_Geometry_hpp_
#define slic3r_Geometry_hpp_
#include "libslic3r.h"
#include "BoundingBox.hpp"
#include "ExPolygon.hpp"
#include "Polygon.hpp"
#include "Polyline.hpp"
#include "boost/polygon/voronoi.hpp"
using boost::polygon::voronoi_builder;
using boost::polygon::voronoi_diagram;
namespace Slic3r { namespace Geometry {
// Generic result of an orientation predicate.
enum Orientation
{
ORIENTATION_CCW = 1,
ORIENTATION_CW = -1,
ORIENTATION_COLINEAR = 0
};
// Return orientation of the three points (clockwise, counter-clockwise, colinear)
// The predicate is exact for the coord_t type, using 64bit signed integers for the temporaries.
// which means, the coord_t types must not have some of the topmost bits utilized.
// As the points are limited to 30 bits + signum,
// the temporaries u, v, w are limited to 61 bits + signum,
// and d is limited to 63 bits + signum and we are good.
static inline Orientation orient(const Point &a, const Point &b, const Point &c)
{
// BOOST_STATIC_ASSERT(sizeof(coord_t) * 2 == sizeof(int64_t));
int64_t u = int64_t(b(0)) * int64_t(c(1)) - int64_t(b(1)) * int64_t(c(0));
int64_t v = int64_t(a(0)) * int64_t(c(1)) - int64_t(a(1)) * int64_t(c(0));
int64_t w = int64_t(a(0)) * int64_t(b(1)) - int64_t(a(1)) * int64_t(b(0));
int64_t d = u - v + w;
return (d > 0) ? ORIENTATION_CCW : ((d == 0) ? ORIENTATION_COLINEAR : ORIENTATION_CW);
}
// Return orientation of the polygon by checking orientation of the left bottom corner of the polygon
// using exact arithmetics. The input polygon must not contain duplicate points
// (or at least the left bottom corner point must not have duplicates).
static inline bool is_ccw(const Polygon &poly)
{
// The polygon shall be at least a triangle.
assert(poly.points.size() >= 3);
if (poly.points.size() < 3)
return true;
// 1) Find the lowest lexicographical point.
unsigned int imin = 0;
for (unsigned int i = 1; i < poly.points.size(); ++ i) {
const Point &pmin = poly.points[imin];
const Point &p = poly.points[i];
if (p(0) < pmin(0) || (p(0) == pmin(0) && p(1) < pmin(1)))
imin = i;
}
// 2) Detect the orientation of the corner imin.
size_t iPrev = ((imin == 0) ? poly.points.size() : imin) - 1;
size_t iNext = ((imin + 1 == poly.points.size()) ? 0 : imin + 1);
Orientation o = orient(poly.points[iPrev], poly.points[imin], poly.points[iNext]);
// The lowest bottom point must not be collinear if the polygon does not contain duplicate points
// or overlapping segments.
assert(o != ORIENTATION_COLINEAR);
return o == ORIENTATION_CCW;
}
inline bool ray_ray_intersection(const Pointf &p1, const Vectorf &v1, const Pointf &p2, const Vectorf &v2, Pointf &res)
{
double denom = v1(0) * v2(1) - v2(0) * v1(1);
if (std::abs(denom) < EPSILON)
return false;
double t = (v2(0) * (p1(1) - p2(1)) - v2(1) * (p1(0) - p2(0))) / denom;
res(0) = p1(0) + t * v1(0);
res(1) = p1(1) + t * v1(1);
return true;
}
inline bool segment_segment_intersection(const Pointf &p1, const Vectorf &v1, const Pointf &p2, const Vectorf &v2, Pointf &res)
{
double denom = v1(0) * v2(1) - v2(0) * v1(1);
if (std::abs(denom) < EPSILON)
// Lines are collinear.
return false;
double s12_x = p1(0) - p2(0);
double s12_y = p1(1) - p2(1);
double s_numer = v1(0) * s12_y - v1(1) * s12_x;
bool denom_is_positive = false;
if (denom < 0.) {
denom_is_positive = true;
denom = - denom;
s_numer = - s_numer;
}
if (s_numer < 0.)
// Intersection outside of the 1st segment.
return false;
double t_numer = v2(0) * s12_y - v2(1) * s12_x;
if (! denom_is_positive)
t_numer = - t_numer;
if (t_numer < 0. || s_numer > denom || t_numer > denom)
// Intersection outside of the 1st or 2nd segment.
return false;
// Intersection inside both of the segments.
double t = t_numer / denom;
res(0) = p1(0) + t * v1(0);
res(1) = p1(1) + t * v1(1);
return true;
}
Polygon convex_hull(Points points);
Polygon convex_hull(const Polygons &polygons);
void chained_path(const Points &points, std::vector<Points::size_type> &retval, Point start_near);
void chained_path(const Points &points, std::vector<Points::size_type> &retval);
template<class T> void chained_path_items(Points &points, T &items, T &retval);
bool directions_parallel(double angle1, double angle2, double max_diff = 0);
template<class T> bool contains(const std::vector<T> &vector, const Point &point);
double rad2deg(double angle);
double rad2deg_dir(double angle);
template<typename T> T deg2rad(T angle) { return T(PI) * angle / T(180.0); }
void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval);
double linint(double value, double oldmin, double oldmax, double newmin, double newmax);
bool arrange(
// input
size_t num_parts, const Pointf &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box,
// output
Pointfs &positions);
class MedialAxis {
public:
Lines lines;
const ExPolygon* expolygon;
double max_width;
double min_width;
MedialAxis(double _max_width, double _min_width, const ExPolygon* _expolygon = NULL)
: expolygon(_expolygon), max_width(_max_width), min_width(_min_width) {};
void build(ThickPolylines* polylines);
void build(Polylines* polylines);
private:
class VD : public voronoi_diagram<double> {
public:
typedef double coord_type;
typedef boost::polygon::point_data<coordinate_type> point_type;
typedef boost::polygon::segment_data<coordinate_type> segment_type;
typedef boost::polygon::rectangle_data<coordinate_type> rect_type;
};
VD vd;
std::set<const VD::edge_type*> edges, valid_edges;
std::map<const VD::edge_type*, std::pair<coordf_t,coordf_t> > thickness;
void process_edge_neighbors(const VD::edge_type* edge, ThickPolyline* polyline);
bool validate_edge(const VD::edge_type* edge);
const Line& retrieve_segment(const VD::cell_type* cell) const;
const Point& retrieve_endpoint(const VD::cell_type* cell) const;
};
} }
#endif
|