Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnest2d/libnest2d/geometry_traits.hpp')
-rw-r--r--src/libnest2d/libnest2d/geometry_traits.hpp825
1 files changed, 825 insertions, 0 deletions
diff --git a/src/libnest2d/libnest2d/geometry_traits.hpp b/src/libnest2d/libnest2d/geometry_traits.hpp
new file mode 100644
index 000000000..a78a03b3a
--- /dev/null
+++ b/src/libnest2d/libnest2d/geometry_traits.hpp
@@ -0,0 +1,825 @@
+#ifndef GEOMETRY_TRAITS_HPP
+#define GEOMETRY_TRAITS_HPP
+
+#include <string>
+#include <type_traits>
+#include <algorithm>
+#include <array>
+#include <vector>
+#include <numeric>
+#include <limits>
+#include <cmath>
+
+#include "common.hpp"
+
+namespace libnest2d {
+
+/// Getting the coordinate data type for a geometry class.
+template<class GeomClass> struct CoordType { using Type = long; };
+
+/// TCoord<GeomType> as shorthand for typename `CoordType<GeomType>::Type`.
+template<class GeomType>
+using TCoord = typename CoordType<remove_cvref_t<GeomType>>::Type;
+
+/// Getting the type of point structure used by a shape.
+template<class Sh> struct PointType { using Type = typename Sh::PointType; };
+
+/// TPoint<ShapeClass> as shorthand for `typename PointType<ShapeClass>::Type`.
+template<class Shape>
+using TPoint = typename PointType<remove_cvref_t<Shape>>::Type;
+
+/**
+ * \brief A point pair base class for other point pairs (segment, box, ...).
+ * \tparam RawPoint The actual point type to use.
+ */
+template<class RawPoint>
+struct PointPair {
+ RawPoint p1;
+ RawPoint p2;
+};
+
+struct PolygonTag {};
+struct MultiPolygonTag {};
+struct BoxTag {};
+struct CircleTag {};
+
+template<class Shape> struct ShapeTag { using Type = typename Shape::Tag; };
+template<class S> using Tag = typename ShapeTag<S>::Type;
+
+template<class S> struct MultiShape { using Type = std::vector<S>; };
+template<class S> using TMultiShape = typename MultiShape<S>::Type;
+
+/**
+ * \brief An abstraction of a box;
+ */
+template<class RawPoint>
+class _Box: PointPair<RawPoint> {
+ using PointPair<RawPoint>::p1;
+ using PointPair<RawPoint>::p2;
+public:
+
+ using Tag = BoxTag;
+ using PointType = RawPoint;
+
+ inline _Box() = default;
+ inline _Box(const RawPoint& p, const RawPoint& pp):
+ PointPair<RawPoint>({p, pp}) {}
+
+ inline _Box(TCoord<RawPoint> width, TCoord<RawPoint> height):
+ _Box(RawPoint{0, 0}, RawPoint{width, height}) {}
+
+ inline const RawPoint& minCorner() const BP2D_NOEXCEPT { return p1; }
+ inline const RawPoint& maxCorner() const BP2D_NOEXCEPT { return p2; }
+
+ inline RawPoint& minCorner() BP2D_NOEXCEPT { return p1; }
+ inline RawPoint& maxCorner() BP2D_NOEXCEPT { return p2; }
+
+ inline TCoord<RawPoint> width() const BP2D_NOEXCEPT;
+ inline TCoord<RawPoint> height() const BP2D_NOEXCEPT;
+
+ inline RawPoint center() const BP2D_NOEXCEPT;
+
+ inline double area() const BP2D_NOEXCEPT {
+ return double(width()*height());
+ }
+};
+
+template<class RawPoint>
+class _Circle {
+ RawPoint center_;
+ double radius_ = 0;
+public:
+
+ using Tag = CircleTag;
+ using PointType = RawPoint;
+
+ _Circle() = default;
+
+ _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 double radius() const BP2D_NOEXCEPT { return radius_; }
+ inline void radius(double r) { radius_ = r; }
+
+ inline double area() const BP2D_NOEXCEPT {
+ return 2.0*Pi*radius_*radius_;
+ }
+};
+
+/**
+ * \brief An abstraction of a directed line segment with two points.
+ */
+template<class RawPoint>
+class _Segment: PointPair<RawPoint> {
+ using PointPair<RawPoint>::p1;
+ using PointPair<RawPoint>::p2;
+ mutable Radians angletox_ = std::nan("");
+public:
+
+ using PointType = RawPoint;
+
+ inline _Segment() = default;
+
+ inline _Segment(const RawPoint& p, const RawPoint& pp):
+ PointPair<RawPoint>({p, pp}) {}
+
+ /**
+ * @brief Get the first point.
+ * @return Returns the starting point.
+ */
+ inline const RawPoint& first() const BP2D_NOEXCEPT { return p1; }
+
+ /**
+ * @brief The end point.
+ * @return Returns the end point of the segment.
+ */
+ inline const RawPoint& second() const BP2D_NOEXCEPT { return p2; }
+
+ inline void first(const RawPoint& p) BP2D_NOEXCEPT
+ {
+ angletox_ = std::nan(""); p1 = p;
+ }
+
+ inline void second(const RawPoint& p) BP2D_NOEXCEPT {
+ angletox_ = std::nan(""); p2 = p;
+ }
+
+ /// Returns the angle measured to the X (horizontal) axis.
+ inline Radians angleToXaxis() const;
+
+ /// The length of the segment in the measure of the coordinate system.
+ inline double length();
+};
+
+// This struct serves almost as a namespace. The only difference is that is can
+// used in friend declarations.
+namespace pointlike {
+
+ template<class RawPoint>
+ inline TCoord<RawPoint> x(const RawPoint& p)
+ {
+ return p(0);
+ }
+
+ template<class RawPoint>
+ inline TCoord<RawPoint> y(const RawPoint& p)
+ {
+ return p(1);
+ }
+
+ template<class RawPoint>
+ inline TCoord<RawPoint>& x(RawPoint& p)
+ {
+ return p(0);
+ }
+
+ template<class RawPoint>
+ inline TCoord<RawPoint>& y(RawPoint& p)
+ {
+ return p(1);
+ }
+
+ template<class RawPoint>
+ inline double distance(const RawPoint& /*p1*/, const RawPoint& /*p2*/)
+ {
+ static_assert(always_false<RawPoint>::value,
+ "PointLike::distance(point, point) unimplemented!");
+ return 0;
+ }
+
+ template<class RawPoint>
+ inline double distance(const RawPoint& /*p1*/,
+ const _Segment<RawPoint>& /*s*/)
+ {
+ static_assert(always_false<RawPoint>::value,
+ "PointLike::distance(point, segment) unimplemented!");
+ return 0;
+ }
+
+ template<class RawPoint>
+ inline std::pair<TCoord<RawPoint>, bool> horizontalDistance(
+ const RawPoint& p, const _Segment<RawPoint>& s)
+ {
+ using Unit = TCoord<RawPoint>;
+ auto x = pointlike::x(p), y = pointlike::y(p);
+ auto x1 = pointlike::x(s.first()), y1 = pointlike::y(s.first());
+ auto x2 = pointlike::x(s.second()), y2 = pointlike::y(s.second());
+
+ TCoord<RawPoint> ret;
+
+ if( (y < y1 && y < y2) || (y > y1 && y > y2) )
+ return {0, false};
+ if ((y == y1 && y == y2) && (x > x1 && x > x2))
+ ret = std::min( x-x1, x -x2);
+ else if( (y == y1 && y == y2) && (x < x1 && x < x2))
+ ret = -std::min(x1 - x, x2 - x);
+ else if(std::abs(y - y1) <= std::numeric_limits<Unit>::epsilon() &&
+ std::abs(y - y2) <= std::numeric_limits<Unit>::epsilon())
+ ret = 0;
+ else
+ ret = x - x1 + (x1 - x2)*(y1 - y)/(y1 - y2);
+
+ return {ret, true};
+ }
+
+ template<class RawPoint>
+ inline std::pair<TCoord<RawPoint>, bool> verticalDistance(
+ const RawPoint& p, const _Segment<RawPoint>& s)
+ {
+ using Unit = TCoord<RawPoint>;
+ auto x = pointlike::x(p), y = pointlike::y(p);
+ auto x1 = pointlike::x(s.first()), y1 = pointlike::y(s.first());
+ auto x2 = pointlike::x(s.second()), y2 = pointlike::y(s.second());
+
+ TCoord<RawPoint> ret;
+
+ if( (x < x1 && x < x2) || (x > x1 && x > x2) )
+ return {0, false};
+ if ((x == x1 && x == x2) && (y > y1 && y > y2))
+ ret = std::min( y-y1, y -y2);
+ else if( (x == x1 && x == x2) && (y < y1 && y < y2))
+ ret = -std::min(y1 - y, y2 - y);
+ else if(std::abs(x - x1) <= std::numeric_limits<Unit>::epsilon() &&
+ std::abs(x - x2) <= std::numeric_limits<Unit>::epsilon())
+ ret = 0;
+ else
+ ret = y - y1 + (y1 - y2)*(x1 - x)/(x1 - x2);
+
+ return {ret, true};
+ }
+}
+
+template<class RawPoint>
+TCoord<RawPoint> _Box<RawPoint>::width() const BP2D_NOEXCEPT
+{
+ return pointlike::x(maxCorner()) - pointlike::x(minCorner());
+}
+
+template<class RawPoint>
+TCoord<RawPoint> _Box<RawPoint>::height() const BP2D_NOEXCEPT
+{
+ return pointlike::y(maxCorner()) - pointlike::y(minCorner());
+}
+
+template<class RawPoint>
+TCoord<RawPoint> getX(const RawPoint& p) { return pointlike::x<RawPoint>(p); }
+
+template<class RawPoint>
+TCoord<RawPoint> getY(const RawPoint& p) { return pointlike::y<RawPoint>(p); }
+
+template<class RawPoint>
+void setX(RawPoint& p, const TCoord<RawPoint>& val)
+{
+ pointlike::x<RawPoint>(p) = val;
+}
+
+template<class RawPoint>
+void setY(RawPoint& p, const TCoord<RawPoint>& val)
+{
+ pointlike::y<RawPoint>(p) = val;
+}
+
+template<class RawPoint>
+inline Radians _Segment<RawPoint>::angleToXaxis() const
+{
+ if(std::isnan(static_cast<double>(angletox_))) {
+ TCoord<RawPoint> dx = getX(second()) - getX(first());
+ TCoord<RawPoint> dy = getY(second()) - getY(first());
+
+ double a = std::atan2(dy, dx);
+ auto s = std::signbit(a);
+
+ if(s) a += Pi_2;
+ angletox_ = a;
+ }
+ return angletox_;
+}
+
+template<class RawPoint>
+inline double _Segment<RawPoint>::length()
+{
+ return pointlike::distance(first(), second());
+}
+
+template<class RawPoint>
+inline RawPoint _Box<RawPoint>::center() const BP2D_NOEXCEPT {
+ auto& minc = minCorner();
+ auto& maxc = maxCorner();
+
+ using Coord = TCoord<RawPoint>;
+
+ RawPoint ret = { // No rounding here, we dont know if these are int coords
+ static_cast<Coord>( (getX(minc) + getX(maxc))/2.0 ),
+ static_cast<Coord>( (getY(minc) + getY(maxc))/2.0 )
+ };
+
+ return ret;
+}
+
+template<class RawShape>
+struct HolesContainer {
+ using Type = std::vector<RawShape>;
+};
+
+template<class RawShape>
+using THolesContainer = typename HolesContainer<remove_cvref_t<RawShape>>::Type;
+
+template<class RawShape>
+struct CountourType {
+ using Type = RawShape;
+};
+
+template<class RawShape>
+using TContour = typename CountourType<remove_cvref_t<RawShape>>::Type;
+
+enum class Orientation {
+ CLOCKWISE,
+ COUNTER_CLOCKWISE
+};
+
+template<class RawShape>
+struct OrientationType {
+
+ // Default Polygon orientation that the library expects
+ static const Orientation Value = Orientation::CLOCKWISE;
+};
+
+enum class Formats {
+ WKT,
+ SVG
+};
+
+// This struct serves as a namespace. The only difference is that it can be
+// used in friend declarations and can be aliased at class scope.
+namespace shapelike {
+
+ template<class RawShape>
+ using Shapes = TMultiShape<RawShape>;
+
+ template<class RawShape>
+ inline RawShape create(const TContour<RawShape>& contour,
+ const THolesContainer<RawShape>& holes)
+ {
+ return RawShape(contour, holes);
+ }
+
+ template<class RawShape>
+ inline RawShape create(TContour<RawShape>&& contour,
+ THolesContainer<RawShape>&& holes)
+ {
+ return RawShape(contour, holes);
+ }
+
+ template<class RawShape>
+ inline RawShape create(const TContour<RawShape>& contour)
+ {
+ return create<RawShape>(contour, {});
+ }
+
+ template<class RawShape>
+ inline RawShape create(TContour<RawShape>&& contour)
+ {
+ return create<RawShape>(contour, {});
+ }
+
+ template<class RawShape>
+ inline THolesContainer<RawShape>& holes(RawShape& /*sh*/)
+ {
+ static THolesContainer<RawShape> empty;
+ return empty;
+ }
+
+ template<class RawShape>
+ inline const THolesContainer<RawShape>& holes(const RawShape& /*sh*/)
+ {
+ static THolesContainer<RawShape> empty;
+ return empty;
+ }
+
+ template<class RawShape>
+ inline TContour<RawShape>& getHole(RawShape& sh, unsigned long idx)
+ {
+ return holes(sh)[idx];
+ }
+
+ template<class RawShape>
+ inline const TContour<RawShape>& getHole(const RawShape& sh,
+ unsigned long idx)
+ {
+ return holes(sh)[idx];
+ }
+
+ template<class RawShape>
+ inline size_t holeCount(const RawShape& sh)
+ {
+ return holes(sh).size();
+ }
+
+ template<class RawShape>
+ inline TContour<RawShape>& getContour(RawShape& sh)
+ {
+ return sh;
+ }
+
+ template<class RawShape>
+ inline const TContour<RawShape>& getContour(const RawShape& sh)
+ {
+ return sh;
+ }
+
+ // Optional, does nothing by default
+ template<class RawShape>
+ inline void reserve(RawShape& /*sh*/, size_t /*vertex_capacity*/) {}
+
+ template<class RawShape, class...Args>
+ inline void addVertex(RawShape& sh, Args...args)
+ {
+ return getContour(sh).emplace_back(std::forward<Args>(args)...);
+ }
+
+ template<class RawShape>
+ inline typename TContour<RawShape>::iterator begin(RawShape& sh)
+ {
+ return getContour(sh).begin();
+ }
+
+ template<class RawShape>
+ inline typename TContour<RawShape>::iterator end(RawShape& sh)
+ {
+ return getContour(sh).end();
+ }
+
+ template<class RawShape>
+ inline typename TContour<RawShape>::const_iterator
+ cbegin(const RawShape& sh)
+ {
+ return getContour(sh).cbegin();
+ }
+
+ template<class RawShape>
+ inline typename TContour<RawShape>::const_iterator cend(const RawShape& sh)
+ {
+ return getContour(sh).cend();
+ }
+
+ template<class RawShape>
+ inline std::string toString(const RawShape& /*sh*/)
+ {
+ return "";
+ }
+
+ template<Formats, class RawShape>
+ inline std::string serialize(const RawShape& /*sh*/, double /*scale*/=1)
+ {
+ static_assert(always_false<RawShape>::value,
+ "ShapeLike::serialize() unimplemented!");
+ return "";
+ }
+
+ template<Formats, class RawShape>
+ inline void unserialize(RawShape& /*sh*/, const std::string& /*str*/)
+ {
+ static_assert(always_false<RawShape>::value,
+ "ShapeLike::unserialize() unimplemented!");
+ }
+
+ template<class RawShape>
+ inline double area(const RawShape& /*sh*/, const PolygonTag&)
+ {
+ static_assert(always_false<RawShape>::value,
+ "ShapeLike::area() unimplemented!");
+ return 0;
+ }
+
+ template<class RawShape>
+ inline bool intersects(const RawShape& /*sh*/, const RawShape& /*sh*/)
+ {
+ static_assert(always_false<RawShape>::value,
+ "ShapeLike::intersects() unimplemented!");
+ 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!");
+ 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!");
+ return false;
+ }
+
+ template<class RawShape>
+ inline bool touches( const RawShape& /*shape*/,
+ const RawShape& /*shape*/)
+ {
+ static_assert(always_false<RawShape>::value,
+ "ShapeLike::touches(shape, shape) unimplemented!");
+ return false;
+ }
+
+ template<class RawShape>
+ inline bool touches( const TPoint<RawShape>& /*point*/,
+ const RawShape& /*shape*/)
+ {
+ static_assert(always_false<RawShape>::value,
+ "ShapeLike::touches(point, shape) unimplemented!");
+ return false;
+ }
+
+ template<class RawShape>
+ inline _Box<TPoint<RawShape>> boundingBox(const RawShape& /*sh*/,
+ const PolygonTag&)
+ {
+ static_assert(always_false<RawShape>::value,
+ "ShapeLike::boundingBox(shape) unimplemented!");
+ }
+
+ template<class RawShapes>
+ inline _Box<TPoint<typename RawShapes::value_type>>
+ boundingBox(const RawShapes& /*sh*/, const MultiPolygonTag&)
+ {
+ static_assert(always_false<RawShapes>::value,
+ "ShapeLike::boundingBox(shapes) unimplemented!");
+ }
+
+ template<class RawShape>
+ inline RawShape convexHull(const RawShape& /*sh*/, const PolygonTag&)
+ {
+ static_assert(always_false<RawShape>::value,
+ "ShapeLike::convexHull(shape) unimplemented!");
+ return RawShape();
+ }
+
+ template<class RawShapes>
+ inline typename RawShapes::value_type
+ convexHull(const RawShapes& /*sh*/, const MultiPolygonTag&)
+ {
+ static_assert(always_false<RawShapes>::value,
+ "ShapeLike::convexHull(shapes) unimplemented!");
+ return typename RawShapes::value_type();
+ }
+
+ template<class RawShape>
+ inline void rotate(RawShape& /*sh*/, const Radians& /*rads*/)
+ {
+ static_assert(always_false<RawShape>::value,
+ "ShapeLike::rotate() unimplemented!");
+ }
+
+ template<class RawShape, class RawPoint>
+ inline void translate(RawShape& /*sh*/, const RawPoint& /*offs*/)
+ {
+ static_assert(always_false<RawShape>::value,
+ "ShapeLike::translate() unimplemented!");
+ }
+
+ template<class RawShape>
+ inline void offset(RawShape& /*sh*/, TCoord<TPoint<RawShape>> /*distance*/)
+ {
+ dout() << "The current geometry backend does not support offsetting!\n";
+ }
+
+ template<class RawShape>
+ inline std::pair<bool, std::string> isValid(const RawShape& /*sh*/)
+ {
+ return {false, "ShapeLike::isValid() unimplemented!"};
+ }
+
+ template<class RawShape>
+ inline bool isConvex(const TContour<RawShape>& sh)
+ {
+ using Vertex = TPoint<RawShape>;
+ auto first = sh.begin();
+ auto middle = std::next(first);
+ auto last = std::next(middle);
+ using CVrRef = const Vertex&;
+
+ auto zcrossproduct = [](CVrRef k, CVrRef k1, CVrRef k2) {
+ auto dx1 = getX(k1) - getX(k);
+ auto dy1 = getY(k1) - getY(k);
+ auto dx2 = getX(k2) - getX(k1);
+ auto dy2 = getY(k2) - getY(k1);
+ return dx1*dy2 - dy1*dx2;
+ };
+
+ auto firstprod = zcrossproduct( *(std::prev(std::prev(sh.end()))),
+ *first,
+ *middle );
+
+ bool ret = true;
+ bool frsign = firstprod > 0;
+ while(last != sh.end()) {
+ auto &k = *first, &k1 = *middle, &k2 = *last;
+ auto zc = zcrossproduct(k, k1, k2);
+ ret &= frsign == (zc > 0);
+ ++first; ++middle; ++last;
+ }
+
+ return ret;
+ }
+
+ // *************************************************************************
+ // No need to implement these
+ // *************************************************************************
+
+ template<class Box>
+ inline Box boundingBox(const Box& box, const BoxTag& )
+ {
+ return box;
+ }
+
+ template<class Circle>
+ inline _Box<typename Circle::PointType> boundingBox(
+ const Circle& circ, const CircleTag&)
+ {
+ using Point = typename Circle::PointType;
+ using Coord = TCoord<Point>;
+ Point pmin = {
+ static_cast<Coord>(getX(circ.center()) - circ.radius()),
+ static_cast<Coord>(getY(circ.center()) - circ.radius()) };
+
+ Point pmax = {
+ static_cast<Coord>(getX(circ.center()) + circ.radius()),
+ static_cast<Coord>(getY(circ.center()) + circ.radius()) };
+
+ return {pmin, pmax};
+ }
+
+ template<class S> // Dispatch function
+ inline _Box<TPoint<S>> boundingBox(const S& sh)
+ {
+ return boundingBox(sh, Tag<S>() );
+ }
+
+ template<class Box>
+ inline double area(const Box& box, const BoxTag& )
+ {
+ return box.area();
+ }
+
+ template<class Circle>
+ inline double area(const Circle& circ, const CircleTag& )
+ {
+ return circ.area();
+ }
+
+ template<class RawShape> // Dispatching function
+ inline double area(const RawShape& sh)
+ {
+ return area(sh, Tag<RawShape>());
+ }
+
+ template<class RawShape>
+ inline double area(const Shapes<RawShape>& shapes)
+ {
+ return std::accumulate(shapes.begin(), shapes.end(), 0.0,
+ [](double a, const RawShape& b) {
+ return a += area(b);
+ });
+ }
+
+ template<class RawShape>
+ inline auto convexHull(const RawShape& sh)
+ -> decltype(convexHull(sh, Tag<RawShape>())) // TODO: C++14 could deduce
+ {
+ return convexHull(sh, Tag<RawShape>());
+ }
+
+ template<class RawShape>
+ inline bool isInside(const TPoint<RawShape>& point,
+ const _Circle<TPoint<RawShape>>& circ)
+ {
+ return pointlike::distance(point, circ.center()) < circ.radius();
+ }
+
+ template<class RawShape>
+ inline bool isInside(const TPoint<RawShape>& point,
+ const _Box<TPoint<RawShape>>& box)
+ {
+ auto px = getX(point);
+ auto py = getY(point);
+ auto minx = getX(box.minCorner());
+ auto miny = getY(box.minCorner());
+ auto maxx = getX(box.maxCorner());
+ auto maxy = getY(box.maxCorner());
+
+ return px > minx && px < maxx && py > miny && py < maxy;
+ }
+
+ template<class RawShape>
+ inline bool isInside(const RawShape& sh,
+ const _Circle<TPoint<RawShape>>& circ)
+ {
+ return std::all_of(cbegin(sh), cend(sh),
+ [&circ](const TPoint<RawShape>& p){
+ return isInside<RawShape>(p, circ);
+ });
+ }
+
+ template<class RawShape>
+ inline bool isInside(const _Box<TPoint<RawShape>>& box,
+ const _Circle<TPoint<RawShape>>& circ)
+ {
+ return isInside<RawShape>(box.minCorner(), circ) &&
+ isInside<RawShape>(box.maxCorner(), circ);
+ }
+
+ template<class RawShape>
+ inline bool isInside(const _Box<TPoint<RawShape>>& ibb,
+ const _Box<TPoint<RawShape>>& box)
+ {
+ auto iminX = getX(ibb.minCorner());
+ auto imaxX = getX(ibb.maxCorner());
+ auto iminY = getY(ibb.minCorner());
+ auto imaxY = getY(ibb.maxCorner());
+
+ auto minX = getX(box.minCorner());
+ auto maxX = getX(box.maxCorner());
+ auto minY = getY(box.minCorner());
+ auto maxY = getY(box.maxCorner());
+
+ return iminX > minX && imaxX < maxX && iminY > minY && imaxY < maxY;
+ }
+
+ template<class RawShape> // Potential O(1) implementation may exist
+ inline TPoint<RawShape>& vertex(RawShape& sh, unsigned long idx)
+ {
+ return *(begin(sh) + idx);
+ }
+
+ template<class RawShape> // Potential O(1) implementation may exist
+ inline const TPoint<RawShape>& vertex(const RawShape& sh,
+ unsigned long idx)
+ {
+ return *(cbegin(sh) + idx);
+ }
+
+ template<class RawShape>
+ inline size_t contourVertexCount(const RawShape& sh)
+ {
+ return cend(sh) - cbegin(sh);
+ }
+
+ template<class RawShape, class Fn>
+ inline void foreachContourVertex(RawShape& sh, Fn fn) {
+ for(auto it = begin(sh); it != end(sh); ++it) fn(*it);
+ }
+
+ template<class RawShape, class Fn>
+ inline void foreachHoleVertex(RawShape& sh, Fn fn) {
+ for(int i = 0; i < holeCount(sh); ++i) {
+ auto& h = getHole(sh, i);
+ for(auto it = begin(h); it != end(h); ++it) fn(*it);
+ }
+ }
+
+ template<class RawShape, class Fn>
+ inline void foreachContourVertex(const RawShape& sh, Fn fn) {
+ for(auto it = cbegin(sh); it != cend(sh); ++it) fn(*it);
+ }
+
+ template<class RawShape, class Fn>
+ inline void foreachHoleVertex(const RawShape& sh, Fn fn) {
+ for(int i = 0; i < holeCount(sh); ++i) {
+ auto& h = getHole(sh, i);
+ for(auto it = cbegin(h); it != cend(h); ++it) fn(*it);
+ }
+ }
+
+ template<class RawShape, class Fn>
+ inline void foreachVertex(RawShape& sh, Fn fn) {
+ foreachContourVertex(sh, fn);
+ foreachHoleVertex(sh, fn);
+ }
+
+ template<class RawShape, class Fn>
+ inline void foreachVertex(const RawShape& sh, Fn fn) {
+ foreachContourVertex(sh, fn);
+ foreachHoleVertex(sh, fn);
+ }
+}
+
+#define DECLARE_MAIN_TYPES(T) \
+ using Polygon = T; \
+ using Point = TPoint<T>; \
+ using Coord = TCoord<Point>; \
+ using Contour = TContour<T>; \
+ using Box = _Box<Point>; \
+ using Circle = _Circle<Point>; \
+ using Segment = _Segment<Point>; \
+ using Polygons = TMultiShape<T>
+
+}
+
+#endif // GEOMETRY_TRAITS_HPP