Gnash  0.8.10
Range2d.h
Go to the documentation of this file.
00001 // 
00002 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
00003 //   Free Software Foundation, Inc
00004 // 
00005 // This program is free software; you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation; either version 3 of the License, or
00008 // (at your option) any later version.
00009 // 
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019 //
00020 // Original author: Sandro Santilli <strk@keybit.net>
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> // for inlines
00030 #include <cmath> // for floor / ceil
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                 // use the default ctor to make a NULL Range2d
00151                 assert(_xmin <= _xmax);
00152                 assert(_ymin <= _ymax);
00153                 // .. or should we raise an exception .. ?
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                 // A WORLD range already enclose every point
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                 // A WORLD range already enclose every point
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                 // use the default ctor to make a NULL Range2d
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); // in case of overflow...
00475                 }
00476 
00477                 if ( yfactor != 1 )
00478                 {
00479                         _ymin = scaleMin(_ymin, yfactor);
00480                         _ymax = scaleMax(_ymax, yfactor);
00481                         assert(_ymin <= _ymax); // in case of overflow...
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                 // NOTE: triggers a compiler warning when T is an unsigned type
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                 // NOTE: whith will likely trigger a compiler
00564                 //       warning when T is an unsigned type
00565                 if ( amount < 0 ) return growBy(-amount);
00566 
00567                 // Turn this range into the NULL range
00568                 // if any dimension collapses.
00569                 // Don't use width() and height() to 
00570                 // avoid superflous checks.
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         // this implementation is for float types, see specialization below
00631         // for ints... 
00632     } 
00633 
00635         //
00639         void expandTo(const Range2d<T>& r)
00640         {
00641                 if ( r.isNull() )
00642                 {
00643                         // the given range will add nothing
00644                         return; 
00645                 }
00646 
00647                 if ( isNull() ) 
00648                 {
00649                         // being null ourself, we'll equal the given range
00650                         *this = r;
00651                         return;
00652                 }
00653 
00654                 if ( isWorld() || r.isWorld() )
00655                 {
00656                         // union with world is always world...
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         // These checks are needed becase
00705         // we don't initialize *all* memebers
00706         // when setting to Null or World
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                 // NULL ranges intersect nothing
00748                 return Range2d<T>(nullRange); 
00749         }
00750 
00751         if ( r1.isWorld() ) {
00752                 // WORLD range intersect everything
00753                 return r2;
00754         }
00755 
00756         if ( r2.isWorld() ) {
00757                 // WORLD range intersect everything
00758                 return r1;
00759         }
00760 
00761         if ( ! r1.intersects(r2) ) {
00762                 // No intersection results in a NULL range
00763                 return Range2d<T>(nullRange); 
00764         }
00765 
00766         return Range2d<T> (
00767                 std::max(r1._xmin, r2._xmin), // xmin
00768                 std::max(r1._ymin, r2._ymin), // ymin
00769                 std::min(r1._xmax, r2._xmax), // xmax
00770                 std::min(r1._ymax, r2._ymax)  // 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 } // namespace gnash::geometry
00840 } // namespace gnash
00841 
00842 #endif // GNASH_RANGE2D_H
00843 
00844 
00845 // Local Variables:
00846 // mode: C++
00847 // indent-tabs-mode: t
00848 // End: