QGIS API Documentation  2.99.0-Master (dcec6bb)
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 #include <qnumeric.h>
27 
28 #include "qgspointxy.h"
29 #include "qgsrectangle.h"
30 #include "qgslogger.h"
31 #include "qgsbox3d.h"
32 
33 QgsRectangle::QgsRectangle( double xMin, double yMin, double xMax, double yMax )
34  : mXmin( xMin )
35  , mYmin( yMin )
36  , mXmax( xMax )
37  , mYmax( yMax )
38 {
39  normalize();
40 }
41 
43 {
44  set( p1, p2 );
45 }
46 
47 QgsRectangle::QgsRectangle( QRectF const &qRectF )
48 {
49  mXmin = qRectF.topLeft().x();
50  mYmin = qRectF.topLeft().y();
51  mXmax = qRectF.bottomRight().x();
52  mYmax = qRectF.bottomRight().y();
53 }
54 
56 {
57  mXmin = r.xMinimum();
58  mYmin = r.yMinimum();
59  mXmax = r.xMaximum();
60  mYmax = r.yMaximum();
61 }
62 
63 void QgsRectangle::set( const QgsPointXY &p1, const QgsPointXY &p2 )
64 {
65  mXmin = p1.x();
66  mXmax = p2.x();
67  mYmin = p1.y();
68  mYmax = p2.y();
69  normalize();
70 }
71 
72 void QgsRectangle::set( double xmin_, double ymin_, double xmax_, double ymax_ )
73 {
74  mXmin = xmin_;
75  mYmin = ymin_;
76  mXmax = xmax_;
77  mYmax = ymax_;
78  normalize();
79 }
80 
82 {
83  if ( isNull() )
84  return;
85 
86  if ( mXmin > mXmax )
87  {
88  std::swap( mXmin, mXmax );
89  }
90  if ( mYmin > mYmax )
91  {
92  std::swap( mYmin, mYmax );
93  }
94 }
95 
97 {
102 }
103 
104 void QgsRectangle::scale( double scaleFactor, const QgsPointXY *cp )
105 {
106  // scale from the center
107  double centerX, centerY;
108  if ( cp )
109  {
110  centerX = cp->x();
111  centerY = cp->y();
112  }
113  else
114  {
115  centerX = mXmin + width() / 2;
116  centerY = mYmin + height() / 2;
117  }
118  scale( scaleFactor, centerX, centerY );
119 }
120 
121 void QgsRectangle::scale( double scaleFactor, double centerX, double centerY )
122 {
123  double newWidth = width() * scaleFactor;
124  double newHeight = height() * scaleFactor;
125  mXmin = centerX - newWidth / 2.0;
126  mXmax = centerX + newWidth / 2.0;
127  mYmin = centerY - newHeight / 2.0;
128  mYmax = centerY + newHeight / 2.0;
129 }
130 
131 void QgsRectangle::grow( double delta )
132 {
133  mXmin -= delta;
134  mXmax += delta;
135  mYmin -= delta;
136  mYmax += delta;
137 }
138 
140 {
141  if ( p.x() < xMinimum() )
142  setXMinimum( p.x() );
143  else if ( p.x() > xMaximum() )
144  setXMaximum( p.x() );
145  if ( p.y() < yMinimum() )
146  setYMinimum( p.y() );
147  if ( p.y() > yMaximum() )
148  setYMaximum( p.y() );
149 }
150 
152 {
153  return QgsRectangle( mXmin - width, mYmin - width, mXmax + width, mYmax + width );
154 }
155 
157 {
158  QgsRectangle intersection = QgsRectangle();
159  //If they don't actually intersect an empty QgsRectangle should be returned
160  if ( !rect || !intersects( *rect ) )
161  {
162  return intersection;
163  }
164 
165  intersection.setXMinimum( mXmin > rect->xMinimum() ? mXmin : rect->xMinimum() );
166  intersection.setXMaximum( mXmax < rect->xMaximum() ? mXmax : rect->xMaximum() );
167  intersection.setYMinimum( mYmin > rect->yMinimum() ? mYmin : rect->yMinimum() );
168  intersection.setYMaximum( mYmax < rect->yMaximum() ? mYmax : rect->yMaximum() );
169  return intersection;
170 }
171 
172 bool QgsRectangle::intersects( const QgsRectangle &rect ) const
173 {
174  double x1 = ( mXmin > rect.mXmin ? mXmin : rect.mXmin );
175  double x2 = ( mXmax < rect.mXmax ? mXmax : rect.mXmax );
176  if ( x1 > x2 )
177  return false;
178  double y1 = ( mYmin > rect.mYmin ? mYmin : rect.mYmin );
179  double y2 = ( mYmax < rect.mYmax ? mYmax : rect.mYmax );
180  if ( y1 > y2 )
181  return false;
182  return true;
183 }
184 
185 bool QgsRectangle::contains( const QgsRectangle &rect ) const
186 {
187  return ( rect.mXmin >= mXmin && rect.mXmax <= mXmax && rect.mYmin >= mYmin && rect.mYmax <= mYmax );
188 }
189 
190 bool QgsRectangle::contains( const QgsPointXY &p ) const
191 {
192  return mXmin <= p.x() && p.x() <= mXmax &&
193  mYmin <= p.y() && p.y() <= mYmax;
194 }
195 
197 {
198  if ( isNull() )
199  *this = rect;
200  else
201  {
202  mXmin = ( ( mXmin < rect.xMinimum() ) ? mXmin : rect.xMinimum() );
203  mXmax = ( ( mXmax > rect.xMaximum() ) ? mXmax : rect.xMaximum() );
204 
205  mYmin = ( ( mYmin < rect.yMinimum() ) ? mYmin : rect.yMinimum() );
206  mYmax = ( ( mYmax > rect.yMaximum() ) ? mYmax : rect.yMaximum() );
207  }
208 
209 }
210 
211 void QgsRectangle::combineExtentWith( double x, double y )
212 {
213  if ( isNull() )
214  *this = QgsRectangle( x, y, x, y );
215  else
216  {
217  mXmin = ( ( mXmin < x ) ? mXmin : x );
218  mXmax = ( ( mXmax > x ) ? mXmax : x );
219 
220  mYmin = ( ( mYmin < y ) ? mYmin : y );
221  mYmax = ( ( mYmax > y ) ? mYmax : y );
222  }
223 }
224 
226 {
227  double xmin = mXmin - v.x();
228  double xmax = mXmax - v.x();
229  double ymin = mYmin - v.y();
230  double ymax = mYmax - v.y();
231  return QgsRectangle( xmin, ymin, xmax, ymax );
232 }
233 
235 {
236  double xmin = mXmin + v.x();
237  double xmax = mXmax + v.x();
238  double ymin = mYmin + v.y();
239  double ymax = mYmax + v.y();
240  return QgsRectangle( xmin, ymin, xmax, ymax );
241 }
242 
244 {
245  mXmin -= v.x();
246  mXmax -= v.x();
247  mYmin -= v.y();
248  mYmax -= v.y();
249  return *this;
250 }
251 
253 {
254  mXmin += v.x();
255  mXmax += v.x();
256  mYmin += v.y();
257  mYmax += v.y();
258  return *this;
259 }
260 
262 {
263  return mXmax <= mXmin || mYmax <= mYmin;
264 }
265 
267 {
268  // rectangle created QgsRectangle() or with rect.setMinimal() ?
269  return ( qgsDoubleNear( mXmin, 0.0 ) && qgsDoubleNear( mXmax, 0.0 ) && qgsDoubleNear( mYmin, 0.0 ) && qgsDoubleNear( mYmax, 0.0 ) ) ||
272 }
273 
275 {
276  QString rep =
277  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
278  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmax );
279 
280  return rep;
281 }
282 
284 {
285  QString rep =
286  QStringLiteral( "POLYGON((" ) +
287  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
288  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
289  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmax ) + ", " +
290  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmax ) + ", " +
291  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) +
292  QStringLiteral( "))" );
293 
294  return rep;
295 }
296 
297 QRectF QgsRectangle::toRectF() const
298 {
299  return QRectF( static_cast< qreal >( mXmin ), static_cast< qreal >( mYmin ), static_cast< qreal >( mXmax - mXmin ), static_cast< qreal >( mYmax - mYmin ) );
300 }
301 
302 QString QgsRectangle::toString( int precision ) const
303 {
304  QString rep;
305 
306  if ( precision < 0 )
307  {
308  precision = 0;
309  if ( ( width() < 10 || height() < 10 ) && ( width() > 0 && height() > 0 ) )
310  {
311  precision = static_cast<int>( ceil( -1.0 * log10( qMin( width(), height() ) ) ) ) + 1;
312  // sanity check
313  if ( precision > 20 )
314  precision = 20;
315  }
316  }
317 
318  if ( isEmpty() )
319  rep = QStringLiteral( "Empty" );
320  else
321  rep = QStringLiteral( "%1,%2 : %3,%4" )
322  .arg( mXmin, 0, 'f', precision )
323  .arg( mYmin, 0, 'f', precision )
324  .arg( mXmax, 0, 'f', precision )
325  .arg( mYmax, 0, 'f', precision );
326 
327  QgsDebugMsgLevel( QString( "Extents : %1" ).arg( rep ), 4 );
328 
329  return rep;
330 }
331 
332 QString QgsRectangle::asPolygon() const
333 {
334 // QString rep = tmp.sprintf("%16f %16f,%16f %16f,%16f %16f,%16f %16f,%16f %16f",
335 // xmin, ymin, xmin, ymax, xmax, ymax, xmax, ymin, xmin, ymin);
336  QString rep;
337 
338  QTextStream foo( &rep );
339 
340  foo.setRealNumberPrecision( 8 );
341  foo.setRealNumberNotation( QTextStream::FixedNotation );
342  // NOTE: a polygon isn't a polygon unless its closed. In the case of
343  // a rectangle, that means 5 points (last == first)
344  foo
345  << mXmin << ' ' << mYmin << ", "
346  << mXmin << ' ' << mYmax << ", "
347  << mXmax << ' ' << mYmax << ", "
348  << mXmax << ' ' << mYmin << ", "
349  << mXmin << ' ' << mYmin;
350 
351  return rep;
352 
353 }
354 
355 bool QgsRectangle::operator==( const QgsRectangle &r1 ) const
356 {
357  return qgsDoubleNear( r1.xMaximum(), xMaximum() ) &&
358  qgsDoubleNear( r1.xMinimum(), xMinimum() ) &&
359  qgsDoubleNear( r1.yMaximum(), yMaximum() ) &&
360  qgsDoubleNear( r1.yMinimum(), yMinimum() );
361 }
362 
363 bool QgsRectangle::operator!=( const QgsRectangle &r1 ) const
364 {
365  return ( ! operator==( r1 ) );
366 }
367 
369 {
370  if ( &r != this )
371  {
372  mXmax = r.xMaximum();
373  mXmin = r.xMinimum();
374  mYmax = r.yMaximum();
375  mYmin = r.yMinimum();
376  }
377 
378  return *this;
379 }
380 
382 {
383  if ( qIsInf( mXmin ) || qIsInf( mYmin ) || qIsInf( mXmax ) || qIsInf( mYmax ) )
384  {
385  return false;
386  }
387  if ( qIsNaN( mXmin ) || qIsNaN( mYmin ) || qIsNaN( mXmax ) || qIsNaN( mYmax ) )
388  {
389  return false;
390  }
391  return true;
392 }
393 
395 {
396  double tmp;
397  tmp = mXmin;
398  mXmin = mYmin;
399  mYmin = tmp;
400  tmp = mXmax;
401  mXmax = mYmax;
402  mYmax = tmp;
403 }
404 
405 QgsBox3d QgsRectangle::toBox3d( double zMin, double zMax ) const
406 {
407  return QgsBox3d( mXmin, mYmin, zMin, mXmax, mYmax, zMax );
408 }
409 
410 QDataStream &operator<<( QDataStream &out, const QgsRectangle &rectangle )
411 {
412  out << rectangle.xMinimum() << rectangle.yMinimum() << rectangle.xMaximum() << rectangle.yMaximum();
413  return out;
414 }
415 
416 QDataStream &operator>>( QDataStream &in, QgsRectangle &rectangle )
417 {
418  double xmin, ymin, xmax, ymax;
419  in >> xmin >> ymin >> xmax >> ymax;
420  rectangle.setXMinimum( xmin );
421  rectangle.setYMinimum( ymin );
422  rectangle.setXMaximum( xmax );
423  rectangle.setYMaximum( ymax );
424  return in;
425 }
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:70
QgsRectangle buffer(double width)
Get rectangle enlarged by buffer.
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:203
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.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:38
void grow(double delta)
Grows the rectangle 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:118
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:191
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:75
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...
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
Definition: MathUtils.cc:437
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:106
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:91
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:80
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:96
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:101
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:65
void invert()
Swap x/y coordinates in the rectangle.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:125