Files
pip/libs/main/math/pirect.h
2026-03-12 14:46:57 +03:00

448 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \~\file pirect.h
//! \~\ingroup Math
//! \~\brief
//! \~english Rect class for 2D geometry
//! \~russian Класс прямоугольника для 2D геометрии
/*
PIP - Platform Independent Primitives
Rect class for 2D geometry
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIRECT_H
#define PIRECT_H
#include "pipoint.h"
//! \~\ingroup Math
//! \~\brief
//! \~english The PIRect class provides a two-dimensional rectangle class for 2D geometry.
//! \~russian Класс PIRect предоставляет двумерный класс прямоугольника для 2D геометрии.
template<typename Type>
class PIP_EXPORT PIRect {
static_assert(std::is_arithmetic<Type>::value, "Type must be arithmetic");
public:
//! \~english Constructs empty rectangle.
//! \~russian Создает пустой прямоугольник.
PIRect() {}
//! \~english Constructs rectangle from bottom-left corner, width and height.
//! \~russian Создает прямоугольник по левому нижнему углу, ширине и высоте.
PIRect(Type left_, Type bottom_, Type width_, Type height_) {
set(left_, bottom_, width_, height_);
normalize();
}
//! \~english Constructs rectangle from opposite corners.
//! \~russian Создает прямоугольник по двум противоположным углам.
PIRect(const PIPoint<Type> & bottom_left, const PIPoint<Type> & top_right) {
bl = bottom_left;
tr = top_right;
normalize();
}
// PIRect(const PIPoint<Type> & p0, const PIPoint<Type> & p1, const PIPoint<Type> & p2) {
// set(piMin<Type>(p0.x, p1.x, p2.x), piMin<Type>(p0.y, p1.y, p2.y),
// piMax<Type>(p0.x, p1.x, p2.x), piMax<Type>(p0.y, p1.y, p2.y));
// }
//! \~english Sets rectangle from bottom-left corner, width and height.
//! \~russian Задает прямоугольник по левому нижнему углу, ширине и высоте.
PIRect<Type> & set(Type left_, Type bottom_, Type width_, Type height_) {
bl = PIPoint<Type>(left_, bottom_);
tr = PIPoint<Type>(left_ + width_, bottom_ + height_);
return normalize();
}
//! \~english Sets rectangle from two opposite corners.
//! \~russian Задает прямоугольник по двум противоположным углам.
PIRect<Type> & set(const PIPoint<Type> & top_left, const PIPoint<Type> & bottom_right) {
bl = top_left;
tr = bottom_right;
return normalize();
}
//! \~english Checks point against current rectangle bounds.
//! \~russian Проверяет точку относительно текущих границ прямоугольника.
bool pointIn(Type x, Type y) const { return (x <= bl.x && x >= tr.x && y <= bl.y && y >= tr.y); }
//! \~english Checks point against current rectangle bounds.
//! \~russian Проверяет точку относительно текущих границ прямоугольника.
bool pointIn(const PIPoint<Type> & p) const { return pointIn(p.x, p.y); }
//! \~english Returns `true` if width and height are zero.
//! \~russian Возвращает `true`, если ширина и высота равны нулю.
bool isEmpty() const { return (width() == 0 && height() == 0); }
//! \~english Shifts the rectangle by `x` and `y`.
//! \~russian Сдвигает прямоугольник на `x` и `y`.
PIRect<Type> & translate(Type x, Type y) {
bl.translate(x, y);
tr.translate(x, y);
return *this;
}
//! \~english Shifts the rectangle by a point offset.
//! \~russian Сдвигает прямоугольник на смещение, заданное точкой.
PIRect<Type> & translate(const PIPoint<Type> & p) {
bl.translate(p);
tr.translate(p);
return *this;
}
//! \~english Returns translated copy of the rectangle.
//! \~russian Возвращает смещенную копию прямоугольника.
PIRect<Type> translated(Type x, Type y) const {
PIRect<Type> r(*this);
r.translate(x, y);
return r;
}
//! \~english Returns copy shifted by a point offset.
//! \~russian Возвращает копию, смещенную на точку.
PIRect<Type> translated(const PIPoint<Type> & p) const {
PIRect<Type> r(*this);
r.translate(p);
return r;
}
//! \~english Same as \a translate().
//! \~russian Синоним \a translate().
PIRect<Type> & move(Type x, Type y) { return translate(x, y); }
//! \~english Same as \a translate().
//! \~russian Синоним \a translate().
PIRect<Type> & move(const PIPoint<Type> & p) { return translate(p); }
//! \~english Same as \a translated().
//! \~russian Синоним \a translated().
PIRect<Type> moved(Type x, Type y) const {
PIRect<Type> r(*this);
r.translate(x, y);
return r;
}
//! \~english Same as \a translated().
//! \~russian Синоним \a translated().
PIRect<Type> moved(const PIPoint<Type> & p) const {
PIRect<Type> r(*this);
r.translate(p);
return r;
}
//! \~english Scales rectangle extents by `x` and `y`.
//! \~russian Масштабирует размеры прямоугольника по `x` и `y`.
PIRect<Type> & scale(Type x, Type y) {
setWidth(width() * x);
setHeight(height() * y);
return normalize();
}
//! \~english Scales both extents by `s`.
//! \~russian Масштабирует обе стороны на `s`.
PIRect<Type> & scale(Type s) { return scale(s, s); }
//! \~english Scales extents by point components.
//! \~russian Масштабирует стороны по компонентам точки.
PIRect<Type> & scale(const PIPoint<Type> & p) { return scale(p.x, p.y); }
//! \~english Returns scaled copy of the rectangle.
//! \~russian Возвращает масштабированную копию прямоугольника.
PIRect<Type> scaled(Type x, Type y) const {
PIRect<Type> r(*this);
r.scale(x, y);
return r;
}
//! \~english Returns copy scaled uniformly.
//! \~russian Возвращает копию с равномерным масштабированием.
PIRect<Type> scaled(Type s) const {
PIRect<Type> r(*this);
r.scale(s);
return r;
}
//! \~english Returns copy scaled by point components.
//! \~russian Возвращает копию, масштабированную по компонентам точки.
PIRect<Type> scaled(const PIPoint<Type> & p) const {
PIRect<Type> r(*this);
r.scale(p);
return r;
}
//! \~english Normalizes corner order.
//! \~russian Нормализует порядок углов.
PIRect<Type> & normalize() {
if (bl.x > tr.x) piSwap<Type>(bl.x, tr.x);
if (bl.y > tr.y) piSwap<Type>(bl.y, tr.y);
return *this;
}
//! \~english Returns normalized copy of the rectangle.
//! \~russian Возвращает нормализованную копию прямоугольника.
PIRect<Type> normalized() const {
PIRect<Type> r(*this);
r.normalize();
return r;
}
//! \~english Updates bounds using rectangle `r` and normalizes the result.
//! \~russian Обновляет границы по прямоугольнику `r` и нормализует результат.
PIRect<Type> & unite(const PIRect<Type> & r) {
bl.x = piMax<Type>(bl.x, r.left());
bl.y = piMax<Type>(bl.y, r.bottom());
tr.x = piMin<Type>(tr.x, r.right());
tr.y = piMin<Type>(tr.y, r.top());
return normalize();
}
//! \~english Returns copy after \a unite().
//! \~russian Возвращает копию после \a unite().
PIRect<Type> united(const PIRect<Type> & rect) const {
PIRect<Type> r(*this);
r.unite(rect);
return r;
}
//! \~english Replaces rectangle with intersection with `r`.
//! \~russian Заменяет прямоугольник пересечением с `r`.
PIRect<Type> & intersect(const PIRect<Type> & r) {
bl.x = piMax<Type>(bl.x, r.left());
bl.y = piMax<Type>(bl.y, r.bottom());
tr.x = piMin<Type>(tr.x, r.right());
tr.y = piMin<Type>(tr.y, r.top());
if (bl.x > tr.x || bl.y > tr.y) bl = tr = PIPoint<Type>();
return *this;
}
//! \~english Returns copy after \a intersect().
//! \~russian Возвращает копию после \a intersect().
PIRect<Type> intersected(const PIRect<Type> & rect) const {
PIRect<Type> r(*this);
r.intersect(rect);
return r;
}
//! \~english Returns top edge coordinate.
//! \~russian Возвращает координату верхней границы.
Type top() const { return tr.y; }
//! \~english Returns left edge coordinate.
//! \~russian Возвращает координату левой границы.
Type left() const { return bl.x; }
//! \~english Returns right edge coordinate.
//! \~russian Возвращает координату правой границы.
Type right() const { return tr.x; }
//! \~english Returns bottom edge coordinate.
//! \~russian Возвращает координату нижней границы.
Type bottom() const { return bl.y; }
//! \~english Returns rectangle width.
//! \~russian Возвращает ширину прямоугольника.
Type width() const { return tr.x - bl.x; }
//! \~english Returns rectangle height.
//! \~russian Возвращает высоту прямоугольника.
Type height() const { return tr.y - bl.y; }
//! \~english Returns top-left corner.
//! \~russian Возвращает левый верхний угол.
PIPoint<Type> topLeft() const { return PIPoint<Type>(bl.x, tr.y); }
//! \~english Returns top-right corner.
//! \~russian Возвращает правый верхний угол.
PIPoint<Type> topRigth() const { return tr; }
//! \~english Returns bottom-left corner.
//! \~russian Возвращает левый нижний угол.
PIPoint<Type> bottomLeft() const { return bl; }
//! \~english Returns bottom-right corner.
//! \~russian Возвращает правый нижний угол.
PIPoint<Type> bottomRight() const { return PIPoint<Type>(tr.x, bl.y); }
//! \~english Returns rectangle center.
//! \~russian Возвращает центр прямоугольника.
PIPoint<Type> center() const { return bl.moved(width() / 2, height() / 2); }
//! \~english Sets top edge coordinate.
//! \~russian Задает координату верхней границы.
void setTop(Type v) {
tr.y = v;
normalize();
}
//! \~english Sets left edge coordinate.
//! \~russian Задает координату левой границы.
void setLeft(Type v) {
bl.x = v;
normalize();
}
//! \~english Sets right edge coordinate.
//! \~russian Задает координату правой границы.
void setRigth(Type v) {
tr.x = v;
normalize();
}
//! \~english Sets bottom edge coordinate.
//! \~russian Задает координату нижней границы.
void setBottom(Type v) {
bl.y = v;
normalize();
}
//! \~english Updates stored width-related extent.
//! \~russian Обновляет хранимую горизонтальную размерность.
void setWidth(Type v) { setTop(bl.x + v); }
//! \~english Updates stored height-related extent.
//! \~russian Обновляет хранимую вертикальную размерность.
void setHeight(Type v) { setRigth(bl.y + v); }
//! \~english Sets top-left corner.
//! \~russian Задает левый верхний угол.
void setTopLeft(const PIPoint<Type> & p) {
setLeft(p.x);
setTop(p.y);
}
//! \~english Sets bottom-right corner.
//! \~russian Задает правый нижний угол.
void setBottomRight(const PIPoint<Type> & p) {
setRigth(p.x);
setBottom(p.y);
}
//! \~english Sets bottom-left corner.
//! \~russian Задает левый нижний угол.
void setBottomLeft(const PIPoint<Type> & p) {
bl = p;
normalize();
}
//! \~english Sets top-right corner.
//! \~russian Задает правый верхний угол.
void setTopRigth(const PIPoint<Type> & p) {
tr = p;
normalize();
}
//! \~english Repositions rectangle around center point `p`.
//! \~russian Перемещает прямоугольник так, чтобы его центром стала точка `p`.
void setCenter(const PIPoint<Type> & p) {
Type w = width();
Type h = height();
bl = p.translated(-w / 2, -h / 2);
tr = PIPoint<Type>(bl.x + w, bl.y + h);
}
//! \~english Sets rectangle size from current bottom-left corner.
//! \~russian Задает размер прямоугольника от текущего левого нижнего угла.
void setSize(Type w, Type h) {
tr = PIPoint<Type>(bl.x + w, bl.y + h);
normalize();
}
//! \~english Shifts both coordinates by `x`.
//! \~russian Сдвигает обе координаты на `x`.
void operator+=(Type x) { translate(x, x); }
//! \~english Shifts rectangle by a point offset.
//! \~russian Сдвигает прямоугольник на смещение, заданное точкой.
void operator+=(const PIPoint<Type> & p) { translate(p); }
//! \~english Shifts both coordinates by `-x`.
//! \~russian Сдвигает обе координаты на `-x`.
void operator-=(Type x) { translate(-x, -x); }
//! \~english Shifts rectangle by the negated point offset.
//! \~russian Сдвигает прямоугольник на отрицательное смещение точки.
void operator-=(const PIPoint<Type> & p) { translate(-p); }
//! \~english Same as \a unite().
//! \~russian Синоним \a unite().
void operator|=(const PIRect<Type> & r) { unite(r); }
//! \~english Same as \a intersect().
//! \~russian Синоним \a intersect().
void operator&=(const PIRect<Type> & r) { intersect(r); }
//! \~english Returns translated copy of the rectangle.
//! \~russian Возвращает смещенную копию прямоугольника.
PIRect<Type> operator+(const PIPoint<Type> & p) { return translated(p); }
//! \~english Returns copy shifted by the negated point offset.
//! \~russian Возвращает копию, смещенную на отрицательное смещение точки.
PIRect<Type> operator-(const PIPoint<Type> & p) { return translated(-p); }
//! \~english Returns copy after \a unite().
//! \~russian Возвращает копию после \a unite().
PIRect<Type> operator|(const PIRect<Type> & r) { return united(r); }
//! \~english Returns copy after \a intersect().
//! \~russian Возвращает копию после \a intersect().
PIRect<Type> operator&(const PIRect<Type> & r) { return intersected(r); }
//! \~english Checks whether rectangle corners are equal.
//! \~russian Проверяет равенство углов прямоугольников.
bool operator==(const PIRect<Type> & r) const { return (bl == r.bl && tr == r.tr); }
//! \~english Checks whether rectangle corners differ.
//! \~russian Проверяет различие углов прямоугольников.
bool operator!=(const PIRect<Type> & r) const { return (bl != r.bl || tr != r.tr); }
private:
PIPoint<Type> bl;
PIPoint<Type> tr;
};
//! \relatesalso PICout
//! \~english Writes rectangle description to \a PICout.
//! \~russian Выводит описание прямоугольника в \a PICout.
template<typename Type>
PICout operator<<(PICout & s, const PIRect<Type> & v) {
s.space();
s.saveAndSetControls(0);
s << "Rect{" << v.bottomLeft() << ":" << v.width() << "x" << v.height() << "}";
s.restoreControls();
return s;
}
//! \~english Alias for rectangle with `int` coordinates.
//! \~russian Псевдоним прямоугольника с координатами типа `int`.
typedef PIRect<int> PIRecti;
//! \~english Alias for rectangle with `uint` coordinates.
//! \~russian Псевдоним прямоугольника с координатами типа `uint`.
typedef PIRect<uint> PIRectu;
//! \~english Alias for rectangle with `float` coordinates.
//! \~russian Псевдоним прямоугольника с координатами типа `float`.
typedef PIRect<float> PIRectf;
//! \~english Alias for rectangle with `double` coordinates.
//! \~russian Псевдоним прямоугольника с координатами типа `double`.
typedef PIRect<double> PIRectd;
#endif // PIRECT_H