QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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#include "qgspoint.h"
20#include "qgslogger.h"
21#include "qgsvector3d.h"
22
23QgsBox3D::QgsBox3D( double xmin, double ymin, double zmin, double xmax, double ymax, double zmax, bool normalize )
24 : mBounds2d( xmin, ymin, xmax, ymax, false )
25 , mZmin( zmin )
26 , mZmax( zmax )
27{
28 if ( normalize )
29 {
31 }
32}
33
34QgsBox3D::QgsBox3D( const QgsPoint &p1, const QgsPoint &p2, bool normalize )
35 : mBounds2d( p1.x(), p1.y(), p2.x(), p2.y(), false )
36 , mZmin( p1.z() )
37 , mZmax( p2.z() )
38{
39 if ( normalize )
40 {
42 }
43}
44
45QgsBox3D::QgsBox3D( const QgsRectangle &rect, double zMin, double zMax, bool normalize )
46 : mBounds2d( rect )
47 , mZmin( zMin )
48 , mZmax( zMax )
49{
50 if ( normalize )
51 {
53 }
54}
55
56void QgsBox3D::setXMinimum( double x )
57{
58 mBounds2d.setXMinimum( x );
59}
60
61void QgsBox3D::setXMaximum( double x )
62{
63 mBounds2d.setXMaximum( x );
64}
65
66void QgsBox3D::setYMinimum( double y )
67{
68 mBounds2d.setYMinimum( y );
69}
70
71void QgsBox3D::setYMaximum( double y )
72{
73 mBounds2d.setYMaximum( y );
74}
75
76void QgsBox3D::setZMinimum( double z )
77{
78 mZmin = z;
79}
80
81void QgsBox3D::setZMaximum( double z )
82{
83 mZmax = z;
84}
85
91{
92 mBounds2d.setNull();
93 mZmin = std::numeric_limits<double>::max();
94 mZmax = -std::numeric_limits<double>::max();
95}
96
98{
99 mBounds2d.normalize();
100 if ( mZmin > mZmax )
101 {
102 std::swap( mZmin, mZmax );
103 }
104}
105
107{
108 return QgsVector3D( 0.5 * ( mBounds2d.xMinimum() + mBounds2d.xMaximum() ),
109 0.5 * ( mBounds2d.yMinimum() + mBounds2d.yMaximum() ),
110 0.5 * ( mZmin + mZmax ) );
111}
112
114{
115 const QgsRectangle intersect2d = mBounds2d.intersect( other.mBounds2d );
116 const double zMin = std::max( mZmin, other.mZmin );
117 const double zMax = std::min( mZmax, other.mZmax );
118 return QgsBox3D( intersect2d.xMinimum(), intersect2d.yMinimum(), zMin,
119 intersect2d.xMaximum(), intersect2d.yMaximum(), zMax );
120}
121
122bool QgsBox3D::is2d() const
123{
124 return qgsDoubleNear( mZmin, mZmax ) || ( mZmin > mZmax ) || std::isnan( mZmin ) || std::isnan( mZmax ) ;
125}
126
127bool QgsBox3D::is3D() const
128{
129 return !is2d() && !isNull();
130}
131
132bool QgsBox3D::intersects( const QgsBox3D &other ) const
133{
134 if ( !mBounds2d.intersects( other.mBounds2d ) )
135 return false;
136
137 if ( other.is2d() || is2d() )
138 {
139 return true;
140 }
141 else
142 {
143 const double z1 = ( mZmin > other.mZmin ? mZmin : other.mZmin );
144 const double z2 = ( mZmax < other.mZmax ? mZmax : other.mZmax );
145 return z1 <= z2;
146 }
147}
148
149bool QgsBox3D::contains( const QgsBox3D &other ) const
150{
151 if ( !mBounds2d.contains( other.mBounds2d ) )
152 return false;
153
154 if ( other.is2d() || is2d() )
155 {
156 return true;
157 }
158 else
159 {
160 return ( other.mZmin >= mZmin && other.mZmax <= mZmax );
161 }
162}
163
164bool QgsBox3D::contains( const QgsPoint &p ) const
165{
166 if ( is3D() )
167 {
168 return contains( p.x(), p.y(), p.z() );
169 }
170 else
171 {
172 return mBounds2d.contains( p );
173 }
174}
175
176bool QgsBox3D::contains( double x, double y, double z ) const
177{
178 if ( !mBounds2d.contains( x, y ) )
179 {
180 return false;
181 }
182
183 if ( std::isnan( z ) || is2d() )
184 {
185 return true;
186 }
187 else
188 {
189 return mZmin <= z && z <= mZmax;
190 }
191}
192
197{
198 if ( isNull() )
199 *this = box;
200 else if ( !box.isNull() )
201 {
202 // FIXME: mBounds2d.combineExtentWith( box.mBounds2d ); cannot be used at the moment
203 // because QgsRectangle(0, 0, 0, 0) is considered as null.
204 // Thus, combining QgsBox3D(0, 0, 0, 0, 0, 0) with another box will ignore the
205 // 0 2d coordinates.
206 mBounds2d.setXMinimum( ( mBounds2d.xMinimum() < box.xMinimum() ) ? mBounds2d.xMinimum() : box.xMinimum() );
207 mBounds2d.setXMaximum( ( mBounds2d.xMaximum() > box.xMaximum() ) ? mBounds2d.xMaximum() : box.xMaximum() );
208 mBounds2d.setYMinimum( ( mBounds2d.yMinimum() < box.yMinimum() ) ? mBounds2d.yMinimum() : box.yMinimum() );
209 mBounds2d.setYMaximum( ( mBounds2d.yMaximum() > box.yMaximum() ) ? mBounds2d.yMaximum() : box.yMaximum() );
210 mZmin = ( mZmin < box.zMinimum() ) ? mZmin : box.zMinimum();
211 mZmax = ( mZmax > box.zMaximum() ) ? mZmax : box.zMaximum();
212 }
213}
214
218void QgsBox3D::combineWith( double x, double y, double z )
219{
220 if ( isNull() )
221 *this = QgsBox3D( x, y, z, x, y, z );
222 else
223 {
224 // FIXME: mBounds2d.combineExtentWith( box.mBounds2d ); cannot be used at the moment
225 // because QgsRectangle(0, 0, 0, 0) is considered as null.
226 // Thus, combining QgsBox3D(0, 0, 0, 0, 0, 0) will ignore the 0 2d coordinates.
227 mBounds2d.setXMinimum( ( mBounds2d.xMinimum() ) < x ? mBounds2d.xMinimum() : x );
228 mBounds2d.setXMaximum( ( mBounds2d.xMaximum() ) > x ? mBounds2d.xMaximum() : x );
229 mBounds2d.setYMinimum( ( mBounds2d.yMinimum() ) < y ? mBounds2d.yMinimum() : y );
230 mBounds2d.setYMaximum( ( mBounds2d.yMaximum() ) > y ? mBounds2d.yMaximum() : y );
231 mZmin = ( mZmin < z ) ? mZmin : z;
232 mZmax = ( mZmax > z ) ? mZmax : z;
233 }
234}
235
236double QgsBox3D::distanceTo( const QVector3D &point ) const
237{
238 const double dx = std::max( mBounds2d.xMinimum() - point.x(), std::max( 0., point.x() - mBounds2d.xMaximum() ) );
239 const double dy = std::max( mBounds2d.yMinimum() - point.y(), std::max( 0., point.y() - mBounds2d.yMaximum() ) );
240 if ( is2d() || std::isnan( point.z() ) )
241 {
242 return std::hypot( dx, dy );
243 }
244 else
245 {
246 const double dz = std::max( mZmin - point.z(), std::max( 0., point.z() - mZmax ) );
247 return std::hypot( dx, dy, dz );
248 }
249}
250
251bool QgsBox3D::operator==( const QgsBox3D &other ) const
252{
253 return mBounds2d == other.mBounds2d &&
254 qgsDoubleNear( mZmin, other.mZmin ) &&
255 qgsDoubleNear( mZmax, other.mZmax );
256}
257
258void QgsBox3D::scale( double scaleFactor, const QgsPoint &center )
259{
260 // scale from the center
261 double centerX, centerY, centerZ;
262 if ( !center.isEmpty() )
263 {
264 centerX = center.x();
265 centerY = center.y();
266 centerZ = center.z();
267 }
268 else
269 {
270 centerX = ( xMinimum() + xMaximum() ) / 2;
271 centerY = ( yMinimum() + yMaximum() ) / 2;
272 centerZ = ( zMinimum() + zMaximum() ) / 2;
273 }
274 scale( scaleFactor, centerX, centerY, centerZ );
275}
276
277void QgsBox3D::scale( double scaleFactor, double centerX, double centerY, double centerZ )
278{
279 setXMinimum( centerX + ( xMinimum() - centerX ) * scaleFactor );
280 setXMaximum( centerX + ( xMaximum() - centerX ) * scaleFactor );
281
282 setYMinimum( centerY + ( yMinimum() - centerY ) * scaleFactor );
283 setYMaximum( centerY + ( yMaximum() - centerY ) * scaleFactor );
284
285 setZMinimum( centerZ + ( zMinimum() - centerZ ) * scaleFactor );
286 setZMaximum( centerZ + ( zMaximum() - centerZ ) * scaleFactor );
287}
288
290{
291 return ( std::isnan( mBounds2d.xMinimum() ) && std::isnan( mBounds2d.xMaximum() )
292 && std::isnan( mBounds2d.yMinimum() ) && std::isnan( mBounds2d.xMaximum() )
293 && std::isnan( mZmin ) && std::isnan( mZmax ) )
294 ||
295 ( mBounds2d.xMinimum() == std::numeric_limits<double>::max() && mBounds2d.yMinimum() == std::numeric_limits<double>::max() && mZmin == std::numeric_limits<double>::max()
296 && mBounds2d.xMaximum() == -std::numeric_limits<double>::max() && mBounds2d.yMaximum() == -std::numeric_limits<double>::max() && mZmax == -std::numeric_limits<double>::max() );
297}
298
300{
301 return mZmax < mZmin || qgsDoubleNear( mZmax, mZmin ) || mBounds2d.isEmpty();
302}
303
304QString QgsBox3D::toString( int precision ) const
305{
306 QString rep;
307
308 if ( precision < 0 )
309 {
310 precision = 0;
311 if ( ( width() < 10 || height() < 10 ) && ( width() > 0 && height() > 0 ) )
312 {
313 precision = static_cast<int>( std::ceil( -1.0 * std::log10( std::min( width(), height() ) ) ) ) + 1;
314 // sanity check
315 if ( precision > 20 )
316 precision = 20;
317 }
318 }
319
320 if ( isNull() )
321 rep = QStringLiteral( "Null" );
322 else if ( isEmpty() )
323 rep = QStringLiteral( "Empty" );
324 else
325 rep = QStringLiteral( "%1,%2,%3 : %4,%5,%6" )
326 .arg( mBounds2d.xMinimum(), 0, 'f', precision )
327 .arg( mBounds2d.yMinimum(), 0, 'f', precision )
328 .arg( mZmin, 0, 'f', precision )
329 .arg( mBounds2d.xMaximum(), 0, 'f', precision )
330 .arg( mBounds2d.yMaximum(), 0, 'f', precision )
331 .arg( mZmax, 0, 'f', precision );
332
333 QgsDebugMsgLevel( QStringLiteral( "Extents : %1" ).arg( rep ), 4 );
334
335 return rep;
336}
337
338QVector<QgsVector3D> QgsBox3D::corners() const
339{
340 return
341 {
342 QgsVector3D( mBounds2d.xMinimum(), mBounds2d.yMinimum(), mZmin ),
343 QgsVector3D( mBounds2d.xMinimum(), mBounds2d.yMaximum(), mZmin ),
344 QgsVector3D( mBounds2d.xMaximum(), mBounds2d.yMinimum(), mZmin ),
345 QgsVector3D( mBounds2d.xMaximum(), mBounds2d.yMaximum(), mZmin ),
346
347 QgsVector3D( mBounds2d.xMinimum(), mBounds2d.yMinimum(), mZmax ),
348 QgsVector3D( mBounds2d.xMinimum(), mBounds2d.yMaximum(), mZmax ),
349 QgsVector3D( mBounds2d.xMaximum(), mBounds2d.yMinimum(), mZmax ),
350 QgsVector3D( mBounds2d.xMaximum(), mBounds2d.yMaximum(), mZmax )
351 };
352}
353
355{
356 return QgsBox3D( mBounds2d.xMinimum() - v.x(), mBounds2d.yMinimum() - v.y(), mZmin - v.z(),
357 mBounds2d.xMaximum() - v.x(), mBounds2d.yMaximum() - v.y(), mZmax - v.z() );
358}
359
361{
362 return QgsBox3D( mBounds2d.xMinimum() + v.x(), mBounds2d.yMinimum() + v.y(), mZmin + v.z(),
363 mBounds2d.xMaximum() + v.x(), mBounds2d.yMaximum() + v.y(), mZmax + v.z() );
364}
365
367{
368 mBounds2d.set( mBounds2d.xMinimum() - v.x(), mBounds2d.yMinimum() - v.y(),
369 mBounds2d.xMaximum() - v.x(), mBounds2d.yMaximum() - v.y() );
370 mZmin -= v.z();
371 mZmax -= v.z();
372 return *this;
373}
374
376{
377 mBounds2d.set( mBounds2d.xMinimum() + v.x(), mBounds2d.yMinimum() + v.y(),
378 mBounds2d.xMaximum() + v.x(), mBounds2d.yMaximum() + v.y() );
379 mZmin += v.z();
380 mZmax += v.z();
381 return *this;
382}
A 3-dimensional box composed of x, y, z coordinates.
Definition: qgsbox3d.h:43
double yMaximum() const
Returns the maximum y value.
Definition: qgsbox3d.h:197
QgsBox3D operator-(const QgsVector3D &v) const
Returns a box offset from this one in the direction of the reversed vector.
Definition: qgsbox3d.cpp:354
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:304
void scale(double scaleFactor, const QgsPoint &center=QgsPoint())
Scale the rectangle around a center QgsPoint.
Definition: qgsbox3d.cpp:258
void setZMinimum(double z)
Sets the minimum z value.
Definition: qgsbox3d.cpp:76
void setYMaximum(double y)
Sets the maximum y value.
Definition: qgsbox3d.cpp:71
bool is3D() const
Returns true if the box can be considered a 3-dimensional box, i.e.
Definition: qgsbox3d.cpp:127
void setZMaximum(double z)
Sets the maximum z value.
Definition: qgsbox3d.cpp:81
bool intersects(const QgsBox3D &other) const
Returns true if box intersects with another box.
Definition: qgsbox3d.cpp:132
double xMinimum() const
Returns the minimum x value.
Definition: qgsbox3d.h:162
bool contains(const QgsBox3D &other) const
Returns true when box contains other box.
Definition: qgsbox3d.cpp:149
double zMaximum() const
Returns the maximum z value.
Definition: qgsbox3d.h:225
QgsVector3D center() const
Returns the center of the box as a vector.
Definition: qgsbox3d.cpp:106
double xMaximum() const
Returns the maximum x value.
Definition: qgsbox3d.h:169
void normalize()
Normalize the box so it has non-negative width/height/depth.
Definition: qgsbox3d.cpp:97
void setXMaximum(double x)
Sets the maximum x value.
Definition: qgsbox3d.cpp:61
void combineWith(const QgsBox3D &box)
Expands the bbox so that it covers both the original rectangle and the given rectangle.
Definition: qgsbox3d.cpp:196
bool is2d() const
Returns true if the box can be considered a 2-dimensional box, i.e.
Definition: qgsbox3d.cpp:122
QVector< QgsVector3D > corners() const
Returns an array of all box corners as 3D vectors.
Definition: qgsbox3d.cpp:338
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.cpp:236
QgsBox3D operator+(const QgsVector3D &v) const
Returns a box offset from this one in the direction of the vector.
Definition: qgsbox3d.cpp:360
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:23
double width() const
Returns the width of the box.
Definition: qgsbox3d.h:244
QgsBox3D & operator+=(const QgsVector3D &v)
Moves this box in the direction of the vector.
Definition: qgsbox3d.cpp:375
QgsBox3D intersect(const QgsBox3D &other) const
Returns the intersection of this box and another 3D box.
Definition: qgsbox3d.cpp:113
void setNull()
Mark a box as being null (holding no spatial information).
Definition: qgsbox3d.cpp:90
void setYMinimum(double y)
Sets the minimum y value.
Definition: qgsbox3d.cpp:66
double zMinimum() const
Returns the minimum z value.
Definition: qgsbox3d.h:218
double yMinimum() const
Returns the minimum y value.
Definition: qgsbox3d.h:190
double height() const
Returns the height of the box.
Definition: qgsbox3d.h:251
QgsBox3D & operator-=(const QgsVector3D &v)
Moves this box in the direction of the reversed vector.
Definition: qgsbox3d.cpp:366
void setXMinimum(double x)
Sets the minimum x value.
Definition: qgsbox3d.cpp:56
bool isNull() const
Test if the box is null (holding no spatial information).
Definition: qgsbox3d.cpp:289
bool operator==(const QgsBox3D &other) const
Definition: qgsbox3d.cpp:251
bool isEmpty() const
Returns true if the box is empty.
Definition: qgsbox3d.cpp:299
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
Q_GADGET double x
Definition: qgspoint.h:52
double z
Definition: qgspoint.h:54
double y
Definition: qgspoint.h:53
A rectangle specified with double values.
Definition: qgsrectangle.h:42
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
Definition: qgsrectangle.h:385
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:201
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:159
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
Definition: qgsrectangle.h:371
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:211
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:149
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:196
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:206
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
Definition: qgsrectangle.h:120
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:164
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:154
void normalize()
Normalize the rectangle so it has non-negative width/height.
Definition: qgsrectangle.h:216
bool isEmpty() const
Returns true if the rectangle has no area.
Definition: qgsrectangle.h:492
void setNull()
Mark a rectangle as being null (holding no spatial information).
Definition: qgsrectangle.h:176
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Definition: qgsrectangle.h:355
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
Definition: qgsvector3d.h:31
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:50
double z() const
Returns Z coordinate.
Definition: qgsvector3d.h:52
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:48
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5207
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
int precision