2024-03-19 17:45:12 +08:00

224 lines
8.5 KiB
C++

/**************************************************************************************/
/* */
/* Visualization Library */
/* http://visualizationlibrary.org */
/* */
/* Copyright (c) 2005-2020, Michele Bosi */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without modification, */
/* are permitted provided that the following conditions are met: */
/* */
/* - Redistributions of source code must retain the above copyright notice, this */
/* list of conditions and the following disclaimer. */
/* */
/* - Redistributions in binary form must reproduce the above copyright notice, this */
/* list of conditions and the following disclaimer in the documentation and/or */
/* other materials provided with the distribution. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
/* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* */
/**************************************************************************************/
#ifndef Rect_INCLUDE_ONCE
#define Rect_INCLUDE_ONCE
#include <vlCore/Vector2.hpp>
namespace vl
{
/**
* Implements the common functions of RectI and RectF.
*/
template<typename T>
class Rect
{
public:
Rect(const Rect& other)
{
mX = other.x();
mY = other.y();
mWidth = other.width();
mHeight = other.height();
}
Rect()
{
// null Rect
mX = 0;
mY = 0;
mWidth = -1;
mHeight = -1;
}
Rect(T x, T y, T width, T height)
{
mX = x;
mY = y;
mWidth = width;
mHeight = height;
}
T x() const { return mX; }
T y() const { return mY; }
T width() const { return mWidth; }
T height() const { return mHeight; }
T bottom() const { return mY; }
T left() const { return mX; }
T top() const { return mY+mHeight-1; }
T right() const { return mX+mWidth-1; }
void setX(T x) { mX = x; }
void setY(T y) { mY = y; }
void setWidth(T w) { mWidth = w; }
void setHeight(T h) { mHeight = h; }
bool isNull() const { return width() < 0 || height() < 0; }
bool isPoint() const { return width() == 0 && height() == 0; }
Rect intersected(const Rect& other) const
{
if (isNull() || other.isNull())
return other;
T Ax1 = left();
T Ax2 = right();
T Ay1 = bottom();
T Ay2 = top();
T Bx1 = other.left();
T Bx2 = other.right();
T By1 = other.bottom();
T By2 = other.top();
if (Ax1 < Bx1) Ax1 = Bx1;
if (Ay1 < By1) Ay1 = By1;
if (Ax2 > Bx2) Ax2 = Bx2;
if (Ay2 > By2) Ay2 = By2;
return Rect(Ax1,Ay1,Ax2-Ax1+1,Ay2-Ay1+1);
}
Rect united(const Rect& other) const
{
if (other.isNull())
return *this;
if (isNull())
return other;
T Ax1 = left();
T Ax2 = right();
T Ay1 = bottom();
T Ay2 = top();
T Bx1 = other.left();
T Bx2 = other.right();
T By1 = other.bottom();
T By2 = other.top();
if (Ax1 > Bx1) Ax1 = Bx1;
if (Ay1 > By1) Ay1 = By1;
if (Ax2 < Bx2) Ax2 = Bx2;
if (Ay2 < By2) Ay2 = By2;
return Rect(Ax1,Ay1,Ax2-Ax1+1,Ay2-Ay1+1);
}
/**
* Defines a sort of lexicographic sorting that make possible the use of the Rect class with STL containers like std::set, std::map etc.
*/
bool operator<(const Rect& other) const
{
if (mX != other.mX)
return mX < other.mX;
else
if (mWidth != other.mWidth)
return mWidth < other.mWidth;
else
if (mHeight != other.mHeight)
return mHeight < other.mHeight;
else
if (mY != other.mY)
return mY < other.mY;
else
return false;
}
protected:
T mX;
T mY;
T mWidth;
T mHeight;
};
/**
* The RectI class represents a 2D rectangular area using \p int precision.
* This class is mainly used to manipulate rectangles in pixel coordinates (as opposed to real coordinates).
* The RectI and RectF differ in the following way:
* - RectF dimensions are implemented using \a float precision, while RectI uses \a int precision.
* - RectF::right() returns x()+width(), while RectI::right() returns x()+width()-1
* - RectF::top() return y()+height(), while RectI::top() return y()+height()-1
* \sa
* - RectF
*/
class RectI: public Rect<int>
{
public:
RectI() {}
RectI(int x, int y, int width, int height) { mX=x; mY=y; mWidth=width; mHeight=height; }
RectI(const Rect<int>& other) { *this = other; }
RectI(const RectI& other): Rect<int>(other) { *this = other; }
// operator Rect<int>() const { return Rect<int>(x(), y(), width(), height()); }
RectI& operator=(const Rect<int>& other) { mX=other.x(); mY=other.y(); mWidth=other.width(); mHeight=other.height(); return *this; }
RectI& operator=(const RectI& other) { mX=other.x(); mY=other.y(); mWidth=other.width(); mHeight=other.height(); return *this; }
int top() const { return mY+mHeight-1; }
int right() const { return mX+mWidth-1; }
ivec2 bottomLeft() const { return ivec2(bottom(),left()); }
ivec2 topRight() const { return ivec2(top(),right()); }
};
/**
* The RectF class represents a 2D rectangular area using \p float precision.
* This class is mainly used to manipulate rectangles in real coordinates (as opposed to pixel coordinates).
* The RectI and RectF differ in the following way:
* - RectF dimensions are implemented using \a float precision, while RectI uses \a int precision.
* - RectF::right() returns x()+width(), while RectI::right() returns x()+width()-1
* - RectF::top() return y()+height(), while RectI::top() return y()+height()-1
* \sa
* - RectI
*/
class RectF: public Rect<float>
{
public:
RectF() {}
RectF(float x, float y, float width, float height) { mX=x; mY=y; mWidth=width; mHeight=height; }
RectF(const RectF& other): Rect<float>(other) { *this = other; }
RectF(const Rect<float>& other) { *this = other; }
// operator Rect<float>() const { return Rect<float>(x(), y(), width(), height()); }
RectF& operator=(const Rect<float>& other) { mX=other.x(); mY=other.y(); mWidth=other.width(); mHeight=other.height(); return *this; }
RectF& operator=(const RectF& other) { mX=other.x(); mY=other.y(); mWidth=other.width(); mHeight=other.height(); return *this; }
float top() const { return mY+mHeight; }
float right() const { return mX+mWidth; }
fvec2 bottomLeft() const { return fvec2(bottom(),left()); }
fvec2 topRight() const { return fvec2(top(),right()); }
void addPoint(const fvec2& p)
{
fvec2 tr = topRight();
fvec2 bl = bottomLeft();
if (p.x() < bl.x())
bl.x() = p.x();
if (p.y() < bl.y())
bl.y() = p.y();
if (p.x() > tr.x())
tr.x() = p.x();
if (p.y() > tr.y())
tr.y() = p.y();
mX = bl.x();
mY = bl.y();
mWidth = tr.x() - bl.x();
mHeight = tr.y() - bl.y();
}
};
}
#endif