diff --git a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp index c05d08d0d..9f881e7e0 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp +++ b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp @@ -113,6 +113,7 @@ template<> struct CountourType<PolygonImpl> { template<> struct ShapeTag<PolygonImpl> { using Type = PolygonTag; }; template<> struct ShapeTag<PathImpl> { using Type = PathTag; }; +template<> struct ShapeTag<PointImpl> { using Type = PointTag; }; template<> struct ShapeTag<TMultiShape<PolygonImpl>> { using Type = MultiPolygonTag; diff --git a/src/libnest2d/include/libnest2d/geometry_traits.hpp b/src/libnest2d/include/libnest2d/geometry_traits.hpp index 828044afe..917f5280d 100644 --- a/src/libnest2d/include/libnest2d/geometry_traits.hpp +++ b/src/libnest2d/include/libnest2d/geometry_traits.hpp @@ -69,12 +69,14 @@ struct PointPair { RawPoint p2; }; +struct PointTag {}; struct PolygonTag {}; struct PathTag {}; struct MultiPolygonTag {}; struct BoxTag {}; struct CircleTag {}; +/// Meta-functions to derive the tags template<class Shape> struct ShapeTag { using Type = typename Shape::Tag; }; template<class S> using Tag = typename ShapeTag<remove_cvref_t<S>>::Type; @@ -131,7 +133,7 @@ public: _Circle(const RawPoint& center, double r): center_(center), radius_(r) {} inline const RawPoint& center() const BP2D_NOEXCEPT { return center_; } - inline const void center(const RawPoint& c) { center_ = c; } + inline void center(const RawPoint& c) { center_ = c; } inline double radius() const BP2D_NOEXCEPT { return radius_; } inline void radius(double r) { radius_ = r; } @@ -518,21 +520,19 @@ inline bool intersects(const RawShape& /*sh*/, const RawShape& /*sh*/) return false; } -template<class RawShape> -inline bool isInside(const TPoint<RawShape>& /*point*/, - const RawShape& /*shape*/) -{ - static_assert(always_false<RawShape>::value, - "shapelike::isInside(point, shape) unimplemented!"); +template<class TGuest, class THost> +inline bool isInside(const TGuest&, const THost&, + const PointTag&, const PolygonTag&) { + static_assert(always_false<THost>::value, + "shapelike::isInside(point, path) unimplemented!"); return false; } -template<class RawShape> -inline bool isInside(const RawShape& /*shape*/, - const RawShape& /*shape*/) -{ - static_assert(always_false<RawShape>::value, - "shapelike::isInside(shape, shape) unimplemented!"); +template<class TGuest, class THost> +inline bool isInside(const TGuest&, const THost&, + const PolygonTag&, const PolygonTag&) { + static_assert(always_false<THost>::value, + "shapelike::isInside(shape, shape) unimplemented!"); return false; } @@ -651,7 +651,7 @@ template<class RawPath> inline bool isConvex(const RawPath& sh, const PathTag&) template<class RawShape> inline typename TContour<RawShape>::iterator -begin(RawShape& sh, const PolygonTag& t) +begin(RawShape& sh, const PolygonTag&) { return begin(contour(sh), PathTag()); } @@ -818,16 +818,16 @@ inline auto convexHull(const RawShape& sh) return convexHull(sh, Tag<RawShape>()); } -template<class RawShape> -inline bool isInside(const TPoint<RawShape>& point, - const _Circle<TPoint<RawShape>>& circ) +template<class TP, class TC> +inline bool isInside(const TP& point, const TC& circ, + const PointTag&, const CircleTag&) { return pointlike::distance(point, circ.center()) < circ.radius(); } -template<class RawShape> -inline bool isInside(const TPoint<RawShape>& point, - const _Box<TPoint<RawShape>>& box) +template<class TP, class TB> +inline bool isInside(const TP& point, const TB& box, + const PointTag&, const BoxTag&) { auto px = getX(point); auto py = getY(point); @@ -839,27 +839,27 @@ inline bool isInside(const TPoint<RawShape>& point, return px > minx && px < maxx && py > miny && py < maxy; } -template<class RawShape> -inline bool isInside(const RawShape& sh, - const _Circle<TPoint<RawShape>>& circ) +template<class RawShape, class TC> +inline bool isInside(const RawShape& sh, const TC& circ, + const PolygonTag&, const CircleTag&) { - return std::all_of(cbegin(sh), cend(sh), - [&circ](const TPoint<RawShape>& p){ - return isInside<RawShape>(p, circ); + return std::all_of(cbegin(sh), cend(sh), [&circ](const TPoint<RawShape>& p) + { + return isInside(p, circ, PointTag(), CircleTag()); }); } -template<class RawShape> -inline bool isInside(const _Box<TPoint<RawShape>>& box, - const _Circle<TPoint<RawShape>>& circ) +template<class TB, class TC> +inline bool isInside(const TB& box, const TC& circ, + const BoxTag&, const CircleTag&) { - return isInside<RawShape>(box.minCorner(), circ) && - isInside<RawShape>(box.maxCorner(), circ); + return isInside(box.minCorner(), circ, BoxTag(), CircleTag()) && + isInside(box.maxCorner(), circ, BoxTag(), CircleTag()); } -template<class RawShape> -inline bool isInside(const _Box<TPoint<RawShape>>& ibb, - const _Box<TPoint<RawShape>>& box) +template<class TBGuest, class TBHost> +inline bool isInside(const TBGuest& ibb, const TBHost& box, + const BoxTag&, const BoxTag&) { auto iminX = getX(ibb.minCorner()); auto imaxX = getX(ibb.maxCorner()); @@ -874,6 +874,18 @@ inline bool isInside(const _Box<TPoint<RawShape>>& ibb, return iminX > minX && imaxX < maxX && iminY > minY && imaxY < maxY; } +template<class RawShape, class TB> +inline bool isInside(const RawShape& poly, const TB& box, + const PolygonTag&, const BoxTag&) +{ + return isInside(boundingBox(poly), box, BoxTag(), BoxTag()); +} + +template<class TGuest, class THost> +inline bool isInside(const TGuest& guest, const THost& host) { + return isInside(guest, host, Tag<TGuest>(), Tag<THost>()); +} + template<class RawShape> // Potential O(1) implementation may exist inline TPoint<RawShape>& vertex(RawShape& sh, unsigned long idx, const PolygonTag&) diff --git a/src/libnest2d/include/libnest2d/libnest2d.hpp b/src/libnest2d/include/libnest2d/libnest2d.hpp index 3d0c6f9a4..49baa65f2 100644 --- a/src/libnest2d/include/libnest2d/libnest2d.hpp +++ b/src/libnest2d/include/libnest2d/libnest2d.hpp @@ -482,12 +482,12 @@ public: template<class RawShape> inline bool _Item<RawShape>::isInside(const _Box<TPoint<RawShape>>& box) const { - return sl::isInside<RawShape>(boundingBox(), box); + return sl::isInside(boundingBox(), box); } template<class RawShape> inline bool _Item<RawShape>::isInside(const _Circle<TPoint<RawShape>>& circ) const { - return sl::isInside<RawShape>(transformedShape(), circ); + return sl::isInside(transformedShape(), circ); } template<class RawShape> using _ItemRef = std::reference_wrapper<_Item<RawShape>>; diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp index 4573027e4..6fb717a7a 100644 --- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp +++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp @@ -916,8 +916,8 @@ private: if(config_.alignment == Config::Alignment::DONT_ALIGN) ins_check = [&binbb, norm](const Box& fullbb) { double ret = 0; - if(sl::isInside<RawShape>(fullbb, binbb)) - ret += norm*norm; + if(!sl::isInside(fullbb, binbb)) + ret += norm; return ret; }; else @@ -958,9 +958,10 @@ private: ecache[opt.nfpidx].coords(opt.hidx, opt.relpos); }; - auto boundaryCheck = - [&merged_pile, &getNfpPoint, &item, &bin, &iv, &startpos] - (const Optimum& o) + auto alignment = config_.alignment; + + auto boundaryCheck = [alignment, &merged_pile, &getNfpPoint, + &item, &bin, &iv, &startpos] (const Optimum& o) { auto v = getNfpPoint(o); auto d = v - iv; @@ -971,7 +972,12 @@ private: auto chull = sl::convexHull(merged_pile); merged_pile.pop_back(); - return overfit(chull, bin); + double miss = 0; + if(alignment == Config::Alignment::DONT_ALIGN) + miss = sl::isInside(chull, bin) ? -1.0 : 1.0; + else miss = overfit(chull, bin); + + return miss; }; Optimum optimum(0, 0); diff --git a/src/libnest2d/include/libnest2d/utils/boost_alg.hpp b/src/libnest2d/include/libnest2d/utils/boost_alg.hpp index c573edb47..a6988ca00 100644 --- a/src/libnest2d/include/libnest2d/utils/boost_alg.hpp +++ b/src/libnest2d/include/libnest2d/utils/boost_alg.hpp @@ -356,13 +356,15 @@ inline double area(const PolygonImpl& shape, const PolygonTag&) #endif template<> -inline bool isInside(const PointImpl& point, const PolygonImpl& shape) +inline bool isInside(const PointImpl& point, const PolygonImpl& shape, + const PointTag&, const PolygonTag&) { return boost::geometry::within(point, shape); } template<> -inline bool isInside(const PolygonImpl& sh1, const PolygonImpl& sh2) +inline bool isInside(const PolygonImpl& sh1, const PolygonImpl& sh2, + const PolygonTag&, const PolygonTag&) { return boost::geometry::within(sh1, sh2); }