QGIS API Documentation  2.99.0-Master (19b062c)
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 if ( !rect.isNull() )
225  {
226  mXmin = std::min( mXmin, rect.xMinimum() );
227  mXmax = std::max( mXmax, rect.xMaximum() );
228  mYmin = std::min( mYmin, rect.yMinimum() );
229  mYmax = std::max( mYmax, rect.yMaximum() );;
230  }
231 }
232 
233 void QgsRectangle::combineExtentWith( double x, double y )
234 {
235  if ( isNull() )
236  *this = QgsRectangle( x, y, x, y );
237  else
238  {
239  mXmin = ( ( mXmin < x ) ? mXmin : x );
240  mXmax = ( ( mXmax > x ) ? mXmax : x );
241 
242  mYmin = ( ( mYmin < y ) ? mYmin : y );
243  mYmax = ( ( mYmax > y ) ? mYmax : y );
244  }
245 }
246 
248 {
249  double xmin = mXmin - v.x();
250  double xmax = mXmax - v.x();
251  double ymin = mYmin - v.y();
252  double ymax = mYmax - v.y();
253  return QgsRectangle( xmin, ymin, xmax, ymax );
254 }
255 
257 {
258  double xmin = mXmin + v.x();
259  double xmax = mXmax + v.x();
260  double ymin = mYmin + v.y();
261  double ymax = mYmax + v.y();
262  return QgsRectangle( xmin, ymin, xmax, ymax );
263 }
264 
266 {
267  mXmin -= v.x();
268  mXmax -= v.x();
269  mYmin -= v.y();
270  mYmax -= v.y();
271  return *this;
272 }
273 
275 {
276  mXmin += v.x();
277  mXmax += v.x();
278  mYmin += v.y();
279  mYmax += v.y();
280  return *this;
281 }
282 
284 {
285  return mXmax < mXmin || mYmax < mYmin || qgsDoubleNear( mXmax, mXmin ) || qgsDoubleNear( mYmax, mYmin );
286 }
287 
289 {
290  // rectangle created QgsRectangle() or with rect.setMinimal() ?
291  return ( qgsDoubleNear( mXmin, 0.0 ) && qgsDoubleNear( mXmax, 0.0 ) && qgsDoubleNear( mYmin, 0.0 ) && qgsDoubleNear( mYmax, 0.0 ) ) ||
292  ( qgsDoubleNear( mXmin, std::numeric_limits<double>::max() ) && qgsDoubleNear( mYmin, std::numeric_limits<double>::max() ) &&
293  qgsDoubleNear( mXmax, -std::numeric_limits<double>::max() ) && qgsDoubleNear( mYmax, -std::numeric_limits<double>::max() ) );
294 }
295 
297 {
298  QString rep =
299  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
300  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmax );
301 
302  return rep;
303 }
304 
306 {
307  QString rep =
308  QStringLiteral( "POLYGON((" ) +
309  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
310  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
311  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmax ) + ", " +
312  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmax ) + ", " +
313  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) +
314  QStringLiteral( "))" );
315 
316  return rep;
317 }
318 
319 QRectF QgsRectangle::toRectF() const
320 {
321  return QRectF( static_cast< qreal >( mXmin ), static_cast< qreal >( mYmin ), static_cast< qreal >( mXmax - mXmin ), static_cast< qreal >( mYmax - mYmin ) );
322 }
323 
324 QString QgsRectangle::toString( int precision ) const
325 {
326  QString rep;
327 
328  if ( precision < 0 )
329  {
330  precision = 0;
331  if ( ( width() < 10 || height() < 10 ) && ( width() > 0 && height() > 0 ) )
332  {
333  precision = static_cast<int>( std::ceil( -1.0 * std::log10( std::min( width(), height() ) ) ) ) + 1;
334  // sanity check
335  if ( precision > 20 )
336  precision = 20;
337  }
338  }
339 
340  if ( isEmpty() )
341  rep = QStringLiteral( "Empty" );
342  else
343  rep = QStringLiteral( "%1,%2 : %3,%4" )
344  .arg( mXmin, 0, 'f', precision )
345  .arg( mYmin, 0, 'f', precision )
346  .arg( mXmax, 0, 'f', precision )
347  .arg( mYmax, 0, 'f', precision );
348 
349  QgsDebugMsgLevel( QString( "Extents : %1" ).arg( rep ), 4 );
350 
351  return rep;
352 }
353 
354 QString QgsRectangle::asPolygon() const
355 {
356 // QString rep = tmp.sprintf("%16f %16f,%16f %16f,%16f %16f,%16f %16f,%16f %16f",
357 // xmin, ymin, xmin, ymax, xmax, ymax, xmax, ymin, xmin, ymin);
358  QString rep;
359 
360  QTextStream foo( &rep );
361 
362  foo.setRealNumberPrecision( 8 );
363  foo.setRealNumberNotation( QTextStream::FixedNotation );
364  // NOTE: a polygon isn't a polygon unless its closed. In the case of
365  // a rectangle, that means 5 points (last == first)
366  foo
367  << mXmin << ' ' << mYmin << ", "
368  << mXmin << ' ' << mYmax << ", "
369  << mXmax << ' ' << mYmax << ", "
370  << mXmax << ' ' << mYmin << ", "
371  << mXmin << ' ' << mYmin;
372 
373  return rep;
374 
375 }
376 
377 bool QgsRectangle::operator==( const QgsRectangle &r1 ) const
378 {
379  return qgsDoubleNear( r1.xMaximum(), xMaximum() ) &&
380  qgsDoubleNear( r1.xMinimum(), xMinimum() ) &&
381  qgsDoubleNear( r1.yMaximum(), yMaximum() ) &&
382  qgsDoubleNear( r1.yMinimum(), yMinimum() );
383 }
384 
385 bool QgsRectangle::operator!=( const QgsRectangle &r1 ) const
386 {
387  return ( ! operator==( r1 ) );
388 }
389 
391 {
392  if ( &r != this )
393  {
394  mXmax = r.xMaximum();
395  mXmin = r.xMinimum();
396  mYmax = r.yMaximum();
397  mYmin = r.yMinimum();
398  }
399 
400  return *this;
401 }
402 
404 {
405  if ( std::isinf( mXmin ) || std::isinf( mYmin ) || std::isinf( mXmax ) || std::isinf( mYmax ) )
406  {
407  return false;
408  }
409  if ( std::isnan( mXmin ) || std::isnan( mYmin ) || std::isnan( mXmax ) || std::isnan( mYmax ) )
410  {
411  return false;
412  }
413  return true;
414 }
415 
417 {
418  std::swap( mXmin, mYmin );
419  std::swap( mXmax, mYmax );
420 }
421 
422 QgsBox3d QgsRectangle::toBox3d( double zMin, double zMax ) const
423 {
424  return QgsBox3d( mXmin, mYmin, zMin, mXmax, mYmax, zMax );
425 }
426 
427 QDataStream &operator<<( QDataStream &out, const QgsRectangle &rectangle )
428 {
429  out << rectangle.xMinimum() << rectangle.yMinimum() << rectangle.xMaximum() << rectangle.yMaximum();
430  return out;
431 }
432 
433 QDataStream &operator>>( QDataStream &in, QgsRectangle &rectangle )
434 {
435  double xmin, ymin, xmax, ymax;
436  in >> xmin >> ymin >> xmax >> ymax;
437  rectangle.setXMinimum( xmin );
438  rectangle.setYMinimum( ymin );
439  rectangle.setXMaximum( xmax );
440  rectangle.setYMaximum( ymax );
441  return in;
442 }
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