QGIS API Documentation  2.99.0-Master (7705179)
qgsrectangle.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrectangle.cpp - description
3  -------------------
4  begin : Sat Jun 22 2002
5  copyright : (C) 2002 by Gary E.Sherman
6  email : sherman at mrcc.com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include <algorithm>
19 #include <cmath>
20 #include <limits>
21 #include <QRectF>
22 #include <QString>
23 #include <QTextStream>
24 #include <QTransform>
25 #include <QRegExp>
26 
27 #include "qgspointxy.h"
28 #include "qgsrectangle.h"
29 #include "qgslogger.h"
30 #include "qgsbox3d.h"
31 
32 QgsRectangle::QgsRectangle( double xMin, double yMin, double xMax, double yMax )
33  : mXmin( xMin )
34  , mYmin( yMin )
35  , mXmax( xMax )
36  , mYmax( yMax )
37 {
38  normalize();
39 }
40 
42 {
43  set( p1, p2 );
44 }
45 
46 QgsRectangle::QgsRectangle( QRectF const &qRectF )
47 {
48  mXmin = qRectF.topLeft().x();
49  mYmin = qRectF.topLeft().y();
50  mXmax = qRectF.bottomRight().x();
51  mYmax = qRectF.bottomRight().y();
52 }
53 
55 {
56  mXmin = r.xMinimum();
57  mYmin = r.yMinimum();
58  mXmax = r.xMaximum();
59  mYmax = r.yMaximum();
60 }
61 
62 void QgsRectangle::set( const QgsPointXY &p1, const QgsPointXY &p2 )
63 {
64  mXmin = p1.x();
65  mXmax = p2.x();
66  mYmin = p1.y();
67  mYmax = p2.y();
68  normalize();
69 }
70 
71 void QgsRectangle::set( double xmin_, double ymin_, double xmax_, double ymax_ )
72 {
73  mXmin = xmin_;
74  mYmin = ymin_;
75  mXmax = xmax_;
76  mYmax = ymax_;
77  normalize();
78 }
79 
81 {
82  if ( isNull() )
83  return;
84 
85  if ( mXmin > mXmax )
86  {
87  std::swap( mXmin, mXmax );
88  }
89  if ( mYmin > mYmax )
90  {
91  std::swap( mYmin, mYmax );
92  }
93 }
94 
96 {
97  mXmin = std::numeric_limits<double>::max();
98  mYmin = std::numeric_limits<double>::max();
99  mXmax = -std::numeric_limits<double>::max();
100  mYmax = -std::numeric_limits<double>::max();
101 }
102 
103 void QgsRectangle::scale( double scaleFactor, const QgsPointXY *cp )
104 {
105  // scale from the center
106  double centerX, centerY;
107  if ( cp )
108  {
109  centerX = cp->x();
110  centerY = cp->y();
111  }
112  else
113  {
114  centerX = mXmin + width() / 2;
115  centerY = mYmin + height() / 2;
116  }
117  scale( scaleFactor, centerX, centerY );
118 }
119 
120 void QgsRectangle::scale( double scaleFactor, double centerX, double centerY )
121 {
122  double newWidth = width() * scaleFactor;
123  double newHeight = height() * scaleFactor;
124  mXmin = centerX - newWidth / 2.0;
125  mXmax = centerX + newWidth / 2.0;
126  mYmin = centerY - newHeight / 2.0;
127  mYmax = centerY + newHeight / 2.0;
128 }
129 
130 void QgsRectangle::grow( double delta )
131 {
132  mXmin -= delta;
133  mXmax += delta;
134  mYmin -= delta;
135  mYmax += delta;
136 }
137 
139 {
140  if ( p.x() < xMinimum() )
141  setXMinimum( p.x() );
142  else if ( p.x() > xMaximum() )
143  setXMaximum( p.x() );
144  if ( p.y() < yMinimum() )
145  setYMinimum( p.y() );
146  if ( p.y() > yMaximum() )
147  setYMaximum( p.y() );
148 }
149 
151 {
152  return QgsRectangle( mXmin - width, mYmin - width, mXmax + width, mYmax + width );
153 }
154 
156 {
157  QgsRectangle intersection = QgsRectangle();
158  if ( rect && intersects( *rect ) )
159  {
160  intersection.setXMinimum( mXmin > rect->xMinimum() ? mXmin : rect->xMinimum() );
161  intersection.setXMaximum( mXmax < rect->xMaximum() ? mXmax : rect->xMaximum() );
162  intersection.setYMinimum( mYmin > rect->yMinimum() ? mYmin : rect->yMinimum() );
163  intersection.setYMaximum( mYmax < rect->yMaximum() ? mYmax : rect->yMaximum() );
164  }
165  return intersection;
166 }
167 
168 bool QgsRectangle::intersects( const QgsRectangle &rect ) const
169 {
170  double x1 = ( mXmin > rect.mXmin ? mXmin : rect.mXmin );
171  double x2 = ( mXmax < rect.mXmax ? mXmax : rect.mXmax );
172  if ( x1 > x2 )
173  return false;
174  double y1 = ( mYmin > rect.mYmin ? mYmin : rect.mYmin );
175  double y2 = ( mYmax < rect.mYmax ? mYmax : rect.mYmax );
176  return y1 <= y2;
177 }
178 
179 bool QgsRectangle::contains( const QgsRectangle &rect ) const
180 {
181  return ( rect.mXmin >= mXmin && rect.mXmax <= mXmax && rect.mYmin >= mYmin && rect.mYmax <= mYmax );
182 }
183 
184 bool QgsRectangle::contains( const QgsPointXY &p ) const
185 {
186  return mXmin <= p.x() && p.x() <= mXmax &&
187  mYmin <= p.y() && p.y() <= mYmax;
188 }
189 
191 {
192  if ( isNull() )
193  *this = rect;
194  else
195  {
196  mXmin = ( ( mXmin < rect.xMinimum() ) ? mXmin : rect.xMinimum() );
197  mXmax = ( ( mXmax > rect.xMaximum() ) ? mXmax : rect.xMaximum() );
198 
199  mYmin = ( ( mYmin < rect.yMinimum() ) ? mYmin : rect.yMinimum() );
200  mYmax = ( ( mYmax > rect.yMaximum() ) ? mYmax : rect.yMaximum() );
201  }
202 
203 }
204 
205 void QgsRectangle::combineExtentWith( double x, double y )
206 {
207  if ( isNull() )
208  *this = QgsRectangle( x, y, x, y );
209  else
210  {
211  mXmin = ( ( mXmin < x ) ? mXmin : x );
212  mXmax = ( ( mXmax > x ) ? mXmax : x );
213 
214  mYmin = ( ( mYmin < y ) ? mYmin : y );
215  mYmax = ( ( mYmax > y ) ? mYmax : y );
216  }
217 }
218 
220 {
221  double xmin = mXmin - v.x();
222  double xmax = mXmax - v.x();
223  double ymin = mYmin - v.y();
224  double ymax = mYmax - v.y();
225  return QgsRectangle( xmin, ymin, xmax, ymax );
226 }
227 
229 {
230  double xmin = mXmin + v.x();
231  double xmax = mXmax + v.x();
232  double ymin = mYmin + v.y();
233  double ymax = mYmax + v.y();
234  return QgsRectangle( xmin, ymin, xmax, ymax );
235 }
236 
238 {
239  mXmin -= v.x();
240  mXmax -= v.x();
241  mYmin -= v.y();
242  mYmax -= v.y();
243  return *this;
244 }
245 
247 {
248  mXmin += v.x();
249  mXmax += v.x();
250  mYmin += v.y();
251  mYmax += v.y();
252  return *this;
253 }
254 
256 {
257  return mXmax < mXmin || mYmax < mYmin || qgsDoubleNear( mXmax, mXmin ) || qgsDoubleNear( mYmax, mYmin );
258 }
259 
261 {
262  // rectangle created QgsRectangle() or with rect.setMinimal() ?
263  return ( qgsDoubleNear( mXmin, 0.0 ) && qgsDoubleNear( mXmax, 0.0 ) && qgsDoubleNear( mYmin, 0.0 ) && qgsDoubleNear( mYmax, 0.0 ) ) ||
264  ( qgsDoubleNear( mXmin, std::numeric_limits<double>::max() ) && qgsDoubleNear( mYmin, std::numeric_limits<double>::max() ) &&
265  qgsDoubleNear( mXmax, -std::numeric_limits<double>::max() ) && qgsDoubleNear( mYmax, -std::numeric_limits<double>::max() ) );
266 }
267 
269 {
270  QString rep =
271  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
272  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmax );
273 
274  return rep;
275 }
276 
278 {
279  QString rep =
280  QStringLiteral( "POLYGON((" ) +
281  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
282  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
283  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmax ) + ", " +
284  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmax ) + ", " +
285  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) +
286  QStringLiteral( "))" );
287 
288  return rep;
289 }
290 
291 QRectF QgsRectangle::toRectF() const
292 {
293  return QRectF( static_cast< qreal >( mXmin ), static_cast< qreal >( mYmin ), static_cast< qreal >( mXmax - mXmin ), static_cast< qreal >( mYmax - mYmin ) );
294 }
295 
296 QString QgsRectangle::toString( int precision ) const
297 {
298  QString rep;
299 
300  if ( precision < 0 )
301  {
302  precision = 0;
303  if ( ( width() < 10 || height() < 10 ) && ( width() > 0 && height() > 0 ) )
304  {
305  precision = static_cast<int>( std::ceil( -1.0 * std::log10( std::min( width(), height() ) ) ) ) + 1;
306  // sanity check
307  if ( precision > 20 )
308  precision = 20;
309  }
310  }
311 
312  if ( isEmpty() )
313  rep = QStringLiteral( "Empty" );
314  else
315  rep = QStringLiteral( "%1,%2 : %3,%4" )
316  .arg( mXmin, 0, 'f', precision )
317  .arg( mYmin, 0, 'f', precision )
318  .arg( mXmax, 0, 'f', precision )
319  .arg( mYmax, 0, 'f', precision );
320 
321  QgsDebugMsgLevel( QString( "Extents : %1" ).arg( rep ), 4 );
322 
323  return rep;
324 }
325 
326 QString QgsRectangle::asPolygon() const
327 {
328 // QString rep = tmp.sprintf("%16f %16f,%16f %16f,%16f %16f,%16f %16f,%16f %16f",
329 // xmin, ymin, xmin, ymax, xmax, ymax, xmax, ymin, xmin, ymin);
330  QString rep;
331 
332  QTextStream foo( &rep );
333 
334  foo.setRealNumberPrecision( 8 );
335  foo.setRealNumberNotation( QTextStream::FixedNotation );
336  // NOTE: a polygon isn't a polygon unless its closed. In the case of
337  // a rectangle, that means 5 points (last == first)
338  foo
339  << mXmin << ' ' << mYmin << ", "
340  << mXmin << ' ' << mYmax << ", "
341  << mXmax << ' ' << mYmax << ", "
342  << mXmax << ' ' << mYmin << ", "
343  << mXmin << ' ' << mYmin;
344 
345  return rep;
346 
347 }
348 
349 bool QgsRectangle::operator==( const QgsRectangle &r1 ) const
350 {
351  return qgsDoubleNear( r1.xMaximum(), xMaximum() ) &&
352  qgsDoubleNear( r1.xMinimum(), xMinimum() ) &&
353  qgsDoubleNear( r1.yMaximum(), yMaximum() ) &&
354  qgsDoubleNear( r1.yMinimum(), yMinimum() );
355 }
356 
357 bool QgsRectangle::operator!=( const QgsRectangle &r1 ) const
358 {
359  return ( ! operator==( r1 ) );
360 }
361 
363 {
364  if ( &r != this )
365  {
366  mXmax = r.xMaximum();
367  mXmin = r.xMinimum();
368  mYmax = r.yMaximum();
369  mYmin = r.yMinimum();
370  }
371 
372  return *this;
373 }
374 
376 {
377  if ( std::isinf( mXmin ) || std::isinf( mYmin ) || std::isinf( mXmax ) || std::isinf( mYmax ) )
378  {
379  return false;
380  }
381  if ( std::isnan( mXmin ) || std::isnan( mYmin ) || std::isnan( mXmax ) || std::isnan( mYmax ) )
382  {
383  return false;
384  }
385  return true;
386 }
387 
389 {
390  double tmp;
391  tmp = mXmin;
392  mXmin = mYmin;
393  mYmin = tmp;
394  tmp = mXmax;
395  mXmax = mYmax;
396  mYmax = tmp;
397 }
398 
399 QgsBox3d QgsRectangle::toBox3d( double zMin, double zMax ) const
400 {
401  return QgsBox3d( mXmin, mYmin, zMin, mXmax, mYmax, zMax );
402 }
403 
404 QDataStream &operator<<( QDataStream &out, const QgsRectangle &rectangle )
405 {
406  out << rectangle.xMinimum() << rectangle.yMinimum() << rectangle.xMaximum() << rectangle.yMaximum();
407  return out;
408 }
409 
410 QDataStream &operator>>( QDataStream &in, QgsRectangle &rectangle )
411 {
412  double xmin, ymin, xmax, ymax;
413  in >> xmin >> ymin >> xmax >> ymax;
414  rectangle.setXMinimum( xmin );
415  rectangle.setYMinimum( ymin );
416  rectangle.setXMaximum( xmax );
417  rectangle.setYMaximum( ymax );
418  return in;
419 }
QgsRectangle & operator+=(const QgsVector v)
Moves this rectangle in the direction of the vector.
bool contains(const QgsRectangle &rect) const
Return true when rectangle contains other rectangle.
QgsRectangle & operator=(const QgsRectangle &r1)
Assignment operator.
A rectangle specified with double values.
Definition: qgsrectangle.h:38
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:75
double y
Definition: qgspointxy.h:47
A class to represent a 2D point.
Definition: qgspointxy.h:42
QgsRectangle(double xMin=0, double yMin=0, double xMax=0, double yMax=0)
Constructor.
void scale(double scaleFactor, const QgsPointXY *c=nullptr)
Scale the rectangle around its center point.
QDataStream & operator>>(QDataStream &in, QgsRectangle &rectangle)
Reads a rectangle from stream in into rectangle.
void include(const QgsPointXY &p)
Updates the rectangle to include the specified point.
QgsRectangle intersect(const QgsRectangle *rect) const
Return the intersection with the given rectangle.
A 3-dimensional box composed of x, y, z coordinates.
Definition: qgsbox3d.h:34
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:210
QString asWktPolygon() const
Returns a string representation of the rectangle as a WKT Polygon.
QgsRectangle operator-(const QgsVector v) const
Returns a rectangle offset from this one in the direction of the reversed vector. ...
QgsRectangle operator+(const QgsVector v) const
Returns a rectangle offset from this one in the direction of the vector.
QgsRectangle buffered(double width) const
Get rectangle enlarged by buffer.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:38
void grow(double delta)
Grows the rectangle in place by the specified amount.
bool isEmpty() const
Returns true if the rectangle is empty.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:123
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:198
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:80
QString asPolygon() const
Returns the rectangle as a polygon.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
QString asWktCoordinates() const
Returns a string representation of the rectangle in WKT format.
bool isFinite() const
Returns true if the rectangle has finite boundaries.
double x
Definition: qgspointxy.h:46
A class to represent a vector.
Definition: qgsvector.h:26
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:111
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:96
void combineExtentWith(const QgsRectangle &rect)
Expand the rectangle so that covers both the original rectangle and the given rectangle.
bool operator==(const QgsRectangle &r1) const
Comparison operator.
QRectF toRectF() const
Returns a QRectF with same coordinates as the rectangle.
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:85
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:101
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:106
double x() const
Returns the vector&#39;s x-component.
Definition: qgsvector.cpp:82
void normalize()
Normalize the rectangle so it has non-negative width/height.
bool operator!=(const QgsRectangle &r1) const
Comparison operator.
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
double y() const
Returns the vector&#39;s y-component.
Definition: qgsvector.cpp:87
QgsRectangle & operator-=(const QgsVector v)
Moves this rectangle in the direction of the reversed vector.
QDataStream & operator<<(QDataStream &out, const QgsRectangle &rectangle)
Writes the list rectangle to stream out.
void set(const QgsPointXY &p1, const QgsPointXY &p2)
Sets the rectangle from two QgsPoints.
QgsBox3d toBox3d(double zMin, double zMax) const
Converts the rectangle to a 3D box, with the specified zMin and zMax z values.
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:70
void invert()
Swap x/y coordinates in the rectangle.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:130