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