Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
libnest2d::nfp Namespace Reference

A collection of static methods for handling the no fit polygon creation. More...

Classes

struct  MaxNfpLevel
 
struct  NfpImpl
 
struct  NfpImpl< S, NfpLevel::CONVEX_ONLY >
 

Typedefs

template<class RawShape >
using NfpResult = std::pair< RawShape, TPoint< RawShape > >
 
template<class RawShape >
using Shapes = TMultiShape< RawShape >
 

Enumerations

enum class  NfpLevel : unsigned {
  CONVEX_ONLY , ONE_CONVEX , BOTH_CONCAVE , ONE_CONVEX_WITH_HOLES ,
  BOTH_CONCAVE_WITH_HOLES
}
 The complexity level of a polygon that an NFP implementation can handle. More...
 

Functions

template<>
TMultiShape< PolygonImplmerge (const TMultiShape< PolygonImpl > &shapes)
 
template<class RawShapes >
RawShapes merge (const RawShapes &)
 
template<class RawShape >
TMultiShape< RawShape > merge (const TMultiShape< RawShape > &shc, const RawShape &sh)
 
template<class RawShape >
TPoint< RawShape > leftmostDownVertex (const RawShape &sh)
 
template<class RawShape >
TPoint< RawShape > rightmostUpVertex (const RawShape &sh)
 
template<class RawShape >
TPoint< RawShape > referenceVertex (const RawShape &sh)
 
template<class RawShape , class Ratio = double>
NfpResult< RawShape > nfpConvexOnly (const RawShape &sh, const RawShape &other)
 
template<NfpLevel nfptype, class RawShape >
NfpResult< RawShape > noFitPolygon (const RawShape &sh, const RawShape &other)
 Helper function to get the NFP.
 

Variables

const double BP2D_CONSTEXPR TwoPi = 2*Pi
 

Detailed Description

A collection of static methods for handling the no fit polygon creation.

Typedef Documentation

◆ NfpResult

template<class RawShape >
using libnest2d::nfp::NfpResult = typedef std::pair<RawShape, TPoint<RawShape> >

◆ Shapes

template<class RawShape >
using libnest2d::nfp::Shapes = typedef TMultiShape<RawShape>

Enumeration Type Documentation

◆ NfpLevel

enum class libnest2d::nfp::NfpLevel : unsigned
strong

The complexity level of a polygon that an NFP implementation can handle.

Enumerator
CONVEX_ONLY 
ONE_CONVEX 
BOTH_CONCAVE 
ONE_CONVEX_WITH_HOLES 
BOTH_CONCAVE_WITH_HOLES 

Function Documentation

◆ leftmostDownVertex()

template<class RawShape >
TPoint< RawShape > libnest2d::nfp::leftmostDownVertex ( const RawShape &  sh)
inline

Get the vertex of the polygon that is at the lowest values (bottom) in the Y axis and if there are more than one vertices on the same Y coordinate than the result will be the leftmost (with the highest X coordinate).

144{
145
146 // find min x and min y vertex
147 auto it = std::min_element(shapelike::cbegin(sh), shapelike::cend(sh),
148 __nfp::_vsort<RawShape>);
149
150 return it == shapelike::cend(sh) ? TPoint<RawShape>() : *it;;
151}
typename PointType< remove_cvref_t< Shape > >::Type TPoint
TPoint<ShapeClass> as shorthand for typename PointType<ShapeClass>::Type.
Definition geometry_traits.hpp:46

References libnest2d::shapelike::cbegin(), and libnest2d::shapelike::cend().

+ Here is the call graph for this function:

◆ merge() [1/3]

template<class RawShapes >
RawShapes libnest2d::nfp::merge ( const RawShapes &  )
inline

Merge a bunch of polygons with the specified additional polygon.

Template Parameters
RawShapethe Polygon data type.
Parameters
shcThe pile of polygons that will be unified with sh.
shA single polygon to unify with shc.
Returns
A set of polygons that is the union of the input polygons. Note that mostly it will be a set containing only one big polygon but if the input polygons are disjunct than the resulting set will contain more polygons.
112{
113 static_assert(always_false<RawShapes>::value,
114 "Nfp::merge(shapes, shape) unimplemented!");
115}
Definition common.hpp:95

◆ merge() [2/3]

template<>
TMultiShape< PolygonImpl > libnest2d::nfp::merge ( const TMultiShape< PolygonImpl > &  shapes)
inline
260{
261 return Slic3r::union_ex(shapes);
262}
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, ClipperLib::PolyFillType fill_type)
Definition ClipperUtils.cpp:774

References Slic3r::union_ex().

