#include "ofRectangle.h"
#include "ofMath.h"
#include "ofLog.h"
#include "ofVectorMath.h"
using namespace std;
ofRectangle::ofRectangle() : x(position.x), y(position.y) {
set(0,0,0,0);
}
ofRectangle::~ofRectangle(){}
ofRectangle::ofRectangle(float px, float py, float w, float h) : x(position.x), y(position.y) {
set(px,py,w,h);
}
ofRectangle::ofRectangle(const glm::vec3& p, float w, float h) : x(position.x), y(position.y) {
set(p,w,h);
}
ofRectangle::ofRectangle(const glm::vec2& p, float w, float h) : x(position.x), y(position.y) {
set(p,w,h);
}
ofRectangle::ofRectangle(const ofRectangle& rect) : x(position.x), y(position.y) {
set(rect);
}
ofRectangle::ofRectangle(const glm::vec3& p0, const glm::vec3& p1) : x(position.x), y(position.y) {
set(p0,p1);
}
ofRectangle::ofRectangle(const glm::vec2& p0, const glm::vec2& p1) : x(position.x), y(position.y) {
set(p0,p1);
}
void ofRectangle::set(float px, float py, float w, float h) {
x = px;
y = py;
width = w;
height = h;
}
void ofRectangle::set(const glm::vec3& p, float w, float h) {
set(glm::vec2(p), w, h);
}
void ofRectangle::set(const glm::vec2& p, float w, float h) {
set(p.x, p.y, w, h);
}
void ofRectangle::set(const ofRectangle& rect){
set(rect.x, rect.y, rect.width, rect.height);
}
void ofRectangle::set(const glm::vec3& p0, const glm::vec3& p1) {
set(glm::vec2(p0), glm::vec2(p1));
}
void ofRectangle::set(const glm::vec2& p0, const glm::vec2& p1) {
float x0,y0,x1,y1;
x0 = std::min(p0.x, p1.x);
x1 = std::max(p0.x, p1.x);
y0 = std::min(p0.y, p1.y);
y1 = std::max(p0.y, p1.y);
float w = x1 - x0;
float h = y1 - y0;
set(x0,y0,w,h);
}
void ofRectangle::setX(float px) {
x = px;
}
void ofRectangle::setY(float py) {
y = py;
}
void ofRectangle::setWidth(float w) {
width = w;
}
void ofRectangle::setHeight(float h) {
height = h;
}
void ofRectangle::setPosition(float px, float py) {
position.x = px;
position.y = py;
}
void ofRectangle::setPosition(const glm::vec3& p) {
position = p;
}
void ofRectangle::setSize(float w, float h) {
width = w;
height = h;
}
void ofRectangle::setFromCenter(float px, float py, float w, float h) {
set(px - w*0.5f, py - h*0.5f, w, h);
}
void ofRectangle::setFromCenter(const glm::vec3& p, float w, float h) {
setFromCenter(glm::vec2(p),w,h);
}
void ofRectangle::setFromCenter(const glm::vec2& p, float w, float h) {
setFromCenter(p.x, p.y, w, h);
}
void ofRectangle::translate(float dx, float dy) {
translateX(dx);
translateY(dy);
}
void ofRectangle::translate(const glm::vec3& dp) {
translate(glm::vec2(dp));
}
void ofRectangle::translate(const glm::vec2& dp) {
translateX(dp.x);
translateY(dp.y);
}
void ofRectangle::translateX(float dx) {
x += dx;
}
void ofRectangle::translateY(float dy) {
y += dy;
}
void ofRectangle::scale(float s) {
scaleWidth(s);
scaleHeight(s);
}
void ofRectangle::scale(float sX, float sY) {
scaleWidth(sX);
scaleHeight(sY);
}
void ofRectangle::scale(const glm::vec3& s) {
scale(glm::vec2(s));
}
void ofRectangle::scale(const glm::vec2& s) {
scaleWidth(s.x);
scaleHeight(s.y);
}
void ofRectangle::scaleWidth(float sX) {
width *= sX;
}
void ofRectangle::scaleHeight(float sY) {
height *= sY;
}
void ofRectangle::scaleFromCenter(float s) {
scaleFromCenter(s,s);
}
void ofRectangle::scaleFromCenter(float sX, float sY) {
scaleFromCenter({sX,sY,0.f});
}
void ofRectangle::scaleFromCenter(const glm::vec3& s) {
scaleFromCenter(glm::vec2(s));
}
void ofRectangle::scaleFromCenter(const glm::vec2& s) {
if(ofIsFloatEqual(s.x, 1.0f) && ofIsFloatEqual(s.y, 1.0f)) return;
float newWidth = width * s.x;
float newHeight = height * s.y;
auto center = getCenter();
x = center.x - newWidth / 2.0f;
y = center.y - newHeight / 2.0f;
width = newWidth;
height = newHeight;
}
void ofRectangle::scaleTo(const ofRectangle& targetRect,
ofScaleMode scaleMode) {
if(scaleMode == OF_SCALEMODE_FIT) {
scaleTo(targetRect,
OF_ASPECT_RATIO_KEEP,
OF_ALIGN_HORZ_CENTER,
OF_ALIGN_VERT_CENTER);
} else if(scaleMode == OF_SCALEMODE_FILL) {
scaleTo(targetRect,
OF_ASPECT_RATIO_KEEP_BY_EXPANDING,
OF_ALIGN_HORZ_CENTER,
OF_ALIGN_VERT_CENTER);
} else if(scaleMode == OF_SCALEMODE_CENTER) {
alignTo(targetRect,
OF_ALIGN_HORZ_CENTER,
OF_ALIGN_VERT_CENTER);
} else if(scaleMode == OF_SCALEMODE_STRETCH_TO_FILL) {
scaleTo(targetRect,
OF_ASPECT_RATIO_IGNORE,
OF_ALIGN_HORZ_CENTER,
OF_ALIGN_VERT_CENTER);
} else {
scaleTo(targetRect,
OF_ASPECT_RATIO_KEEP);
}
}
void ofRectangle::scaleTo(const ofRectangle& targetRect,
ofAspectRatioMode subjectAspectRatioMode,
ofAlignHorz sharedHorzAnchor,
ofAlignVert sharedVertAnchor) {
scaleTo(targetRect,
subjectAspectRatioMode,
sharedHorzAnchor,
sharedVertAnchor,
sharedHorzAnchor,
sharedVertAnchor);
}
void ofRectangle::scaleTo(const ofRectangle& targetRect,
ofAspectRatioMode aspectRatioMode,
ofAlignHorz modelHorzAnchor,
ofAlignVert modelVertAnchor,
ofAlignHorz thisHorzAnchor,
ofAlignVert thisVertAnchor) {
float tw = targetRect.getWidth();
float th = targetRect.getHeight();
float sw = getWidth();
float sh = getHeight();
if(aspectRatioMode == OF_ASPECT_RATIO_KEEP_BY_EXPANDING ||
aspectRatioMode == OF_ASPECT_RATIO_KEEP) {
if(fabs(sw) >= FLT_EPSILON || fabs(sh) >= FLT_EPSILON) {
float wRatio = fabs(tw) / fabs(sw);
float hRatio = fabs(th) / fabs(sh);
if(aspectRatioMode == OF_ASPECT_RATIO_KEEP_BY_EXPANDING) {
scale(std::max(wRatio,hRatio));
} else if(aspectRatioMode == OF_ASPECT_RATIO_KEEP) {
scale(std::min(wRatio,hRatio));
}
} else {
ofLogWarning("ofRectangle") << "scaleTo(): no scaling applied to avoid divide by zero, rectangle has 0 width and/or height: " << sw << "x" << sh;
}
} else if(aspectRatioMode == OF_ASPECT_RATIO_IGNORE) {
width = tw;
height = th;
} else {
ofLogWarning("ofRectangle") << "scaleTo(): unknown ofAspectRatioMode = " << aspectRatioMode << ", using OF_ASPECT_RATIO_IGNORE";
width = tw;
height = th;
}
alignTo(targetRect,
modelHorzAnchor,
modelVertAnchor,
thisHorzAnchor,
thisVertAnchor);
}
void ofRectangle::alignToHorz(const float& targetX,
ofAlignHorz thisHorzAnchor) {
if(thisHorzAnchor != OF_ALIGN_HORZ_IGNORE) {
translateX(targetX - getHorzAnchor(thisHorzAnchor));
} else {
ofLogVerbose("ofRectangle") << "alignToHorz(): thisHorzAnchor == OF_ALIGN_HORZ_IGNORE, no alignment applied";
}
}
void ofRectangle::alignToHorz(const ofRectangle& targetRect,
ofAlignHorz sharedAnchor) {
alignToHorz(targetRect, sharedAnchor, sharedAnchor);
}
void ofRectangle::alignToHorz(const ofRectangle& targetRect,
ofAlignHorz targetHorzAnchor,
ofAlignHorz thisHorzAnchor) {
if(targetHorzAnchor != OF_ALIGN_HORZ_IGNORE &&
thisHorzAnchor != OF_ALIGN_HORZ_IGNORE) {
alignToHorz(targetRect.getHorzAnchor(targetHorzAnchor),thisHorzAnchor);
} else {
if(targetHorzAnchor == OF_ALIGN_HORZ_IGNORE) {
ofLogVerbose("ofRectangle") << "alignToHorz(): targetHorzAnchor == OF_ALIGN_HORZ_IGNORE, no alignment applied";
} else {
ofLogVerbose("ofRectangle") << "alignToHorz(): thisHorzAnchor == OF_ALIGN_HORZ_IGNORE, no alignment applied";
}
}
}
void ofRectangle::alignToVert(const float& targetY,
ofAlignVert thisVertAnchor) {
if(thisVertAnchor != OF_ALIGN_VERT_IGNORE) {
translateY(targetY - getVertAnchor(thisVertAnchor));
} else {
ofLogVerbose("ofRectangle") << "alignToVert(): thisVertAnchor == OF_ALIGN_VERT_IGNORE, no alignment applied";
}
}
void ofRectangle::alignToVert(const ofRectangle& targetRect,
ofAlignVert sharedAnchor) {
alignToVert(targetRect,sharedAnchor,sharedAnchor);
}
void ofRectangle::alignToVert(const ofRectangle& targetRect,
ofAlignVert targetVertAnchor,
ofAlignVert thisVertAnchor) {
if(targetVertAnchor != OF_ALIGN_VERT_IGNORE &&
thisVertAnchor != OF_ALIGN_VERT_IGNORE) {
alignToVert(targetRect.getVertAnchor(targetVertAnchor),thisVertAnchor);
} else {
if(targetVertAnchor == OF_ALIGN_VERT_IGNORE) {
ofLogVerbose("ofRectangle") << "alignToVert(): targetVertAnchor == OF_ALIGN_VERT_IGNORE, no alignment applied";
} else {
ofLogVerbose("ofRectangle") << "alignToVert(): thisVertAnchor == OF_ALIGN_VERT_IGNORE, no alignment applied";
}
}
}
void ofRectangle::alignTo(const glm::vec3& targetPoint,
ofAlignHorz thisHorzAnchor,
ofAlignVert thisVertAnchor) {
alignTo(glm::vec2(targetPoint), thisHorzAnchor, thisVertAnchor);
}
void ofRectangle::alignTo(const glm::vec2& targetPoint,
ofAlignHorz thisHorzAnchor,
ofAlignVert thisVertAnchor) {
alignToHorz(targetPoint.x, thisHorzAnchor);
alignToVert(targetPoint.y, thisVertAnchor);
}
void ofRectangle::alignTo(const ofRectangle& targetRect,
ofAlignHorz sharedHorzAnchor,
ofAlignVert sharedVertAnchor) {
alignTo(targetRect,
sharedHorzAnchor,
sharedVertAnchor,
sharedHorzAnchor,
sharedVertAnchor);
}
void ofRectangle::alignTo(const ofRectangle& targetRect,
ofAlignHorz targetHorzAnchor,
ofAlignVert targetVertAnchor,
ofAlignHorz thisHorzAnchor,
ofAlignVert thisVertAnchor) {
alignToHorz(targetRect,targetHorzAnchor,thisHorzAnchor);
alignToVert(targetRect,targetVertAnchor,thisVertAnchor);
}
bool ofRectangle::inside(float px, float py) const {
return inside({px,py});
}
bool ofRectangle::inside(const glm::vec3& p) const {
return inside(glm::vec2(p));
}
bool ofRectangle::inside(const glm::vec2& p) const {
return p.x > getMinX() && p.y > getMinY() &&
p.x < getMaxX() && p.y < getMaxY();
}
bool ofRectangle::inside(const ofRectangle& rect) const {
return inside(rect.getMinX(),rect.getMinY()) &&
inside(rect.getMaxX(),rect.getMaxY());
}
bool ofRectangle::inside(const glm::vec3& p0, const glm::vec3& p1) const {
return inside(glm::vec2(p0), glm::vec2(p1));
}
bool ofRectangle::inside(const glm::vec2& p0, const glm::vec2& p1) const {
return inside(p0) && inside(p1);
}
bool ofRectangle::intersects(const ofRectangle& rect) const {
return (getMinX() < rect.getMaxX() && getMaxX() > rect.getMinX() &&
getMinY() < rect.getMaxY() && getMaxY() > rect.getMinY());
}
bool ofRectangle::intersects(const glm::vec3& p0, const glm::vec3& p1) const {
return intersects(glm::vec2(p0), glm::vec2(p1));
}
bool ofRectangle::intersects(const glm::vec2& p0, const glm::vec2& p1) const {
glm::vec2 p;
glm::vec2 topLeft(getTopLeft());
glm::vec2 topRight(getTopRight());
glm::vec2 bottomRight(getBottomRight());
glm::vec2 bottomLeft(getBottomLeft());
return inside(p0) ||
inside(p1) ||
ofLineSegmentIntersection(p0, p1, topLeft, topRight, p) ||
ofLineSegmentIntersection(p0, p1, topRight, bottomRight, p) ||
ofLineSegmentIntersection(p0, p1, bottomRight, bottomLeft, p) ||
ofLineSegmentIntersection(p0, p1, bottomLeft, topLeft, p);
}
void ofRectangle::growToInclude(float px, float py) {
growToInclude({px,py});
}
void ofRectangle::growToInclude(const glm::vec3& p) {
growToInclude(glm::vec2(p));
}
void ofRectangle::growToInclude(const glm::vec2& p) {
float x0 = std::min(getMinX(),p.x);
float x1 = std::max(getMaxX(),p.x);
float y0 = std::min(getMinY(),p.y);
float y1 = std::max(getMaxY(),p.y);
float w = x1 - x0;
float h = y1 - y0;
set(x0,y0,w,h);
}
void ofRectangle::growToInclude(const ofRectangle& rect) {
float x0 = std::min(getMinX(),rect.getMinX());
float x1 = std::max(getMaxX(),rect.getMaxX());
float y0 = std::min(getMinY(),rect.getMinY());
float y1 = std::max(getMaxY(),rect.getMaxY());
float w = x1 - x0;
float h = y1 - y0;
set(x0,y0,w,h);
}
void ofRectangle::growToInclude(const glm::vec3& p0, const glm::vec3& p1) {
growToInclude(glm::vec2(p0), glm::vec2(p1));
}
void ofRectangle::growToInclude(const glm::vec2& p0, const glm::vec2& p1) {
growToInclude(p0);
growToInclude(p1);
}
ofRectangle ofRectangle::getIntersection(const ofRectangle& rect) const {
float x0 = std::max(getMinX(),rect.getMinX());
float x1 = std::min(getMaxX(),rect.getMaxX());
float w = x1 - x0;
if(w < 0.0f) return ofRectangle(0,0,0,0);
float y0 = std::max(getMinY(),rect.getMinY());
float y1 = std::min(getMaxY(),rect.getMaxY());
float h = y1 - y0;
if(h < 0.0f) return ofRectangle(0,0,0,0);
return ofRectangle(x0,y0,w,h);
}
ofRectangle ofRectangle::getUnion(const ofRectangle& rect) const {
ofRectangle united = *this;
united.growToInclude(rect);
return united;
}
void ofRectangle::standardize() {
if(width < 0.0f) {
x += width;
width = -1.0f * width;
}
if(height < 0.0f) {
y += height;
height = -1.0f * height;
}
}
ofRectangle ofRectangle::getStandardized() const {
if(isStandardized()) {
return *this;
} else {
ofRectangle canRect(*this);
canRect.standardize();
return canRect;
}
}
bool ofRectangle::isStandardized() const {
return width >= 0.0f && height >= 0.0f;
}
float ofRectangle::getArea() const {
return fabs(width) * fabs(height);
}
float ofRectangle::getPerimeter() const {
return 2.0f * fabs(width) + 2.0f * fabs(height);
}
float ofRectangle::getAspectRatio() const {
return fabs(width) / fabs(height);
}
bool ofRectangle::isEmpty() const {
return ofIsFloatEqual(width, 0.0f) && ofIsFloatEqual(height, 0.0f);
}
glm::vec3 ofRectangle::getMin() const {
return {getMinX(),getMinY(),0.f};
}
glm::vec3 ofRectangle::getMax() const {
return {getMaxX(),getMaxY(),0.f};
}
float ofRectangle::getMinX() const {
return std::min(x, x + width);
}
float ofRectangle::getMaxX() const {
return std::max(x, x + width);
}
float ofRectangle::getMinY() const{
return std::min(y, y + height);
}
float ofRectangle::getMaxY() const {
return std::max(y, y + height);
}
float ofRectangle::getLeft() const {
return getMinX();
}
float ofRectangle::getRight() const {
return getMaxX();
}
float ofRectangle::getTop() const {
return getMinY();
}
float ofRectangle::getBottom() const {
return getMaxY();
}
glm::vec3 ofRectangle::getTopLeft() const {
return getMin();
}
glm::vec3 ofRectangle::getTopRight() const {
return {getRight(), getTop(), 0.f};
}
glm::vec3 ofRectangle::getBottomLeft() const {
return glm::vec3(getLeft(), getBottom(), 0.f);
}
glm::vec3 ofRectangle::getBottomRight() const {
return getMax();
}
float ofRectangle::getHorzAnchor(ofAlignHorz anchor) const {
switch (anchor) {
case OF_ALIGN_HORZ_IGNORE:
ofLogError("ofRectangle") << "getHorzAnchor(): unable to get anchor for OF_ALIGN_HORZ_IGNORE, returning 0";
return 0.0f;
case OF_ALIGN_HORZ_LEFT:
return getLeft();
case OF_ALIGN_HORZ_RIGHT:
return getRight();
case OF_ALIGN_HORZ_CENTER:
return getCenter().x;
default:
ofLogError("ofRectangle") << "getHorzAnchor(): unknown ofAlignHorz = " << anchor << ", returning 0.0";
return 0.0f;
}
}
float ofRectangle::getVertAnchor(ofAlignVert anchor) const {
switch (anchor) {
case OF_ALIGN_VERT_IGNORE:
ofLogError("ofRectangle") << "getVertAnchor(): unable to get anchor for OF_ALIGN_VERT_IGNORE, returning 0.0";
return 0.0f;
case OF_ALIGN_VERT_TOP:
return getTop();
case OF_ALIGN_VERT_BOTTOM:
return getBottom();
case OF_ALIGN_VERT_CENTER:
return getCenter().y;
default:
ofLogError("ofRectangle") << "getVertAnchor(): unknown ofAlignVert = " << anchor << ", returning 0.0";
return 0.0f;
}
}
bool ofRectangle::operator != (const ofRectangle& rect) const {
return (x != rect.x) || (y != rect.y) || (width != rect.width) || (height != rect.height);
}
const glm::vec3& ofRectangle::getPosition() const {
return position;
}
glm::vec3& ofRectangle::getPositionRef() {
return position;
}
glm::vec3 ofRectangle::getCenter() const {
return {x + width * 0.5f, y + height * 0.5f, 0.f};
}
float ofRectangle::getX() const {
return x;
}
float ofRectangle::getY() const {
return y;
}
float ofRectangle::getWidth() const {
return width;
}
float ofRectangle::getHeight() const {
return height;
}
glm::vec2 ofRectangle::map(const glm::vec2 & coeff) const {
return glm::vec2(
ofMap(coeff.x, 0.0f, 1.0f, getMinX(), getMaxX(), false),
ofMap(coeff.y, 0.0f, 1.0f, getMinY(), getMaxY(), false)
);
}
ofRectangle ofRectangle::map(const ofRectangle & coeff) const {
return ofRectangle(
map(glm::vec2(coeff.getMinX(), coeff.getMinY())),
map(glm::vec2(coeff.getMaxX(), coeff.getMaxY()))
);
}
glm::vec2 ofRectangle::mapClamp(const glm::vec2 & coeff) const {
return glm::vec2(
ofMap(coeff.x, 0.0f, 1.0f, getMinX(), getMaxX(), true),
ofMap(coeff.y, 0.0f, 1.0f, getMinY(), getMaxY(), true)
);
}
ofRectangle ofRectangle::mapClamp(const ofRectangle & coeff) const {
return ofRectangle(
mapClamp(glm::vec2(coeff.getMinX(), coeff.getMinY())),
mapClamp(glm::vec2(coeff.getMaxX(), coeff.getMaxY()))
);
}
ofRectangle& ofRectangle::operator = (const ofRectangle& rect) {
set(rect);
return *this;
}
ofRectangle ofRectangle::operator + (const glm::vec3 & point){
return operator+(glm::vec2(point));
}
ofRectangle ofRectangle::operator + (const glm::vec2 & point){
ofRectangle rect=*this;
rect.x += point.x;
rect.y += point.y;
return rect;
}
ofRectangle ofRectangle::operator - (const glm::vec3 & point){
return operator-(glm::vec2(point));
}
ofRectangle ofRectangle::operator - (const glm::vec2 & point){
ofRectangle rect=*this;
rect.x -= point.x;
rect.y -= point.y;
return rect;
}
bool ofRectangle::operator == (const ofRectangle& rect) const {
return ofIsFloatEqual(x, rect.x) && ofIsFloatEqual(y, rect.y) && ofIsFloatEqual(width, rect.width) && ofIsFloatEqual(height, rect.height);
}
bool ofRectangle::isZero() const{
return ofIsFloatEqual(x, 0.0f) && ofIsFloatEqual(y, 0.0f) && ofIsFloatEqual(width, 0.0f) && ofIsFloatEqual(height, 0.0f);
}
ostream& operator<<(ostream& os, const ofRectangle& rect){
os << rect.position << ", " << rect.width << ", " << rect.height;
return os;
}
istream& operator>>(istream& is, ofRectangle& rect){
is >> rect.position;
is.ignore(2);
is >> rect.width;
is.ignore(2);
is >> rect.height;
return is;
}
Comments