QGIS API Documentation  2.99.0-Master (f1c3692)
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 "qgsgeometry.h"
28 #include "qgspointxy.h"
29 #include "qgsrectangle.h"
30 #include "qgslogger.h"
31 #include "qgsbox3d.h"
32 #include "qgspolygon.h"
33 #include "qgslinestring.h"
34 
35 QgsRectangle::QgsRectangle( double xMin, double yMin, double xMax, double yMax )
36  : mXmin( xMin )
37  , mYmin( yMin )
38  , mXmax( xMax )
39  , mYmax( yMax )
40 {
41  normalize();
42 }
43 
45 {
46  set( p1, p2 );
47 }
48 
49 QgsRectangle::QgsRectangle( QRectF const &qRectF )
50 {
51  mXmin = qRectF.topLeft().x();
52  mYmin = qRectF.topLeft().y();
53  mXmax = qRectF.bottomRight().x();
54  mYmax = qRectF.bottomRight().y();
55 }
56 
58 {
59  mXmin = r.xMinimum();
60  mYmin = r.yMinimum();
61  mXmax = r.xMaximum();
62  mYmax = r.yMaximum();
63 }
64 
65 QgsRectangle QgsRectangle::fromWkt( const QString &wkt )
66 {
67  QgsGeometry geom = QgsGeometry::fromWkt( wkt );
68  if ( geom.isMultipart() )
69  return QgsRectangle();
70 
71  QgsPolygonXY poly = geom.asPolygon();
72 
73  if ( poly.size() != 1 )
74  return QgsRectangle();
75 
76  QgsPolylineXY polyline = geom.asPolygon().at( 0 );
77  if ( polyline.size() == 5 && polyline.at( 0 ) == polyline.at( 4 ) && geom.isGeosValid() )
78  return QgsRectangle( polyline.at( 0 ).x(), polyline.at( 0 ).y(), polyline.at( 2 ).x(), polyline.at( 2 ).y() );
79  else
80  return QgsRectangle();
81 }
82 
84 {
85  double xMin = center.x() - width / 2.0;
86  double xMax = xMin + width;
87  double yMin = center.y() - height / 2.0;
88  double yMax = yMin + height;
89  return QgsRectangle( xMin, yMin, xMax, yMax );
90 }
91 
92 void QgsRectangle::set( const QgsPointXY &p1, const QgsPointXY &p2 )
93 {
94  mXmin = p1.x();
95  mXmax = p2.x();
96  mYmin = p1.y();
97  mYmax = p2.y();
98  normalize();
99 }
100 
101 void QgsRectangle::set( double xmin_, double ymin_, double xmax_, double ymax_ )
102 {
103  mXmin = xmin_;
104  mYmin = ymin_;
105  mXmax = xmax_;
106  mYmax = ymax_;
107  normalize();
108 }
109 
111 {
112  if ( isNull() )
113  return;
114 
115  if ( mXmin > mXmax )
116  {
117  std::swap( mXmin, mXmax );
118  }
119  if ( mYmin > mYmax )
120  {
121  std::swap( mYmin, mYmax );
122  }
123 }
124 
126 {
127  mXmin = std::numeric_limits<double>::max();
128  mYmin = std::numeric_limits<double>::max();
129  mXmax = -std::numeric_limits<double>::max();
130  mYmax = -std::numeric_limits<double>::max();
131 }
132 
133 void QgsRectangle::scale( double scaleFactor, const QgsPointXY *cp )
134 {
135  // scale from the center
136  double centerX, centerY;
137  if ( cp )
138  {
139  centerX = cp->x();
140  centerY = cp->y();
141  }
142  else
143  {
144  centerX = mXmin + width() / 2;
145  centerY = mYmin + height() / 2;
146  }
147  scale( scaleFactor, centerX, centerY );
148 }
149 
150 void QgsRectangle::scale( double scaleFactor, double centerX, double centerY )
151 {
152  double newWidth = width() * scaleFactor;
153  double newHeight = height() * scaleFactor;
154  mXmin = centerX - newWidth / 2.0;
155  mXmax = centerX + newWidth / 2.0;
156  mYmin = centerY - newHeight / 2.0;
157  mYmax = centerY + newHeight / 2.0;
158 }
159 
160 void QgsRectangle::grow( double delta )
161 {
162  mXmin -= delta;
163  mXmax += delta;
164  mYmin -= delta;
165  mYmax += delta;
166 }
167 
169 {
170  if ( p.x() < xMinimum() )
171  setXMinimum( p.x() );
172  else if ( p.x() > xMaximum() )
173  setXMaximum( p.x() );
174  if ( p.y() < yMinimum() )
175  setYMinimum( p.y() );
176  if ( p.y() > yMaximum() )
177  setYMaximum( p.y() );
178 }
179 
181 {
182  return QgsRectangle( mXmin - width, mYmin - width, mXmax + width, mYmax + width );
183 }
184 
186 {
187  QgsRectangle intersection = QgsRectangle();
188  if ( rect && intersects( *rect ) )
189  {
190  intersection.setXMinimum( mXmin > rect->xMinimum() ? mXmin : rect->xMinimum() );
191  intersection.setXMaximum( mXmax < rect->xMaximum() ? mXmax : rect->xMaximum() );
192  intersection.setYMinimum( mYmin > rect->yMinimum() ? mYmin : rect->yMinimum() );
193  intersection.setYMaximum( mYmax < rect->yMaximum() ? mYmax : rect->yMaximum() );
194  }
195  return intersection;
196 }
197 
198 bool QgsRectangle::intersects( const QgsRectangle &rect ) const
199 {
200  double x1 = ( mXmin > rect.mXmin ? mXmin : rect.mXmin );
201  double x2 = ( mXmax < rect.mXmax ? mXmax : rect.mXmax );
202  if ( x1 > x2 )
203  return false;
204  double y1 = ( mYmin > rect.mYmin ? mYmin : rect.mYmin );
205  double y2 = ( mYmax < rect.mYmax ? mYmax : rect.mYmax );
206  return y1 <= y2;
207 }
208 
209 bool QgsRectangle::contains( const QgsRectangle &rect ) const
210 {
211  return ( rect.mXmin >= mXmin && rect.mXmax <= mXmax && rect.mYmin >= mYmin && rect.mYmax <= mYmax );
212 }
213 
214 bool QgsRectangle::contains( const QgsPointXY &p ) const
215 {
216  return mXmin <= p.x() && p.x() <= mXmax &&
217  mYmin <= p.y() && p.y() <= mYmax;
218 }
219 
221 {
222  if ( isNull() )
223  *this = rect;
224  else
225  {
226  mXmin = ( ( mXmin < rect.xMinimum() ) ? mXmin : rect.xMinimum() );
227  mXmax = ( ( mXmax > rect.xMaximum() ) ? mXmax : rect.xMaximum() );
228 
229  mYmin = ( ( mYmin < rect.yMinimum() ) ? mYmin : rect.yMinimum() );
230  mYmax = ( ( mYmax > rect.yMaximum() ) ? mYmax : rect.yMaximum() );
231  }
232 
233 }
234 
235 void QgsRectangle::combineExtentWith( double x, double y )
236 {
237  if ( isNull() )
238  *this = QgsRectangle( x, y, x, y );
239  else
240  {
241  mXmin = ( ( mXmin < x ) ? mXmin : x );
242  mXmax = ( ( mXmax > x ) ? mXmax : x );
243 
244  mYmin = ( ( mYmin < y ) ? mYmin : y );
245  mYmax = ( ( mYmax > y ) ? mYmax : y );
246  }
247 }
248 
250 {
251  double xmin = mXmin - v.x();
252  double xmax = mXmax - v.x();
253  double ymin = mYmin - v.y();
254  double ymax = mYmax - v.y();
255  return QgsRectangle( xmin, ymin, xmax, ymax );
256 }
257 
259 {
260  double xmin = mXmin + v.x();
261  double xmax = mXmax + v.x();
262  double ymin = mYmin + v.y();
263  double ymax = mYmax + v.y();
264  return QgsRectangle( xmin, ymin, xmax, ymax );
265 }
266 
268 {
269  mXmin -= v.x();
270  mXmax -= v.x();
271  mYmin -= v.y();
272  mYmax -= v.y();
273  return *this;
274 }
275 
277 {
278  mXmin += v.x();
279  mXmax += v.x();
280  mYmin += v.y();
281  mYmax += v.y();
282  return *this;
283 }
284 
286 {
287  return mXmax < mXmin || mYmax < mYmin || qgsDoubleNear( mXmax, mXmin ) || qgsDoubleNear( mYmax, mYmin );
288 }
289 
291 {
292  // rectangle created QgsRectangle() or with rect.setMinimal() ?
293  return ( qgsDoubleNear( mXmin, 0.0 ) && qgsDoubleNear( mXmax, 0.0 ) && qgsDoubleNear( mYmin, 0.0 ) && qgsDoubleNear( mYmax, 0.0 ) ) ||
294  ( qgsDoubleNear( mXmin, std::numeric_limits<double>::max() ) && qgsDoubleNear( mYmin, std::numeric_limits<double>::max() ) &&
295  qgsDoubleNear( mXmax, -std::numeric_limits<double>::max() ) && qgsDoubleNear( mYmax, -std::numeric_limits<double>::max() ) );
296 }
297 
299 {
300  QString rep =
301  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
302  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmax );
303 
304  return rep;
305 }
306 
308 {
309  QString rep =
310  QStringLiteral( "POLYGON((" ) +
311  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
312  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
313  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmax ) + ", " +
314  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmax ) + ", " +
315  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) +
316  QStringLiteral( "))" );
317 
318  return rep;
319 }
320 
321 QRectF QgsRectangle::toRectF() const
322 {
323  return QRectF( static_cast< qreal >( mXmin ), static_cast< qreal >( mYmin ), static_cast< qreal >( mXmax - mXmin ), static_cast< qreal >( mYmax - mYmin ) );
324 }
325 
326 QString QgsRectangle::toString( int precision ) const
327 {
328  QString rep;
329 
330  if ( precision < 0 )
331  {
332  precision = 0;
333  if ( ( width() < 10 || height() < 10 ) && ( width() > 0 && height() > 0 ) )
334  {
335  precision = static_cast<int>( std::ceil( -1.0 * std::log10( std::min( width(), height() ) ) ) ) + 1;
336  // sanity check
337  if ( precision > 20 )
338  precision = 20;
339  }
340  }
341 
342  if ( isEmpty() )
343  rep = QStringLiteral( "Empty" );
344  else
345  rep = QStringLiteral( "%1,%2 : %3,%4" )
346  .arg( mXmin, 0, 'f', precision )
347  .arg( mYmin, 0, 'f', precision )
348  .arg( mXmax, 0, 'f', precision )
349  .arg( mYmax, 0, 'f', precision );
350 
351  QgsDebugMsgLevel( QString( "Extents : %1" ).arg( rep ), 4 );
352 
353  return rep;
354 }
355 
356 QString QgsRectangle::asPolygon() const
357 {
358 // QString rep = tmp.sprintf("%16f %16f,%16f %16f,%16f %16f,%16f %16f,%16f %16f",
359 // xmin, ymin, xmin, ymax, xmax, ymax, xmax, ymin, xmin, ymin);
360  QString rep;
361 
362  QTextStream foo( &rep );
363 
364  foo.setRealNumberPrecision( 8 );
365  foo.setRealNumberNotation( QTextStream::FixedNotation );
366  // NOTE: a polygon isn't a polygon unless its closed. In the case of
367  // a rectangle, that means 5 points (last == first)
368  foo
369  << mXmin << ' ' << mYmin << ", "
370  << mXmin << ' ' << mYmax << ", "
371  << mXmax << ' ' << mYmax << ", "
372  << mXmax << ' ' << mYmin << ", "
373  << mXmin << ' ' << mYmin;
374 
375  return rep;
376 
377 }
378 
379 bool QgsRectangle::operator==( const QgsRectangle &r1 ) const
380 {
381  return qgsDoubleNear( r1.xMaximum(), xMaximum() ) &&
382  qgsDoubleNear( r1.xMinimum(), xMinimum() ) &&
383  qgsDoubleNear( r1.yMaximum(), yMaximum() ) &&
384  qgsDoubleNear( r1.yMinimum(), yMinimum() );
385 }
386 
387 bool QgsRectangle::operator!=( const QgsRectangle &r1 ) const
388 {
389  return ( ! operator==( r1 ) );
390 }
391 
393 {
394  if ( &r != this )
395  {
396  mXmax = r.xMaximum();
397  mXmin = r.xMinimum();
398  mYmax = r.yMaximum();
399  mYmin = r.yMinimum();
400  }
401 
402  return *this;
403 }
404 
406 {
407  if ( std::isinf( mXmin ) || std::isinf( mYmin ) || std::isinf( mXmax ) || std::isinf( mYmax ) )
408  {
409  return false;
410  }
411  if ( std::isnan( mXmin ) || std::isnan( mYmin ) || std::isnan( mXmax ) || std::isnan( mYmax ) )
412  {
413  return false;
414  }
415  return true;
416 }
417 
419 {
420  std::swap( mXmin, mYmin );
421  std::swap( mXmax, mYmax );
422 }
423 
424 QgsBox3d QgsRectangle::toBox3d( double zMin, double zMax ) const
425 {
426  return QgsBox3d( mXmin, mYmin, zMin, mXmax, mYmax, zMax );
427 }
428 
429 QDataStream &operator<<( QDataStream &out, const QgsRectangle &rectangle )
430 {
431  out << rectangle.xMinimum() << rectangle.yMinimum() << rectangle.xMaximum() << rectangle.yMaximum();
432  return out;
433 }
434 
435 QDataStream &operator>>( QDataStream &in, QgsRectangle &rectangle )
436 {
437  double xmin, ymin, xmax, ymax;
438  in >> xmin >> ymin >> xmax >> ymax;
439  rectangle.setXMinimum( xmin );
440  rectangle.setYMinimum( ymin );
441  rectangle.setXMaximum( xmax );
442  rectangle.setYMaximum( ymax );
443  return in;
444 }
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:39
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:90
static QgsRectangle fromWkt(const QString &wkt)
Creates a new rectangle from a wkt string.
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
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.
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item...
Definition: qgsgeometry.h:73
void include(const QgsPointXY &p)
Updates the rectangle to include the specified point.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
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:35
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:227
bool isGeosValid() const
Checks validity of the geometry using GEOS.
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.
static QgsRectangle fromCenterAndSize(QgsPointXY center, double width, double height)
Creates a new rectangle, given the specified center point and width and height.
#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.
QgsPolygonXY asPolygon() const
Returns contents of the geometry as a polygon if wkbType is WKBPolygon, otherwise an empty list...
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:138
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:213
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:95
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:47
A class to represent a vector.
Definition: qgsvector.h:27
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:126
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:111
void combineExtentWith(const QgsRectangle &rect)
Expand the rectangle so that covers both the original rectangle and the given rectangle.
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
bool operator==(const QgsRectangle &r1) const
Comparison operator.
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Definition: qgsgeometry.h:49
QRectF toRectF() const
Returns a QRectF with same coordinates as the rectangle.
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:100
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:116
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:121
double x() const
Returns the vector&#39;s x-component.
Definition: qgsvector.cpp:76
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:166
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:81
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:85
void invert()
Swap x/y coordinates in the rectangle.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:145