| |
| |
|
|
| #pragma once |
|
|
| #include <algorithm> |
| #include <cmath> |
| #include <iostream> |
| #include <type_traits> |
|
|
| #ifndef _GEOMETRY_NO_TORCH |
| #include <torch/torch.h> |
| #endif |
|
|
| #include "cuda_intellisense.cuh" |
|
|
| #ifndef __NVCC__ |
| #define SORT_ALGO std::sort |
| #define SWAP std::swap |
|
|
| template<typename ...Args> |
| using tuple_t = std::tuple<Args...>; |
|
|
| #else |
|
|
| #include <thrust/sort.h> |
| #include <thrust/tuple.h> |
|
|
| #define SORT_ALGO thrust::sort |
| #define SWAP thrust::swap |
|
|
| template<typename ...Args> |
| using tuple_t = thrust::tuple<Args...>; |
| #endif |
|
|
| template<typename T> |
| struct Point_ { |
| typedef T inner_type; |
|
|
| T X, Y; |
|
|
| Point_() = default; |
|
|
| __any_device__ |
| Point_(T x, T y) : X(x), Y(y) {} |
|
|
| __any_device__ |
| Point_(T *ptr) : X(ptr[0]), Y(ptr[1]) {} |
|
|
| #ifndef _GEOMETRY_NO_TORCH |
| template<typename T2> |
| __any_device__ |
| Point_(const torch::TensorAccessor<T2, 1> &accessor) : X(accessor[0]), Y(accessor[1]) {} |
|
|
| template<typename T2> |
| __any_device__ |
| Point_(const torch::PackedTensorAccessor64<T2, 1> &accessor) : X(accessor[0]), Y(accessor[1]) {} |
| #endif |
|
|
| __any_device__ |
| Point_ &operator+=(const Point_ &other); |
|
|
| __any_device__ |
| Point_ &operator-=(const Point_ &other); |
|
|
| __any_device__ |
| Point_ &operator*=(const Point_ &other); |
|
|
| __any_device__ |
| Point_ &operator/=(const Point_ &other); |
|
|
| template<typename W> |
| __any_device__ |
| Point_ &operator/=(W w); |
|
|
| template<typename W> |
| __any_device__ |
| Point_ &operator*=(W w); |
|
|
| __any_device__ |
| Point_ operator-() { |
| return { -X, -Y }; |
| } |
|
|
| __any_device__ |
| T Sum() const { return X + Y; } |
|
|
| __any_device__ |
| T Angle() const; |
|
|
| __any_device__ |
| void swap(Point_ &other) noexcept { |
| SWAP(X, other.X); |
| SWAP(Y, other.Y); |
| } |
| }; |
|
|
| template<typename T> |
| __lib_inline__ __any_device__ |
| void swap(Point_<T> &a, Point_<T> &b) { |
| a.swap(b); |
| } |
|
|
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ T Point_<T>::Angle() const { |
| #ifndef __NVCC__ |
| using std::atan2; |
| #endif |
| return atan2(Y, X); |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ Point_<T> min(const Point_<T> &a, const Point_<T> &b) { |
| #ifndef __NVCC__ |
| using std::min; |
| #endif |
| return { |
| min(a.X, b.X), |
| min(a.Y, b.Y) |
| }; |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ Point_<T> max(const Point_<T> &a, const Point_<T> &b) { |
| #ifndef __NVCC__ |
| using std::max; |
| #endif |
| return { |
| max(a.X, b.X), |
| max(a.Y, b.Y) |
| }; |
| } |
|
|
| template<typename T> |
| struct AABB_ { |
| typedef T inner_type; |
|
|
| T X; |
| T Y; |
| T MaxX; |
| T MaxY; |
|
|
| AABB_() = default; |
| __any_device__ |
| AABB_(T x, T y, T maxX, T maxY) |
| : X(x), Y(y), MaxX(maxX), MaxY(maxY) {} |
|
|
| __any_device__ |
| bool Contains(const Point_<T> &p) const { |
| return p.X >= X && p.X < MaxX && |
| p.Y >= Y && p.Y < MaxY; |
| } |
|
|
| __any_device__ __lib_inline__ |
| AABB_ Union(const AABB_ &other) const { |
| #ifndef __NVCC__ |
| using std::min; |
| using std::max; |
| #endif |
| T minX = min(X, other.X); |
| T maxX = max(MaxX, other.MaxX); |
| T minY = min(Y, other.Y); |
| T maxY = max(MaxY, other.MaxY); |
|
|
| return { minX, minY, maxX, maxY }; |
| } |
|
|
| __any_device__ |
| AABB_ &operator-=(const Point_<T> &offset) { |
| X -= offset.X; |
| MaxX -= offset.X; |
| Y -= offset.Y; |
| MaxY -= offset.Y; |
| return *this; |
| } |
|
|
| __any_device__ |
| __lib_inline__ T Width() const { return MaxX - X; } |
| __any_device__ |
| __lib_inline__ T Height() const { return MaxY - Y; } |
| __any_device__ |
| __lib_inline__ T Area() const { return Width() * Height(); } |
|
|
| __lib_inline__ T &operator[] (int64_t idx) |
| { |
| static_assert(std::is_standard_layout<AABB_<T>>::value, "This function is only valid for standard layout"); |
| return (&X)[idx]; |
| } |
| __lib_inline__ T operator[] (int64_t idx) const |
| { |
| static_assert(std::is_standard_layout<AABB_<T>>::value, "This function is only valid for standard layout"); |
| return (&X)[idx]; |
| } |
|
|
| __any_device__ __lib_inline__ |
| AABB_ Intersection(const AABB_ &other) const { |
| #ifndef __NVCC__ |
| using std::min; |
| using std::max; |
| #endif |
| T minX = max(X, other.X); |
| T minY = max(Y, other.Y); |
| T maxX = min(MaxX, other.MaxX); |
| T maxY = min(MaxY, other.MaxY); |
| |
| minX = min(minX, maxX); |
| minY = min(minY, maxY); |
| return { minX, minY, maxX, maxY }; |
| } |
|
|
| __any_device__ __lib_inline__ |
| T IntersectionArea(const AABB_ &other) const { return Intersection(other).Area(); } |
| }; |
|
|
| template<typename T, typename Derived> |
| struct QuadBase_ { |
| typedef T inner_type; |
|
|
| __any_device__ |
| AABB_<T> Bounds() const; |
|
|
| __any_device__ |
| bool Contains(const Point_<T> &p) const; |
|
|
| __any_device__ |
| T Area() const; |
|
|
| __any_device__ |
| T Height() const; |
|
|
| __any_device__ |
| T Width() const; |
|
|
| template<typename Derived2> |
| __any_device__ |
| T IntersectionArea(const QuadBase_<T, Derived2> &other) const; |
|
|
| template<typename Derived2> |
| __any_device__ |
| T IOU(const QuadBase_<T, Derived2> &other) const; |
|
|
| template<typename Derived2> |
| __any_device__ |
| T IOU_UpperBound(const QuadBase_<T, Derived2> &other) const; |
|
|
| __any_device__ |
| Point_<T> Center() const; |
|
|
| template<typename Derived2> |
| __any_device__ |
| |
| |
| |
| |
| |
| |
| tuple_t<T, T, T> RegionSizes(const QuadBase_<T, Derived2> &other) const; |
|
|
| template<typename Derived2> |
| __any_device__ |
| tuple_t<T, T, T> RegionSizes_UpperBound(const QuadBase_<T, Derived2> &other) const; |
|
|
| __any_device__ |
| Derived &operator/=(T val) { |
| auto rcp = 1 / val; |
| return *this *= rcp; |
| } |
|
|
| __any_device__ |
| Derived &operator*=(T val) { |
| auto dThis = static_cast<Derived*>(this); |
| #pragma unroll |
| for (size_t i = 0; i < 4; ++i) { |
| dThis->Vertices[i] *= val; |
| } |
| return *dThis; |
| } |
|
|
| friend auto begin(const QuadBase_ &q) { return static_cast<const Derived&>(q).Vertices; } |
| friend auto begin(QuadBase_& q) { return static_cast<const Derived&>(q).Vertices; } |
| friend auto end(const QuadBase_ &q) { return static_cast<const Derived&>(q).Vertices + 4; } |
| friend auto end(QuadBase_ &q) { return static_cast<const Derived&>(q).Vertices + 4; } |
| }; |
|
|
| template<typename T> |
| struct Quad_ : QuadBase_<T, Quad_<T>> { |
| Point_<T> *Vertices = nullptr; |
|
|
| Quad_() = default; |
| __any_device__ |
| Quad_(T *dataPtr) |
| : Vertices(reinterpret_cast<Point_<T>*>(dataPtr)) {} |
| __any_device__ |
| Quad_(Point_<T> *dataPtr) |
| : Vertices(dataPtr) {} |
|
|
| template<typename index_t> |
| __any_device__ __lib_inline__ |
| const Point_<T> &operator[](index_t offset) const { return Vertices[offset]; } |
| template<typename index_t> |
| __any_device__ __lib_inline__ |
| Point_<T> &operator[](index_t offset) { return Vertices[offset]; } |
| }; |
|
|
| template<typename T> |
| struct InPlaceQuad_ : public QuadBase_<T, InPlaceQuad_<T>> { |
| Point_<T> Vertices[4]; |
|
|
| InPlaceQuad_() = default; |
| __any_device__ |
| InPlaceQuad_(const T *dataPtr) |
| { |
| #if defined(__NVCC__) |
| T *pVals = reinterpret_cast<T*>(Vertices); |
| #pragma unroll |
| for (uint32_t i = 0; i < 8; ++i) { |
| pVals[i] = dataPtr[i]; |
| } |
| #else |
| using std::copy; |
| copy(dataPtr, dataPtr + 8, reinterpret_cast<T*>(Vertices)); |
| #endif |
| } |
| __any_device__ |
| InPlaceQuad_(const Point_<T> *dataPtr) |
| { |
| #if defined(__NVCC__) |
| #pragma unroll |
| for (uint32_t i = 0; i < 4; ++i) { |
| Vertices[i] = dataPtr[i]; |
| } |
| #else |
| using std::copy; |
| copy(dataPtr, dataPtr + 4, Vertices); |
| #endif |
| } |
|
|
| template<typename index_t> |
| __any_device__ __lib_inline__ |
| const Point_<T> &operator[](index_t v) const { return Vertices[v]; } |
|
|
| template<typename index_t> |
| __any_device__ __lib_inline__ |
| Point_<T> &operator[](index_t v) { return Vertices[v]; } |
| }; |
|
|
| template<typename T, typename Derived> |
| struct PolygonBase_ { |
| typedef T inner_type; |
|
|
| __any_device__ |
| AABB_<T> Bounds() const; |
|
|
| __any_device__ |
| bool Contains(const Point_<T> &p) const; |
|
|
| __any_device__ |
| T EdgeLength() const; |
|
|
| __any_device__ |
| Point_<T> Center() const; |
|
|
| __any_device__ |
| T Area() const; |
| }; |
|
|
| template<typename T> |
| struct Polygon_ : PolygonBase_<T, Polygon_<T>> { |
| Point_<T> *Vertices = nullptr; |
| size_t Count = 0; |
|
|
| Polygon_() = default; |
| __any_device__ |
| Polygon_(T *dataPtr, size_t vertexCount) |
| : Vertices(reinterpret_cast<Point_<T>*>(dataPtr)), Count(vertexCount) {} |
| __any_device__ |
| Polygon_(Point_<T> *dataPtr, size_t vertexCount) |
| : Vertices(dataPtr), Count(vertexCount) {} |
|
|
| __any_device__ |
| const Point_<T> &operator[](size_t offset) const { return Vertices[offset]; } |
| __any_device__ |
| Point_<T> &operator[](size_t offset) { return Vertices[offset]; } |
| }; |
|
|
| template<typename T> |
| struct Segment_ { |
| Point_<T> A, B; |
|
|
| Segment_() = default; |
| __any_device__ |
| Segment_(const Point_<T> &a, const Point_<T> &b) : A(a), B(b) {} |
|
|
| __any_device__ |
| T Length() const; |
| __any_device__ |
| T LengthSq() const; |
| __any_device__ |
| bool Intersection(const Segment_<T> &other, Point_<T> &out_ptAlong) const; |
| }; |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ Point_<T> operator+(const Point_<T> &a, const Point_<T> &b) { |
| return { a.X + b.X, a.Y + b.Y }; |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ Point_<T> operator-(const Point_<T> &a, const Point_<T> &b) { |
| return { a.X - b.X, a.Y - b.Y }; |
| } |
|
|
| template<typename T, typename W> |
| __any_device__ |
| __lib_inline__ Point_<T> operator*(W scale, const Point_<T> &p) { |
| return { scale * p.X, scale * p.Y }; |
| } |
|
|
| template<typename T, typename W> |
| __any_device__ |
| __lib_inline__ Point_<T> operator*(const Point_<T> &p, W scale) { |
| return { scale * p.X, scale * p.Y }; |
| } |
|
|
| template<typename T, typename W> |
| __any_device__ |
| __lib_inline__ Point_<T> operator/(const Point_<T> &p, W divisor) { |
| return { p.X / divisor, p.Y / divisor }; |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ Point_<T> operator*(const Point_<T> &a, const Point_<T> &b) { |
| return { a.X * b.X, a.Y * b.Y }; |
| } |
|
|
| template<typename T, typename W> |
| __any_device__ |
| __lib_inline__ Point_<T> operator-(const Point_<T> &p, W v) { |
| return { p.X - v, p.Y - v }; |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ Point_<T> &Point_<T>::operator+=(const Point_<T> &p) { |
| X = X + p.X; |
| Y = Y + p.Y; |
| return *this; |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ Point_<T> &Point_<T>::operator-=(const Point_<T> &p) { |
| X = X - p.X; |
| Y = Y - p.Y; |
| return *this; |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ Point_<T> &Point_<T>::operator*=(const Point_<T> &p) { |
| X = X * p.X; |
| Y = Y * p.Y; |
| return *this; |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ Point_<T> &Point_<T>::operator/=(const Point_<T> &p) { |
| X = X / p.X; |
| Y = Y / p.Y; |
| return *this; |
| } |
|
|
| template<typename T> |
| template<typename W> |
| __any_device__ |
| __lib_inline__ Point_<T> &Point_<T>::operator/=(W val) { |
| |
| X /= val; |
| Y /= val; |
| return *this; |
| } |
|
|
| template<typename T> |
| template<typename W> |
| __any_device__ |
| __lib_inline__ Point_<T> &Point_<T>::operator*=(W val) { |
| X *= val; |
| Y *= val; |
| return *this; |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ T dot(const Point_<T> &a, const Point_<T> &b) { |
| return a.X * b.X + a.Y * b.Y; |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ T dot(const Point_<T> &p) { |
| return dot(p, p); |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ T length(const Point_<T> &p) { |
| #ifndef __NVCC__ |
| using std::sqrt; |
| #endif |
| return sqrt(dot(p)); |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ Point_<T> normalize(const Point_<T> &p) { |
| static constexpr T epsilon = std::numeric_limits<T>::epsilon(); |
| auto len = length(p) + epsilon; |
| return { p.X / len, p.Y / len }; |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ Point_<T> ortho_2d(const Point_<T> &p) { |
| return { -p.Y, p.X }; |
| } |
|
|
| template<typename T> |
| __host__ |
| __lib_inline__ std::ostream &operator<<(std::ostream &os, const Point_<T> &p) { |
| return os << "(" << p.X << ", " << p.Y << ")"; |
| } |
|
|
| template<typename T> |
| __host__ |
| __lib_inline__ std::ostream &operator<<(std::ostream &os, const AABB_<T> &b) { |
| return os << "[(" << b.X << ", " << b.Y << "), (" << b.MaxX << ", " << b.MaxY << ")]"; |
| } |
|
|
| template<typename T> |
| __host__ |
| __lib_inline__ std::ostream &operator<<(std::ostream &os, const Segment_<T> &s) { |
| return os << "[(" << s.A.X << ", " << s.A.Y << "), (" << s.B.X << ", " << s.B.Y << ")]"; |
| } |
|
|
| template<typename T> |
| __host__ |
| __lib_inline__ std::ostream &operator<<(std::ostream &os, const Quad_<T> &q) { |
| os << "[" << q.Vertices[0]; |
| for (size_t i = 1; i < 4; ++i) { |
| os << ", " << q.Vertices[i]; |
| } |
| return os << "]"; |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ int _signum(T val) { |
| return (T(0) < val) - (val < T(0)); |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ T sign(const Point_<T> &p1, const Point_<T> &p2, const Point_<T> &p3) { |
| T ret = (p1.X - p3.X) * (p2.Y - p3.Y) - (p2.X - p3.X) * (p1.Y - p3.Y); |
| auto sgn = _signum(ret); |
| return sgn; |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ T Segment_<T>::Length() const |
| { |
| #ifndef __NVCC__ |
| using std::sqrt; |
| #endif |
| return sqrt(LengthSq()); |
| } |
|
|
| template<typename T> |
| __any_device__ |
| __lib_inline__ T Segment_<T>::LengthSq() const |
| { |
| return dot(B - A); |
| } |
|
|
| template<typename T> |
| __any_device__ |
| inline bool Segment_<T>::Intersection(const Segment_<T> &other, Point_<T> &out_ptAlong) const |
| { |
| auto p1 = A, p2 = B, p3 = other.A, p4 = other.B; |
|
|
| auto denom = (p4.Y - p3.Y) * (p2.X - p1.X) - (p4.X - p3.X) * (p2.Y - p1.Y); |
|
|
| if (abs(denom) < 1e-8) { |
| return false; |
| } |
|
|
| auto numer = (p4.X - p3.X) * (p1.Y - p3.Y) - (p4.Y - p3.Y) * (p1.X - p3.X); |
|
|
| auto t = numer / denom; |
|
|
| auto Bnumer = (p2.X - p1.X) * (p1.Y - p3.Y) - (p2.Y - p1.Y) * (p1.X - p3.X); |
|
|
| auto Bt = Bnumer / denom; |
|
|
| if (t < 0 || t > 1 || Bt < 0 || Bt > 1) { |
| return false; |
| } |
|
|
| out_ptAlong = A + t * (B - A); |
|
|
| return true; |
| } |
|
|
| template<typename quad_t> |
| __any_device__ |
| auto quad_center(const quad_t &quad) -> Point_<typename quad_t::inner_type> |
| { |
| typedef typename quad_t::inner_type T; |
|
|
| Point_<T> center = quad[0]; |
| for (size_t i = 1; i < 4; ++i) { |
| center += quad[i]; |
| } |
|
|
| return center / T{ 4 }; |
| } |
|
|
| template<typename T, typename Derived> |
| __any_device__ |
| Point_<T> QuadBase_<T, Derived>::Center() const { |
| return quad_center(static_cast<const Derived&>(*this)); |
| } |
|
|
| template<typename quad_t> |
| __any_device__ |
| auto quad_bounds(const quad_t &quad) -> AABB_<typename quad_t::inner_type> |
| { |
| #ifndef __NVCC__ |
| using std::min; |
| using std::max; |
| #endif |
| auto minP = quad[0]; |
| auto maxP = minP; |
| for (size_t i = 1; i < 4; ++i) { |
| auto qp = quad[i]; |
| minP = min(minP, qp); |
| maxP = max(maxP, qp); |
| } |
| return { minP.X, minP.Y, maxP.X, maxP.Y }; |
| } |
|
|
| template<typename T, typename Derived> |
| __any_device__ |
| AABB_<T> QuadBase_<T, Derived>::Bounds() const { |
| return quad_bounds(static_cast<const Derived&>(*this)); |
| } |
|
|
| template<typename Quad_t, typename point_t> |
| __any_device__ |
| inline bool quad_contains(const Quad_t &quad, const point_t &pt) |
| { |
| #ifndef __NVCC__ |
| using std::abs; |
| #endif |
|
|
| |
| auto d1 = sign(pt, quad[0], quad[1]); |
| auto d2 = sign(pt, quad[1], quad[2]); |
| auto d3 = sign(pt, quad[2], quad[3]); |
| auto d4 = sign(pt, quad[3], quad[0]); |
|
|
| |
| |
| int tot = d1 + d2 + d3 + d4; |
|
|
| |
| return abs(tot) == 4; |
| } |
|
|
| template<typename T, typename Derived> |
| __any_device__ |
| __lib_inline__ bool QuadBase_<T, Derived>::Contains(const Point_<T> &pt) const |
| { |
| return quad_contains(static_cast<const Derived&>(*this), pt); |
| } |
|
|
| template<typename PtList> |
| __any_device__ |
| inline auto shoelace_area(const PtList &points, size_t numPts, bool isSigned=false) -> decltype(points[0].X) |
| { |
| #ifndef __NVCC__ |
| using std::abs; |
| #endif |
|
|
| decltype(points[0].X) area = 0; |
|
|
| size_t j = numPts - 1; |
| for (size_t i = 0; i < numPts; ++i) { |
| auto Pi = points[i]; |
| auto Pj = points[j]; |
|
|
| area += (Pj.X + Pi.X) * (Pj.Y - Pi.Y); |
| j = i; |
| } |
|
|
| area = area / 2; |
|
|
| if (! isSigned) { |
| area = abs(area); |
| } |
|
|
| return area; |
| } |
|
|
| template<typename T, typename Derived> |
| __any_device__ |
| __lib_inline__ T QuadBase_<T, Derived>::Height() const |
| { |
| auto &d = static_cast<const Derived&>(*this); |
| auto h1 = Segment_<T>(d[1], d[2]).Length(); |
| auto h2 = Segment_<T>(d[3], d[0]).Length(); |
| return (h1 + h2) / 2; |
| } |
|
|
| template<typename T, typename Derived> |
| __any_device__ |
| __lib_inline__ T QuadBase_<T, Derived>::Width() const |
| { |
| auto &d = static_cast<const Derived&>(*this); |
| auto w1 = Segment_<T>(d[0], d[1]).Length(); |
| auto w2 = Segment_<T>(d[3], d[2]).Length(); |
| return (w1 + w2) / 2; |
| } |
|
|
| |
| template<typename T, typename Derived> |
| __any_device__ |
| inline T QuadBase_<T, Derived>::Area() const |
| { |
| |
| return shoelace_area(static_cast<const Derived&>(*this), 4); |
| } |
|
|
| template<typename Quad_t1, typename Quad_t2> |
| __any_device__ |
| inline auto intersection_area(const Quad_t1 &quadsA, const Quad_t2 &quadsB) -> typename Quad_t1::inner_type |
| { |
| #ifndef __NVCC__ |
| using std::atan2; |
| #endif |
|
|
| typedef typename Quad_t1::inner_type T; |
|
|
| static const size_t MAX_PTS = 32; |
|
|
| Point_<T> points[MAX_PTS], sortedPoints[MAX_PTS]; |
| T angles[MAX_PTS]; |
| size_t indices[MAX_PTS]; |
| size_t numPts = 0; |
|
|
| auto addPt = [&] (const Point_<T> &p) { |
| points[numPts] = p; |
| ++numPts; |
| }; |
|
|
| for (size_t i = 0; i < 4; ++i) { |
| Point_<T> aPt = quadsA[i]; |
| Point_<T> bPt = quadsB[i]; |
|
|
| if (quadsA.Contains(bPt)) { |
| addPt(bPt); |
| } |
| if (quadsB.Contains(aPt)) { |
| addPt(aPt); |
| } |
| } |
|
|
| for (size_t i = 0; i < 4; ++i) { |
| Segment_<T> segA{ quadsA[i], quadsA[(i + 1) % 4] }; |
|
|
| for (size_t j = 0; j < 4; ++j) { |
| Segment_<T> segB{ quadsB[j], quadsB[(j + 1) % 4] }; |
|
|
| Point_<T> ptAlong; |
| if (segA.Intersection(segB, ptAlong)) { |
| addPt(ptAlong); |
| } |
| } |
| } |
|
|
| if (numPts == 0) { |
| return 0; |
| } |
|
|
| Point_<T> center{ 0, 0 }; |
| for (size_t i = 0; i < numPts; ++i) { |
| center += points[i]; |
| } |
| center /= numPts; |
|
|
| for (size_t i = 0; i < numPts; ++i) { |
| points[i] -= center; |
|
|
| angles[i] = atan2(points[i].Y, points[i].X); |
|
|
| indices[i] = i; |
| } |
|
|
| |
| SORT_ALGO(indices, indices + numPts, |
| [&] (size_t a, size_t b) { |
| return angles[a] < angles[b]; |
| } |
| ); |
|
|
| for (size_t i = 0; i < numPts; ++i) { |
| sortedPoints[i] = points[indices[i]]; |
| } |
|
|
| |
| T area = shoelace_area(sortedPoints, numPts); |
|
|
| return area; |
| } |
|
|
| template<typename T, typename Derived> |
| template<typename Derived2> |
| __any_device__ |
| __lib_inline__ T QuadBase_<T, Derived>::IntersectionArea(const QuadBase_<T, Derived2> &other) const |
| { |
| return intersection_area( |
| static_cast<const Derived&>(*this), |
| static_cast<const Derived2&>(other) |
| ); |
| } |
|
|
| template<typename T1, typename T2> |
| __any_device__ |
| __lib_inline__ auto geometry_iou(const T1 &a, const T2 &b) -> decltype(a.Area()) |
| { |
| auto aArea = a.Area(); |
| auto bArea = b.Area(); |
| auto ixArea = a.IntersectionArea(b); |
|
|
| auto unionArea = aArea + bArea - ixArea; |
|
|
| return ixArea / unionArea; |
| } |
|
|
| template<typename T, typename Derived> |
| template<typename Derived2> |
| __any_device__ |
| __lib_inline__ T QuadBase_<T, Derived>::IOU(const QuadBase_<T, Derived2> &other) const |
| { |
| return geometry_iou( |
| static_cast<const Derived&>(*this), |
| static_cast<const Derived2&>(other) |
| ); |
| } |
|
|
| template<typename T, typename Derived> |
| template<typename Derived2> |
| __any_device__ |
| __lib_inline__ T QuadBase_<T, Derived>::IOU_UpperBound(const QuadBase_<T, Derived2> &other) const |
| { |
| return geometry_iou( |
| Bounds(), |
| other.Bounds() |
| ); |
| } |
|
|
| template<typename T1, typename T2> |
| __any_device__ __lib_inline__ |
| auto geometry_region_sizes(const T1 &a, const T2 &b) -> tuple_t<decltype(a.Area()), decltype(a.Area()), decltype(a.IntersectionArea(b))> |
| { |
| auto aArea = a.Area(); |
| auto bArea = b.Area(); |
| auto ixArea = a.IntersectionArea(b); |
|
|
| auto unionArea = aArea + bArea - ixArea; |
| auto iou = ixArea / unionArea; |
|
|
| return { ixArea / aArea, ixArea / bArea, iou }; |
| } |
|
|
|
|
| template<typename T, typename Derived> |
| template<typename Derived2> |
| __any_device__ __lib_inline__ |
| tuple_t<T, T, T> QuadBase_<T, Derived>::RegionSizes(const QuadBase_<T, Derived2> &other) const |
| { |
| return geometry_region_sizes( |
| static_cast<const Derived&>(*this), |
| static_cast<const Derived2&>(other) |
| ); |
| } |
|
|
| template<typename T, typename Derived> |
| template<typename Derived2> |
| __any_device__ __lib_inline__ |
| tuple_t<T, T, T> QuadBase_<T, Derived>::RegionSizes_UpperBound(const QuadBase_<T, Derived2> &other) const |
| { |
| return geometry_region_sizes( |
| Bounds(), |
| other.Bounds() |
| ); |
| } |
|
|
| template<typename polygon_t> |
| __any_device__ |
| auto polygon_bounds(const polygon_t &poly) -> AABB_<typename polygon_t::inner_type> |
| { |
| #ifndef __NVCC__ |
| using std::min; |
| using std::max; |
| #endif |
| auto minP = poly[0]; |
| auto maxP = minP; |
| for (size_t i = 1; i < poly.Count; ++i) { |
| auto qp = poly[i]; |
| minP = min(minP, qp); |
| maxP = max(maxP, qp); |
| } |
| return { minP.X, minP.Y, maxP.X, maxP.Y }; |
| } |
|
|
| template<typename T, typename Derived> |
| __any_device__ |
| AABB_<T> PolygonBase_<T, Derived>::Bounds() const { |
| return polygon_bounds(static_cast<const Derived&>(*this)); |
| } |
|
|
| template<typename polygon_t, typename point_t> |
| __any_device__ |
| bool polygon_contains(const polygon_t &poly, const point_t &pt) |
| { |
| typedef typename polygon_t::inner_type T; |
|
|
| |
| Segment_<T> testSeg{ pt, { -1e6, -2e6 }}; |
| Point_<T> trash; |
|
|
| int32_t ixCount = 0; |
| for (size_t i = 0; i < poly.Count; ++i) { |
| Segment_<T> polySeg{ poly[i], poly[(i + 1) % poly.Count] }; |
|
|
| if (testSeg.Intersection(polySeg, trash)) { |
| ++ixCount; |
| } |
| } |
|
|
| |
| return (ixCount % 2) == 1; |
| } |
|
|
| template<typename T, typename Derived> |
| __any_device__ |
| bool PolygonBase_<T, Derived>::Contains(const Point_<T> &pt) const { |
| return polygon_contains(static_cast<const Derived&>(*this), pt); |
| } |
|
|
| template<typename polygon_t> |
| __any_device__ |
| auto polygon_edge_length(const polygon_t &poly) -> typename polygon_t::inner_type |
| { |
| typedef typename polygon_t::inner_type T; |
|
|
| T ret = 0; |
|
|
| for (size_t i = 0; i < poly.Count; ++i) { |
| Segment_<T> seg{ poly[i], poly[(i + 1) % poly.Count] }; |
|
|
| ret += seg.Length(); |
| } |
|
|
| return ret; |
| } |
|
|
| template<typename T, typename Derived> |
| __any_device__ |
| T PolygonBase_<T, Derived>::EdgeLength() const { |
| return polygon_edge_length(static_cast<const Derived&>(*this)); |
| } |
|
|
| template<typename polygon_t> |
| __any_device__ |
| auto polygon_center(const polygon_t &poly) -> Point_<typename polygon_t::inner_type> |
| { |
| typedef typename polygon_t::inner_type T; |
|
|
| T cx = 0, cy = 0, a = 0; |
| size_t j = poly.Count - 1; |
| for (size_t i = 0; i < poly.Count; ++i) { |
| Point_<T> p0 = poly[i]; |
| Point_<T> p1 = poly[j]; |
|
|
| T common = (p0.X * p1.Y - p1.X * p0.Y); |
| cx += (p0.X + p1.X) * common; |
| cy += (p0.Y + p1.Y) * common; |
| a += common; |
|
|
| j = i; |
| } |
|
|
| a /= 2; |
|
|
| Point_<T> center{ cx / (6 * a), cy / (6 * a) }; |
|
|
| return center; |
| } |
|
|
| template<typename T, typename Derived> |
| __any_device__ |
| Point_<T> PolygonBase_<T, Derived>::Center() const { |
| return polygon_center(static_cast<const Derived&>(*this)); |
| } |
|
|
| template<typename T, typename Derived> |
| __any_device__ |
| T PolygonBase_<T, Derived>::Area() const { |
| const Derived &dThis = static_cast<const Derived&>(*this); |
| return shoelace_area(dThis, dThis.Count); |
| } |
|
|
|
|
| template<typename T> |
| __any_device__ |
| Point_<T> nearest_point_on_segment(const Point_<T> &pt, const Segment_<T> &seg) |
| { |
| #ifndef __NVCC__ |
| using std::max; |
| using std::min; |
| #endif |
|
|
| const T l2 = seg.LengthSq(); |
|
|
| if (l2 == 0.0) { |
| return seg.A; |
| } |
|
|
| const auto v = seg.A; |
| const auto w = seg.B; |
| |
| |
| auto t = dot(pt - v, w - v) / l2; |
|
|
| |
| t = max(static_cast<T>(0), min(static_cast<T>(1), t)); |
|
|
| const auto projection = v + t * (w - v); |
|
|
| return projection; |
| } |
|
|
|
|
| template<typename T> |
| __any_device__ |
| Segment_<T> shortest_line_between_segments(const Segment_<T> &a, const Segment_<T> &b) |
| { |
| Segment_<T> segs[] = { |
| { a.A, nearest_point_on_segment(a.A, b) }, |
| { a.B, nearest_point_on_segment(a.B, b) }, |
| { nearest_point_on_segment(b.A, a), b.A }, |
| { nearest_point_on_segment(b.B, a), b.B } |
| }; |
|
|
| T minDist = std::numeric_limits<T>::max(); |
| size_t idx; |
|
|
| #pragma unroll |
| for (size_t i = 0; i < 4; ++i) { |
| T dist = segs[i].LengthSq(); |
| if (dist < minDist) { |
| minDist = dist; |
| idx = i; |
| } |
| } |
|
|
| return segs[idx]; |
| } |
|
|
| |
| template<typename T> |
| __any_device__ |
| T distance_to_segment(const Point_<T> &pt, const Segment_<T> &seg) |
| { |
| auto projection = nearest_point_on_segment(pt, seg); |
|
|
| auto dist = length(pt - projection); |
|
|
| return dist; |
| } |
|
|