summaryrefslogtreecommitdiffstats
path: root/ml/dlib/dlib/geometry/rectangle.h
diff options
context:
space:
mode:
Diffstat (limited to 'ml/dlib/dlib/geometry/rectangle.h')
-rw-r--r--ml/dlib/dlib/geometry/rectangle.h824
1 files changed, 824 insertions, 0 deletions
diff --git a/ml/dlib/dlib/geometry/rectangle.h b/ml/dlib/dlib/geometry/rectangle.h
new file mode 100644
index 000000000..3d67ca8c4
--- /dev/null
+++ b/ml/dlib/dlib/geometry/rectangle.h
@@ -0,0 +1,824 @@
+// Copyright (C) 2005 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_RECTANGLe_
+#define DLIB_RECTANGLe_
+
+#include "rectangle_abstract.h"
+#include "../algs.h"
+#include <algorithm>
+#include <iostream>
+#include "../serialize.h"
+#include "vector.h"
+#include "../image_processing/generic_image.h"
+
+namespace dlib
+{
+
+// ----------------------------------------------------------------------------------------
+
+ class rectangle
+ {
+ /*!
+ INITIAL VALUE
+ The initial value of this object is defined by its constructor.
+
+ CONVENTION
+ left() == l
+ top() == t
+ right() == r
+ bottom() == b
+ !*/
+
+ public:
+
+ rectangle (
+ long l_,
+ long t_,
+ long r_,
+ long b_
+ ) :
+ l(l_),
+ t(t_),
+ r(r_),
+ b(b_)
+ {}
+
+ rectangle (
+ unsigned long w,
+ unsigned long h
+ ) :
+ l(0),
+ t(0),
+ r(static_cast<long>(w)-1),
+ b(static_cast<long>(h)-1)
+ {
+ DLIB_ASSERT((w > 0 && h > 0) || (w == 0 && h == 0),
+ "\trectangle(width,height)"
+ << "\n\twidth and height must be > 0 or both == 0"
+ << "\n\twidth: " << w
+ << "\n\theight: " << h
+ << "\n\tthis: " << this
+ );
+ }
+
+ rectangle (
+ const point& p
+ ) :
+ l(p.x()),
+ t(p.y()),
+ r(p.x()),
+ b(p.y())
+ {
+ }
+
+ rectangle (
+ const point& p1,
+ const point& p2
+ )
+ {
+ *this = rectangle(p1) + rectangle(p2);
+ }
+
+ template <typename T>
+ rectangle (
+ const vector<T,2>& p1,
+ const vector<T,2>& p2
+ )
+ {
+ *this = rectangle(p1) + rectangle(p2);
+ }
+
+ rectangle (
+ ) :
+ l(0),
+ t(0),
+ r(-1),
+ b(-1)
+ {}
+
+ long top (
+ ) const { return t; }
+
+ long& top (
+ ) { return t; }
+
+ void set_top (
+ long top_
+ ) { t = top_; }
+
+ long left (
+ ) const { return l; }
+
+ long& left (
+ ) { return l; }
+
+ void set_left (
+ long left_
+ ) { l = left_; }
+
+ long right (
+ ) const { return r; }
+
+ long& right (
+ ) { return r; }
+
+ void set_right (
+ long right_
+ ) { r = right_; }
+
+ long bottom (
+ ) const { return b; }
+
+ long& bottom (
+ ) { return b; }
+
+ void set_bottom (
+ long bottom_
+ ) { b = bottom_; }
+
+ const point tl_corner (
+ ) const { return point(left(), top()); }
+
+ const point bl_corner (
+ ) const { return point(left(), bottom()); }
+
+ const point tr_corner (
+ ) const { return point(right(), top()); }
+
+ const point br_corner (
+ ) const { return point(right(), bottom()); }
+
+ unsigned long width (
+ ) const
+ {
+ if (is_empty())
+ return 0;
+ else
+ return r - l + 1;
+ }
+
+ unsigned long height (
+ ) const
+ {
+ if (is_empty())
+ return 0;
+ else
+ return b - t + 1;
+ }
+
+ unsigned long area (
+ ) const
+ {
+ return width()*height();
+ }
+
+ bool is_empty (
+ ) const { return (t > b || l > r); }
+
+ rectangle operator + (
+ const rectangle& rhs
+ ) const
+ {
+ if (rhs.is_empty())
+ return *this;
+ else if (is_empty())
+ return rhs;
+
+ return rectangle (
+ std::min(l,rhs.l),
+ std::min(t,rhs.t),
+ std::max(r,rhs.r),
+ std::max(b,rhs.b)
+ );
+ }
+
+ rectangle intersect (
+ const rectangle& rhs
+ ) const
+ {
+ return rectangle (
+ std::max(l,rhs.l),
+ std::max(t,rhs.t),
+ std::min(r,rhs.r),
+ std::min(b,rhs.b)
+ );
+ }
+
+ bool contains (
+ const point& p
+ ) const
+ {
+ if (p.x() < l || p.x() > r || p.y() < t || p.y() > b)
+ return false;
+ return true;
+ }
+
+ bool contains (
+ long x,
+ long y
+ ) const
+ {
+ if (x < l || x > r || y < t || y > b)
+ return false;
+ return true;
+ }
+
+ bool contains (
+ const rectangle& rect
+ ) const
+ {
+ return (rect + *this == *this);
+ }
+
+ rectangle& operator+= (
+ const point& p
+ )
+ {
+ *this = *this + rectangle(p);
+ return *this;
+ }
+
+ rectangle& operator+= (
+ const rectangle& rect
+ )
+ {
+ *this = *this + rect;
+ return *this;
+ }
+
+ bool operator== (
+ const rectangle& rect
+ ) const
+ {
+ return (l == rect.l) && (t == rect.t) && (r == rect.r) && (b == rect.b);
+ }
+
+ bool operator!= (
+ const rectangle& rect
+ ) const
+ {
+ return !(*this == rect);
+ }
+
+ inline bool operator< (const dlib::rectangle& b) const
+ {
+ if (left() < b.left()) return true;
+ else if (left() > b.left()) return false;
+ else if (top() < b.top()) return true;
+ else if (top() > b.top()) return false;
+ else if (right() < b.right()) return true;
+ else if (right() > b.right()) return false;
+ else if (bottom() < b.bottom()) return true;
+ else if (bottom() > b.bottom()) return false;
+ else return false;
+ }
+
+ private:
+ long l;
+ long t;
+ long r;
+ long b;
+ };
+
+// ----------------------------------------------------------------------------------------
+
+ inline void serialize (
+ const rectangle& 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 rectangle");
+ }
+ }
+
+ inline void deserialize (
+ rectangle& 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 rectangle");
+ }
+ }
+
+ inline std::ostream& operator<< (
+ std::ostream& out,
+ const rectangle& item
+ )
+ {
+ out << "[(" << item.left() << ", " << item.top() << ") (" << item.right() << ", " << item.bottom() << ")]";
+ return out;
+ }
+
+ inline std::istream& operator>>(
+ std::istream& in,
+ rectangle& 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;
+ }
+
+ point p1, p2;
+ in >> p1;
+ in >> p2;
+ item = rectangle(p1) + rectangle(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 const rectangle centered_rect (
+ long x,
+ long y,
+ unsigned long width,
+ unsigned long height
+ )
+ {
+ rectangle result;
+ result.set_left ( x - static_cast<long>(width) / 2 );
+ result.set_top ( y - static_cast<long>(height) / 2 );
+ result.set_right ( result.left() + width - 1 );
+ result.set_bottom ( result.top() + height - 1 );
+ return result;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline rectangle intersect (
+ const rectangle& a,
+ const rectangle& b
+ ) { return a.intersect(b); }
+
+// ----------------------------------------------------------------------------------------
+
+ inline unsigned long area (
+ const rectangle& a
+ ) { return a.area(); }
+
+// ----------------------------------------------------------------------------------------
+
+ inline point center (
+ const dlib::rectangle& rect
+ )
+ {
+ point temp(rect.left() + rect.right() + 1,
+ rect.top() + rect.bottom() + 1);
+
+ if (temp.x() < 0)
+ temp.x() -= 1;
+
+ if (temp.y() < 0)
+ temp.y() -= 1;
+
+ return temp/2;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline dlib::vector<double,2> dcenter (
+ const dlib::rectangle& rect
+ )
+ {
+ dlib::vector<double,2> temp(rect.left() + rect.right(),
+ rect.top() + rect.bottom());
+
+ return temp/2.0;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline long distance_to_rect_edge (
+ const rectangle& rect,
+ const point& p
+ )
+ {
+ using std::max;
+ using std::min;
+ using std::abs;
+
+ const long dist_x = min(abs(p.x()-rect.left()), abs(p.x()-rect.right()));
+ const long dist_y = min(abs(p.y()-rect.top()), abs(p.y()-rect.bottom()));
+
+ if (rect.contains(p))
+ return min(dist_x,dist_y);
+ else if (rect.left() <= p.x() && p.x() <= rect.right())
+ return dist_y;
+ else if (rect.top() <= p.y() && p.y() <= rect.bottom())
+ return dist_x;
+ else
+ return dist_x + dist_y;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const point nearest_point (
+ const rectangle& rect,
+ const point& p
+ )
+ {
+ point temp(p);
+ if (temp.x() < rect.left())
+ temp.x() = rect.left();
+ else if (temp.x() > rect.right())
+ temp.x() = rect.right();
+
+ if (temp.y() < rect.top())
+ temp.y() = rect.top();
+ else if (temp.y() > rect.bottom())
+ temp.y() = rect.bottom();
+
+ return temp;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline size_t nearest_rect (
+ const std::vector<rectangle>& rects,
+ const point& p
+ )
+ {
+ DLIB_ASSERT(rects.size() > 0);
+ size_t idx = 0;
+ double best_dist = std::numeric_limits<double>::infinity();
+
+ for (size_t i = 0; i < rects.size(); ++i)
+ {
+ if (rects[i].contains(p))
+ {
+ return i;
+ }
+ else
+ {
+ double dist = (nearest_point(rects[i],p)-p).length();
+ if (dist < best_dist)
+ {
+ best_dist = dist;
+ idx = i;
+ }
+ }
+ }
+ return idx;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <typename T, typename U>
+ double distance_to_line (
+ const std::pair<vector<T,2>,vector<T,2> >& line,
+ const vector<U,2>& p
+ )
+ {
+ const vector<double,2> delta = p-line.second;
+ const double along_dist = (line.first-line.second).normalize().dot(delta);
+ return std::sqrt(std::max(0.0,delta.length_squared() - along_dist*along_dist));
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline void clip_line_to_rectangle (
+ const rectangle& box,
+ point& p1,
+ point& p2
+ )
+ {
+ // Now clip the line segment so it is contained inside box.
+ if (p1.x() == p2.x())
+ {
+ if (!box.contains(p1))
+ p1.y() = box.top();
+ if (!box.contains(p2))
+ p2.y() = box.bottom();
+ }
+ else if (p1.y() == p2.y())
+ {
+ if (!box.contains(p1))
+ p1.x() = box.left();
+ if (!box.contains(p2))
+ p2.x() = box.right();
+ }
+ else
+ {
+ // We use these relations to find alpha values. These values tell us
+ // how to generate points intersecting the rectangle boundaries. We then
+ // test the resulting points for ones that are inside the rectangle and output
+ // those.
+ //box.left() == alpha1*(p1.x()-p2.x()) + p2.x();
+ //box.right() == alpha2*(p1.x()-p2.x()) + p2.x();
+
+ const point d = p1-p2;
+ double alpha1 = (box.left() -p2.x())/(double)d.x();
+ double alpha2 = (box.right() -p2.x())/(double)d.x();
+ double alpha3 = (box.top() -p2.y())/(double)d.y();
+ double alpha4 = (box.bottom()-p2.y())/(double)d.y();
+
+ const point c1 = alpha1*d + p2;
+ const point c2 = alpha2*d + p2;
+ const point c3 = alpha3*d + p2;
+ const point c4 = alpha4*d + p2;
+
+ if (!box.contains(p1))
+ p1 = c1;
+ if (!box.contains(p2))
+ p2 = c2;
+ if (box.contains(c3))
+ {
+ if (!box.contains(p2))
+ p2 = c3;
+ else if (!box.contains(p1))
+ p1 = c3;
+ }
+ if (box.contains(c4))
+ {
+ if (!box.contains(p2))
+ p2 = c4;
+ else if (!box.contains(p1))
+ p1 = c4;
+ }
+ }
+
+ p1 = nearest_point(box, p1);
+ p2 = nearest_point(box, p2);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const rectangle centered_rect (
+ const point& p,
+ unsigned long width,
+ unsigned long height
+ )
+ {
+ return centered_rect(p.x(),p.y(),width,height);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const rectangle centered_rect (
+ const rectangle& rect,
+ unsigned long width,
+ unsigned long height
+ )
+ {
+ return centered_rect((rect.left()+rect.right())/2, (rect.top()+rect.bottom())/2, width, height);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const rectangle shrink_rect (
+ const rectangle& rect,
+ long num
+ )
+ {
+ return rectangle(rect.left()+num, rect.top()+num, rect.right()-num, rect.bottom()-num);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const rectangle grow_rect (
+ const rectangle& rect,
+ long num
+ )
+ {
+ return shrink_rect(rect, -num);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const rectangle shrink_rect (
+ const rectangle& rect,
+ long width,
+ long height
+ )
+ {
+ return rectangle(rect.left()+width, rect.top()+height, rect.right()-width, rect.bottom()-height);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const rectangle grow_rect (
+ const rectangle& rect,
+ long width,
+ long height
+ )
+ {
+ return shrink_rect(rect, -width, -height);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const rectangle translate_rect (
+ const rectangle& rect,
+ const point& p
+ )
+ {
+ rectangle result;
+ result.set_top ( rect.top() + p.y() );
+ result.set_bottom ( rect.bottom() + p.y() );
+ result.set_left ( rect.left() + p.x() );
+ result.set_right ( rect.right() + p.x() );
+ return result;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const rectangle translate_rect (
+ const rectangle& rect,
+ long x,
+ long y
+ )
+ {
+ rectangle result;
+ result.set_top ( rect.top() + y );
+ result.set_bottom ( rect.bottom() + y );
+ result.set_left ( rect.left() + x );
+ result.set_right ( rect.right() + x );
+ return result;
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const rectangle resize_rect (
+ const rectangle& rect,
+ unsigned long width,
+ unsigned long height
+ )
+ {
+ return rectangle(rect.left(),rect.top(),
+ rect.left()+width-1,
+ rect.top()+height-1);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const rectangle resize_rect_width (
+ const rectangle& rect,
+ unsigned long width
+ )
+ {
+ return rectangle(rect.left(),rect.top(),
+ rect.left()+width-1,
+ rect.bottom());
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const rectangle resize_rect_height (
+ const rectangle& rect,
+ unsigned long height
+ )
+ {
+ return rectangle(rect.left(),rect.top(),
+ rect.right(),
+ rect.top()+height-1);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const rectangle move_rect (
+ const rectangle& rect,
+ const point& p
+ )
+ {
+ return rectangle(p.x(), p.y(), p.x()+rect.width()-1, p.y()+rect.height()-1);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline const rectangle move_rect (
+ const rectangle& rect,
+ long x,
+ long y
+ )
+ {
+ return rectangle(x, y, x+rect.width()-1, y+rect.height()-1);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline rectangle set_rect_area (
+ const rectangle& rect,
+ unsigned long area
+ )
+ {
+ DLIB_ASSERT(area > 0);
+
+ if (rect.area() == 0)
+ {
+ // In this case we will make the output rectangle a square with the requested
+ // area.
+ unsigned long scale = std::round(std::sqrt(area));
+ return centered_rect(rect, scale, scale);
+ }
+ else
+ {
+ double scale = std::sqrt(area/(double)rect.area());
+ return centered_rect(rect, (long)std::round(rect.width()*scale), (long)std::round(rect.height()*scale));
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline rectangle set_aspect_ratio (
+ const rectangle& rect,
+ double ratio
+ )
+ {
+ DLIB_ASSERT(ratio > 0,
+ "\t rectangle set_aspect_ratio()"
+ << "\n\t ratio: " << ratio
+ );
+
+ // aspect ratio is w/h
+
+ // we need to find the rectangle that is nearest to rect in area but
+ // with an aspect ratio of ratio.
+
+ // w/h == ratio
+ // w*h == rect.area()
+
+ if (ratio >= 1)
+ {
+ const long h = static_cast<long>(std::sqrt(rect.area()/ratio) + 0.5);
+ const long w = static_cast<long>(h*ratio + 0.5);
+ return centered_rect(rect, w, h);
+ }
+ else
+ {
+ const long w = static_cast<long>(std::sqrt(rect.area()*ratio) + 0.5);
+ const long h = static_cast<long>(w/ratio + 0.5);
+ return centered_rect(rect, w, h);
+ }
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ template <
+ typename T
+ >
+ inline const rectangle get_rect (
+ const T& m
+ )
+ {
+ return rectangle(0, 0, num_columns(m)-1, num_rows(m)-1);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline rectangle operator+ (
+ const rectangle& r,
+ const point& p
+ )
+ {
+ return r + rectangle(p);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+ inline rectangle operator+ (
+ const point& p,
+ const rectangle& r
+ )
+ {
+ return r + rectangle(p);
+ }
+
+// ----------------------------------------------------------------------------------------
+
+}
+
+#endif // DLIB_RECTANGLe_
+
+