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.
203{
205 namespace sl = shapelike;
206
207 RawShape rsh;
208 Vertex top_nfp;
209 std::vector<Edge> edgelist;
210
211 auto cap = sl::contourVertexCount(sh) + sl::contourVertexCount(other);
212
213
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 {
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 {
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);
254
255
256 Vertex p1 = e1.second() - e1.first();
257 Vertex p2 = e2.second() - e2.first();
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274 std::array<int, 4> quadrants {0, 3, 1, 2 };
275
276 std::array<int, 2> q {0, 0};
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
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]) {
289 auto lsq1 = pl::magnsq(p1);
290 auto lsq2 = pl::magnsq(p2);
291
292
293
294 int sign = q[0] == 1 || q[0] == 2 ? -1 : 1;
295
296
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
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