mediapipe/mediapipe/framework/deps/rectangle.h
MediaPipe Team cc6a2f7af6 Project import generated by Copybara.
GitOrigin-RevId: 73d686c40057684f8bfaca285368bf1813f9fc26
2022-03-21 12:12:39 -07:00

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_