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