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 "qgsgeometry.h"
19 #include "qgspointxy.h"
20 #include "qgsrectangle.h"
21 #include "qgslogger.h"
22 #include "qgsbox3d.h"
23 #include "qgspolygon.h"
24 #include "qgslinestring.h"
25
26 #include <QString>
27 #include <QTextStream>
28 #include <QTransform>
29
30 #include <algorithm>
31 #include <cmath>
32 #include <limits>
33
fromWkt(const QString & wkt)34 QgsRectangle QgsRectangle::fromWkt( const QString &wkt )
35 {
36 const QgsGeometry geom = QgsGeometry::fromWkt( wkt );
37 if ( geom.isMultipart() )
38 return QgsRectangle();
39
40 const QgsPolygonXY poly = geom.asPolygon();
41
42 if ( poly.size() != 1 )
43 return QgsRectangle();
44
45 const QgsPolylineXY polyline = geom.asPolygon().at( 0 );
46 if ( polyline.size() == 5 && polyline.at( 0 ) == polyline.at( 4 ) && geom.isGeosValid() )
47 return QgsRectangle( polyline.at( 0 ).x(), polyline.at( 0 ).y(), polyline.at( 2 ).x(), polyline.at( 2 ).y() );
48 else
49 return QgsRectangle();
50 }
51
fromCenterAndSize(const QgsPointXY & center,double width,double height)52 QgsRectangle QgsRectangle::fromCenterAndSize( const QgsPointXY ¢er, double width, double height )
53 {
54 const double xMin = center.x() - width / 2.0;
55 const double xMax = xMin + width;
56 const double yMin = center.y() - height / 2.0;
57 const double yMax = yMin + height;
58 return QgsRectangle( xMin, yMin, xMax, yMax );
59 }
60
scaled(double scaleFactor,const QgsPointXY * center) const61 QgsRectangle QgsRectangle::scaled( double scaleFactor, const QgsPointXY *center ) const
62 {
63 QgsRectangle scaledRect = QgsRectangle( *this );
64 scaledRect.scale( scaleFactor, center );
65 return scaledRect;
66 }
67
operator -(const QgsVector v) const68 QgsRectangle QgsRectangle::operator-( const QgsVector v ) const
69 {
70 const double xmin = mXmin - v.x();
71 const double xmax = mXmax - v.x();
72 const double ymin = mYmin - v.y();
73 const double ymax = mYmax - v.y();
74 return QgsRectangle( xmin, ymin, xmax, ymax );
75 }
76
operator +(const QgsVector v) const77 QgsRectangle QgsRectangle::operator+( const QgsVector v ) const
78 {
79 const double xmin = mXmin + v.x();
80 const double xmax = mXmax + v.x();
81 const double ymin = mYmin + v.y();
82 const double ymax = mYmax + v.y();
83 return QgsRectangle( xmin, ymin, xmax, ymax );
84 }
85
operator -=(const QgsVector v)86 QgsRectangle &QgsRectangle::operator-=( const QgsVector v )
87 {
88 mXmin -= v.x();
89 mXmax -= v.x();
90 mYmin -= v.y();
91 mYmax -= v.y();
92 return *this;
93 }
94
operator +=(const QgsVector v)95 QgsRectangle &QgsRectangle::operator+=( const QgsVector v )
96 {
97 mXmin += v.x();
98 mXmax += v.x();
99 mYmin += v.y();
100 mYmax += v.y();
101 return *this;
102 }
103
asWktCoordinates() const104 QString QgsRectangle::asWktCoordinates() const
105 {
106 QString rep =
107 qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) + QLatin1String( ", " ) +
108 qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmax );
109
110 return rep;
111 }
112
asWktPolygon() const113 QString QgsRectangle::asWktPolygon() const
114 {
115 QString rep =
116 QLatin1String( "POLYGON((" ) +
117 qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) + QLatin1String( ", " ) +
118 qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmin ) + QLatin1String( ", " ) +
119 qgsDoubleToString( mXmax ) + ' ' + qgsDoubleToString( mYmax ) + QLatin1String( ", " ) +
120 qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmax ) + QLatin1String( ", " ) +
121 qgsDoubleToString( mXmin ) + ' ' + qgsDoubleToString( mYmin ) +
122 QStringLiteral( "))" );
123
124 return rep;
125 }
126
toString(int precision) const127 QString QgsRectangle::toString( int precision ) const
128 {
129 QString rep;
130
131 if ( precision < 0 )
132 {
133 precision = 0;
134 if ( ( width() < 10 || height() < 10 ) && ( width() > 0 && height() > 0 ) )
135 {
136 precision = static_cast<int>( std::ceil( -1.0 * std::log10( std::min( width(), height() ) ) ) ) + 1;
137 // sanity check
138 if ( precision > 20 )
139 precision = 20;
140 }
141 }
142
143 if ( isEmpty() )
144 rep = QStringLiteral( "Empty" );
145 else
146 rep = QStringLiteral( "%1,%2 : %3,%4" )
147 .arg( mXmin, 0, 'f', precision )
148 .arg( mYmin, 0, 'f', precision )
149 .arg( mXmax, 0, 'f', precision )
150 .arg( mYmax, 0, 'f', precision );
151
152 QgsDebugMsgLevel( QStringLiteral( "Extents : %1" ).arg( rep ), 4 );
153
154 return rep;
155 }
156
asPolygon() const157 QString QgsRectangle::asPolygon() const
158 {
159 // QString rep = tmp.sprintf("%16f %16f,%16f %16f,%16f %16f,%16f %16f,%16f %16f",
160 // xmin, ymin, xmin, ymax, xmax, ymax, xmax, ymin, xmin, ymin);
161 QString rep;
162
163 QTextStream foo( &rep );
164
165 foo.setRealNumberPrecision( 8 );
166 foo.setRealNumberNotation( QTextStream::FixedNotation );
167 // NOTE: a polygon isn't a polygon unless its closed. In the case of
168 // a rectangle, that means 5 points (last == first)
169 foo
170 << mXmin << ' ' << mYmin << ", "
171 << mXmin << ' ' << mYmax << ", "
172 << mXmax << ' ' << mYmax << ", "
173 << mXmax << ' ' << mYmin << ", "
174 << mXmin << ' ' << mYmin;
175
176 return rep;
177
178 }
179
toBox3d(double zMin,double zMax) const180 QgsBox3d QgsRectangle::toBox3d( double zMin, double zMax ) const
181 {
182 return QgsBox3d( mXmin, mYmin, zMin, mXmax, mYmax, zMax );
183 }
184
snappedToGrid(double spacing) const185 QgsRectangle QgsRectangle::snappedToGrid( double spacing ) const
186 {
187 // helper function
188 auto gridifyValue = []( double value, double spacing ) -> double
189 {
190 if ( spacing > 0 )
191 return std::round( value / spacing ) * spacing;
192 else
193 return value;
194 };
195
196 return QgsRectangle(
197 gridifyValue( mXmin, spacing ),
198 gridifyValue( mYmin, spacing ),
199 gridifyValue( mXmax, spacing ),
200 gridifyValue( mYmax, spacing )
201 );
202 }
203
operator <<(QDataStream & out,const QgsRectangle & rectangle)204 QDataStream &operator<<( QDataStream &out, const QgsRectangle &rectangle )
205 {
206 out << rectangle.xMinimum() << rectangle.yMinimum() << rectangle.xMaximum() << rectangle.yMaximum();
207 return out;
208 }
209
operator >>(QDataStream & in,QgsRectangle & rectangle)210 QDataStream &operator>>( QDataStream &in, QgsRectangle &rectangle )
211 {
212 double xmin, ymin, xmax, ymax;
213 in >> xmin >> ymin >> xmax >> ymax;
214 rectangle.setXMinimum( xmin );
215 rectangle.setYMinimum( ymin );
216 rectangle.setXMaximum( xmax );
217 rectangle.setYMaximum( ymax );
218 return in;
219 }
220