```// Copyright (C) 2015  Davis E. King (davis@dlib.net)
#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_

```