|
|
|
|
|
|
|
|
|
|
|
#include "geometry_api.h" |
|
|
|
|
|
#include "../graph_detection/encode_util.h" |
|
|
|
|
|
#include "../geometry.h" |
|
|
#include "matrix2x2.h" |
|
|
|
|
|
using namespace std; |
|
|
|
|
|
template<typename T> |
|
|
void _calc_poly_min_rrect(const torch::TensorAccessor<T, 2> vertices, torch::TensorAccessor<T, 2> outRRect); |
|
|
template<typename T> |
|
|
void _calc_quad_min_rrect(const torch::TensorAccessor<T, 2> vertices, torch::TensorAccessor<T, 2> outRRect); |
|
|
|
|
|
torch::Tensor calc_poly_min_rrect(torch::Tensor vertices) |
|
|
{ |
|
|
if (vertices.size(0) < 3) { |
|
|
throw runtime_error("Invalid polygon! Expected >= 3 vertices, got " + to_string(vertices.size(0))); |
|
|
} |
|
|
|
|
|
auto ret = torch::empty({ 4, 2 }, vertices.options()); |
|
|
|
|
|
auto retAcc = ret.accessor<float, 2>(); |
|
|
|
|
|
if (vertices.size(0) != 4) { |
|
|
|
|
|
vertices = vertices.contiguous(); |
|
|
_calc_poly_min_rrect(vertices.accessor<float, 2>(), retAcc); |
|
|
} else { |
|
|
_calc_quad_min_rrect(vertices.accessor<float, 2>(), retAcc); |
|
|
} |
|
|
|
|
|
return ret; |
|
|
} |
|
|
|
|
|
|
|
|
template<typename T> |
|
|
void _calc_bounds(const torch::TensorAccessor<T, 2> &vertices, torch::TensorAccessor<T, 2> &outRRect, |
|
|
const Point_<T> &leftCenter, const Point_<T> &rightCenter) |
|
|
{ |
|
|
typedef Point_<T> Pointf; |
|
|
|
|
|
Pointf vecAlong = rightCenter - leftCenter; |
|
|
auto alongMag = length(vecAlong); |
|
|
|
|
|
if (alongMag == 0.0f) { |
|
|
throw runtime_error("Invalid polygon!"); |
|
|
} |
|
|
|
|
|
vecAlong /= alongMag; |
|
|
|
|
|
Pointf dOrtho{ -vecAlong.Y, vecAlong.X }; |
|
|
|
|
|
Pointf center = (leftCenter + rightCenter) / 2.0f; |
|
|
|
|
|
Matrix2x2<T> rotMat{ vecAlong, dOrtho }; |
|
|
|
|
|
auto get_fn = [&vertices, ¢er] (int64_t i) { |
|
|
return Pointf{ vertices[i] } - center; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Pointf minPt{ 0, 0 }, maxPt{ 0, 0 }; |
|
|
auto tx_fn = [&minPt, &maxPt] (int64_t i, const Pointf &pt) { |
|
|
minPt = min(minPt, pt); |
|
|
maxPt = max(maxPt, pt); |
|
|
}; |
|
|
|
|
|
matmul_fn(vertices.size(0), get_fn, rotMat, tx_fn, transpose_tag{}); |
|
|
|
|
|
Pointf rotBox[4] = { |
|
|
minPt, |
|
|
{ maxPt.X, minPt.Y }, |
|
|
maxPt, |
|
|
{ minPt.X, maxPt.Y } |
|
|
}; |
|
|
|
|
|
auto get_fn2 = [&rotBox] (int64_t i) { |
|
|
return rotBox[i]; |
|
|
}; |
|
|
|
|
|
auto assign_fn = [¢er, &outRRect] (int64_t i, const Pointf &pt) { |
|
|
outRRect[i][0] = pt.X + center.X; |
|
|
outRRect[i][1] = pt.Y + center.Y; |
|
|
}; |
|
|
|
|
|
matmul_fn(4, get_fn2, rotMat, assign_fn, contiguous_tag{}); |
|
|
} |
|
|
|
|
|
|
|
|
template<typename T> |
|
|
void _calc_poly_min_rrect(const torch::TensorAccessor<T, 2> vertices, torch::TensorAccessor<T, 2> outRRect) |
|
|
{ |
|
|
typedef Point_<T> Pointf; |
|
|
typedef Polygon_<T> Polygonf; |
|
|
|
|
|
Polygonf poly{ vertices.data(), vertices.size(0) }; |
|
|
|
|
|
vector<graph_detection::Edge> bottoms = graph_detection::find_bottom(poly, false); |
|
|
|
|
|
if (bottoms.size() != 2) { |
|
|
throw runtime_error("Invalid polygon!"); |
|
|
} |
|
|
|
|
|
vector<graph_detection::Edge> longEdges[2]; |
|
|
graph_detection::find_long_edges(poly, bottoms.data(), longEdges[0], longEdges[1]); |
|
|
|
|
|
|
|
|
|
|
|
Pointf cpts[2]; |
|
|
for (size_t i = 0; i < 2; ++i) { |
|
|
auto &pedge = longEdges[i]; |
|
|
|
|
|
cpts[i] = Pointf{0.0f, 0.0f}; |
|
|
float ct = 0; |
|
|
for (size_t z = 0; z < pedge.size(); ++z) { |
|
|
auto edge = pedge[z]; |
|
|
Pointf p1 = poly[edge.A]; |
|
|
Pointf p2 = poly[edge.B]; |
|
|
cpts[i] += (p1 + p2) / 2.0f; |
|
|
ct += 1.0f; |
|
|
} |
|
|
|
|
|
if (ct < 1.0f) { |
|
|
throw runtime_error("Edge was empty!"); |
|
|
} |
|
|
cpts[i] /= ct; |
|
|
} |
|
|
|
|
|
float vpp = graph_detection::vector_sin(cpts[0] - cpts[1]); |
|
|
if (vpp >= 0) { |
|
|
swap(bottoms[0], bottoms[1]); |
|
|
} |
|
|
|
|
|
|
|
|
Pointf edge1[2] = { poly[bottoms[0].A], poly[bottoms[0].B] }; |
|
|
Pointf edge2[2] = { poly[bottoms[1].A], poly[bottoms[1].B] }; |
|
|
|
|
|
Pointf c0 = (edge1[0] + edge1[1]) / 2.0f; |
|
|
Pointf c1 = (edge2[0] + edge2[1]) / 2.0f; |
|
|
|
|
|
_calc_bounds(vertices, outRRect, c0, c1); |
|
|
} |
|
|
|
|
|
template<typename T> |
|
|
void _calc_quad_min_rrect(const torch::TensorAccessor<T, 2> vertices, torch::TensorAccessor<T, 2> outRRect) |
|
|
{ |
|
|
typedef Point_<T> Pointf; |
|
|
|
|
|
|
|
|
|
|
|
Pointf pts[4] = { |
|
|
vertices[0], vertices[1], vertices[2], vertices[3] |
|
|
}; |
|
|
|
|
|
Pointf c0 = (pts[0] + pts[3]) / 2.0f; |
|
|
Pointf c1 = (pts[1] + pts[2]) / 2.0f; |
|
|
|
|
|
_calc_bounds(vertices, outRRect, c0, c1); |
|
|
} |
|
|
|