QGIS API Documentation  2.99.0-Master (9fdd060)
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 
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 QgsRectangle QgsRectangle::fromWkt( const QString &wkt )
64 {
65  QgsGeometry geom = QgsGeometry::fromWkt( wkt );
66  if ( geom.isMultipart() )
67  return QgsRectangle();
68 
69  QgsPolygon poly = geom.asPolygon();
70 
71  if ( poly.size() != 1 )
72  return QgsRectangle();
73 
74  QgsPolyline polyline = geom.asPolygon().at( 0 );
75  if ( polyline.size() == 5 && polyline.at( 0 ) == polyline.at( 4 ) && geom.isGeosValid() )
76  return QgsRectangle( polyline.at( 0 ).x(), polyline.at( 0 ).y(), polyline.at( 2 ).x(), polyline.at( 2 ).y() );
77  else
78  return QgsRectangle();
79 }
80 
81 void QgsRectangle::set( const QgsPointXY &p1, const QgsPointXY &p2 )
82 {
83  mXmin = p1.x();
84  mXmax = p2.x();
85  mYmin = p1.y();
86  mYmax = p2.y();
87  normalize();
88 }
89 
90 void QgsRectangle::set( double xmin_, double ymin_, double xmax_, double ymax_ )
91 {
92  mXmin = xmin_;
93  mYmin = ymin_;
94  mXmax = xmax_;
95  mYmax = ymax_;
96  normalize();
97 }
98 
100 {
101  if ( isNull() )
102  return;
103 
104  if ( mXmin > mXmax )
105  {
106  std::swap( mXmin, mXmax );
107  }
108  if ( mYmin > mYmax )
109  {
110  std::swap( mYmin, mYmax );
111  }
112 }
113 
115 {
116  mXmin = std::numeric_limits<double>::max();
117  mYmin = std::numeric_limits<double>::max();
118  mXmax = -std::numeric_limits<double>::max();
119  mYmax = -std::numeric_limits<double>::max();
120 }
121 
122 void QgsRectangle::scale( double scaleFactor, const QgsPointXY *cp )
123 {
124  // scale from the center
125  double centerX, centerY;
126  if ( cp )
127  {
128  centerX = cp->x();
129  centerY = cp->y();
130  }
131  else
132  {
133  centerX = mXmin + width() / 2;
134  centerY = mYmin + height() / 2;
135  }
136  scale( scaleFactor, centerX, centerY );
137 }
138 
139 void QgsRectangle::scale( double scaleFactor, double centerX, double centerY )
140 {
141  double newWidth = width() * scaleFactor;
142  double newHeight = height() * scaleFactor;
143  mXmin = centerX - newWidth / 2.0;
144  mXmax = centerX + newWidth / 2.0;
145  mYmin = centerY - newHeight / 2.0;
146  mYmax = centerY + newHeight / 2.0;
147 }
148 
149 void QgsRectangle::grow( double delta )
150 {
151  mXmin -= delta;
152  mXmax += delta;
153  mYmin -= delta;
154  mYmax += delta;
155 }
156 
158 {
159  if ( p.x() < xMinimum() )
160  setXMinimum( p.x() );
161  else if ( p.x() > xMaximum() )
162  setXMaximum( p.x() );
163  if ( p.y() < yMinimum() )
164  setYMinimum( p.y() );
165  if ( p.y() > yMaximum() )
166  setYMaximum( p.y() );
167 }
168 
170 {
171  return QgsRectangle( mXmin - width, mYmin - width, mXmax + width, mYmax + width );
172 }
173 
175 {
176  QgsRectangle intersection = QgsRectangle();
177  if ( rect && intersects( *rect ) )
178  {
179  intersection.setXMinimum( mXmin > rect->xMinimum() ? mXmin : rect->xMinimum() );
180  intersection.setXMaximum( mXmax < rect->xMaximum() ? mXmax : rect->xMaximum() );
181  intersection.setYMinimum( mYmin > rect->yMinimum() ? mYmin : rect->yMinimum() );
182  intersection.setYMaximum( mYmax < rect->yMaximum() ? mYmax : rect->yMaximum() );
183  }
184  return intersection;
185 }
186 
187 bool QgsRectangle::intersects( const QgsRectangle &rect ) const
188 {
189  double x1 = ( mXmin > rect.mXmin ? mXmin : rect.mXmin );
190  double x2 = ( mXmax < rect.mXmax ? mXmax : rect.mXmax );
191  if ( x1 > x2 )
192  return false;
193  double y1 = ( mYmin > rect.mYmin ? mYmin : rect.mYmin );
194  double y2 = ( mYmax < rect.mYmax ? mYmax : rect.mYmax );
195  return y1 <= y2;
196 }
197 
198 bool QgsRectangle::contains( const QgsRectangle &rect ) const
199 {
200  return ( rect.mXmin >= mXmin && rect.mXmax <= mXmax && rect.mYmin >= mYmin && rect.mYmax <= mYmax );
201 }
202 
203 bool QgsRectangle::contains( const QgsPointXY &p ) const
204 {
205  return mXmin <= p.x() && p.x() <= mXmax &&
206  mYmin <= p.y() && p.y() <= mYmax;
207 }
208 
210 {
211  if ( isNull() )
212  *this = rect;
213  else
214  {
215  mXmin = ( ( mXmin < rect.xMinimum() ) ? mXmin : rect.xMinimum() );
216  mXmax = ( ( mXmax > rect.xMaximum() ) ? mXmax : rect.xMaximum() );
217 
218  mYmin = ( ( mYmin < rect.yMinimum() ) ? mYmin : rect.yMinimum() );
219  mYmax = ( ( mYmax > rect.yMaximum() ) ? mYmax : rect.yMaximum() );
220  }
221 
222 }
223 
224 void QgsRectangle::combineExtentWith( double x, double y )
225 {
226  if ( isNull() )
227  *this = QgsRectangle( x, y, x, y );
228  else
229  {
230  mXmin = ( ( mXmin < x ) ? mXmin : x );
231  mXmax = ( ( mXmax > x ) ? mXmax : x );
232 
233  mYmin = ( ( mYmin < y ) ? mYmin : y );
234  mYmax = ( ( mYmax > y ) ? mYmax : y );
235  }
236 }
237 
239 {
240  double xmin = mXmin - v.x();
241  double xmax = mXmax - v.x();
242  double ymin = mYmin - v.y();
243  double ymax = mYmax - v.y();
244  return QgsRectangle( xmin, ymin, xmax, ymax );
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  mXmin -= v.x();
259  mXmax -= v.x();
260  mYmin -= v.y();
261  mYmax -= v.y();
262  return *this;
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  return mXmax < mXmin || mYmax < mYmin || qgsDoubleNear( mXmax, mXmin ) || qgsDoubleNear( mYmax, mYmin );
277 }
278 
280 {
281  // rectangle created QgsRectangle() or with rect.setMinimal() ?
282  return ( qgsDoubleNear( mXmin, 0.0 ) && qgsDoubleNear( mXmax, 0.0 ) && qgsDoubleNear( mYmin, 0.0 ) && qgsDoubleNear( mYmax, 0.0 ) ) ||
283  ( qgsDoubleNear( mXmin, std::numeric_limits<double>::max() ) && qgsDoubleNear( mYmin, std::numeric_limits<double>::max() ) &&
284  qgsDoubleNear( mXmax, -std::numeric_limits<double>::max() ) && qgsDoubleNear( mYmax, -std::numeric_limits<double>::max() ) );
285 }
286 
288 {
289  QString rep =
290  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
291  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmax );
292 
293  return rep;
294 }
295 
297 {
298  QString rep =
299  QStringLiteral( "POLYGON((" ) +
300  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
301  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmin ) + ", " +
302  qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmax ) + ", " +
303  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmax ) + ", " +
304  qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) +
305  QStringLiteral( "))" );
306 
307  return rep;
308 }
309 
310 QRectF QgsRectangle::toRectF() const
311 {
312  return QRectF( static_cast< qreal >( mXmin ), static_cast< qreal >( mYmin ), static_cast< qreal >( mXmax - mXmin ), static_cast< qreal >( mYmax - mYmin ) );
313 }
314 
315 QString QgsRectangle::toString( int precision ) const
316 {
317  QString rep;
318 
319  if ( precision < 0 )
320  {
321  precision = 0;
322  if ( ( width() < 10 || height() < 10 ) && ( width() > 0 && height() > 0 ) )
323  {
324  precision = static_cast<int>( std::ceil( -1.0 * std::log10( std::min( width(), height() ) ) ) ) + 1;
325  // sanity check
326  if ( precision > 20 )
327  precision = 20;
328  }
329  }
330 
331  if ( isEmpty() )
332  rep = QStringLiteral( "Empty" );
333  else
334  rep = QStringLiteral( "%1,%2 : %3,%4" )
335  .arg( mXmin, 0, 'f', precision )
336  .arg( mYmin, 0, 'f', precision )
337  .arg( mXmax, 0, 'f', precision )
338  .arg( mYmax, 0, 'f', precision );
339 
340  QgsDebugMsgLevel( QString( "Extents : %1" ).arg( rep ), 4 );
341 
342  return rep;
343 }
344 
345 QString QgsRectangle::asPolygon() const
346 {
347 // QString rep = tmp.sprintf("%16f %16f,%16f %16f,%16f %16f,%16f %16f,%16f %16f",
348 // xmin, ymin, xmin, ymax, xmax, ymax, xmax, ymin, xmin, ymin);
349  QString rep;
350 
351  QTextStream foo( &rep );
352 
353  foo.setRealNumberPrecision( 8 );
354  foo.setRealNumberNotation( QTextStream::FixedNotation );
355  // NOTE: a polygon isn't a polygon unless its closed. In the case of
356  // a rectangle, that means 5 points (last == first)
357  foo
358  << mXmin << ' ' << mYmin << ", "
359  << mXmin << ' ' << mYmax << ", "
360  << mXmax << ' ' << mYmax << ", "
361  << mXmax << ' ' << mYmin << ", "
362  << mXmin << ' ' << mYmin;
363 
364  return rep;
365 
366 }
367 
368 bool QgsRectangle::operator==( const QgsRectangle &r1 ) const
369 {
370  return qgsDoubleNear( r1.xMaximum(), xMaximum() ) &&
371  qgsDoubleNear( r1.xMinimum(), xMinimum() ) &&
372  qgsDoubleNear( r1.yMaximum(), yMaximum() ) &&
373  qgsDoubleNear( r1.yMinimum(), yMinimum() );
374 }
375 
376 bool QgsRectangle::operator!=( const QgsRectangle &r1 ) const
377 {
378  return ( ! operator==( r1 ) );
379 }
380 
382 {
383  if ( &r != this )
384  {
385  mXmax = r.xMaximum();
386  mXmin = r.xMinimum();
387  mYmax = r.yMaximum();
388  mYmin = r.yMinimum();
389  }
390 
391  return *this;
392 }
393 
395 {
396  if ( std::isinf( mXmin ) || std::isinf( mYmin ) || std::isinf( mXmax ) || std::isinf( mYmax ) )
397  {
398  return false;
399  }
400  if ( std::isnan( mXmin ) || std::isnan( mYmin ) || std::isnan( mXmax ) || std::isnan( mYmax ) )
401  {
402  return false;
403  }
404  return true;
405 }
406 
408 {
409  std::swap( mXmin, mYmin );
410  std::swap( mXmax, mYmax );
411 }
412 
413 QgsBox3d QgsRectangle::toBox3d( double zMin, double zMax ) const
414 {
415  return QgsBox3d( mXmin, mYmin, zMin, mXmax, mYmax, zMax );
416 }
417 
418 QDataStream &operator<<( QDataStream &out, const QgsRectangle &rectangle )
419 {
420  out << rectangle.xMinimum() << rectangle.yMinimum() << rectangle.xMaximum() << rectangle.yMaximum();
421  return out;
422 }
423 
424 QDataStream &operator>>( QDataStream &in, QgsRectangle &rectangle )
425 {
426  double xmin, ymin, xmax, ymax;
427  in >> xmin >> ymin >> xmax >> ymax;
428  rectangle.setXMinimum( xmin );
429  rectangle.setYMinimum( ymin );
430  rectangle.setXMaximum( xmax );
431  rectangle.setYMaximum( ymax );
432  return in;
433 }
QgsPolygon asPolygon() const
Returns contents of the geometry as a polygon if wkbType is WKBPolygon, otherwise an empty list...
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:83
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.
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:94
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.
QVector< QgsPointXY > QgsPolyline
Polyline is represented as a vector of points.
Definition: qgsgeometry.h:49
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:131
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:88
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...
QVector< QgsPolyline > QgsPolygon
Polygon: first item of the list is outer ring, inner rings (if any) start from second item...
Definition: qgsgeometry.h:56
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:119
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:104
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.
QRectF toRectF() const
Returns a QRectF with same coordinates as the rectangle.
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:93
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:109
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:114
double x() const
Returns the vector&#39;s x-component.
Definition: qgsvector.cpp:76
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:78
void invert()
Swap x/y coordinates in the rectangle.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:138