diff options
Diffstat (limited to 'ml/dlib/dlib/geometry/rectangle.h')
-rw-r--r-- | ml/dlib/dlib/geometry/rectangle.h | 824 |
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_ + + |