dlib C++ Library - rectangle.h

// 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;
 }
// ----------------------------------------------------------------------------------------
 template <typename T>
 inline const dlib::vector<T,2> nearest_point (
 const rectangle& rect,
 const dlib::vector<T,2>& p
 )
 {
 dlib::vector<T,2> 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>
 inline void clip_line_to_rectangle (
 const rectangle& box,
 dlib::vector<T,2>& p1,
 dlib::vector<T,2>& 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 dlib::vector<T,2> 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 dlib::vector<T,2> c1 = alpha1*d + p2;
 const dlib::vector<T,2> c2 = alpha2*d + p2;
 const dlib::vector<T,2> c3 = alpha3*d + p2;
 const dlib::vector<T,2> 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 std::vector<rectangle> centered_rects (
 const std::vector<point>& pts,
 unsigned long width,
 unsigned long height
 )
 {
 std::vector<rectangle> tmp;
 tmp.reserve(pts.size());
 for (auto& p : pts)
 tmp.emplace_back(centered_rect(p, width, height));
 return tmp;
 }
// ----------------------------------------------------------------------------------------
 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 scale_rect (
 const rectangle& rect,
 double scale
 )
 {
 DLIB_ASSERT(scale > 0, "scale factor must be > 0");
 const long l = std::lround(rect.left()*scale);
 const long t = std::lround(rect.top()*scale);
 const long r = std::lround(rect.right()*scale);
 const long b = std::lround(rect.bottom()*scale);
 return rectangle(l, t, r, b);
 }
// ----------------------------------------------------------------------------------------
 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);
 }
// ----------------------------------------------------------------------------------------
 // Circumvent what appears to be a bug in Visual Studio 2019's optimizer
 // (see: https://forum.juce.com/t/warning-in-the-lastest-vs2019/38267)
#if defined (_MSC_VER)
#pragma warning ( push )
#pragma warning ( disable: 4723 )
#endif
 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
 {
 const double scale = std::sqrt(area/static_cast<double>(rect.area()));
 return centered_rect(rect, std::lround(rect.width()*scale), std::lround(rect.height()*scale));
 }
 }
#if defined (_MSC_VER)
#pragma warning ( pop )
#endif
// ----------------------------------------------------------------------------------------
 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_

AltStyle によって変換されたページ (->オリジナル) /