503 lines
12 KiB
C++
503 lines
12 KiB
C++
// Copyright (C) 2015 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#ifndef DLIB_DRECTANGLe_
|
|
#define DLIB_DRECTANGLe_
|
|
|
|
#include "drectangle_abstract.h"
|
|
#include "rectangle.h"
|
|
|
|
namespace dlib
|
|
{
|
|
class drectangle;
|
|
drectangle operator* (
|
|
const drectangle& rect,
|
|
const double& scale
|
|
);
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
class drectangle
|
|
{
|
|
public:
|
|
|
|
drectangle (
|
|
) : l(0), t(0), r(-1), b(-1) {}
|
|
|
|
drectangle (
|
|
double l_,
|
|
double t_,
|
|
double r_,
|
|
double b_
|
|
) :
|
|
l(l_),
|
|
t(t_),
|
|
r(r_),
|
|
b(b_)
|
|
{}
|
|
|
|
drectangle (
|
|
const dlib::vector<double,2>& p
|
|
) :
|
|
l(p.x()),
|
|
t(p.y()),
|
|
r(p.x()),
|
|
b(p.y())
|
|
{
|
|
}
|
|
|
|
template <typename T, typename U>
|
|
drectangle (
|
|
const vector<T,2>& p1,
|
|
const vector<U,2>& p2
|
|
)
|
|
{
|
|
*this = drectangle(p1) + drectangle(p2);
|
|
}
|
|
|
|
drectangle (
|
|
const rectangle& rect
|
|
) : l(rect.left()),
|
|
t(rect.top()),
|
|
r(rect.right()),
|
|
b(rect.bottom()) {}
|
|
|
|
operator rectangle (
|
|
) const
|
|
{
|
|
return rectangle((long)std::floor(l+0.5),
|
|
(long)std::floor(t+0.5),
|
|
(long)std::floor(r+0.5),
|
|
(long)std::floor(b+0.5));
|
|
}
|
|
|
|
double left() const { return l; }
|
|
double top() const { return t; }
|
|
double right() const { return r; }
|
|
double bottom() const { return b; }
|
|
|
|
double& left() { return l; }
|
|
double& top() { return t; }
|
|
double& right() { return r; }
|
|
double& bottom() { return b; }
|
|
|
|
const dlib::vector<double,2> tl_corner (
|
|
) const { return dlib::vector<double,2>(left(), top()); }
|
|
|
|
const dlib::vector<double,2> bl_corner (
|
|
) const { return dlib::vector<double,2>(left(), bottom()); }
|
|
|
|
const dlib::vector<double,2> tr_corner (
|
|
) const { return dlib::vector<double,2>(right(), top()); }
|
|
|
|
const dlib::vector<double,2> br_corner (
|
|
) const { return dlib::vector<double,2>(right(), bottom()); }
|
|
|
|
double width (
|
|
) const
|
|
{
|
|
if (is_empty())
|
|
return 0;
|
|
else
|
|
return r - l + 1;
|
|
}
|
|
|
|
double height (
|
|
) const
|
|
{
|
|
if (is_empty())
|
|
return 0;
|
|
else
|
|
return b - t + 1;
|
|
}
|
|
|
|
double area (
|
|
) const
|
|
{
|
|
return width()*height();
|
|
}
|
|
|
|
bool is_empty (
|
|
) const { return (t > b || l > r); }
|
|
|
|
drectangle operator + (
|
|
const drectangle& rhs
|
|
) const
|
|
{
|
|
if (rhs.is_empty())
|
|
return *this;
|
|
else if (is_empty())
|
|
return rhs;
|
|
|
|
return drectangle (
|
|
std::min(l,rhs.l),
|
|
std::min(t,rhs.t),
|
|
std::max(r,rhs.r),
|
|
std::max(b,rhs.b)
|
|
);
|
|
}
|
|
|
|
drectangle intersect (
|
|
const drectangle& rhs
|
|
) const
|
|
{
|
|
return drectangle (
|
|
std::max(l,rhs.l),
|
|
std::max(t,rhs.t),
|
|
std::min(r,rhs.r),
|
|
std::min(b,rhs.b)
|
|
);
|
|
}
|
|
|
|
bool contains (
|
|
const dlib::vector<double,2>& p
|
|
) const
|
|
{
|
|
if (p.x() < l || p.x() > r || p.y() < t || p.y() > b)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool contains (
|
|
const drectangle& rect
|
|
) const
|
|
{
|
|
if (rect.is_empty())
|
|
return true;
|
|
if (l <= rect.left() &&
|
|
r >= rect.right() &&
|
|
t <= rect.top() &&
|
|
b >= rect.bottom())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
drectangle& operator *= (
|
|
const double& scale
|
|
)
|
|
{
|
|
*this = *this*scale;
|
|
return *this;
|
|
}
|
|
|
|
drectangle& operator /= (
|
|
const double& scale
|
|
)
|
|
{
|
|
*this = *this*(1.0/scale);
|
|
return *this;
|
|
}
|
|
|
|
drectangle& operator += (
|
|
const dlib::vector<double,2>& p
|
|
)
|
|
{
|
|
*this = *this + drectangle(p);
|
|
return *this;
|
|
}
|
|
|
|
bool operator== (
|
|
const drectangle& rect
|
|
) const
|
|
{
|
|
return (l == rect.l) && (t == rect.t) && (r == rect.r) && (b == rect.b);
|
|
}
|
|
|
|
bool operator!= (
|
|
const drectangle& rect
|
|
) const
|
|
{
|
|
return !(*this == rect);
|
|
}
|
|
|
|
private:
|
|
double l;
|
|
double t;
|
|
double r;
|
|
double b;
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
inline void serialize (
|
|
const drectangle& item,
|
|
std::ostream& out
|
|
)
|
|
{
|
|
try
|
|
{
|
|
serialize(item.left(),out);
|
|
serialize(item.top(),out);
|
|
serialize(item.right(),out);
|
|
serialize(item.bottom(),out);
|
|
}
|
|
catch (serialization_error& e)
|
|
{
|
|
throw serialization_error(e.info + "\n while serializing an object of type drectangle");
|
|
}
|
|
}
|
|
|
|
inline void deserialize (
|
|
drectangle& item,
|
|
std::istream& in
|
|
)
|
|
{
|
|
try
|
|
{
|
|
deserialize(item.left(),in);
|
|
deserialize(item.top(),in);
|
|
deserialize(item.right(),in);
|
|
deserialize(item.bottom(),in);
|
|
}
|
|
catch (serialization_error& e)
|
|
{
|
|
throw serialization_error(e.info + "\n while deserializing an object of type drectangle");
|
|
}
|
|
}
|
|
|
|
inline std::ostream& operator<< (
|
|
std::ostream& out,
|
|
const drectangle& item
|
|
)
|
|
{
|
|
out << "[(" << item.left() << ", " << item.top() << ") (" << item.right() << ", " << item.bottom() << ")]";
|
|
return out;
|
|
}
|
|
|
|
inline std::istream& operator>>(
|
|
std::istream& in,
|
|
drectangle& item
|
|
)
|
|
{
|
|
// ignore any whitespace
|
|
while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n')
|
|
in.get();
|
|
// now eat the leading '[' character
|
|
if (in.get() != '[')
|
|
{
|
|
in.setstate(in.rdstate() | std::ios::failbit);
|
|
return in;
|
|
}
|
|
|
|
dlib::vector<double,2> p1, p2;
|
|
in >> p1;
|
|
in >> p2;
|
|
item = drectangle(p1) + drectangle(p2);
|
|
|
|
// ignore any whitespace
|
|
while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n')
|
|
in.get();
|
|
// now eat the trailing ']' character
|
|
if (in.get() != ']')
|
|
{
|
|
in.setstate(in.rdstate() | std::ios::failbit);
|
|
}
|
|
return in;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
inline dlib::vector<double,2> center (
|
|
const drectangle& rect
|
|
)
|
|
{
|
|
dlib::vector<double,2> temp(rect.left() + rect.right(),
|
|
rect.top() + rect.bottom());
|
|
|
|
return temp/2.0;
|
|
}
|
|
|
|
inline dlib::vector<double,2> dcenter (
|
|
const drectangle& rect
|
|
)
|
|
{
|
|
return center(rect);
|
|
}
|
|
|
|
inline drectangle operator* (
|
|
const drectangle& rect,
|
|
const double& scale
|
|
)
|
|
{
|
|
if (!rect.is_empty())
|
|
{
|
|
const double width = (rect.right()-rect.left())*scale;
|
|
const double height = (rect.bottom()-rect.top())*scale;
|
|
const dlib::vector<double,2> p = center(rect);
|
|
return drectangle(p.x()-width/2, p.y()-height/2, p.x()+width/2, p.y()+height/2);
|
|
}
|
|
else
|
|
{
|
|
return rect;
|
|
}
|
|
}
|
|
|
|
inline drectangle operator* (
|
|
const double& scale,
|
|
const drectangle& rect
|
|
)
|
|
{
|
|
return rect*scale;
|
|
}
|
|
|
|
inline drectangle operator/ (
|
|
const drectangle& rect,
|
|
const double& scale
|
|
)
|
|
{
|
|
return rect*(1.0/scale);
|
|
}
|
|
|
|
inline drectangle operator+ (
|
|
const drectangle& r,
|
|
const dlib::vector<double,2>& p
|
|
)
|
|
{
|
|
return r + drectangle(p);
|
|
}
|
|
|
|
inline drectangle operator+ (
|
|
const dlib::vector<double,2>& p,
|
|
const drectangle& r
|
|
)
|
|
{
|
|
return r + drectangle(p);
|
|
}
|
|
|
|
template <typename T>
|
|
inline drectangle translate_rect (
|
|
const drectangle& rect,
|
|
const dlib::vector<T,2>& p
|
|
)
|
|
{
|
|
drectangle result;
|
|
result.top () = rect.top() + p.y();
|
|
result.bottom () = rect.bottom() + p.y();
|
|
result.left () = rect.left() + p.x();
|
|
result.right () = rect.right() + p.x();
|
|
return result;
|
|
}
|
|
|
|
inline drectangle intersect (
|
|
const drectangle& a,
|
|
const drectangle& b
|
|
) { return a.intersect(b); }
|
|
|
|
inline double area (
|
|
const drectangle& a
|
|
) { return a.area(); }
|
|
|
|
inline drectangle centered_drect (
|
|
const dlib::vector<double,2>& p,
|
|
double width,
|
|
double height
|
|
)
|
|
{
|
|
width--;
|
|
height--;
|
|
|
|
return drectangle(p.x()-width/2, p.y()-height/2, p.x()+width/2, p.y()+height/2);
|
|
}
|
|
|
|
inline drectangle centered_drect (
|
|
const drectangle& rect,
|
|
double width,
|
|
double height
|
|
)
|
|
{
|
|
return centered_drect(dcenter(rect), width, height);
|
|
}
|
|
|
|
inline const drectangle shrink_rect (
|
|
const drectangle& rect,
|
|
double num
|
|
)
|
|
{
|
|
return drectangle(rect.left()+num, rect.top()+num, rect.right()-num, rect.bottom()-num);
|
|
}
|
|
|
|
inline const drectangle grow_rect (
|
|
const drectangle& rect,
|
|
double num
|
|
)
|
|
{
|
|
return shrink_rect(rect, -num);
|
|
}
|
|
|
|
inline const drectangle shrink_rect (
|
|
const drectangle& rect,
|
|
double width,
|
|
double height
|
|
)
|
|
{
|
|
return drectangle(rect.left()+width, rect.top()+height, rect.right()-width, rect.bottom()-height);
|
|
}
|
|
|
|
inline const drectangle grow_rect (
|
|
const drectangle& rect,
|
|
double width,
|
|
double height
|
|
)
|
|
{
|
|
return shrink_rect(rect, -width, -height);
|
|
}
|
|
|
|
inline const drectangle scale_rect (
|
|
const drectangle& rect,
|
|
double scale
|
|
)
|
|
{
|
|
DLIB_ASSERT(scale > 0, "scale factor must be > 0");
|
|
|
|
double l = rect.left() * scale;
|
|
double t = rect.top() * scale;
|
|
double r = rect.right() * scale;
|
|
double b = rect.bottom() * scale;
|
|
return drectangle(l, t, r, b);
|
|
}
|
|
|
|
inline drectangle set_rect_area (
|
|
const drectangle& rect,
|
|
double area
|
|
)
|
|
{
|
|
DLIB_ASSERT(area >= 0, "drectangle can't have a negative area.");
|
|
|
|
if (area == 0)
|
|
return drectangle(dcenter(rect));
|
|
|
|
if (rect.area() == 0)
|
|
{
|
|
// In this case we will make the output rectangle a square with the requested
|
|
// area.
|
|
double scale = std::sqrt(area);
|
|
return centered_drect(rect, scale, scale);
|
|
}
|
|
else
|
|
{
|
|
double scale = std::sqrt(area/rect.area());
|
|
return centered_drect(rect, rect.width()*scale, rect.height()*scale);
|
|
}
|
|
}
|
|
|
|
inline drectangle set_aspect_ratio (
|
|
const drectangle& rect,
|
|
double ratio
|
|
)
|
|
{
|
|
DLIB_ASSERT(ratio > 0,
|
|
"\t drectangle set_aspect_ratio()"
|
|
<< "\n\t ratio: " << ratio
|
|
);
|
|
|
|
const double h = std::sqrt(rect.area()/ratio);
|
|
const double w = h*ratio;
|
|
return centered_drect(rect, w, h);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
#endif // DLIB_DRECTANGLe_
|
|
|