00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef GNASH_RANGE2D_H
00024 #define GNASH_RANGE2D_H
00025
00026 #include <ostream>
00027 #include <limits>
00028 #include <algorithm>
00029 #include <cassert>
00030 #include <cmath>
00031
00032 namespace gnash {
00033
00034 namespace geometry {
00035
00037 enum RangeKind {
00039 finiteRange,
00040
00042 nullRange,
00043
00047
00051 worldRange
00052 };
00053
00055
00068 template <typename T>
00069 class Range2d
00070 {
00071 public:
00072
00074 template <typename U>
00075 friend std::ostream& operator<< (std::ostream& os, const Range2d<U>& rect);
00076
00078
00083 template <typename U>
00084 friend bool operator== (const Range2d<U>& r1, const Range2d<U>& r2);
00085
00087
00092 template <typename U>
00093 friend bool operator!= (const Range2d<U>& r1, const Range2d<U>& r2);
00094
00096
00099 template <typename U> friend Range2d<U>
00100 Intersection(const Range2d<U>& r1, const Range2d<U>& r2);
00101
00103 template <typename U> friend Range2d<U>
00104 Union(const Range2d<U>& r1, const Range2d<U>& r2);
00105
00107
00114 Range2d(RangeKind kind=nullRange)
00115 :
00116 _xmin(T()),
00117 _xmax(T()),
00118 _ymin(T()),
00119 _ymax(T())
00120 {
00121 switch ( kind )
00122 {
00123 case worldRange:
00124 setWorld();
00125 break;
00126 case nullRange:
00127 setNull();
00128 break;
00129 default:
00130 case finiteRange:
00131 break;
00132 }
00133 }
00134
00136
00143 Range2d(T xmin, T ymin, T xmax, T ymax)
00144 :
00145 _xmin(xmin),
00146 _xmax(xmax),
00147 _ymin(ymin),
00148 _ymax(ymax)
00149 {
00150
00151 assert(_xmin <= _xmax);
00152 assert(_ymin <= _ymax);
00153
00154 }
00155
00157 template <typename U>
00158 Range2d(const Range2d<U>& from)
00159 {
00160 if ( from.isWorld() ) {
00161 setWorld();
00162 } else if ( from.isNull() ) {
00163 setNull();
00164 } else {
00165 _xmin = roundMin(from.getMinX());
00166 _ymin = roundMin(from.getMinY());
00167 _xmax = roundMax(from.getMaxX());
00168 _ymax = roundMax(from.getMaxY());
00169 }
00170 }
00171
00173 bool isNull() const
00174 {
00175 return _xmax < _xmin;
00176 }
00177
00179
00182 Range2d<T>& setNull()
00183 {
00184 _xmin = std::numeric_limits<T>::max();
00185 _xmax = std::numeric_limits<T>::min();
00186 return *this;
00187 }
00188
00190 bool isWorld() const
00191 {
00192 return _xmax == std::numeric_limits<T>::max()
00193 && _xmin == std::numeric_limits<T>::min();
00194 }
00195
00197
00200 bool isFinite() const
00201 {
00202 return ( ! isNull() && ! isWorld() );
00203 }
00204
00206
00214 Range2d<T>& setWorld()
00215 {
00216 _xmin = std::numeric_limits<T>::min();
00217 _xmax = std::numeric_limits<T>::max();
00218 return *this;
00219 }
00220
00224
00228 template <typename U>
00229 bool contains(U x, U y) const
00230 {
00231 if ( isNull() ) return false;
00232 if ( isWorld() ) return true;
00233 if (x < _xmin || x > _xmax || y < _ymin || y > _ymax)
00234 {
00235 return false;
00236 }
00237 return true;
00238 }
00239
00242
00250 bool contains(const Range2d<T>& other) const
00251 {
00252 if ( isNull() || other.isNull() ) return false;
00253 if ( isWorld() ) return true;
00254 if ( other.isWorld() ) return false;
00255
00256 return _xmin <= other._xmin &&
00257 _xmax >= other._xmax &&
00258 _ymin <= other._ymin &&
00259 _ymax >= other._ymax;
00260 }
00261
00265
00269 bool intersects(const Range2d<T>& other) const
00270 {
00271 if ( isNull() || other.isNull() ) return false;
00272 if ( isWorld() || other.isWorld() ) return true;
00273
00274 if ( _xmin > other._xmax ) return false;
00275 if ( _xmax < other._xmin ) return false;
00276 if ( _ymin > other._ymax ) return false;
00277 if ( _ymax < other._ymin ) return false;
00278 return true;
00279 }
00280
00282
00285 Range2d<T>& expandTo(T x, T y)
00286 {
00287
00288 if ( isWorld() ) return *this;
00289
00290 if ( isNull() )
00291 {
00292 setTo(x,y);
00293 }
00294 else
00295 {
00296 _xmin = std::min(_xmin, x);
00297 _ymin = std::min(_ymin, y);
00298 _xmax = std::max(_xmax, x);
00299 _ymax = std::max(_ymax, y);
00300 }
00301
00302 return *this;
00303 }
00304
00306
00309 Range2d<T>& expandToCircle(T x, T y, T radius)
00310 {
00311
00312 if ( isWorld() ) return *this;
00313
00314 expandTo(x-radius, y);
00315 expandTo(x+radius, y);
00316
00317 expandTo(x, y-radius);
00318 expandTo(x, y+radius);
00319
00320 return *this;
00321 }
00322
00324
00327 Range2d<T>& setTo(T x, T y)
00328 {
00329 _xmin = _xmax = x;
00330 _ymin = _ymax = y;
00331 return *this;
00332 }
00333
00335
00341
00344 Range2d<T>& setTo(T xmin, T ymin, T xmax, T ymax)
00345 {
00346 _xmin = xmin;
00347 _xmax = xmax;
00348 _ymin = ymin;
00349 _ymax = ymax;
00350
00351
00352 assert(_xmin <= _xmax);
00353 assert(_ymin <= _ymax);
00354
00355 return *this;
00356 }
00357
00359
00362 T width() const
00363 {
00364 assert ( ! isWorld() );
00365 if ( isNull() ) return 0;
00366 return _xmax-_xmin;
00367 }
00368
00370
00373 T height() const
00374 {
00375 assert ( ! isWorld() );
00376 if ( isNull() ) return 0;
00377 return _ymax-_ymin;
00378 }
00379
00381
00389 Range2d<T>& shiftX(T offset)
00390 {
00391 if ( isNull() || isWorld() ) return *this;
00392 _xmin += offset;
00393 _xmax += offset;
00394 return *this;
00395 }
00396
00398
00406 Range2d<T>& shiftY(T offset)
00407 {
00408 if ( isNull() || isWorld() ) return *this;
00409 _ymin += offset;
00410 _ymax += offset;
00411 return *this;
00412 }
00413
00415 Range2d<T>& scaleX(float factor)
00416 {
00417 return scale(factor, 1);
00418 }
00419
00421 Range2d<T>& scaleY(float factor)
00422 {
00423 return scale(1, factor);
00424 }
00425
00427
00459 Range2d<T>& scale(float xfactor, float yfactor)
00460 {
00461 assert(xfactor >= 0 && yfactor >= 0);
00462
00463 if ( ! isFinite() ) return *this;
00464
00465 if ( xfactor == 0 || yfactor == 0 )
00466 {
00467 return setNull();
00468 }
00469
00470 if ( xfactor != 1 )
00471 {
00472 _xmin = scaleMin(_xmin, xfactor);
00473 _xmax = scaleMax(_xmax, xfactor);
00474 assert(_xmin <= _xmax);
00475 }
00476
00477 if ( yfactor != 1 )
00478 {
00479 _ymin = scaleMin(_ymin, yfactor);
00480 _ymax = scaleMax(_ymax, yfactor);
00481 assert(_ymin <= _ymax);
00482 }
00483
00484 return *this;
00485 }
00486
00488 Range2d<T>& scale(float factor)
00489 {
00490 return scale(factor, factor);
00491 }
00492
00494
00508 Range2d<T>& growBy(T amount)
00509 {
00510 if ( isNull() || isWorld() || amount==0 ) return *this;
00511
00512
00513 if ( amount < 0 ) return shrinkBy(-amount);
00514
00515 T newxmin = _xmin - amount;
00516 if (newxmin > _xmin ) return setWorld();
00517 else _xmin = newxmin;
00518
00519 T newxmax = _xmax + amount;
00520 if (newxmax < _xmax ) return setWorld();
00521 else _xmax = newxmax;
00522
00523 T newymin = _ymin - amount;
00524 if (newymin > _ymin ) return setWorld();
00525 else _ymin = newymin;
00526
00527 T newymax = _ymax + amount;
00528 if (newymax < _ymax ) return setWorld();
00529 else _ymax = newymax;
00530
00531 return *this;
00532
00533 }
00534
00536
00559 Range2d<T>& shrinkBy(T amount)
00560 {
00561 if ( isNull() || isWorld() || amount==0 ) return *this;
00562
00563
00564
00565 if ( amount < 0 ) return growBy(-amount);
00566
00567
00568
00569
00570
00571
00572 if ( _xmax - _xmin <= amount ) return setNull();
00573 if ( _ymax - _ymin <= amount ) return setNull();
00574
00575 _xmin += amount;
00576 _ymin += amount;
00577 _xmax -= amount;
00578 _ymax -= amount;
00579
00580 return *this;
00581
00582 }
00583
00585
00588 T getMinX() const
00589 {
00590 assert ( isFinite() );
00591 return _xmin;
00592 }
00593
00595
00598 T getMaxX() const
00599 {
00600 assert ( isFinite() );
00601 return _xmax;
00602 }
00603
00605
00608 T getMinY() const
00609 {
00610 assert ( isFinite() );
00611 return _ymin;
00612 }
00613
00615
00618 T getMaxY() const
00619 {
00620 assert ( isFinite() );
00621 return _ymax;
00622 }
00623
00626 T getArea() const {
00627 assert ( !isWorld() );
00628 if ( isNull() ) return 0;
00629 return (_xmax - _xmin) * (_ymax - _ymin);
00630
00631
00632 }
00633
00635
00639 void expandTo(const Range2d<T>& r)
00640 {
00641 if ( r.isNull() )
00642 {
00643
00644 return;
00645 }
00646
00647 if ( isNull() )
00648 {
00649
00650 *this = r;
00651 return;
00652 }
00653
00654 if ( isWorld() || r.isWorld() )
00655 {
00656
00657 setWorld();
00658 return;
00659 }
00660
00661 _xmin = std::min(_xmin, r._xmin);
00662 _xmax = std::max(_xmax, r._xmax);
00663 _ymin = std::min(_ymin, r._ymin);
00664 _ymax = std::max(_ymax, r._ymax);
00665
00666 }
00667
00668 private:
00669
00670 T _xmin, _xmax, _ymin, _ymax;
00671
00672 T scaleMin(T min, float scale) const {
00673 return roundMin(static_cast<float>(min) * scale);
00674 }
00675
00676 T scaleMax(T max, float scale) const {
00677 return roundMax(static_cast<float>(max) * scale);
00678 }
00679
00680 T roundMin(float v) const {
00681 return static_cast<T>(v);
00682 }
00683
00684 T roundMax(float v) const {
00685 return static_cast<T>(v);
00686 }
00687
00688
00689 };
00690
00691 template <typename T> inline std::ostream&
00692 operator<< (std::ostream& os, const Range2d<T>& rect)
00693 {
00694 if ( rect.isNull() ) return os << "Null range";
00695 if ( rect.isWorld() ) return os << "World range";
00696
00697 return os << "Finite range (" << rect._xmin << "," << rect._ymin
00698 << " " << rect._xmax << "," << rect._ymax << ")";
00699 }
00700
00701 template <typename T> inline bool
00702 operator== (const Range2d<T>& r1, const Range2d<T>& r2)
00703 {
00704
00705
00706
00707
00708 if ( r1.isNull() ) return r2.isNull();
00709 if ( r2.isNull() ) return r1.isNull();
00710 if ( r1.isWorld() ) return r2.isWorld();
00711 if ( r2.isWorld() ) return r1.isWorld();
00712
00713 return r1._xmin == r2._xmin && r1._ymin == r2._ymin &&
00714 r1._xmax == r2._xmax && r1._ymax == r2._ymax;
00715 }
00716
00717 template <typename T> inline bool
00718 operator!= (const Range2d<T>& r1, const Range2d<T>& r2)
00719 {
00720 return ! ( r1 == r2 );
00721 }
00722
00724 template <typename T> inline bool
00725 Intersect(const Range2d<T>& r1, const Range2d<T>& r2)
00726 {
00727 return r1.intersects(r2);
00728 }
00729
00731 template <typename T> inline Range2d<T>
00732 Union(const Range2d<T>& r1, const Range2d<T>& r2)
00733 {
00734 Range2d<T> ret = r1;
00735 ret.expandTo(r2);
00736 return ret;
00737 }
00738
00740
00743 template <typename T> inline Range2d<T>
00744 Intersection(const Range2d<T>& r1, const Range2d<T>& r2)
00745 {
00746 if ( r1.isNull() || r2.isNull() ) {
00747
00748 return Range2d<T>(nullRange);
00749 }
00750
00751 if ( r1.isWorld() ) {
00752
00753 return r2;
00754 }
00755
00756 if ( r2.isWorld() ) {
00757
00758 return r1;
00759 }
00760
00761 if ( ! r1.intersects(r2) ) {
00762
00763 return Range2d<T>(nullRange);
00764 }
00765
00766 return Range2d<T> (
00767 std::max(r1._xmin, r2._xmin),
00768 std::max(r1._ymin, r2._ymin),
00769 std::min(r1._xmax, r2._xmax),
00770 std::min(r1._ymax, r2._ymax)
00771 );
00772
00773 }
00774
00776
00779 template<> inline int
00780 Range2d<int>::roundMin(float min) const
00781 {
00782 return static_cast<int>(std::floor(min));
00783 }
00784
00786
00789 template<> inline unsigned int
00790 Range2d<unsigned int>::roundMin(float min) const
00791 {
00792 return static_cast<unsigned int>(std::floor(min));
00793 }
00794
00796
00799 template<> inline int
00800 Range2d<int>::roundMax(float max) const
00801 {
00802 return static_cast<int>(std::ceil(max));
00803 }
00804
00806
00809 template<> inline unsigned int
00810 Range2d<unsigned int>::roundMax(float max) const
00811 {
00812 return static_cast<unsigned int>(std::ceil(static_cast<float>(max)));
00813 }
00814
00816
00819 template<> inline int
00820 Range2d<int>::getArea() const
00821 {
00822 assert ( !isWorld() );
00823 if ( isNull() ) return 0;
00824 return (_xmax - _xmin + 1) * (_ymax - _ymin + 1);
00825 }
00826
00828
00831 template<> inline unsigned int
00832 Range2d<unsigned int>::getArea() const
00833 {
00834 assert ( isFinite() );
00835 return (_xmax - _xmin + 1) * (_ymax - _ymin + 1);
00836 }
00837
00838
00839 }
00840 }
00841
00842 #endif // GNASH_RANGE2D_H
00843
00844
00845
00846
00847
00848