Program Listing for File RotatedRect.hpp
↰ Return to documentation for file (include/depthai/common/RotatedRect.hpp)
#pragma once
// std
#include <cstdint>
// shared
#include "depthai/common/Point2f.hpp"
#include "depthai/common/Rect.hpp"
#include "depthai/common/Size2f.hpp"
#include "depthai/utility/Serialization.hpp"
namespace dai {
struct RotatedRect {
Point2f center;
Size2f size;
float angle = 0.f;
RotatedRect() = default;
RotatedRect(const Point2f& center, const Size2f& size, float angle) : center(center), size(size), angle(angle) {
if(size.isNormalized() != center.isNormalized()) {
throw std::runtime_error("Cannot create RotatedRect with mixed normalization");
}
}
RotatedRect(const Rect& rect, float angle = 0.f)
: center(rect.x + rect.width / 2.0f, rect.y + rect.height / 2.0f, rect.isNormalized()),
size(rect.width, rect.height, rect.isNormalized()),
angle(angle) {}
operator Rect() const {
const auto [minx, miny, maxx, maxy] = getOuterRect();
return Rect(minx, miny, maxx - minx, maxy - miny);
}
bool isNormalized() const {
if(size.isNormalized() != center.isNormalized()) {
throw std::runtime_error("Cannot denormalize RotatedRect with mixed normalization");
}
return size.isNormalized();
}
RotatedRect normalize(unsigned int width, unsigned int height) const {
if(width == 0 || height == 0) {
throw std::runtime_error("Width and height must be non-zero to denormalize RotatedRect");
}
if(isNormalized()) return *this;
RotatedRect normalized = *this;
normalized.center = dai::Point2f(center.x / width, center.y / height, true);
normalized.size = dai::Size2f(size.width / width, size.height / height, true);
return normalized;
}
RotatedRect denormalize(unsigned int width, unsigned int height, bool force = false) const {
if(width == 0 || height == 0) {
throw std::runtime_error("Width and height must be non-zero to denormalize RotatedRect");
}
if(!force && !isNormalized()) return *this;
RotatedRect denormalized = *this;
denormalized.center = dai::Point2f(center.x * width, center.y * height, false);
denormalized.size = dai::Size2f(size.width * width, size.height * height, false);
return denormalized;
}
std::array<dai::Point2f, 4> getPoints() const {
float angleRad = angle * 3.14159265358979323846f / 180.0f;
float halfWidth = size.width / 2.0f;
float halfHeight = size.height / 2.0f;
// Precompute sin and cos of the angle
float cosAngle = std::cos(angleRad);
float sinAngle = std::sin(angleRad);
// Corners relative to the center before rotation
std::array<dai::Point2f, 4> corners;
corners[0] = {-halfWidth, -halfHeight};
corners[1] = {halfWidth, -halfHeight};
corners[2] = {halfWidth, halfHeight};
corners[3] = {-halfWidth, halfHeight};
// Rotate each corner and translate it back to the center position
for(auto& corner : corners) {
float x = corner.x;
float y = corner.y;
corner.x = x * cosAngle - y * sinAngle + center.x;
corner.y = x * sinAngle + y * cosAngle + center.y;
}
return corners;
}
std::array<float, 4> getOuterRect() const {
auto points = getPoints();
float minx = std::min({points[0].x, points[1].x, points[2].x, points[3].x});
float maxx = std::max({points[0].x, points[1].x, points[2].x, points[3].x});
float miny = std::min({points[0].y, points[1].y, points[2].y, points[3].y});
float maxy = std::max({points[0].y, points[1].y, points[2].y, points[3].y});
return {minx, miny, maxx, maxy};
}
};
DEPTHAI_SERIALIZE_EXT(RotatedRect, center, size, angle);
} // namespace dai