Referenced by libnest2d::placers::_NofitPolyPlacer< RawShape, TBin >::calcnfp(), merge(), and libnest2d::placers::_NofitPolyPlacer< RawShape, TBin >::preload().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ merge() [3/3]

template<class RawShape >
TMultiShape< RawShape > libnest2d::nfp::merge ( const TMultiShape< RawShape > &  shc,
const RawShape &  sh 
)
inline

Merge a bunch of polygons with the specified additional polygon.

Template Parameters
RawShapethe Polygon data type.
Parameters
shcThe pile of polygons that will be unified with sh.
shA single polygon to unify with shc.
Returns
A set of polygons that is the union of the input polygons. Note that mostly it will be a set containing only one big polygon but if the input polygons are disjunct than the resulting set will contain more polygons.
131{
132 auto m = nfp::merge(shc);
133 m.emplace_back(sh);
134 return nfp::merge(m);
135}

References merge().

+ Here is the call graph for this function:

◆ nfpConvexOnly()

template<class RawShape , class Ratio = double>
NfpResult< RawShape > libnest2d::nfp::nfpConvexOnly ( const RawShape &  sh,
const RawShape &  other 
)
inline

The "trivial" Cuninghame-Green implementation of NFP for convex polygons.

You can use this even if you provide implementations for the more complex cases (Through specializing the the NfpImpl struct). Currently, no other cases are covered in the library.

Complexity should be no more than nlogn (std::sort) in the number of edges of the input polygons.

Template Parameters
RawShapethe Polygon data type.
Parameters
shThe stationary polygon
cotherThe orbiting polygon
Returns
Returns a pair of the NFP and its reference vertex of the two input polygons which have to be strictly convex. The resulting NFP is proven to be convex as well in this case.
203{
204 using Vertex = TPoint<RawShape>; using Edge = _Segment<Vertex>;
205 namespace sl = shapelike;
206
207 RawShape rsh; // Final nfp placeholder
208 Vertex top_nfp;
209 std::vector<Edge> edgelist;
210
211 auto cap = sl::contourVertexCount(sh) + sl::contourVertexCount(other);
212
213 // Reserve the needed memory
214 edgelist.reserve(cap);
215 sl::reserve(rsh, static_cast<unsigned long>(cap));
216 auto add_edge = [&edgelist](const Vertex &v1, const Vertex &v2) {
217 Edge e{v1, v2};
218 if (e.sqlength() > 0)
219 edgelist.emplace_back(e);
220 };
221
222 { // place all edges from sh into edgelist
223 auto first = sl::cbegin(sh);
224 auto next = std::next(first);
225
226 while(next != sl::cend(sh)) {
227 add_edge(*(first), *(next));
228
229 ++first; ++next;
230 }
231
232 if constexpr (ClosureTypeV<RawShape> == Closure::OPEN)
233 add_edge(*sl::rcbegin(sh), *sl::cbegin(sh));
234 }
235
236 { // place all edges from other into edgelist
237 auto first = sl::cbegin(other);
238 auto next = std::next(first);
239
240 while(next != sl::cend(other)) {
241 add_edge(*(next), *(first));
242
243 ++first; ++next;
244 }
245
246 if constexpr (ClosureTypeV<RawShape> == Closure::OPEN)
247 add_edge(*sl::cbegin(other), *sl::rcbegin(other));
248 }
249
250 std::sort(edgelist.begin(), edgelist.end(),
251 [](const Edge& e1, const Edge& e2)
252 {
253 const Vertex ax(1, 0); // Unit vector for the X axis
254
255 // get cectors from the edges
256 Vertex p1 = e1.second() - e1.first();
257 Vertex p2 = e2.second() - e2.first();
258
259 // Quadrant mapping array. The quadrant of a vector can be determined
260 // from the dot product of the vector and its perpendicular pair
261 // with the unit vector X axis. The products will carry the values
262 // lcos = dot(p, ax) = l * cos(phi) and
263 // lsin = -dotperp(p, ax) = l * sin(phi) where
264 // l is the length of vector p. From the signs of these values we can
265 // construct an index which has the sign of lcos as MSB and the
266 // sign of lsin as LSB. This index can be used to retrieve the actual
267 // quadrant where vector p resides using the following map:
268 // (+ is 0, - is 1)
269 // cos | sin | decimal | quadrant
270 // + | + | 0 | 0
271 // + | - | 1 | 3
272 // - | + | 2 | 1
273 // - | - | 3 | 2
274 std::array<int, 4> quadrants {0, 3, 1, 2 };
275
276 std::array<int, 2> q {0, 0}; // Quadrant indices for p1 and p2
277
278 using TDots = std::array<TCompute<Vertex>, 2>;
279 TDots lcos { pl::dot(p1, ax), pl::dot(p2, ax) };
280 TDots lsin { -pl::dotperp(p1, ax), -pl::dotperp(p2, ax) };
281
282 // Construct the quadrant indices for p1 and p2
283 for(size_t i = 0; i < 2; ++i)
284 if(lcos[i] == 0) q[i] = lsin[i] > 0 ? 1 : 3;
285 else if(lsin[i] == 0) q[i] = lcos[i] > 0 ? 0 : 2;
286 else q[i] = quadrants[((lcos[i] < 0) << 1) + (lsin[i] < 0)];
287
288 if(q[0] == q[1]) { // only bother if p1 and p2 are in the same quadrant
289 auto lsq1 = pl::magnsq(p1); // squared magnitudes, avoid sqrt
290 auto lsq2 = pl::magnsq(p2); // squared magnitudes, avoid sqrt
291
292 // We will actually compare l^2 * cos^2(phi) which saturates the
293 // cos function. But with the quadrant info we can get the sign back
294 int sign = q[0] == 1 || q[0] == 2 ? -1 : 1;
295
296 // If Ratio is an actual rational type, there is no precision loss
297 auto pcos1 = Ratio(lcos[0]) / lsq1 * sign * lcos[0];
298 auto pcos2 = Ratio(lcos[1]) / lsq2 * sign * lcos[1];
299
300 if constexpr (is_clockwise<RawShape>())
301 return q[0] < 2 ? pcos1 < pcos2 : pcos1 > pcos2;
302 else
303 return q[0] < 2 ? pcos1 > pcos2 : pcos1 < pcos2;
304 }
305
306 // If in different quadrants, compare the quadrant indices only.
307 if constexpr (is_clockwise<RawShape>())
308 return q[0] > q[1];
309 else
310 return q[0] < q[1];
311 });
312
313 __nfp::buildPolygon(edgelist, rsh, top_nfp);
314
315 return {rsh, top_nfp};
316}
EIGEN_DEVICE_FUNC const SignReturnType sign() const
Definition ArrayCwiseUnaryOps.h:184
An abstraction of a directed line segment with two points.
Definition geometry_traits.hpp:246

