Files
pip/libs/main/math/pirect.h

379 lines
12 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
//! \~russian Класс прямоугольника
/*
PIP - Platform Independent Primitives
Rect class
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"
//! \brief
//! \~english Rect class
//! \~russian Класс прямоугольника
//! \~\details
//! \~russian
//! Этот класс описывает прямоугольник на плоскости в прямоугольной системе координат
template<typename Type>
class PIP_EXPORT PIRect {
static_assert(std::is_arithmetic<Type>::value, "Type must be arithmetic");
public:
//! \~english Default constructor.
//! \~russian Конструктор по умолчанию.
PIRect() {}
//! \~english Constructor from bottom-left corner coordinates and width/height.
//! \~russian Конструктор прямоугольника из координат левого нижнего угла и размеров ширины и высоты
PIRect(Type left_, Type bottom_, Type width_, Type height_) {
set(left_, bottom_, width_, height_);
normalize();
}
//! \~english Constructor from bottom-left and top-right points.
//! \~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 Set rectangle from coordinates and dimensions.
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 Set rectangle from two points.
PIRect<Type> & set(const PIPoint<Type> & top_left, const PIPoint<Type> & bottom_right) {
bl = top_left;
tr = bottom_right;
return normalize();
}
//! \~english Check if point with given coordinates is inside the rectangle.
//! \~russian Возвращает true если точка с указанными координатами принадлежит прямоугольнику
bool pointIn(Type x, Type y) const { return (x <= bl.x && x >= tr.x && y <= bl.y && y >= tr.y); }
//! \~english Check if point is inside the rectangle.
//! \~russian Возвращает true если точка с указанными координатами принадлежит прямоугольнику
bool pointIn(const PIPoint<Type> & p) const { return pointIn(p.x, p.y); }
//! \~english Check if rectangle is empty.
bool isEmpty() const { return (width() == 0 && height() == 0); }
//! \~english Translate rectangle by x and y.
PIRect<Type> & translate(Type x, Type y) {
bl.translate(x, y);
tr.translate(x, y);
return *this;
}
//! \~english Translate rectangle by point.
PIRect<Type> & translate(const PIPoint<Type> & p) {
bl.translate(p);
tr.translate(p);
return *this;
}
//! \~english Create a copy of rectangle and translate it by x and y.
PIRect<Type> translated(Type x, Type y) const {
PIRect<Type> r(*this);
r.translate(x, y);
return r;
}
//! \~english Create a copy of rectangle and translate it by point.
PIRect<Type> translated(const PIPoint<Type> & p) const {
PIRect<Type> r(*this);
r.translate(p);
return r;
}
//! \~english Translate rectangle by x and y. Alias for \a translate().
PIRect<Type> & move(Type x, Type y) { return translate(x, y); }
//! \~english Translate rectangle by point. Alias for \a translate().
PIRect<Type> & move(const PIPoint<Type> & p) { return translate(p); }
//! \~english Create a copy of rectangle and translate it by x and y. Alias for \a translated().
PIRect<Type> moved(Type x, Type y) const {
PIRect<Type> r(*this);
r.translate(x, y);
return r;
}
//! \~english Create a copy of rectangle and translate it by point. Alias for \a translated().
PIRect<Type> moved(const PIPoint<Type> & p) const {
PIRect<Type> r(*this);
r.translate(p);
return r;
}
//! \~english Scale rectangle by x and y factors.
PIRect<Type> & scale(Type x, Type y) {
setWidth(width() * x);
setHeight(height() * y);
return normalize();
}
//! \~english Scale rectangle uniformly.
PIRect<Type> & scale(Type s) { return scale(s, s); }
//! \~english Scale rectangle by point factors.
PIRect<Type> & scale(const PIPoint<Type> & p) { return scale(p.x, p.y); }
//! \~english Create a copy of rectangle and scale it by x and y factors.
PIRect<Type> scaled(Type x, Type y) const {
PIRect<Type> r(*this);
r.scale(x, y);
return r;
}
//! \~english Create a copy of rectangle and scale it uniformly.
PIRect<Type> scaled(Type s) const {
PIRect<Type> r(*this);
r.scale(s);
return r;
}
//! \~english Create a copy of rectangle and scale it by point factors.
PIRect<Type> scaled(const PIPoint<Type> & p) const {
PIRect<Type> r(*this);
r.scale(p);
return r;
}
//! \~english Normalize rectangle so that left <= right and bottom <= top.
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 Create normalized copy of rectangle.
PIRect<Type> normalized() const {
PIRect<Type> r(*this);
r.normalize();
return r;
}
//! \~english Unite rectangle with another rectangle.
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 Create united copy of rectangle with another rectangle.
PIRect<Type> united(const PIRect<Type> & rect) const {
PIRect<Type> r(*this);
r.unite(rect);
return r;
}
//! \~english Intersect rectangle with another rectangle.
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 Create intersected copy of rectangle with another rectangle.
PIRect<Type> intersected(const PIRect<Type> & rect) const {
PIRect<Type> r(*this);
r.intersect(rect);
return r;
}
//! \~english Get top coordinate.
Type top() const { return tr.y; }
//! \~english Get left coordinate.
Type left() const { return bl.x; }
//! \~english Get right coordinate.
Type right() const { return tr.x; }
//! \~english Get bottom coordinate.
Type bottom() const { return bl.y; }
//! \~english Get rectangle width.
Type width() const { return tr.x - bl.x; }
//! \~english Get rectangle height.
Type height() const { return tr.y - bl.y; }
//! \~english Get top-left corner point.
PIPoint<Type> topLeft() const { return PIPoint<Type>(bl.x, tr.y); }
//! \~english Get top-right corner point.
PIPoint<Type> topRigth() const { return tr; }
//! \~english Get bottom-left corner point.
PIPoint<Type> bottomLeft() const { return bl; }
//! \~english Get bottom-right corner point.
PIPoint<Type> bottomRight() const { return PIPoint<Type>(tr.x, bl.y); }
//! \~english Get center point of rectangle.
PIPoint<Type> center() const { return bl.moved(width() / 2, height() / 2); }
//! \~english Set top coordinate.
void setTop(Type v) {
tr.y = v;
normalize();
}
//! \~english Set left coordinate.
void setLeft(Type v) {
bl.x = v;
normalize();
}
//! \~english Set right coordinate.
void setRigth(Type v) {
tr.x = v;
normalize();
}
//! \~english Set bottom coordinate.
void setBottom(Type v) {
bl.y = v;
normalize();
}
//! \~english Set rectangle width.
void setWidth(Type v) { setTop(bl.x + v); }
//! \~english Set rectangle height.
void setHeight(Type v) { setRigth(bl.y + v); }
//! \~english Set top-left corner point.
void setTopLeft(const PIPoint<Type> & p) {
setLeft(p.x);
setTop(p.y);
}
//! \~english Set bottom-right corner point.
void setBottomRight(const PIPoint<Type> & p) {
setRigth(p.x);
setBottom(p.y);
}
//! \~english Set bottom-left corner point.
void setBottomLeft(const PIPoint<Type> & p) {
bl = p;
normalize();
}
//! \~english Set top-right corner point.
void setTopRigth(const PIPoint<Type> & p) {
tr = p;
normalize();
}
//! \~english Set center point.
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 Set rectangle size.
void setSize(Type w, Type h) {
tr = PIPoint<Type>(bl.x + w, bl.y + h);
normalize();
}
//! \~english Translate rectangle by x on both coordinates.
void operator+=(Type x) { translate(x, x); }
//! \~english Translate rectangle by point.
void operator+=(const PIPoint<Type> & p) { translate(p); }
//! \~english Translate rectangle by negative x on both coordinates.
void operator-=(Type x) { translate(-x, -x); }
//! \~english Translate rectangle by negative point.
void operator-=(const PIPoint<Type> & p) { translate(-p); }
//! \~english Unite rectangle with another.
void operator|=(const PIRect<Type> & r) { unite(r); }
//! \~english Intersect rectangle with another.
void operator&=(const PIRect<Type> & r) { intersect(r); }
//! \~english Translate rectangle by point.
PIRect<Type> operator+(const PIPoint<Type> & p) { return translated(p); }
//! \~english Translate rectangle by negative point.
PIRect<Type> operator-(const PIPoint<Type> & p) { return translated(-p); }
//! \~english Unite rectangle with another.
PIRect<Type> operator|(const PIRect<Type> & r) { return united(r); }
//! \~english Intersect rectangle with another.
PIRect<Type> operator&(const PIRect<Type> & r) { return intersected(r); }
//! \~english Check equality of two rectangles.
bool operator==(const PIRect<Type> & r) const { return (bl == r.bl && tr == r.tr); }
//! \~english Check inequality of two rectangles.
bool operator!=(const PIRect<Type> & r) const { return (bl != r.bl || tr != r.tr); }
private:
PIPoint<Type> bl;
PIPoint<Type> tr;
};
//! \~english Stream output operator for PIRect.
//! \~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;
}
typedef PIRect<int> PIRecti;
typedef PIRect<uint> PIRectu;
typedef PIRect<float> PIRectf;
typedef PIRect<double> PIRectd;
#endif // PIRECT_H