QGIS API Documentation 4.1.0-Master (60fea48833c)
Loading...
Searching...
No Matches
qgsbox3d.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsbox3d.cpp
3 ------------
4 begin : April 2017
5 copyright : (C) 2017 by Nyall Dawson
6 email : nyall dot dawson at gmail dot 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 "qgsbox3d.h"
19
20#include "qgslogger.h"
21#include "qgspoint.h"
22#include "qgsvector3d.h"
23
24#include <QString>
25
26#include "moc_qgsbox3d.cpp"
27
28using namespace Qt::StringLiterals;
29
30QgsBox3D::QgsBox3D( double xmin, double ymin, double zmin, double xmax, double ymax, double zmax, bool normalize )
31 : mBounds2d( xmin, ymin, xmax, ymax, false )
32 , mZmin( zmin )
33 , mZmax( zmax )
34{
35 if ( normalize )
36 {
38 }
39}
40
41QgsBox3D::QgsBox3D( const QgsPoint &p1, const QgsPoint &p2, bool normalize )
42 : mBounds2d( p1.x(), p1.y(), p2.x(), p2.y(), false )
43 , mZmin( p1.z() )
44 , mZmax( p2.z() )
45{
46 if ( normalize )
47 {
49 }
50}
51
52QgsBox3D::QgsBox3D( const QgsRectangle &rect, double zMin, double zMax, bool normalize )
53 : mBounds2d( rect )
54 , mZmin( zMin )
55 , mZmax( zMax )
56{
57 if ( normalize )
58 {
60 }
61}
62
63QgsBox3D::QgsBox3D( const QgsVector3D &corner1, const QgsVector3D &corner2, bool normalize )
64 : mBounds2d( corner1.x(), corner1.y(), corner2.x(), corner2.y(), false )
65 , mZmin( corner1.z() )
66 , mZmax( corner2.z() )
67{
68 if ( normalize )
69 {
71 }
72}
73
74void QgsBox3D::setXMinimum( double x )
75{
76 mBounds2d.setXMinimum( x );
77}
78
79void QgsBox3D::setXMaximum( double x )
80{
81 mBounds2d.setXMaximum( x );
82}
83
84void QgsBox3D::setYMinimum( double y )
85{
86 mBounds2d.setYMinimum( y );
87}
88
89void QgsBox3D::setYMaximum( double y )
90{
91 mBounds2d.setYMaximum( y );
92}
93
94void QgsBox3D::setZMinimum( double z )
95{
96 mZmin = z;
97}
98
99void QgsBox3D::setZMaximum( double z )
100{
101 mZmax = z;
102}
103
109{
110 mBounds2d.setNull();
111 mZmin = std::numeric_limits<double>::max();
112 mZmax = -std::numeric_limits<double>::max();
113}
114
116{
117 mBounds2d.normalize();
118 if ( mZmin > mZmax )
119 {
120 std::swap( mZmin, mZmax );
121 }
122}
123
125{
126 return QgsVector3D( 0.5 * ( mBounds2d.xMinimum() + mBounds2d.xMaximum() ), 0.5 * ( mBounds2d.yMinimum() + mBounds2d.yMaximum() ), 0.5 * ( mZmin + mZmax ) );
127}
128
130{
131 const QgsRectangle intersect2d = mBounds2d.intersect( other.mBounds2d );
132 const double zMin = std::max( mZmin, other.mZmin );
133 const double zMax = std::min( mZmax, other.mZmax );
134 return QgsBox3D( intersect2d.xMinimum(), intersect2d.yMinimum(), zMin, intersect2d.xMaximum(), intersect2d.yMaximum(), zMax );
135}
136
137bool QgsBox3D::is2d() const
138{
139 return qgsDoubleNear( mZmin, mZmax ) || ( mZmin > mZmax ) || std::isnan( mZmin ) || std::isnan( mZmax );
140}
141
142bool QgsBox3D::is3D() const
143{
144 return !is2d() && !isNull();
145}
146
147bool QgsBox3D::intersects( const QgsBox3D &other ) const
148{
149 if ( !mBounds2d.intersects( other.mBounds2d ) )
150 return false;
151
152 if ( other.is2d() || is2d() )
153 {
154 return true;
155 }
156 else
157 {
158 const double z1 = ( mZmin > other.mZmin ? mZmin : other.mZmin );
159 const double z2 = ( mZmax < other.mZmax ? mZmax : other.mZmax );
160 return z1 <= z2;
161 }
162}
163
164bool QgsBox3D::contains( const QgsBox3D &other ) const
165{
166 if ( !mBounds2d.contains( other.mBounds2d ) )
167 return false;
168
169 if ( other.is2d() || is2d() )
170 {
171 return true;
172 }
173 else
174 {
175 return ( other.mZmin >= mZmin && other.mZmax <= mZmax );
176 }
177}
178
179bool QgsBox3D::contains( const QgsPoint &p ) const
180{
181 if ( is3D() )
182 {
183 return contains( p.x(), p.y(), p.z() );
184 }
185 else
186 {
187 return mBounds2d.contains( p );
188 }
189}
190
191bool QgsBox3D::contains( double x, double y, double z ) const
192{
193 if ( !mBounds2d.contains( x, y ) )
194 {
195 return false;
196 }
197
198 if ( std::isnan( z ) || is2d() )
199 {
200 return true;
201 }
202 else
203 {
204 return mZmin <= z && z <= mZmax;
205 }
206}
207
212{
213 if ( isNull() )
214 *this = box;
215 else if ( !box.isNull() )
216 {
217 // FIXME: mBounds2d.combineExtentWith( box.mBounds2d ); cannot be used at the moment
218 // because QgsRectangle(0, 0, 0, 0) is considered as null.
219 // Thus, combining QgsBox3D(0, 0, 0, 0, 0, 0) with another box will ignore the
220 // 0 2d coordinates.
221 mBounds2d.setXMinimum( ( mBounds2d.xMinimum() < box.xMinimum() ) ? mBounds2d.xMinimum() : box.xMinimum() );
222 mBounds2d.setXMaximum( ( mBounds2d.xMaximum() > box.xMaximum() ) ? mBounds2d.xMaximum() : box.xMaximum() );
223 mBounds2d.setYMinimum( ( mBounds2d.yMinimum() < box.yMinimum() ) ? mBounds2d.yMinimum() : box.yMinimum() );
224 mBounds2d.setYMaximum( ( mBounds2d.yMaximum() > box.yMaximum() ) ? mBounds2d.yMaximum() : box.yMaximum() );
225 mZmin = ( mZmin < box.zMinimum() ) ? mZmin : box.zMinimum();
226 mZmax = ( mZmax > box.zMaximum() ) ? mZmax : box.zMaximum();
227 }
228}
229
233void QgsBox3D::combineWith( double x, double y, double z )
234{
235 if ( isNull() )
236 *this = QgsBox3D( x, y, z, x, y, z );
237 else
238 {
239 // FIXME: mBounds2d.combineExtentWith( box.mBounds2d ); cannot be used at the moment
240 // because QgsRectangle(0, 0, 0, 0) is considered as null.
241 // Thus, combining QgsBox3D(0, 0, 0, 0, 0, 0) will ignore the 0 2d coordinates.
242 mBounds2d.setXMinimum( ( mBounds2d.xMinimum() ) < x ? mBounds2d.xMinimum() : x );
243 mBounds2d.setXMaximum( ( mBounds2d.xMaximum() ) > x ? mBounds2d.xMaximum() : x );
244 mBounds2d.setYMinimum( ( mBounds2d.yMinimum() ) < y ? mBounds2d.yMinimum() : y );
245 mBounds2d.setYMaximum( ( mBounds2d.yMaximum() ) > y ? mBounds2d.yMaximum() : y );
246 mZmin = ( mZmin < z ) ? mZmin : z;
247 mZmax = ( mZmax > z ) ? mZmax : z;
248 }
249}
250
251double QgsBox3D::distanceTo( const QgsVector3D &point ) const
252{
253 const double dx = std::max( mBounds2d.xMinimum() - point.x(), std::max( 0., point.x() - mBounds2d.xMaximum() ) );
254 const double dy = std::max( mBounds2d.yMinimum() - point.y(), std::max( 0., point.y() - mBounds2d.yMaximum() ) );
255 if ( is2d() || std::isnan( point.z() ) )
256 {
257 return std::hypot( dx, dy );
258 }
259 else
260 {
261 const double dz = std::max( mZmin - point.z(), std::max( 0., point.z() - mZmax ) );
262 return std::hypot( dx, dy, dz );
263 }
264}
265
266bool QgsBox3D::operator==( const QgsBox3D &other ) const
267{
268 return mBounds2d == other.mBounds2d && qgsDoubleNear( mZmin, other.mZmin ) && qgsDoubleNear( mZmax, other.mZmax );
269}
270
271void QgsBox3D::scale( double scaleFactor, const QgsPoint &center )
272{
273 // scale from the center
274 double centerX, centerY, centerZ;
275 if ( !center.isEmpty() )
276 {
277 centerX = center.x();
278 centerY = center.y();
279 centerZ = center.z();
280 }
281 else
282 {
283 centerX = ( xMinimum() + xMaximum() ) / 2;
284 centerY = ( yMinimum() + yMaximum() ) / 2;
285 centerZ = ( zMinimum() + zMaximum() ) / 2;
286 }
287 scale( scaleFactor, centerX, centerY, centerZ );
288}
289
290void QgsBox3D::scale( double scaleFactor, double centerX, double centerY, double centerZ )
291{
292 setXMinimum( centerX + ( xMinimum() - centerX ) * scaleFactor );
293 setXMaximum( centerX + ( xMaximum() - centerX ) * scaleFactor );
294
295 setYMinimum( centerY + ( yMinimum() - centerY ) * scaleFactor );
296 setYMaximum( centerY + ( yMaximum() - centerY ) * scaleFactor );
297
298 setZMinimum( centerZ + ( zMinimum() - centerZ ) * scaleFactor );
299 setZMaximum( centerZ + ( zMaximum() - centerZ ) * scaleFactor );
300}
301
302void QgsBox3D::grow( double delta )
303{
304 if ( isNull() )
305 return;
306 mBounds2d.grow( delta );
307 mZmin -= delta;
308 mZmax += delta;
309}
310
312{
313 return ( std::isnan( mBounds2d.xMinimum() ) && std::isnan( mBounds2d.xMaximum() )
314 && std::isnan( mBounds2d.yMinimum() ) && std::isnan( mBounds2d.xMaximum() )
315 && std::isnan( mZmin ) && std::isnan( mZmax ) )
316 ||
317 ( mBounds2d.xMinimum() == std::numeric_limits<double>::max() && mBounds2d.yMinimum() == std::numeric_limits<double>::max() && mZmin == std::numeric_limits<double>::max()
318 && mBounds2d.xMaximum() == -std::numeric_limits<double>::max() && mBounds2d.yMaximum() == -std::numeric_limits<double>::max() && mZmax == -std::numeric_limits<double>::max() );
319}
320
322{
323 return mZmax < mZmin || qgsDoubleNear( mZmax, mZmin ) || mBounds2d.isEmpty();
324}
325
326QString QgsBox3D::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 ( isNull() )
343 rep = u"Null"_s;
344 else if ( isEmpty() )
345 rep = u"Empty"_s;
346 else
347 rep = u"%1,%2,%3 : %4,%5,%6"_s.arg( mBounds2d.xMinimum(), 0, 'f', precision )
348 .arg( mBounds2d.yMinimum(), 0, 'f', precision )
349 .arg( mZmin, 0, 'f', precision )
350 .arg( mBounds2d.xMaximum(), 0, 'f', precision )
351 .arg( mBounds2d.yMaximum(), 0, 'f', precision )
352 .arg( mZmax, 0, 'f', precision );
353
354 QgsDebugMsgLevel( u"Extents : %1"_s.arg( rep ), 4 );
355
356 return rep;
357}
358
359QVector<QgsVector3D> QgsBox3D::corners() const
360{
361 return {
362 QgsVector3D( mBounds2d.xMinimum(), mBounds2d.yMinimum(), mZmin ),
363 QgsVector3D( mBounds2d.xMinimum(), mBounds2d.yMaximum(), mZmin ),
364 QgsVector3D( mBounds2d.xMaximum(), mBounds2d.yMinimum(), mZmin ),
365 QgsVector3D( mBounds2d.xMaximum(), mBounds2d.yMaximum(), mZmin ),
366
367 QgsVector3D( mBounds2d.xMinimum(), mBounds2d.yMinimum(), mZmax ),
368 QgsVector3D( mBounds2d.xMinimum(), mBounds2d.yMaximum(), mZmax ),
369 QgsVector3D( mBounds2d.xMaximum(), mBounds2d.yMinimum(), mZmax ),
370 QgsVector3D( mBounds2d.xMaximum(), mBounds2d.yMaximum(), mZmax )
371 };
372}
373
375{
376 return QgsBox3D( mBounds2d.xMinimum() - v.x(), mBounds2d.yMinimum() - v.y(), mZmin - v.z(), mBounds2d.xMaximum() - v.x(), mBounds2d.yMaximum() - v.y(), mZmax - v.z() );
377}
378
380{
381 return QgsBox3D( mBounds2d.xMinimum() + v.x(), mBounds2d.yMinimum() + v.y(), mZmin + v.z(), mBounds2d.xMaximum() + v.x(), mBounds2d.yMaximum() + v.y(), mZmax + v.z() );
382}
383
385{
386 mBounds2d.set( mBounds2d.xMinimum() - v.x(), mBounds2d.yMinimum() - v.y(), mBounds2d.xMaximum() - v.x(), mBounds2d.yMaximum() - v.y() );
387 mZmin -= v.z();
388 mZmax -= v.z();
389 return *this;
390}
391
393{
394 mBounds2d.set( mBounds2d.xMinimum() + v.x(), mBounds2d.yMinimum() + v.y(), mBounds2d.xMaximum() + v.x(), mBounds2d.yMaximum() + v.y() );
395 mZmin += v.z();
396 mZmax += v.z();
397 return *this;
398}
double yMaximum() const
Returns the maximum y value.
Definition qgsbox3d.h:240
QgsBox3D operator-(const QgsVector3D &v) const
Returns a box offset from this one in the direction of the reversed vector.
Definition qgsbox3d.cpp:374
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin,zmin : xmax,ymax,zmax Coordinates will be truncated...
Definition qgsbox3d.cpp:326
void scale(double scaleFactor, const QgsPoint &center=QgsPoint())
Scale the rectangle around a center QgsPoint.
Definition qgsbox3d.cpp:271
void setZMinimum(double z)
Sets the minimum z value.
Definition qgsbox3d.cpp:94
void setYMaximum(double y)
Sets the maximum y value.
Definition qgsbox3d.cpp:89
bool is3D() const
Returns true if the box can be considered a 3-dimensional box, i.e.
Definition qgsbox3d.cpp:142
void setZMaximum(double z)
Sets the maximum z value.
Definition qgsbox3d.cpp:99
bool intersects(const QgsBox3D &other) const
Returns true if box intersects with another box.
Definition qgsbox3d.cpp:147
double xMinimum() const
Returns the minimum x value.
Definition qgsbox3d.h:205
bool contains(const QgsBox3D &other) const
Returns true when box contains other box.
Definition qgsbox3d.cpp:164
double zMaximum() const
Returns the maximum z value.
Definition qgsbox3d.h:268
QgsVector3D center() const
Returns the center of the box as a vector.
Definition qgsbox3d.cpp:124
double xMaximum() const
Returns the maximum x value.
Definition qgsbox3d.h:212
void normalize()
Normalize the box so it has non-negative width/height/depth.
Definition qgsbox3d.cpp:115
void setXMaximum(double x)
Sets the maximum x value.
Definition qgsbox3d.cpp:79
void combineWith(const QgsBox3D &box)
Expands the bbox so that it covers both the original rectangle and the given rectangle.
Definition qgsbox3d.cpp:211
bool is2d() const
Returns true if the box can be considered a 2-dimensional box, i.e.
Definition qgsbox3d.cpp:137
Q_DECL_DEPRECATED double distanceTo(const QVector3D &point) const
Returns the smallest distance between the box and the point point (returns 0 if the point is inside t...
Definition qgsbox3d.h:397
QVector< QgsVector3D > corners() const
Returns an array of all box corners as 3D vectors.
Definition qgsbox3d.cpp:359
QgsBox3D operator+(const QgsVector3D &v) const
Returns a box offset from this one in the direction of the vector.
Definition qgsbox3d.cpp:379
void set(double xMin, double yMin, double zMin, double xMax, double yMax, double zMax, bool normalize=true)
Sets the box from a set of (x,y,z) minimum and maximum coordinates.
Definition qgsbox3d.h:173
QgsBox3D(double xmin=std::numeric_limits< double >::quiet_NaN(), double ymin=std::numeric_limits< double >::quiet_NaN(), double zmin=std::numeric_limits< double >::quiet_NaN(), double xmax=std::numeric_limits< double >::quiet_NaN(), double ymax=std::numeric_limits< double >::quiet_NaN(), double zmax=std::numeric_limits< double >::quiet_NaN(), bool normalize=true)
Constructor for QgsBox3D which accepts the ranges of x/y/z coordinates.
Definition qgsbox3d.cpp:30
double width() const
Returns the width of the box.
Definition qgsbox3d.h:287
QgsBox3D & operator+=(const QgsVector3D &v)
Moves this box in the direction of the vector.
Definition qgsbox3d.cpp:392
QgsBox3D intersect(const QgsBox3D &other) const
Returns the intersection of this box and another 3D box.
Definition qgsbox3d.cpp:129
void setNull()
Mark a box as being null (holding no spatial information).
Definition qgsbox3d.cpp:108
void setYMinimum(double y)
Sets the minimum y value.
Definition qgsbox3d.cpp:84
void grow(double delta)
Grows the box in place by the specified amount in all dimensions.
Definition qgsbox3d.cpp:302
double zMinimum() const
Returns the minimum z value.
Definition qgsbox3d.h:261
double yMinimum() const
Returns the minimum y value.
Definition qgsbox3d.h:233
double height() const
Returns the height of the box.
Definition qgsbox3d.h:294
QgsBox3D & operator-=(const QgsVector3D &v)
Moves this box in the direction of the reversed vector.
Definition qgsbox3d.cpp:384
void setXMinimum(double x)
Sets the minimum x value.
Definition qgsbox3d.cpp:74
bool isNull() const
Test if the box is null (holding no spatial information).
Definition qgsbox3d.cpp:311
bool operator==(const QgsBox3D &other) const
Definition qgsbox3d.cpp:266
bool isEmpty() const
Returns true if the box is empty.
Definition qgsbox3d.cpp:321
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
double z
Definition qgspoint.h:58
double x
Definition qgspoint.h:56
double y
Definition qgspoint.h:57
A rectangle specified with double values.
double xMinimum
double yMinimum
double xMaximum
double yMaximum
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
Definition qgsvector3d.h:33
double y() const
Returns Y coordinate.
Definition qgsvector3d.h:60
double z() const
Returns Z coordinate.
Definition qgsvector3d.h:62
double x() const
Returns X coordinate.
Definition qgsvector3d.h:58
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6975
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63