1 #ifndef ARRANGE_HPP
2 #define ARRANGE_HPP
3 
4 #include "ExPolygon.hpp"
5 
6 namespace Slic3r {
7 
8 class BoundingBox;
9 
10 namespace arrangement {
11 
12 /// A geometry abstraction for a circular print bed. Similarly to BoundingBox.
13 class CircleBed {
14     Point center_;
15     double radius_;
16 public:
17 
CircleBed()18     inline CircleBed(): center_(0, 0), radius_(std::nan("")) {}
CircleBed(const Point & c,double r)19     explicit inline CircleBed(const Point& c, double r): center_(c), radius_(r) {}
20 
radius() const21     inline double radius() const { return radius_; }
center() const22     inline const Point& center() const { return center_; }
23 };
24 
25 /// Representing an unbounded bed.
26 struct InfiniteBed {
27     Point center;
InfiniteBedSlic3r::arrangement::InfiniteBed28     explicit InfiniteBed(const Point &p = {0, 0}): center{p} {}
29 };
30 
31 /// A logical bed representing an object not being arranged. Either the arrange
32 /// has not yet successfully run on this ArrangePolygon or it could not fit the
33 /// object due to overly large size or invalid geometry.
34 static const constexpr int UNARRANGED = -1;
35 
36 /// Input/Output structure for the arrange() function. The poly field will not
37 /// be modified during arrangement. Instead, the translation and rotation fields
38 /// will mark the needed transformation for the polygon to be in the arranged
39 /// position. These can also be set to an initial offset and rotation.
40 ///
41 /// The bed_idx field will indicate the logical bed into which the
42 /// polygon belongs: UNARRANGED means no place for the polygon
43 /// (also the initial state before arrange), 0..N means the index of the bed.
44 /// Zero is the physical bed, larger than zero means a virtual bed.
45 struct ArrangePolygon {
46     ExPolygon poly;                 /// The 2D silhouette to be arranged
47     Vec2crd   translation{0, 0};    /// The translation of the poly
48     double    rotation{0.0};        /// The rotation of the poly in radians
49     coord_t   inflation = 0;        /// Arrange with inflated polygon
50     int       bed_idx{UNARRANGED};  /// To which logical bed does poly belong...
51     int       priority{0};
52 
53     // If empty, any rotation is allowed (currently unsupported)
54     // If only a zero is there, no rotation is allowed
55     std::vector<double> allowed_rotations = {0.};
56 
57     /// Optional setter function which can store arbitrary data in its closure
58     std::function<void(const ArrangePolygon&)> setter = nullptr;
59 
60     /// Helper function to call the setter with the arrange data arguments
applySlic3r::arrangement::ArrangePolygon61     void apply() const { if (setter) setter(*this); }
62 
63     /// Test if arrange() was called previously and gave a successful result.
is_arrangedSlic3r::arrangement::ArrangePolygon64     bool is_arranged() const { return bed_idx != UNARRANGED; }
65 
transformed_polySlic3r::arrangement::ArrangePolygon66     inline ExPolygon transformed_poly() const
67     {
68         ExPolygon ret = poly;
69         ret.rotate(rotation);
70         ret.translate(translation.x(), translation.y());
71 
72         return ret;
73     }
74 };
75 
76 using ArrangePolygons = std::vector<ArrangePolygon>;
77 
78 struct ArrangeParams {
79 
80     /// The minimum distance which is allowed for any
81     /// pair of items on the print bed in any direction.
82     coord_t min_obj_distance = 0;
83 
84     /// The accuracy of optimization.
85     /// Goes from 0.0 to 1.0 and scales performance as well
86     float accuracy = 1.f;
87 
88     /// Allow parallel execution.
89     bool parallel = true;
90 
91     bool allow_rotations = false;
92 
93     /// Progress indicator callback called when an object gets packed.
94     /// The unsigned argument is the number of items remaining to pack.
95     std::function<void(unsigned)> progressind;
96 
97     std::function<void(const ArrangePolygon &)> on_packed;
98 
99     /// A predicate returning true if abort is needed.
100     std::function<bool(void)>     stopcondition;
101 
102     ArrangeParams() = default;
ArrangeParamsSlic3r::arrangement::ArrangeParams103     explicit ArrangeParams(coord_t md) : min_obj_distance(md) {}
104 };
105 
106 /**
107  * \brief Arranges the input polygons.
108  *
109  * WARNING: Currently, only convex polygons are supported by the libnest2d
110  * library which is used to do the arrangement. This might change in the future
111  * this is why the interface contains a general polygon capable to have holes.
112  *
113  * \param items Input vector of ArrangePolygons. The transformation, rotation
114  * and bin_idx fields will be changed after the call finished and can be used
115  * to apply the result on the input polygon.
116  */
117 template<class TBed> void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const TBed &bed, const ArrangeParams &params = {});
118 
119 // A dispatch function that determines the bed shape from a set of points.
120 template<> void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const Points &bed, const ArrangeParams &params);
121 
122 extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const BoundingBox &bed, const ArrangeParams &params);
123 extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const CircleBed &bed, const ArrangeParams &params);
124 extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const Polygon &bed, const ArrangeParams &params);
125 extern template void arrange(ArrangePolygons &items, const ArrangePolygons &excludes, const InfiniteBed &bed, const ArrangeParams &params);
126 
arrange(ArrangePolygons & items,const Points & bed,const ArrangeParams & params={})127 inline void arrange(ArrangePolygons &items, const Points &bed, const ArrangeParams &params = {}) { arrange(items, {}, bed, params); }
arrange(ArrangePolygons & items,const BoundingBox & bed,const ArrangeParams & params={})128 inline void arrange(ArrangePolygons &items, const BoundingBox &bed, const ArrangeParams &params = {}) { arrange(items, {}, bed, params); }
arrange(ArrangePolygons & items,const CircleBed & bed,const ArrangeParams & params={})129 inline void arrange(ArrangePolygons &items, const CircleBed &bed, const ArrangeParams &params = {}) { arrange(items, {}, bed, params); }
arrange(ArrangePolygons & items,const Polygon & bed,const ArrangeParams & params={})130 inline void arrange(ArrangePolygons &items, const Polygon &bed, const ArrangeParams &params = {}) { arrange(items, {}, bed, params); }
arrange(ArrangePolygons & items,const InfiniteBed & bed,const ArrangeParams & params={})131 inline void arrange(ArrangePolygons &items, const InfiniteBed &bed, const ArrangeParams &params = {}) { arrange(items, {}, bed, params); }
132 
133 }} // namespace Slic3r::arrangement
134 
135 #endif // MODELARRANGE_HPP
136