197 lines
4.8 KiB
C++
197 lines
4.8 KiB
C++
/*
|
||
* © Copyright 2014 – Urheberrechtshinweis
|
||
* Alle Rechte vorbehalten / All Rights Reserved
|
||
*
|
||
* Programmcode ist urheberrechtlich geschuetzt.
|
||
* Das Urheberrecht liegt, soweit nicht ausdruecklich anders gekennzeichnet, bei Frank Ebner.
|
||
* Einige Aenderungen beigetragen von Toni Fetzer
|
||
* Keine Verwendung ohne explizite Genehmigung.
|
||
* (vgl. § 106 ff UrhG / § 97 UrhG)
|
||
*/
|
||
|
||
#ifndef GEO_BBOX2_H
|
||
#define GEO_BBOX2_H
|
||
|
||
#include "Point2.h"
|
||
#include "Line2.h"
|
||
#include <vector>
|
||
|
||
class BBox2 {
|
||
|
||
protected:
|
||
|
||
static constexpr float MAX = +99999999;
|
||
static constexpr float MIN = -99999999;
|
||
|
||
/** minimum */
|
||
Point2 p1;
|
||
|
||
/** maximum */
|
||
Point2 p2;
|
||
|
||
public:
|
||
|
||
/** empty ctor */
|
||
BBox2() : p1(MAX,MAX), p2(MIN,MIN) {;}
|
||
|
||
/** ctor */
|
||
BBox2(const Point2& p1, const Point2& p2) : p1(p1), p2(p2) {;}
|
||
|
||
/** ctor */
|
||
BBox2(const float x1, const float y1, const float x2, const float y2) : p1(x1,y1), p2(x2,y2) {;}
|
||
|
||
/** adjust the bounding-box by adding this point */
|
||
void add(const Point2& p) {
|
||
add(p.x, p.y);
|
||
}
|
||
|
||
/** adjust the bounding-box by adding this point */
|
||
void add(const float x, const float y) {
|
||
|
||
if (x > p2.x) {p2.x = x;}
|
||
if (y > p2.y) {p2.y = y;}
|
||
|
||
if (x < p1.x) {p1.x = x;}
|
||
if (y < p1.y) {p1.y = y;}
|
||
|
||
}
|
||
|
||
/** the area spanned by the bbox */
|
||
float getArea() const {return getSize().x * getSize().y;}
|
||
|
||
/** returns true if the bbox is not yet configured */
|
||
bool isInvalid() const {
|
||
return p1.x == MAX || p1.y == MAX || p2.x == MIN || p2.y == MIN;
|
||
}
|
||
|
||
/** get the bbox's minimum */
|
||
const Point2& getMin() const {return p1;}
|
||
|
||
/** get the bbox's maximum */
|
||
const Point2& getMax() const {return p2;}
|
||
|
||
/** get the bbox's size [max-min] */
|
||
const Point2 getSize() const {return p2-p1;}
|
||
|
||
/** get the bbox's center point */
|
||
Point2 getCenter() const { return (p1+p2) / 2; }
|
||
|
||
|
||
Point2 getCorner1() const {return Point2(p1.x, p1.y);}
|
||
Point2 getCorner2() const {return Point2(p2.x, p1.y);}
|
||
Point2 getCorner3() const {return Point2(p1.x, p2.y);}
|
||
Point2 getCorner4() const {return Point2(p2.x, p2.y);}
|
||
|
||
|
||
/** equal? */
|
||
bool operator == (const BBox2& o) const {
|
||
return (p1.x == o.p1.x) &&
|
||
(p1.y == o.p1.y) &&
|
||
(p2.x == o.p2.x) &&
|
||
(p2.y == o.p2.y);
|
||
}
|
||
|
||
bool intersects(const BBox2& o) const {
|
||
// TODO is this correct?
|
||
if (o.p2.x < p1.x) {return false;}
|
||
if (o.p1.x > p2.x) {return false;}
|
||
if (o.p2.y < p1.y) {return false;}
|
||
if (o.p1.y > p2.y) {return false;}
|
||
return true;
|
||
// return (p1.x <= o.p2.x) &&
|
||
// (p1.y <= o.p2.y) &&
|
||
// (p2.x >= o.p1.x) &&
|
||
// (p2.y >= o.p1.y);
|
||
}
|
||
|
||
BBox2 combine(const BBox2& o) {
|
||
|
||
// TODO is this correct?
|
||
const float x1 = std::min(p1.x, o.p1.x);
|
||
const float x2 = std::max(p2.x, o.p2.x);
|
||
|
||
const float y1 = std::min(p1.y, o.p1.y);
|
||
const float y2 = std::max(p2.y, o.p2.y);
|
||
|
||
return BBox2(x1,y1, x2,y2);
|
||
|
||
}
|
||
|
||
BBox2 intersection(const BBox2& o) const {
|
||
// TODO is this correct?
|
||
const float x1 = std::max(p1.x, o.p1.x);
|
||
const float x2 = std::min(p2.x, o.p2.x);
|
||
|
||
const float y1 = std::max(p1.y, o.p1.y);
|
||
const float y2 = std::min(p2.y, o.p2.y);
|
||
|
||
return BBox2(x1,y1, x2,y2);
|
||
|
||
}
|
||
|
||
/** does the BBox intersect with the given line? */
|
||
bool intersects (const Line2& l) const {
|
||
const Line2 l1(p1.x, p1.y, p2.x, p1.y); // upper
|
||
const Line2 l2(p1.x, p2.y, p2.x, p2.y); // lower
|
||
const Line2 l3(p1.x, p1.y, p1.x, p2.y); // left
|
||
const Line2 l4(p2.x, p1.y, p2.x, p2.y); // right
|
||
return l.getSegmentIntersection(l1) ||
|
||
l.getSegmentIntersection(l2) ||
|
||
l.getSegmentIntersection(l3) ||
|
||
l.getSegmentIntersection(l4);
|
||
}
|
||
|
||
std::vector<Line2> lines() const {
|
||
return std::vector<Line2>(
|
||
{
|
||
Line2(p1.x, p1.y, p2.x, p1.y),
|
||
Line2(p1.x, p2.y, p2.x, p2.y),
|
||
Line2(p1.x, p1.y, p1.x, p2.y),
|
||
Line2(p2.x, p1.y, p2.x, p2.y)
|
||
}
|
||
);
|
||
}
|
||
|
||
bool contains(const Point2& p) const {
|
||
return contains(p.x, p.y);
|
||
}
|
||
|
||
bool contains(const float x, const float y) const {
|
||
if (x < p1.x) {return false;}
|
||
if (x > p2.x) {return false;}
|
||
if (y < p1.y) {return false;}
|
||
if (y > p2.y) {return false;}
|
||
return true;
|
||
}
|
||
|
||
/** grow the bbox by the amount given for each dimension */
|
||
void grow(const Point2& p) {
|
||
p1 -= p; // decrease minimum
|
||
p2 += p; // increase maximum
|
||
}
|
||
|
||
/** grow the bbox by the amount given for each dimension */
|
||
void grow(const float val) {
|
||
p1 -= Point2(val, val); // decrease minimum
|
||
p2 += Point2(val, val); // increase maximum
|
||
}
|
||
|
||
/** grow the bbox by the amount given for each dimension */
|
||
void growRel(const float val) {
|
||
const Point2 center = (p1+p2)/2;
|
||
p1 += (p1-center)*val; // decrease minimum
|
||
p2 += (p2-center)*val; // increase maximum
|
||
}
|
||
|
||
|
||
/** combine two bboxes */
|
||
static BBox2 join(const BBox2& bb1, const BBox2& bb2) {
|
||
const Point2 min( std::min(bb1.p1.x, bb2.p1.x), std::min(bb1.p1.y, bb2.p1.y) );
|
||
const Point2 max( std::max(bb1.p2.x, bb2.p2.x), std::max(bb1.p2.y, bb2.p2.y) );
|
||
return BBox2(min, max);
|
||
}
|
||
|
||
};
|
||
|
||
#endif // GEO_BBOX2_H
|