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