Files
Extern/C3d/Include/mb_rect.h
T
Dario Sassi 905577a744 Extern :
- C3d aggiornamento delle librerie.
2020-11-21 18:27:05 +00:00

778 lines
39 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/**
\file
\brief \ru Габаритный прямоугольник.
\en Bounding rectangle. \~
*/
////////////////////////////////////////////////////////////////////////////////
#ifndef __MB_RECT_H
#define __MB_RECT_H
#include <mb_cart_point.h>
#include <mb_homogeneous.h>
#include <mb_cube_tree.h>
#include <utility>
#include <vector>
class MATH_CLASS MbMatrix;
class MATH_CLASS MbRect;
namespace c3d // namespace C3D
{
typedef std::pair<MbRect *, size_t> RectPtrIndex; ///< \ru Габаритный куб и индекс. \en Bounding box and index.
typedef std::pair<const MbRect *, size_t> ConstRectPtrIndex; ///< \ru Габаритный куб и индекс. \en Bounding box and index.
typedef std::vector<RectPtrIndex> RectsPtrIndices; ///< \ru Вектор габаритных кубов и индексов. \en Vector of bounding boxes and indices.
typedef std::vector<ConstRectPtrIndex> ConstRectsPtrIndices; ///< \ru Вектор габаритных кубов и индексов. \en Vector of bounding boxes and indices.
typedef std::vector<MbRect> RectsVector; ///< \ru Вектор габаритных кубов. \en Vector of bounding boxes.
typedef MbCubeTree<MbRect, MbRect, MbCartPoint> RectsTree; ///< \ru Дерево габаритных кубов. \en Tree of bounding boxes.
} // namespace C3D
//------------------------------------------------------------------------------
/** \brief \ru Возможные положения двух габаритов относительно друг друга.
\en Possible locations of two bounding boxes relative to each other. \~
\details \ru Возможные положения двух габаритов относительно друг друга.
\en Possible locations of two bounding boxes relative to each other. \~
\ingroup Mathematic_Base_2D
*/
// ---
enum TaeTwoRectPos {
rp_FirstInside, ///< \ru Первый включает в себя второй габарит. \en The first bounding box includes the second one.
rp_SecondInside, ///< \ru Второй включает в себя первый габарит. \en The second bounding box includes the first one.
rp_Intersect, ///< \ru Габариты пересекаются. \en Bounding boxes intersect.
rp_NoIntersect ///< \ru Габариты не пересекаются. \en Bounding boxes do not intersect.
};
//------------------------------------------------------------------------------
/** \brief \ru Габаритный прямоугольник.
\en Bounding rectangle. \~
\details \ru Габаритный прямоугольник в двумерном пространстве. \n
Используется для быстрого оценочного определения близости двумерных объектов.
\en Bounding box in two-dimensional space. \n
Used for fast estimation of two-dimensional objects proximity. \~
\ingroup Mathematic_Base_2D
*/
// ---
class MATH_CLASS MbRect {
public :
double left; ///< \ru Левая граница габаритного прямоугольника. \en Left bound of bounding box.
double bottom; ///< \ru Нижняя граница габаритного прямоугольника. \en Bottom bound of bounding box.
double right; ///< \ru Правая граница габаритного прямоугольника. \en Right bound of bounding box.
double top; ///< \ru Верхняя граница габаритного прямоугольника. \en Top bound of bounding box.
public:
/// \ru Конструктор пустого габарита. \en Constructor of an empty bounding box.
MbRect() { SetEmpty(); }
/// \ru Конструктор по заданным значениям границ. \en Constructor by given bounds.
MbRect( double _left, double _bottom, double _right, double _top ) : left(_left), bottom(_bottom), right(_right), top(_top) {}
/// \ru Конструктор по другому габариту. \en Constructor by another bounding box.
MbRect( const MbRect & r ) : left(r.left), bottom(r.bottom), right(r.right), top(r.top) {}
/// \ru Конструктор по двум диагональным точкам. \en The constructor by two diagonal points.
MbRect( const MbCartPoint & p1, const MbCartPoint & p2 ) {
Set(p1.x, p1.y, p2.x, p2.y);
Normalize();
}
/// \ru Конструктор по габариту с последующей трансформацией по матрице. \en Constructor by bounding box with subsequent transformation by the matrix.
MbRect( const MbRect & r, const MbMatrix & m ) : left(r.left), bottom(r.bottom), right(r.right), top(r.top) {
Transform( m );
}
#ifdef __DEBUG_MEMORY_ALLOCATE_FREE_
~MbRect(); ///< \ru Деструктор. \en Destructor.
#endif
/// \ru Установить заданные значения границ. \en Set given values of bounds.
void Set( double _left, double _bottom, double _right, double _top );
/// \ru Установить заданные значения границ. \en Set given values of bounds.
void Set( const MbRect & r );
/// \ru Установить заданные значения границ. \en Set given values of bounds.
void Set( const MbCartPoint & p1, const MbCartPoint & p2 );
/// \ru Установить значения границ как окрестность точки. \en Set values of bounds as point neighborhood.
void Set( const MbCartPoint & p, double eps );
/// \ru Установить значения границ как окрестность точки. \en Set values of bounds as point neighborhood.
void Set( const MbCartPoint & p, double dx, double dy );
/// \ru Установить нулевым. \en Set to zero.
void SetNull();
/// \ru Установить пустым ("вывернутым"). \en Set empty ("everted").
void SetEmpty();
/// \ru Проверить на пустоту. \en Check for emptiness.
bool IsEmpty() const;
/// \ru Проверить габарит на вырожденность по оси X. \en Check bounding box for degeneracy by X-axis.
bool IsDegenerateX() const;
/// \ru Проверить габарит на вырожденность по оси Y. \en Check bounding box for degeneracy by Y-axis.
bool IsDegenerateY() const;
/// \ru Проверить габариты на равенство. \en Check bounding boxes for equality.
bool IsSame( const MbRect &, double eps ) const;
/// \ru Проверить габариты на равенство. \en Check bounding boxes for equality.
bool IsSame( const MbRect &, double xeps, double yeps ) const;
/// \ru Проверить габариты на равенство. \en Check bounding boxes for equality.
bool operator == ( const MbRect & other ) const;
/// \ru Проверить габариты на неравенство. \en Check bounding boxes for inequality.
bool operator != ( const MbRect & other ) const;
/// \ru Присвоить значение другого габарита. \en Assign a value of another bounding box.
void operator = ( const MbRect & other ) { Set( other ); }
/// \ru Получить верхнюю границу. \en Get top bound.
double GetTop () const { return top; }
/// \ru Получить нижнюю границу. \en Get bottom bound.
double GetBottom() const { return bottom; }
/// \ru Получить левую границу. \en Get left bound.
double GetLeft () const { return left; }
/// \ru Получить правую границу. \en Get right bound.
double GetRight () const { return right; }
/// \ru Установить верхнюю границу. \en Set top bound.
void SetTop ( double _top ) { top = _top; }
/// \ru Установить нижнюю границу. \en Set bottom bound.
void SetBottom( double _bottom ) { bottom = _bottom; }
/// \ru Установить левую границу. \en Set left bound.
void SetLeft ( double _left ) { left = _left; }
/// \ru Установить правую границу. \en Set right bound.
void SetRight ( double _right ) { right = _right; }
/// \ru Получить минимум по X. \en Get minimum by X.
double GetXMin() const { return left; }
/// \ru Получить минимум по Y. \en Get minimum by Y.
double GetYMin() const { return bottom; }
/// \ru Получить максимум по X. \en Get maximum by X.
double GetXMax() const { return right; }
/// \ru Получить максимум по Y. \en Get maximum by Y.
double GetYMax() const { return top; }
/// \ru Получить середину по X. \en Get middle by X.
double GetXMid() const { return 0.5 * ( left + right ); }
/// \ru Получить середину по Y. \en Get middle by Y.
double GetYMid() const { return 0.5 * ( bottom + top ); }
/// \ru Установить минимум по X. \en Set minimum by X.
void SetXMin( double s ) { left = s; }
/// \ru Установить максимум по X. \en Set maximum by X.
void SetYMin( double s ) { bottom = s; }
/// \ru Установить минимум по Y. \en Set minimum by Y.
void SetXMax( double s ) { right = s; }
///< \ru Установить максимум по Y. \en Set maximum by Y.
void SetYMax( double s ) { top = s; }
/// \ru Найти ширину габарита. \en Find width of bounding box.
double Width() const { return right - left; }
/// \ru Найти высоту габарита. \en Find height of bounding box.
double Height() const { return top - bottom; }
/// \ru Дать длину по X. \en Get length by X.
double GetLengthX() const { return right - left; } //-V524
/// \ru Дать длину по Y. \en Get length by Y.
double GetLengthY() const { return top - bottom; } //-V524
/// \ru Дать половину периметра. \en Get half of perimeter.
double GetLength( double eps ) const;
/// \ru Дать площадь. \en Get area.
double GetSquare( double eps ) const;
/// \ru Дать длину диагонали. \en Get the diagonal length.
double GetDiagonal() const { return ::_hypot( left - right, top - bottom ); }
/// \ru Вычислить габарит пересечения двух габаритов. \en Calculate bounding box of two bounding boxes intersection.
bool Intersection( const MbRect & rect1, const MbRect & rect2, double eps = Math::LengthEps );
/// \ru Вычислить суммарный габарит двух габаритов. \en Calculate bounding box enclosing two bounding boxes.
bool Union ( const MbRect & rect1, const MbRect & rect2 );
/// \ru Проверить принадлежность габариту заданной точки. \en Check if the bounding box contains the given point.
bool Contains( const MbCartPoint & p, double eps = Math::LengthEps ) const;
/// \ru Проверить принадлежность габариту заданной точки. \en Check if the bounding box contains the given point.
bool Contains( double x, double y, double eps = Math::LengthEps ) const;
/// \ru Проверить принадлежность габариту заданной точки. \en Check if the bounding box contains the given point.
bool Contains( const MbCartPoint & p, double xeps, double yeps ) const;
/// \ru Проверить принадлежность габариту заданной точки. \en Check if the bounding box contains the given point.
bool Contains( double x, double y, double xeps, double yeps ) const;
/// \ru Проверить принадлежность габариту заданной координаты по X. \en Check if the bounding box contains the given X coordinate.
bool ContainsX( double x, double eps = Math::LengthEps ) const ;
/// \ru Проверить принадлежность габариту заданной координаты по Y. \en Check if the bounding box contains the given Y coordinate.
bool ContainsY( double y, double eps = Math::LengthEps ) const ;
/// \ru Вычислить коды расположения точки относительно прямоугольника. \en Calculate the codes of a point location relative to the rectangle.
void OutCodes( const MbCartPoint & p, unsigned int & outcodes, double eps = METRIC_PRECISION ) const;
/** \brief \ru Вычислить расстояние до ближайшей границы габаритного прямоугольника.
\en Calculate the distance to the nearest boundary of the bounding box. \~
\details \ru Найденное расстояние до ближайшей границы имеет отрицательное значение, если точка находится внутри, и положительное - если снаружи.
\en The calculated distance is negative if the point is inside, and is positive if it is outside. \~
\param[in] point - \ru Исследуемая точка.
\en The investigated point. \~
\return \ru Возвращает расстояние до границы.
\en Returns the distance to the boundary. \~
*/
double DistanceToPoint( const MbCartPoint & point ) const;
/// \ru Вычислить расстояние до точки. \en Calculate the distance to a point.
double DistanceToPoint( const MbCartPoint & to,
unsigned int & outcodes ) const;
/** \brief \ru Вычислить расстояние до куба.
\en Calculate the distance to the cube. \~
\details \ru Возвращается ноль, если кубы пересекаются или один содержится в другом.
\en It returns zero if the cubes intersect or one is contained in the other. \~
\param[in] cube - \ru Другой куб.
\en Other cube. \~
\param[in] eps - \ru Метрическая точность.
\en A metric tolerance. \~
\return \ru Возвращает расстояние до границы.
\en Returns the distance to the boundary. \~
*/
double DistanceToCube( const MbRect & cube, double eps = Math::metricRegion ) const;
/// \ru Вычислить минимальное и максимальное расстояния до точки. \en Calculate minimal and maximal distances to a point.
void CalcDistances( const MbCartPoint & to,
double & dmin, double & dmax,
unsigned int & outcodes ) const;
// \ru Пересекается ли габарит с другим габаритом. \en Whether the bounding box intersects with another bounding box.
/// \ru Проверить, пересекается ли габарит с другим габаритом с признаком пересечения. \en Whether the bounding box intersects with another bounding box with intersection attribute.
bool Intersect( const MbRect &, TaeTwoRectPos & ) const;
/// \ru Проверить пересекается ли габарит с другим габаритом. \en Whether the bounding box intersects with another bounding box.
bool Intersect( const MbRect & other, double eps = Math::LengthEps ) const;
/// \ru Проверить пересекается ли габарит с другим габаритом. \en Whether the bounding box intersects with another bounding box.
bool Intersect( const MbRect & other, double xeps, double yeps ) const;
/// \ru Сделать другой прямоугольник из этого, сжав его. \en Create new rectangle from the current one by shrinking.
MbRect CompressedBy( double dLeft, double dBottom,
double dRight, double dTop) const ;
/// \ru Нормализовать себя. \en Normalize oneself.
MbRect & Normalize();
/// \ru Преобразовать по матрице. \en Transform by matrix.
void Transform( const MbMatrix & );
/// \ru Масштабировать. \en Scale.
void Scale( double sx, double sy );
/// \ru Включить в себя прямоугольник. \en Enclose a rectangle.
MbRect & operator |= ( const MbRect & );
/// \ru Включить в себя точку. \en Enclose a point.
MbRect & operator |= ( const MbCartPoint & );
/// \ru Включить в себя точку. \en Enclose a point.
MbRect & operator |= ( const MbHomogeneous & );
/// \ru Включить в себя массив точек. \en Enclose an array of points.
MbRect & operator |= ( const SArray<MbCartPoint> & );
/// \ru Включить в себя массив точек. \en Enclose an array of points.
MbRect & operator |= ( const SArray<MbHomogeneous> & );
/// \ru Включить в себя точку,заданную как XY. \en Enclose a point specified as XY.
void Include( double x, double y );
/// \ru Включить в себя координату X. \en Enclose an X-coordinate.
void IncludeX( double x );
/// \ru Включить в себя координату Y. \en Enclose an Y-coordinate.
void IncludeY( double y );
/// \ru Включить в себя интервал от X - dx до X + dx. \en Enclose a range from X - dx to X + dx.
void IncludeXInterval( double x, double dx );
/// \ru Включить в себя интервал от Y - dy до Y + dy. \en Enclose a range from Y - dy to Y + dy.
void IncludeYInterval( double y, double dy );
// \ru Сдвинуть прямоугольник \en Move rectangle
/// \ru Cдвинуть прямоугольник. \en Move rectangle.
void Move( const MbVector & to );
/// \ru Cдвинуть прямоугольник. \en Move rectangle.
void Move( double dx, double dy );
/// \ru Масштабировать относительно 0. \en Scale relative to 0.
void Scale( double scale );
/// \ru Расширить прямоугольник. \en Extend rectangle.
void Enlarge( double x, double y );
/// \ru Расширить прямоугольник во все стороны. \en Extend rectangle in all directions.
void Enlarge( double delta );
/// \ru Поличить охватывающий прямоугольник. \en Get the covering rectangle.
void GetOusideRect( MbRect & r ) const { r = *this; }
/// \ru Вернуть точку центра габарита. \en Get center of the bounding box.
void GetCenter( MbCartPoint & p ) const {
p.x = (left + right) * 0.5;
p.y = (top + bottom) * 0.5;
}
// \ru Вершины габаритного прямоугольника \en Vertices of bounding box
// Y
// |
// 3 - - - 2
// | |
// | |
// 0 - - - 1 - X
//
/// \ru Дать количество вершин. \en Get count of vertices.
size_t GetVerticesCount() const { return 4; } //-V112
/// \ru Выдать вершину габаритного прямоугольника по индексу от 0 до 3. \en Get vertex of bounding rectangle by index in range from 0 to 3.
void GetVertex( size_t index, MbCartPoint & p ) const;
/// \ru Получить ссылку на себя. \en Get reference to itself.
const MbRect & GetRect() const { return *this; }
/// \ru Количество координат точки. \en The number of point coordinates.
static size_t GetDimension() { return 2; }
/// \ru Доступ к координате по индексу. \en Access to a coordinate by an index.
double GetMin( size_t k ) const { return k ? bottom : left; }
/// \ru Доступ к координате по индексу. \en Access to a coordinate by an index.
double GetMax( size_t k ) const { return k ? top : right; }
/// \ru Дать длина по стороне. \en Get side length.
double GetSideLength( size_t k ) const { return k ? ::fabs( GetLengthY() ) : ::fabs( GetLengthX() ); }
/// \ru Получить ссылку на себя. \en Get reference to itself.
const MbRect & GetCube() const { return *this; }
KNOWN_OBJECTS_RW_REF_OPERATORS_EX( MbRect, MATH_FUNC_EX )
DECLARE_NEW_DELETE_CLASS( MbRect )
DECLARE_NEW_DELETE_CLASS_EX( MbRect )
}; // MbRect
//------------------------------------------------------------------------------
// \ru Установить заданные значения границ \en Set given values of bounds
// ---
inline void MbRect::Set( double _left, double _bottom, double _right, double _top )
{
left = _left;
top = _top;
right = _right;
bottom = _bottom;
}
//------------------------------------------------------------------------------
// \ru Установить заданные значения границ \en Set given values of bounds
// ---
inline void MbRect::Set( const MbRect & r )
{
left = r.left;
top = r.top;
right = r.right;
bottom = r.bottom;
}
//------------------------------------------------------------------------------
// \ru Установить значения границ как окрестность точки. \en Set values of bounds as point neighborhood.
// ---
inline void MbRect::Set( const MbCartPoint & p1, const MbCartPoint & p2 )
{
left = std_min( p1.x, p2.x );
right = std_max( p1.x, p2.x );
bottom = std_min( p1.y, p2.y );
top = std_max( p1.y, p2.y );
}
//------------------------------------------------------------------------------
// \ru Установить значения границ как окрестность точки. \en Set values of bounds as point neighborhood.
// ---
inline void MbRect::Set( const MbCartPoint & p, double eps )
{
eps = ::fabs( eps );
left = p.x - eps;
right = p.x + eps;
bottom = p.y - eps;
top = p.y + eps;
}
//------------------------------------------------------------------------------
// \ru Установить значения границ как окрестность точки. \en Set values of bounds as point neighborhood.
// ---
inline void MbRect::Set( const MbCartPoint & p, double dx, double dy )
{
dx = ::fabs( dx );
dy = ::fabs( dy );
left = p.x - dx;
right = p.x + dx;
bottom = p.y - dy;
top = p.y + dy;
}
//------------------------------------------------------------------------------
// \ru Установить нулевым \en Set to zero
// ---
inline void MbRect::SetNull() {
left = top = right = bottom = 0;
}
//------------------------------------------------------------------------------
// \ru Установить пустым ("вывернутым") \en Set empty ("everted")
// ---
inline void MbRect::SetEmpty() {
Set( MB_MAXDOUBLE, MB_MAXDOUBLE, -MB_MAXDOUBLE, -MB_MAXDOUBLE );
}
//------------------------------------------------------------------------------
// \ru Проверка на пустоту \en Check for emptiness
// ---
inline bool MbRect::IsEmpty() const {
return ( left > right ) || ( bottom > top );
}
//------------------------------------------------------------------------------
// \ru Проверка габарита по оси 0X \en Check bounding box by 0X-axis
// ---
inline bool MbRect::IsDegenerateX() const {
return fabs( right - left ) < Math::LengthEps;
}
//------------------------------------------------------------------------------
// \ru Проверка габарита по оси 0Y \en Check bounding box by 0Y-axis
// ---
inline bool MbRect::IsDegenerateY() const {
return fabs( top - bottom ) < Math::LengthEps;
}
//------------------------------------------------------------------------------
// \ru Проверка равенства с другим прямоугольником \en Check for equality with another rectangle
// ---
inline bool MbRect::IsSame( const MbRect & other, double eps ) const {
return ::fabs( other.left - left ) < eps &&
::fabs( other.right - right ) < eps &&
::fabs( other.top - top ) < eps &&
::fabs( other.bottom - bottom ) < eps;
}
//------------------------------------------------------------------------------
// \ru Проверка равенства с другим прямоугольником \en Check for equality with another rectangle
// ---
inline bool MbRect::IsSame( const MbRect & other, double xeps, double yeps ) const {
return ::fabs( other.left - left ) < xeps &&
::fabs( other.right - right ) < xeps &&
::fabs( other.top - top ) < yeps &&
::fabs( other.bottom - bottom ) < yeps;
}
//------------------------------------------------------------------------------
// \ru Проверка равенства с другим прямоугольником \en Check for equality with another rectangle
// ---
inline bool MbRect::operator == ( const MbRect & other ) const {
return ::fabs( other.left - left ) < Math::LengthEps &&
::fabs( other.right - right ) < Math::LengthEps &&
::fabs( other.top - top ) < Math::LengthEps &&
::fabs( other.bottom - bottom ) < Math::LengthEps;
}
//------------------------------------------------------------------------------
// \ru Проверка неравенства с другим прямоугольником \en Check for inequality with another rectangle
// ---
inline bool MbRect::operator != ( const MbRect & other ) const {
return !( other == *this );
}
//------------------------------------------------------------------------------
// \ru Проверка на то, что заданная точка лежит внутри прямоугольника \en Check that a given point is inside the rectangle
// ---
inline bool MbRect::Contains( const MbCartPoint & p, double eps ) const {
return ( p.x >= (left - eps) ) && ( p.x <= (right + eps) ) &&
( p.y >= (bottom - eps) ) && ( p.y <= (top + eps) );
}
//------------------------------------------------------------------------------
// \ru Проверка на то, что заданная точка лежит внутри прямоугольника \en Check that a given point is inside the rectangle
// ---
inline bool MbRect::Contains( double x, double y, double eps ) const {
return ( x >= (left - eps) ) && ( x <= (right + eps) ) &&
( y >= (bottom - eps) ) && ( y <= (top + eps) );
}
//------------------------------------------------------------------------------
// \ru Проверка на то, что заданная точка лежит внутри прямоугольника \en Check that a given point is inside the rectangle
// ---
inline bool MbRect::Contains( const MbCartPoint & p, double xeps, double yeps ) const {
return ( p.x >= (left - xeps) ) && ( p.x <= (right + xeps) ) &&
( p.y >= (bottom - yeps) ) && ( p.y <= (top + yeps) );
}
//------------------------------------------------------------------------------
// \ru Проверка на то, что заданная точка лежит внутри прямоугольника \en Check that a given point is inside the rectangle
// ---
inline bool MbRect::Contains( double x, double y, double xeps, double yeps ) const {
return ( x >= (left - xeps) ) && ( x <= (right + xeps) ) &&
( y >= (bottom - yeps) ) && ( y <= (top + yeps) );
}
//------------------------------------------------------------------------------
// \ru Проверка на то, что заданная координата X лежит внутри прямоугольника \en Check that given X coordinate is inside the rectangle
// ---
inline bool MbRect::ContainsX( double x, double eps ) const {
return ( x > left - eps ) && ( x < right + eps );
}
//------------------------------------------------------------------------------
// \ru Проверка на то, что заданная координата Y лежит внутри прямоугольника \en Check that given Y coordinate is inside the rectangle
// ---
inline bool MbRect::ContainsY( double y, double eps ) const {
return ( y > bottom - eps ) && ( y < top + eps );
}
//------------------------------------------------------------------------------
// \ru Вычисление кодов расположения точки относительно прямоугольника \en Calculate codes of a point location relative to the rectangle
// \ru Бит 0 - точка слева от окна \en Bit 0 - point to the left of a window
// \ru Бит 1 - точка справа от окна \en Bit 1 - point to the right of a window
// \ru Бит 2 - точка ниже окна \en Bit 2 - the point is lower than a window
// \ru Бит 3 - точка выше окна \en Bit 3 - the point is higher than a window
// ---
inline void MbRect::OutCodes( const MbCartPoint & p, unsigned int & outcodes, double eps ) const {
outcodes = ( p.x < left - eps ) |
( ( ( p.x > right + eps ) << 1 ) & 0x2 ) |
( ( ( p.y < bottom - eps ) << 2 ) & 0x4 ) | //-V112
( ( ( p.y > top + eps ) << 3 ) & 0x8 );
}
//------------------------------------------------------------------------------
// \ru Расстояние до точки: если расстояние < 0, то точка лежит внутри \en Distance to a point: if distance is less than 0 then point is inside
// ---
inline double MbRect::DistanceToPoint( const MbCartPoint & pnt ) const {
double dx = std_max( left-pnt.x, pnt.x-right );
double dy = std_max( bottom-pnt.y, pnt.y-top );
return std_max(dx,dy);
}
//------------------------------------------------------------------------------
// \ru Расстояние до точки \en Distance to a point
// ---
inline double MbRect::DistanceToPoint( const MbCartPoint & to,
unsigned int & outcodes ) const
{
if ( IsEmpty() ) {
outcodes = 0xFFFF;
return 1E+6;
}
OutCodes( to, outcodes ); // \ru Вычисление кодов расположения точки \en Calculate codes of a point location
double dx = std_min( fabs( to.x - left), fabs( to.x - right) );
double dy = std_min( fabs( to.y - top), fabs( to.y - bottom) );
return ( outcodes == 0x0 ) ? std_min( dx, dy ) : // \ru Точка внутри прямоугольника \en Point is inside the rectangle
( outcodes == 0x1 || outcodes == 0x2 ) ? dx : // \ru Точка по Y - внутри, по X - вне прямоугольника \en Point is inside rectangle by Y, outside by X
( outcodes == 0x4 || outcodes == 0x8 ) ? dy : // \ru Точка по X - внутри, по Y - вне прямоугольника //-V112 \en Point is inside rectangle by X, outside by Y //-V112
::_hypot( dx, dy ); // \ru Точка по X и по Y - вне прямоугольника \en Point is outside the rectangle by X and Y
}
//------------------------------------------------------------------------------
// \ru Вычисление минимального и максимального расстояний до точки \en Calculate minimal and maximal distances to point
// ---
inline void MbRect::CalcDistances( const MbCartPoint & to,
double & dmin, double & dmax,
unsigned int & outcodes ) const
{
dmin = DistanceToPoint( to, outcodes );
if ( outcodes != 0xFFFF ) { // \ru Прямоугольник не вырожден \en Rectangle is not degenerate
dmax = ::_hypot( to.x - left, to.y - bottom );
double d = ::_hypot( to.x - left, to.y - top );
if ( d > dmax ) dmax = d;
d = ::_hypot( to.x - right, to.y - bottom );
if ( d > dmax ) dmax = d;
d = ::_hypot( to.x - right, to.y - top );
if ( d > dmax ) dmax = d;
}
}
//------------------------------------------------------------------------------
// \ru Сделать другой прям-к из этого, сжав его \en Create a new rectangle from the current one by shrinking
// ---
inline MbRect MbRect::CompressedBy( double dLeft, double dBottom, double dRight, double dTop) const
{
if ( IsEmpty() )
return MbRect();
return MbRect(left+dLeft, bottom+dBottom, right-dRight, top-dTop);
}
//------------------------------------------------------------------------------
// \ru Нормализовать себя \en Normalize oneself
// ---
inline MbRect & MbRect::Normalize() {
double c = UNDEFINED_DBL;
if ( left > right ) { c = left; left = right; right = c; }
if ( top < bottom ) { c = top; top = bottom; bottom = c; }
return *this;
}
//------------------------------------------------------------------------------
// \ru Включить в себя точку \en Enclose a point
// ---
inline MbRect & MbRect::operator |=( const MbCartPoint & p ) {
Include( p.x, p.y );
return *this;
}
//------------------------------------------------------------------------------
// \ru Включить в себя точку \en Enclose a point
// ---
inline MbRect & MbRect::operator |=( const MbHomogeneous & p ) {
Include( p.x, p.y );
return *this;
}
//------------------------------------------------------------------------------
// \ru Включить в себя точку,заданную как XY \en Enclose a point secified as XY
// ---
inline void MbRect::Include( double x, double y ) {
left = std_min(left, x);
bottom = std_min(bottom, y);
right = std_max(right, x);
top = std_max(top, y);
}
//------------------------------------------------------------------------------
// \ru Включить в себя координату X \en Enclose an X-coordinate
// ---
inline void MbRect::IncludeX( double x ) {
left = std_min(left, x);
right = std_max(right, x);
}
//------------------------------------------------------------------------------
// \ru Включить в себя координату Y \en Enclose an Y-coordinate
// ---
inline void MbRect::IncludeY( double y ) {
bottom = std_min(bottom, y);
top = std_max(top, y);
}
//------------------------------------------------------------------------------
// \ru Включить в себя интервал от X - dx до X + dx \en Enclose a range from X - dx to X + dx
// ---
inline void MbRect::IncludeXInterval( double x, double dx ) {
left = std_min( left, x - dx );
right = std_max( right, x + dx );
}
//------------------------------------------------------------------------------
// \ru Включить в себя интервал от Y - dy до Y + dy \en Enclose a range from Y - dy to Y + dy
// ---
inline void MbRect::IncludeYInterval( double y, double dy ) {
bottom = std_min( bottom, y - dy );
top = std_max( top, y + dy );
}
//------------------------------------------------------------------------------
// \ru Включить в себя прямоугольник \en Enclose a rectangle
// ---
inline MbRect& MbRect::operator |= ( const MbRect & other ) {
left = std_min(left, other.left);
bottom = std_min(bottom, other.bottom);
right = std_max(right, other.right);
top = std_max(top, other.top);
return *this;
}
//------------------------------------------------------------------------------
// \ru Сдвинуть прямоугольник \en Move rectangle
// ---
inline void MbRect::Move( const MbVector & to ) {
Move( to.x, to.y );
}
//------------------------------------------------------------------------------
// \ru Сдвинуть прямоугольник \en Move rectangle
// ---
inline void MbRect::Move( double dx, double dy ) {
if ( !IsEmpty() ) {
left += dx;
right += dx;
top += dy;
bottom += dy;
}
}
//------------------------------------------------------------------------------
// \ru Промасштабировать относительно 0 \en Scale relative to 0
// ---
inline void MbRect::Scale( double scale ) {
if ( !IsEmpty() ) {
left *= scale;
right *= scale;
top *= scale;
bottom *= scale;
}
}
//------------------------------------------------------------------------------
// \ru Расширить прямоугольник \en Extend rectangle
// ---
inline void MbRect::Enlarge( double x, double y ) {
if ( !IsEmpty() ) {
left -= x;
right += x;
bottom -= y;
top += y;
}
}
//------------------------------------------------------------------------------
// \ru Расширить прямоугольник во все стороны \en Extend the rectangle in all directions
// \ru НЕ ПРОВЕРЯЕТСЯ вырожденность прямоугольников !!! \en Rectangles degeneracy IS NOT CHECKED !!!
// ---
inline void MbRect::Enlarge( double delta ) {
left -= delta;
right += delta;
bottom -= delta;
top += delta;
}
//------------------------------------------------------------------------------
// \ru Проверка, пересекается ли прям-к с другим прям-ком \en Check if rectangle intersect another rectangle
// \ru НЕ ПРОВЕРЯЕТСЯ вырожденность прямоугольников !!! \en Rectangles degeneracy IS NOT CHECKED !!!
// ---
inline bool MbRect::Intersect( const MbRect & other, double eps ) const {
return std_max( left, other.left ) < std_min( right, other.right ) + eps &&
std_max( bottom, other.bottom ) < std_min( top, other.top ) + eps;
}
//------------------------------------------------------------------------------
// \ru Проверка, пересекается ли прям-к с другим прям-ком \en Check if the rectangle intersect another rectangle
// \ru НЕ ПРОВЕРЯЕТСЯ вырожденность прямоугольников !!! \en Rectangles degeneracy IS NOT CHECKED !!!
// ---
inline bool MbRect::Intersect( const MbRect & other, double xeps, double yeps ) const {
return std_max( left, other.left ) < std_min( right, other.right ) + xeps &&
std_max( bottom, other.bottom ) < std_min( top, other.top ) + yeps;
}
/** \} */
#endif