cc6a2f7af6
GitOrigin-RevId: 73d686c40057684f8bfaca285368bf1813f9fc26
329 lines
10 KiB
C++
329 lines
10 KiB
C++
// Copyright 2019 The MediaPipe Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
// Class for axis-aligned rectangles represented as two corner points
|
|
// (min_x, min_y) and (max_x, max_y). The methods such as Contain, Intersect
|
|
// and IsEmpty() assume that the points in region include the 4 boundary edges.
|
|
// The default box is initialized so that IsEmpty() is true. Note that the
|
|
// use of corner points supports both right-handed (Cartesian) and left-
|
|
// handed (image) coordinate systems.
|
|
|
|
#ifndef MEDIAPIPE_DEPS_RECTANGLE_H_
|
|
#define MEDIAPIPE_DEPS_RECTANGLE_H_
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <iosfwd>
|
|
#include <limits>
|
|
#include <ostream>
|
|
|
|
#include "mediapipe/framework/deps/point2.h"
|
|
#include "mediapipe/framework/port/integral_types.h"
|
|
|
|
template <typename T>
|
|
class Rectangle;
|
|
|
|
template <typename T>
|
|
std::ostream& operator<<(std::ostream&, const Rectangle<T>&);
|
|
|
|
template <typename T>
|
|
class Rectangle {
|
|
public:
|
|
typedef Rectangle<T> Self;
|
|
|
|
// Default constructed rectangle which is empty.
|
|
Rectangle() { SetEmpty(); }
|
|
|
|
// Creates a rectangle from the minimum point and the dimensions.
|
|
Rectangle(const T& x, const T& y, const T& width, const T& height);
|
|
|
|
// Creates a rectangle given two points. The resulting rectangle will
|
|
// have non-negative width and height.
|
|
Rectangle(const Point2<T>& p0, const Point2<T>& p1);
|
|
|
|
// Same as above but using vectors as input.
|
|
Rectangle(const Vector2<T>& p0, const Vector2<T>& p1);
|
|
|
|
// Sets min to be very large numbers and max to be very large negative numbers
|
|
// so that points can be used to correctly extend the rectangle.
|
|
void SetEmpty();
|
|
|
|
// A rectangle is empty if there are no points inside of it. A degenerate
|
|
// rectangle where the corners are coincident has zero area but is not empty.
|
|
bool IsEmpty() const { return min_.x() > max_.x() || min_.y() > max_.y(); }
|
|
|
|
bool operator==(const Rectangle&) const;
|
|
bool operator!=(const Rectangle&) const;
|
|
|
|
// Width and height are both max - min, which may be negative if SetEmpty()
|
|
// was called or the user explicity set the min and max points.
|
|
T Width() const { return max_.x() - min_.x(); }
|
|
T Height() const { return max_.y() - min_.y(); }
|
|
|
|
// Computes the area, which is negative if the width xor height is negative.
|
|
// The value is undefined if SetEmpty() is called.
|
|
// Watch out for large integer rectangles because the area may overflow.
|
|
T Area() const { return Width() * Height(); }
|
|
|
|
// Accessors are provided for both points and sides.
|
|
const T& xmin() const { return min_.x(); }
|
|
const T& xmax() const { return max_.x(); }
|
|
const T& ymin() const { return min_.y(); }
|
|
const T& ymax() const { return max_.y(); }
|
|
|
|
// Returns the min and max corner points.
|
|
const Point2<T>& min_xy() const { return min_; }
|
|
const Point2<T>& max_xy() const { return max_; }
|
|
|
|
// Sets the geometry of the rectangle given two points.
|
|
// The resulting rectangle will have non-negative width and height.
|
|
void Set(const Point2<T>& p0, const Point2<T>& p1);
|
|
|
|
// Same as above using vectors as input.
|
|
void Set(const Vector2<T>& p0, const Vector2<T>& p1);
|
|
|
|
// Sets the geometry of the rectangle given a minimum point and dimensions.
|
|
void Set(const T& x, const T& y, const T& width, const T& height);
|
|
|
|
// Sets the min and max values, and min greater than max is allowable,
|
|
// but the user has to be aware of the consequences such as negative width
|
|
// and height. Both point and side accessors are provided.
|
|
void set_xmin(const T& x) { min_.set_x(x); }
|
|
void set_xmax(const T& x) { max_.set_x(x); }
|
|
void set_ymin(const T& y) { min_.set_y(y); }
|
|
void set_ymax(const T& y) { max_.set_y(y); }
|
|
|
|
void set_min_xy(const Point2<T>& p) { min_.Set(p.x(), p.y()); }
|
|
void set_max_xy(const Point2<T>& p) { max_.Set(p.x(), p.y()); }
|
|
|
|
// Expands a rectangle to contain a point or vector.
|
|
void Expand(const T& x, const T& y);
|
|
void Expand(const Point2<T>& p);
|
|
void Expand(const Vector2<T>& p);
|
|
|
|
// Expands a rectangle to contain another rectangle.
|
|
void Expand(const Rectangle& other);
|
|
|
|
// Returns the union of this rectangle with another rectangle, which
|
|
// is the smallest rectangle that contains both rectangles.
|
|
Rectangle Union(const Rectangle& other) const;
|
|
|
|
// Returns the intersection of this rectangle with another rectangle.
|
|
// If the intersection is empty, returns a rectangle initialized by
|
|
// SetEmpty().
|
|
Rectangle Intersect(const Rectangle& other) const;
|
|
|
|
// Tests if this rectangle has a non-empty intersection with another rectangle
|
|
// including the boundary.
|
|
bool Intersects(const Rectangle& other) const;
|
|
|
|
// Tests if a point is inside or on any of the 4 edges of the rectangle.
|
|
bool Contains(const T& x, const T& y) const;
|
|
bool Contains(const Point2<T>& pt) const;
|
|
bool Contains(const Vector2<T>& pt) const;
|
|
|
|
// Tests if a rectangle is inside or on any of the 4 edges of the rectangle.
|
|
bool Contains(const Rectangle& other) const;
|
|
|
|
// Translates this rectangle by a vector.
|
|
void Translate(const Vector2<T>& v);
|
|
|
|
// Adds a border around the rectangle by subtracting the border size from the
|
|
// min point and adding it to the max point. The border size can be
|
|
// negative.
|
|
void AddBorder(const T& border_size);
|
|
|
|
// Debug printing.
|
|
friend std::ostream& operator<< <T>(std::ostream&, const Rectangle&);
|
|
|
|
private:
|
|
Point2<T> min_;
|
|
Point2<T> max_;
|
|
};
|
|
|
|
//
|
|
// Inline method definitions. These are not placed in the definition of the
|
|
// class to keep the class interface more readable.
|
|
//
|
|
|
|
template <typename T>
|
|
Rectangle<T>::Rectangle(const Point2<T>& p0, const Point2<T>& p1) {
|
|
Set(p0, p1);
|
|
}
|
|
|
|
template <typename T>
|
|
Rectangle<T>::Rectangle(const Vector2<T>& p0, const Vector2<T>& p1) {
|
|
Set(p0, p1);
|
|
}
|
|
|
|
template <typename T>
|
|
Rectangle<T>::Rectangle(const T& x, const T& y, const T& width,
|
|
const T& height) {
|
|
Set(x, y, width, height);
|
|
}
|
|
|
|
// The general version works only when T models Integer (there are more
|
|
// integer classes than float classes).
|
|
template <typename T>
|
|
void Rectangle<T>::SetEmpty() {
|
|
T min_value = std::numeric_limits<T>::min();
|
|
T max_value = std::numeric_limits<T>::max();
|
|
min_.Set(max_value, max_value);
|
|
max_.Set(min_value, min_value);
|
|
}
|
|
|
|
template <>
|
|
inline void Rectangle<float>::SetEmpty() {
|
|
float max_value = std::numeric_limits<float>::max();
|
|
min_.Set(max_value, max_value);
|
|
max_.Set(-max_value, -max_value);
|
|
}
|
|
|
|
template <>
|
|
inline void Rectangle<double>::SetEmpty() {
|
|
double max_value = std::numeric_limits<double>::max();
|
|
min_.Set(max_value, max_value);
|
|
max_.Set(-max_value, -max_value);
|
|
}
|
|
|
|
template <typename T>
|
|
bool Rectangle<T>::operator==(const Rectangle<T>& other) const {
|
|
return min_ == other.min_ && max_ == other.max_;
|
|
}
|
|
|
|
template <typename T>
|
|
bool Rectangle<T>::operator!=(const Rectangle<T>& other) const {
|
|
return !(*this == other);
|
|
}
|
|
|
|
template <typename T>
|
|
void Rectangle<T>::Set(const Vector2<T>& p0, const Vector2<T>& p1) {
|
|
if (p0[0] <= p1[0])
|
|
min_.set_x(p0[0]), max_.set_x(p1[0]);
|
|
else
|
|
max_.set_x(p0[0]), min_.set_x(p1[0]);
|
|
|
|
if (p0[1] <= p1[1])
|
|
min_.set_y(p0[1]), max_.set_y(p1[1]);
|
|
else
|
|
max_.set_y(p0[1]), min_.set_y(p1[1]);
|
|
}
|
|
|
|
template <typename T>
|
|
void Rectangle<T>::Set(const Point2<T>& p0, const Point2<T>& p1) {
|
|
Set(p0.ToVector(), p1.ToVector());
|
|
}
|
|
|
|
template <typename T>
|
|
void Rectangle<T>::Set(const T& x, const T& y, const T& width,
|
|
const T& height) {
|
|
min_.Set(x, y);
|
|
max_.Set(x + width, y + height);
|
|
}
|
|
|
|
template <typename T>
|
|
void Rectangle<T>::Expand(const T& x, const T& y) {
|
|
min_.Set(std::min(x, xmin()), std::min(y, ymin()));
|
|
max_.Set(std::max(x, xmax()), std::max(y, ymax()));
|
|
}
|
|
|
|
template <typename T>
|
|
void Rectangle<T>::Expand(const Point2<T>& p) {
|
|
Expand(p.x(), p.y());
|
|
}
|
|
|
|
template <typename T>
|
|
void Rectangle<T>::Expand(const Vector2<T>& v) {
|
|
Expand(v[0], v[1]);
|
|
}
|
|
|
|
template <typename T>
|
|
void Rectangle<T>::Expand(const Rectangle<T>& other) {
|
|
Expand(other.min_);
|
|
Expand(other.max_);
|
|
}
|
|
|
|
template <typename T>
|
|
void Rectangle<T>::Translate(const Vector2<T>& v) {
|
|
min_ += v;
|
|
max_ += v;
|
|
}
|
|
|
|
template <typename T>
|
|
bool Rectangle<T>::Contains(const T& x, const T& y) const {
|
|
return x >= xmin() && x <= xmax() && y >= ymin() && y <= ymax();
|
|
}
|
|
|
|
template <typename T>
|
|
bool Rectangle<T>::Contains(const Point2<T>& p) const {
|
|
return Contains(p.x(), p.y());
|
|
}
|
|
|
|
template <typename T>
|
|
bool Rectangle<T>::Contains(const Vector2<T>& v) const {
|
|
return Contains(v[0], v[1]);
|
|
}
|
|
|
|
template <typename T>
|
|
bool Rectangle<T>::Contains(const Rectangle<T>& r) const {
|
|
return Contains(r.min_) && Contains(r.max_);
|
|
}
|
|
|
|
template <typename T>
|
|
Rectangle<T> Rectangle<T>::Union(const Rectangle<T>& r) const {
|
|
return Rectangle<T>(
|
|
Point2<T>(std::min(xmin(), r.xmin()), std::min(ymin(), r.ymin())),
|
|
Point2<T>(std::max(xmax(), r.xmax()), std::max(ymax(), r.ymax())));
|
|
}
|
|
|
|
template <typename T>
|
|
Rectangle<T> Rectangle<T>::Intersect(const Rectangle<T>& r) const {
|
|
Point2<T> pmin(std::max(xmin(), r.xmin()), std::max(ymin(), r.ymin()));
|
|
Point2<T> pmax(std::min(xmax(), r.xmax()), std::min(ymax(), r.ymax()));
|
|
|
|
if (pmin.x() > pmax.x() || pmin.y() > pmax.y())
|
|
return Rectangle<T>();
|
|
else
|
|
return Rectangle<T>(pmin, pmax);
|
|
}
|
|
|
|
template <typename T>
|
|
bool Rectangle<T>::Intersects(const Rectangle<T>& r) const {
|
|
return !(IsEmpty() || r.IsEmpty() || r.xmax() < xmin() || xmax() < r.xmin() ||
|
|
r.ymax() < ymin() || ymax() < r.ymin());
|
|
}
|
|
|
|
template <typename T>
|
|
void Rectangle<T>::AddBorder(const T& border_size) {
|
|
min_.Set(xmin() - border_size, ymin() - border_size);
|
|
max_.Set(xmax() + border_size, ymax() + border_size);
|
|
}
|
|
|
|
template <typename T>
|
|
std::ostream& operator<<(std::ostream& out, const Rectangle<T>& r) {
|
|
out << "[(" << r.xmin() << ", " << r.ymin() << "), (" << r.xmax() << ", "
|
|
<< r.ymax() << ")]";
|
|
return out;
|
|
}
|
|
|
|
template <typename T>
|
|
class Rectangle;
|
|
|
|
typedef Rectangle<uint8> Rectangle_b;
|
|
typedef Rectangle<int> Rectangle_i;
|
|
typedef Rectangle<float> Rectangle_f;
|
|
typedef Rectangle<double> Rectangle_d;
|
|
|
|
#endif // MEDIAPIPE_DEPS_RECTANGLE_H_
|