References libnest2d::shapelike::cbegin(), libnest2d::shapelike::cend(), libnest2d::shapelike::contourVertexCount(), libnest2d::pointlike::dot(), libnest2d::pointlike::dotperp(), libnest2d::pointlike::magnsq(), libnest2d::OPEN, libnest2d::shapelike::rcbegin(), libnest2d::shapelike::reserve(), and sign().

Referenced by libnest2d::nfp::NfpImpl< RawShape, nfptype >::operator()().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ noFitPolygon()

template<NfpLevel nfptype, class RawShape >
NfpResult< RawShape > libnest2d::nfp::noFitPolygon ( const RawShape &  sh,
const RawShape &  other 
)
inline

Helper function to get the NFP.

337{
339 return nfps(sh, other);
340}
Definition geometry_traits_nfp.hpp:321

References noFitPolygon().

Referenced by noFitPolygon().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ referenceVertex()

template<class RawShape >
TPoint< RawShape > libnest2d::nfp::referenceVertex ( const RawShape &  sh)
inline

A method to get a vertex from a polygon that always maintains a relative position to the coordinate system: It is always the rightmost top vertex.

This way it does not matter in what order the vertices are stored, the reference will be always the same for the same polygon.

178{
179 return rightmostUpVertex(sh);
180}
TPoint< RawShape > rightmostUpVertex(const RawShape &sh)
Definition geometry_traits_nfp.hpp:159

References rightmostUpVertex().

+ Here is the call graph for this function:

◆ rightmostUpVertex()

template<class RawShape >
TPoint< RawShape > libnest2d::nfp::rightmostUpVertex ( const RawShape &  sh)

Get the vertex of the polygon that is at the highest values (top) in the Y axis and if there are more than one vertices on the same Y coordinate than the result will be the rightmost (with the lowest X coordinate).

160{
161
162 // find max x and max y vertex
163 auto it = std::max_element(shapelike::cbegin(sh), shapelike::cend(sh),
164 __nfp::_vsort<RawShape>);
165
166 return it == shapelike::cend(sh) ? TPoint<RawShape>() : *it;
167}

References libnest2d::shapelike::cbegin(), and libnest2d::shapelike::cend().

Referenced by libnest2d::placers::correctNfpPosition(), and referenceVertex().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ TwoPi

const double BP2D_CONSTEXPR libnest2d::nfp::TwoPi = 2*Pi