#ifndef _SGEOM_H #define _SGEOM_H #include "types.h" #include "utf8.h" #include #ifndef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif // ****************************** // *** SIZE (DIMENSION) CLASS *** // ****************************** template struct SSize { T width; T height; // Constructors SSize() : width(0), height(0) {} SSize(T _w, T _h) : width(_h), height(_w) {} SSize(const SSize &_other) { *this = _other; } // Destructor ~SSize() {} // Operators SSize &operator =(const SSize &_other) { // if (this != &_other) width = _other.width; height = _other.height; return *this; } inline SSize &operator += (const SSize &_s) { *this = *this + _s; return *this; } inline SSize &operator += (const T _value) { width += _value; height += _value; return *this; } inline SSize &operator -= (const SSize &_s) { *this = *this - _s; return *this; } inline SSize &operator -= (const T _value) { width -= _value; height -= _value; return *this; } SSize operator+(const SSize& _s) const { SSize temp(width + _s.width, height + _s.height); return temp; } SSize operator-(const SSize& _s) const { SSize temp(width - _s.width, height - _s.height); return temp; } SSize operator*(const T &_value) const { SSize temp(width * _value, height * _value); return temp; } // Compare operators bool operator==(const SSize &_other) const { return (width == _other.width && height == _other.height); } bool operator!=(const SSize &_other) const { return !(operator == (_other)); } T area() const { T a = width * height; if (a < 0) a = a * static_cast(-1.0); return a; } // Friends // Strictly: this does not need to be friend because struct's variables are public friend std::ostream &operator << (std::ostream &os, const SSize &_s) { os << "Size: width=" << _s.width << " height=" << _s.height; return os; } }; typedef SSize ISize; typedef SSize FSize; typedef SSize DSize; // ************************** // ******* POINT CLASS ****** // ************************** template struct SPoint { T x; T y; // Constructors SPoint() : x(0), y(0) {} SPoint(T _x, T _y) : x(_x), y(_y) {} // Copy constructor SPoint(const SPoint &_other) { *this = _other; } // Destructor ~SPoint() {} // Operarators SPoint &operator =(const SPoint &_other) { // if (this != &_other) x = _other.x; y = _other.y; return *this; } SPoint &operator =(const T &_value) { x = _value; y = _value; return *this; } inline SPoint &operator += (const SPoint &_p) { *this = *this + _p; return *this; } inline SPoint &operator += (const T _value) { x += _value; y += _value; return *this; } inline SPoint &operator -= (const SPoint &_p) { *this = *this - _p; return *this; } inline SPoint &operator -= (const T _value) { x -= _value; y -= _value; return *this; } SPoint operator+(const SPoint& _p) const { SPoint temp(x + _p.x, y + _p.y); return temp; } SPoint operator-(const SPoint& _p) const { SPoint temp(x - _p.x, y - _p.y); return temp; } SPoint operator*(const T &_value) const { SPoint temp(x * _value, y * _value); return temp; } // Negate: p2 = -p1; SPoint operator-( void ) const { T n = static_cast(-1); SPoint temp ((x*n), (y*n)); return temp; } // Compare operators bool operator!=(const SPoint &_p) const { return *this != _p; } bool operator==(const SPoint &_p) const { return (x == _p.x && y == _p.y); } // This is not very accurate math (has seen these in the Cosmoe toolkit.) bool operator < (const SPoint &_p) const { return ( y < _p.y || ( y == _p.y && x < _p.x)); } // Not implemented: // bool operator <= (const SPoint &_p) const bool operator > (const SPoint &_p) const { return ( y > _p.y || ( y == _p.y && x > _p.x)); } // Not implemented: // bool operator >= (const SPoint &_p) const // Friends // Strictly: these does not need to be friends because struct's (not class') variables are always public friend std::ostream &operator << (std::ostream &os, const SPoint &_p) { os << "Point: x=" << _p.x << " y=" << _p.y; return os; } friend SPoint operator - (const SPoint &_p, const T &_value) { SPointtemp(_p.x - _value, _p.y - _value); return temp; } // Utility functions inline bool isZero() const { T n = static_cast(0); return (x == n && y == n); } // Class functions are static functions // The [s]mallest [p]ossible [p]oint static SPoint spp(const SPoint &_p1, const SPoint &_p2) { SPoint temp; temp.x = MIN(_p1.x, _p2.x); temp.y = MIN(_p1.y, _p2.y); return temp; } // The [g]reatest [p]ossible [p]oint static SPoint gpp(const SPoint &_p1, const SPoint &_p2) { SPoint temp; temp.x = MAX(_p1.x, _p2.x); temp.y = MAX(_p1.y, _p2.y); return temp; } }; typedef SPoint IPoint; typedef SPoint FPoint; typedef SPoint DPoint; // ****************************** // ****** RECTANGLE CLASS ******* // ****************************** template struct SRect { T x; T y; T width; T height; SRect(): x(0), y(0), width(0), height(0) {} SRect(T _x, T _y, T _w, T _h): x(_x), y(_y), width(_w), height(_h) {} // Copy constructor SRect(const SRect &_other) { *this = _other; } SRect(const SPoint &_p, T _width, T _height) { *this = SRect(_p.x, _p.y, _width, _height); } SRect(const SPoint &_p, const SSize &_size) { *this = SRect(_p.x, _p.y, _size.width, _size.height); } SRect(const SSize &_size) { *this = SRect(0, 0, _size.width, _size.height); } // Destructor ~SRect() {} // Operators SRect &operator = (const SRect &_rect) { // if (this != &_other) x = _rect.x; y = _rect.y; width = _rect.width; height = _rect.height; return *this; } SRect(const SPoint &_p1, const SPoint &_p2) { x = _p1.x; y = _p1.y; width = _p2.x - _p1.x; height = _p2.y - _p1.y; // this->normalize(); } inline SRect &operator += (const SPoint &_point) { *this = *this + _point; return *this; } inline SRect &operator -= (const SPoint &_point) { *this = *this - _point; return *this; } // Note! Rect + Rect = Union SRect operator+(const SRect &_other) const { SRect temp = SRect::runion(*this, _other); return temp; } // Note! Rect - Rect = Intersection SRect operator-(const SRect &_other) const { SRect temp = SRect::intersection(*this, _other); return temp; } // Rect + Point SRect operator+(const SPoint &_other) const { SRect temp = SRect(x + _other.x, y + _other.y, width, height); return temp; } // Rect - Point SRect operator-(const SPoint &_other) const { SRect temp = SRect(x - _other.x, y - _other.y, width, height); return temp; } // Utility functions SRect &normalize() { if (width < 0) { x = x + width; width = -width; } if (height < 0) { y = y + height; height = -height; } return *this; } T x1() const { return x; } T y1() const { return y; } T x2() const { return x + width; } T y2() const { return y + height; } // First point SPoint p1() const { SPoint temp(x1(),y1()); return temp; } // Second point SPoint p2() const { SPoint temp(x2(),y2()); return temp; } inline T area() const { T a = width * height; if (a < static_cast(0)) a = a * static_cast(-1.0); return a; } inline void setPos(SPoint _p) { setPos(_p.x, _p.y); } inline void setPos(T _x, T _y) { x = _x; y = _y; } inline void moveTo(T _x, T _y) { setPos(_x, _y); } inline void translate(SPoint _p) { moveTo(_p.x, _p.y); } inline void translate(T _dx, T _dy) { x += _dx; y += _dy; } inline void resize(T _dw, T _dh) { width += _dw; height += _dh; } inline void grow(T _dw, T _dh) { resize(_dw, _dh); } // Contains (includes) and intersection tests bool contains(const SPoint&_p, bool _on_the_edge = true) const { return this->contains(_p.x, _p.y, _on_the_edge); } bool contains(T _x, T _y, bool _on_the_edge = true) const { SRect temp = *this; temp.normalize(); if (_on_the_edge) { return ((temp.x1() <= _x) && (_x <= temp.x2()) && (temp.y1() <= _y) && (_y <= temp.y2())); } else { return ((temp.x1() < _x) && (_x < temp.x2()) && (temp.y1() < _y) && (_y < temp.y2())); } } bool contains(const SRect &_other, bool _on_the_edge = true) const { return contains(_other.p1(), _on_the_edge) && contains(_other.p2(), _on_the_edge); } // Intersection of whole or part of the rectangle bool doesIntersect(const SRect &_other) const { SRect r1(*this); SRect r2(_other); r1.normalize(); r2.normalize(); return !( (r2.x > r1.x2()) || (r2.x2() < r1.x) || (r2.y > r1.y2()) || (r2.y2() < r1.y)); } bool isEmpty() { return (area() == static_cast(0.0)); // (x == y == height == width == static_cast(0.0)); } void nullify() { x = y = width = height = static_cast(0.0); } // Static functions are class functions (union is reserved word, that's why runion ;-) static SRect runion(const SRect &_r1, const SRect &_r2) { SRect r1 = _r1; SRect r2 = _r2; r1.normalize(); r2.normalize(); // Get the smallest possible point SPoint spp = SPoint::spp(r1.p1(), r2.p1()); // Get the greatest possible point SPoint gpp = SPoint::gpp(r1.p2(), r2.p2()); SRect rect(spp, gpp); return rect.normalize(); } static SRect intersection_OLD(const SRect &_r1, const SRect &_r2) { SRect temp(0,0,0,0); SRect r1 = _r1; SRect r2 = _r2; r1.normalize(); r2.normalize(); // Speed up this // if(r1.doesIntersect(r2)) if (!((r2.x > r1.x2()) || (r2.x2() < r1.x) || (r2.y > r1.y2()) || (r2.y2() < r1.y))) { T left = MAX(r1.x, r2.x); T top = MAX(r1.y, r2.y); T right = MIN(r1.x2(), r2.x2()); T bottom = MIN(r1.y2(), r2.y2()); temp = SRect(left, top, right - left, bottom - top).normalize(); // if (temp.isEmpty()) temp.nullify(); } return temp; } static SRect intersection(const SRect &_r1, const SRect &_r2) { T x1, y1, x2, y2; SRect temp(0,0,0,0); SRect r1(_r1); SRect r2(_r2); r1.normalize(); r2.normalize(); x1 = MAX (r1.x, r2.x); y1 = MAX (r1.y, r2.y); x2 = MIN (r1.x2(), r2.x2()); y2 = MIN (r1.y2(), r2.y2()); if (x1 >= x2 || y1 >= y2) { ; } else { temp.x = x1; temp.y = y1; temp.width = x2 - x1; temp.height = y2 - y1; } return temp; } // Compare functions bool operator==(const SRect &_other) const { return (x == _other.x && y == _other.y && width == _other.width && height == _other.height); } bool operator!=(const SRect &_other) const { return !(operator == (_other)); } // Friends // Strictly: this does not need to be friend because struct's variables are always public friend std::ostream &operator << (std::ostream &os, const SRect &_r) { os << "Rectangle: x=" << _r.x << " y=" << _r.y << " width=" << _r.width << " height=" << _r.height; return os; } }; typedef SRect IRect; typedef SRect FRect; typedef SRect DRect; static ISize DefaultSize(-1, -1); static IPoint DefaultPoint(0,0); #endif