Quantum GIS API Documentation
1.8
|
00001 /*************************************************************************** 00002 qgsrectangle.cpp - description 00003 ------------------- 00004 begin : Sat Jun 22 2002 00005 copyright : (C) 2002 by Gary E.Sherman 00006 email : sherman at mrcc.com 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 #include <algorithm> 00019 #include <cmath> 00020 #include <limits> 00021 #include <QString> 00022 #include <QTextStream> 00023 #include <qnumeric.h> 00024 00025 #include "qgspoint.h" 00026 #include "qgsrectangle.h" 00027 #include "qgslogger.h" 00028 00029 QgsRectangle::QgsRectangle( double newxmin, double newymin, double newxmax, double newymax ) 00030 : xmin( newxmin ), ymin( newymin ), xmax( newxmax ), ymax( newymax ) 00031 { 00032 normalize(); 00033 } 00034 00035 QgsRectangle::QgsRectangle( QgsPoint const & p1, QgsPoint const & p2 ) 00036 { 00037 set( p1, p2 ); 00038 } 00039 00040 QgsRectangle::QgsRectangle( const QgsRectangle &r ) 00041 { 00042 xmin = r.xMinimum(); 00043 ymin = r.yMinimum(); 00044 xmax = r.xMaximum(); 00045 ymax = r.yMaximum(); 00046 } 00047 00048 void QgsRectangle::set( const QgsPoint& p1, const QgsPoint& p2 ) 00049 { 00050 xmin = p1.x(); 00051 xmax = p2.x(); 00052 ymin = p1.y(); 00053 ymax = p2.y(); 00054 normalize(); 00055 } 00056 00057 void QgsRectangle::set( double xmin_, double ymin_, double xmax_, double ymax_ ) 00058 { 00059 xmin = xmin_; 00060 ymin = ymin_; 00061 xmax = xmax_; 00062 ymax = ymax_; 00063 normalize(); 00064 } 00065 00066 void QgsRectangle::normalize() 00067 { 00068 if ( xmin > xmax ) 00069 { 00070 std::swap( xmin, xmax ); 00071 } 00072 if ( ymin > ymax ) 00073 { 00074 std::swap( ymin, ymax ); 00075 } 00076 } // QgsRectangle::normalize() 00077 00078 00079 void QgsRectangle::setMinimal() 00080 { 00081 xmin = std::numeric_limits<double>::max(); 00082 ymin = std::numeric_limits<double>::max(); 00083 xmax = -std::numeric_limits<double>::max(); 00084 ymax = -std::numeric_limits<double>::max(); 00085 } 00086 00087 void QgsRectangle::scale( double scaleFactor, const QgsPoint * cp ) 00088 { 00089 // scale from the center 00090 double centerX, centerY; 00091 if ( cp ) 00092 { 00093 centerX = cp->x(); 00094 centerY = cp->y(); 00095 } 00096 else 00097 { 00098 centerX = xmin + width() / 2; 00099 centerY = ymin + height() / 2; 00100 } 00101 double newWidth = width() * scaleFactor; 00102 double newHeight = height() * scaleFactor; 00103 xmin = centerX - newWidth / 2.0; 00104 xmax = centerX + newWidth / 2.0; 00105 ymin = centerY - newHeight / 2.0; 00106 ymax = centerY + newHeight / 2.0; 00107 } 00108 00109 void QgsRectangle::expand( double scaleFactor, const QgsPoint * cp ) 00110 { 00111 // scale from the center 00112 double centerX, centerY; 00113 if ( cp ) 00114 { 00115 centerX = cp->x(); 00116 centerY = cp->y(); 00117 } 00118 else 00119 { 00120 centerX = xmin + width() / 2; 00121 centerY = ymin + height() / 2; 00122 } 00123 00124 double newWidth = width() * scaleFactor; 00125 double newHeight = height() * scaleFactor; 00126 xmin = centerX - newWidth; 00127 xmax = centerX + newWidth; 00128 ymin = centerY - newHeight; 00129 ymax = centerY + newHeight; 00130 } 00131 00132 QgsRectangle QgsRectangle::intersect( const QgsRectangle * rect ) const 00133 { 00134 QgsRectangle intersection = QgsRectangle(); 00135 //If they don't actually intersect an empty QgsRectangle should be returned 00136 if ( !rect || !intersects( *rect ) ) 00137 { 00138 return intersection; 00139 } 00140 00141 intersection.setXMinimum( xmin > rect->xMinimum() ? xmin : rect->xMinimum() ); 00142 intersection.setXMaximum( xmax < rect->xMaximum() ? xmax : rect->xMaximum() ); 00143 intersection.setYMinimum( ymin > rect->yMinimum() ? ymin : rect->yMinimum() ); 00144 intersection.setYMaximum( ymax < rect->yMaximum() ? ymax : rect->yMaximum() ); 00145 return intersection; 00146 } 00147 00148 bool QgsRectangle::intersects( const QgsRectangle& rect ) const 00149 { 00150 double x1 = ( xmin > rect.xmin ? xmin : rect.xmin ); 00151 double x2 = ( xmax < rect.xmax ? xmax : rect.xmax ); 00152 if ( x1 > x2 ) 00153 return false; 00154 double y1 = ( ymin > rect.ymin ? ymin : rect.ymin ); 00155 double y2 = ( ymax < rect.ymax ? ymax : rect.ymax ); 00156 if ( y1 > y2 ) 00157 return false; 00158 return true; 00159 } 00160 00161 bool QgsRectangle::contains( const QgsRectangle& rect ) const 00162 { 00163 return ( rect.xmin >= xmin && rect.xmax <= xmax && rect.ymin >= ymin && rect.ymax <= ymax ); 00164 } 00165 00166 bool QgsRectangle::contains( const QgsPoint &p ) const 00167 { 00168 return xmin <= p.x() && p.x() <= xmax && 00169 ymin <= p.y() && p.y() <= ymax; 00170 } 00171 00172 void QgsRectangle::combineExtentWith( QgsRectangle * rect ) 00173 { 00174 00175 xmin = (( xmin < rect->xMinimum() ) ? xmin : rect->xMinimum() ); 00176 xmax = (( xmax > rect->xMaximum() ) ? xmax : rect->xMaximum() ); 00177 00178 ymin = (( ymin < rect->yMinimum() ) ? ymin : rect->yMinimum() ); 00179 ymax = (( ymax > rect->yMaximum() ) ? ymax : rect->yMaximum() ); 00180 00181 } 00182 00183 void QgsRectangle::combineExtentWith( double x, double y ) 00184 { 00185 00186 xmin = (( xmin < x ) ? xmin : x ); 00187 xmax = (( xmax > x ) ? xmax : x ); 00188 00189 ymin = (( ymin < y ) ? ymin : y ); 00190 ymax = (( ymax > y ) ? ymax : y ); 00191 00192 } 00193 00194 bool QgsRectangle::isEmpty() const 00195 { 00196 return xmax <= xmin || ymax <= ymin; 00197 } 00198 00199 QString QgsRectangle::asWktCoordinates() const 00200 { 00201 QString rep = 00202 QString::number( xmin, 'f', 16 ) + " " + 00203 QString::number( ymin, 'f', 16 ) + ", " + 00204 QString::number( xmax, 'f', 16 ) + " " + 00205 QString::number( ymax, 'f', 16 ); 00206 00207 return rep; 00208 } 00209 00210 // Return a string representation of the rectangle with automatic or high precision 00211 QString QgsRectangle::toString( bool automaticPrecision ) const 00212 { 00213 if ( automaticPrecision ) 00214 { 00215 int precision = 0; 00216 if (( width() < 1 || height() < 1 ) && ( width() > 0 && height() > 0 ) ) 00217 { 00218 precision = static_cast<int>( ceil( -1.0 * log10( qMin( width(), height() ) ) ) ) + 1; 00219 // sanity check 00220 if ( precision > 20 ) 00221 precision = 20; 00222 } 00223 return toString( precision ); 00224 } 00225 else 00226 return toString( 16 ); 00227 } 00228 00229 // overloaded version of above fn to allow precision to be set 00230 // Return a string representation of the rectangle with high precision 00231 QString QgsRectangle::toString( int thePrecision ) const 00232 { 00233 QString rep; 00234 if ( isEmpty() ) 00235 rep = "Empty"; 00236 else 00237 rep = QString( "%1,%2 : %3,%4" ) 00238 .arg( xmin, 0, 'f', thePrecision ) 00239 .arg( ymin, 0, 'f', thePrecision ) 00240 .arg( xmax, 0, 'f', thePrecision ) 00241 .arg( ymax, 0, 'f', thePrecision ); 00242 00243 QgsDebugMsgLevel( QString( "Extents : %1" ).arg( rep ), 4 ); 00244 00245 return rep; 00246 } 00247 00248 00249 // Return the rectangle as a set of polygon coordinates 00250 QString QgsRectangle::asPolygon() const 00251 { 00252 // QString rep = tmp.sprintf("%16f %16f,%16f %16f,%16f %16f,%16f %16f,%16f %16f", 00253 // xmin, ymin, xmin, ymax, xmax, ymax, xmax, ymin, xmin, ymin); 00254 QString rep; 00255 00256 QTextStream foo( &rep ); 00257 00258 foo.setRealNumberPrecision( 8 ); 00259 foo.setRealNumberNotation( QTextStream::FixedNotation ); 00260 // NOTE: a polygon isn't a polygon unless its closed. In the case of 00261 // a rectangle, that means 5 points (last == first) 00262 foo << xmin << " " << ymin << ", " 00263 << xmin << " " << ymax << ", " 00264 << xmax << " " << ymax << ", " 00265 << xmax << " " << ymin << ", " 00266 << xmin << " " << ymin; 00267 00268 return rep; 00269 00270 } // QgsRectangle::asPolygon() const 00271 00272 00273 bool QgsRectangle::operator==( const QgsRectangle & r1 ) const 00274 { 00275 return ( r1.xMaximum() == xMaximum() && 00276 r1.xMinimum() == xMinimum() && 00277 r1.yMaximum() == yMaximum() && 00278 r1.yMinimum() == yMinimum() ); 00279 } 00280 00281 00282 bool QgsRectangle::operator!=( const QgsRectangle & r1 ) const 00283 { 00284 return ( ! operator==( r1 ) ); 00285 } 00286 00287 00288 QgsRectangle & QgsRectangle::operator=( const QgsRectangle & r ) 00289 { 00290 if ( &r != this ) 00291 { 00292 xmax = r.xMaximum(); 00293 xmin = r.xMinimum(); 00294 ymax = r.yMaximum(); 00295 ymin = r.yMinimum(); 00296 } 00297 00298 return *this; 00299 } 00300 00301 00302 void QgsRectangle::unionRect( const QgsRectangle& r ) 00303 { 00304 if ( r.xMinimum() < xMinimum() ) 00305 setXMinimum( r.xMinimum() ); 00306 if ( r.xMaximum() > xMaximum() ) 00307 setXMaximum( r.xMaximum() ); 00308 if ( r.yMinimum() < yMinimum() ) 00309 setYMinimum( r.yMinimum() ); 00310 if ( r.yMaximum() > yMaximum() ) 00311 setYMaximum( r.yMaximum() ); 00312 } 00313 00314 bool QgsRectangle::isFinite() const 00315 { 00316 if ( qIsInf( xmin ) || qIsInf( ymin ) || qIsInf( xmax ) || qIsInf( ymax ) ) 00317 { 00318 return false; 00319 } 00320 if ( qIsNaN( xmin ) || qIsNaN( ymin ) || qIsNaN( xmax ) || qIsNaN( ymax ) ) 00321 { 00322 return false; 00323 } 00324 return true; 00325 } 00326 00327 void QgsRectangle::invert() 00328 { 00329 double tmp; 00330 tmp = xmin; xmin = ymin; ymin = tmp; 00331 tmp = xmax; xmax = ymax; ymax = tmp; 00332 }