QGIS API Documentation 3.99.0-Master (8e76e220402)
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() ),
127 0.5 * ( mBounds2d.yMinimum() + mBounds2d.yMaximum() ),
128 0.5 * ( mZmin + mZmax ) );
129}
130
132{
133 const QgsRectangle intersect2d = mBounds2d.intersect( other.mBounds2d );
134 const double zMin = std::max( mZmin, other.mZmin );
135 const double zMax = std::min( mZmax, other.mZmax );
136 return QgsBox3D( intersect2d.xMinimum(), intersect2d.yMinimum(), zMin,
137 intersect2d.xMaximum(), intersect2d.yMaximum(), zMax );
138}
139
140bool QgsBox3D::is2d() const
141{
142 return qgsDoubleNear( mZmin, mZmax ) || ( mZmin > mZmax ) || std::isnan( mZmin ) || std::isnan( mZmax ) ;
143}
144
145bool QgsBox3D::is3D() const
146{
147 return !is2d() && !isNull();
148}
149
150bool QgsBox3D::intersects( const QgsBox3D &other ) const
151{
152 if ( !mBounds2d.intersects( other.mBounds2d ) )
153 return false;
154
155 if ( other.is2d() || is2d() )
156 {
157 return true;
158 }
159 else
160 {
161 const double z1 = ( mZmin > other.mZmin ? mZmin : other.mZmin );
162 const double z2 = ( mZmax < other.mZmax ? mZmax : other.mZmax );
163 return z1 <= z2;
164 }
165}
166
167bool QgsBox3D::contains( const QgsBox3D &other ) const
168{
169 if ( !mBounds2d.contains( other.mBounds2d ) )
170 return false;
171
172 if ( other.is2d() || is2d() )
173 {
174 return true;
175 }
176 else
177 {
178 return ( other.mZmin >= mZmin && other.mZmax <= mZmax );
179 }
180}
181
182bool QgsBox3D::contains( const QgsPoint &p ) const
183{
184 if ( is3D() )
185 {
186 return contains( p.x(), p.y(), p.z() );
187 }
188 else
189 {
190 return mBounds2d.contains( p );
191 }
192}
193
194bool QgsBox3D::contains( double x, double y, double z ) const
195{
196 if ( !mBounds2d.contains( x, y ) )
197 {
198 return false;
199 }
200
201 if ( std::isnan( z ) || is2d() )
202 {
203 return true;
204 }
205 else
206 {
207 return mZmin <= z && z <= mZmax;
208 }
209}
210
215{
216 if ( isNull() )
217 *this = box;
218 else if ( !box.isNull() )
219 {
220 // FIXME: mBounds2d.combineExtentWith( box.mBounds2d ); cannot be used at the moment
221 // because QgsRectangle(0, 0, 0, 0) is considered as null.
222 // Thus, combining QgsBox3D(0, 0, 0, 0, 0, 0) with another box will ignore the
223 // 0 2d coordinates.
224 mBounds2d.setXMinimum( ( mBounds2d.xMinimum() < box.xMinimum() ) ? mBounds2d.xMinimum() : box.xMinimum() );
225 mBounds2d.setXMaximum( ( mBounds2d.xMaximum() > box.xMaximum() ) ? mBounds2d.xMaximum() : box.xMaximum() );
226 mBounds2d.setYMinimum( ( mBounds2d.yMinimum() < box.yMinimum() ) ? mBounds2d.yMinimum() : box.yMinimum() );
227 mBounds2d.setYMaximum( ( mBounds2d.yMaximum() > box.yMaximum() ) ? mBounds2d.yMaximum() : box.yMaximum() );
228 mZmin = ( mZmin < box.zMinimum() ) ? mZmin : box.zMinimum();
229 mZmax = ( mZmax > box.zMaximum() ) ? mZmax : box.zMaximum();
230 }
231}
232
236void QgsBox3D::combineWith( double x, double y, double z )
237{
238 if ( isNull() )
239 *this = QgsBox3D( x, y, z, x, y, z );
240 else
241 {
242 // FIXME: mBounds2d.combineExtentWith( box.mBounds2d ); cannot be used at the moment
243 // because QgsRectangle(0, 0, 0, 0) is considered as null.
244 // Thus, combining QgsBox3D(0, 0, 0, 0, 0, 0) will ignore the 0 2d coordinates.
245 mBounds2d.setXMinimum( ( mBounds2d.xMinimum() ) < x ? mBounds2d.xMinimum() : x );
246 mBounds2d.setXMaximum( ( mBounds2d.xMaximum() ) > x ? mBounds2d.xMaximum() : x );
247 mBounds2d.setYMinimum( ( mBounds2d.yMinimum() ) < y ? mBounds2d.yMinimum() : y );
248 mBounds2d.setYMaximum( ( mBounds2d.yMaximum() ) > y ? mBounds2d.yMaximum() : y );
249 mZmin = ( mZmin < z ) ? mZmin : z;
250 mZmax = ( mZmax > z ) ? mZmax : z;
251 }
252}
253
254double QgsBox3D::distanceTo( const QgsVector3D &point ) const
255{
256 const double dx = std::max( mBounds2d.xMinimum() - point.x(), std::max( 0., point.x() - mBounds2d.xMaximum() ) );
257 const double dy = std::max( mBounds2d.yMinimum() - point.y(), std::max( 0., point.y() - mBounds2d.yMaximum() ) );
258 if ( is2d() || std::isnan( point.z() ) )
259 {
260 return std::hypot( dx, dy );
261 }
262 else
263 {
264 const double dz = std::max( mZmin - point.z(), std::max( 0., point.z() - mZmax ) );
265 return std::hypot( dx, dy, dz );
266 }
267}
268
269bool QgsBox3D::operator==( const QgsBox3D &other ) const
270{
271 return mBounds2d == other.mBounds2d &&
272 qgsDoubleNear( mZmin, other.mZmin ) &&
273 qgsDoubleNear( mZmax, other.mZmax );
274}
275
276void QgsBox3D::scale( double scaleFactor, const QgsPoint &center )
277{
278 // scale from the center
279 double centerX, centerY, centerZ;
280 if ( !center.isEmpty() )
281 {
282 centerX = center.x();
283 centerY = center.y();
284 centerZ = center.z();
285 }
286 else
287 {
288 centerX = ( xMinimum() + xMaximum() ) / 2;
289 centerY = ( yMinimum() + yMaximum() ) / 2;
290 centerZ = ( zMinimum() + zMaximum() ) / 2;
291 }
292 scale( scaleFactor, centerX, centerY, centerZ );
293}
294
295void QgsBox3D::scale( double scaleFactor, double centerX, double centerY, double centerZ )
296{
297 setXMinimum( centerX + ( xMinimum() - centerX ) * scaleFactor );
298 setXMaximum( centerX + ( xMaximum() - centerX ) * scaleFactor );
299
300 setYMinimum( centerY + ( yMinimum() - centerY ) * scaleFactor );
301 setYMaximum( centerY + ( yMaximum() - centerY ) * scaleFactor );
302
303 setZMinimum( centerZ + ( zMinimum() - centerZ ) * scaleFactor );
304 setZMaximum( centerZ + ( zMaximum() - centerZ ) * scaleFactor );
305}
306
307void QgsBox3D::grow( double delta )
308{
309 if ( isNull() )
310 return;
311 mBounds2d.grow( delta );
312 mZmin -= delta;
313 mZmax += delta;
314}
315
317{
318 return ( std::isnan( mBounds2d.xMinimum() ) && std::isnan( mBounds2d.xMaximum() )
319 && std::isnan( mBounds2d.yMinimum() ) && std::isnan( mBounds2d.xMaximum() )
320 && std::isnan( mZmin ) && std::isnan( mZmax ) )
321 ||
322 ( mBounds2d.xMinimum() == std::numeric_limits<double>::max() && mBounds2d.yMinimum() == std::numeric_limits<double>::max() && mZmin == std::numeric_limits<double>::max()
323 && mBounds2d.xMaximum() == -std::numeric_limits<double>::max() && mBounds2d.yMaximum() == -std::numeric_limits<double>::max() && mZmax == -std::numeric_limits<double>::max() );
324}
325
327{
328 return mZmax < mZmin || qgsDoubleNear( mZmax, mZmin ) || mBounds2d.isEmpty();
329}
330
331QString QgsBox3D::toString( int precision ) const
332{
333 QString rep;
334
335 if ( precision < 0 )
336 {
337 precision = 0;
338 if ( ( width() < 10 || height() < 10 ) && ( width() > 0 && height() > 0 ) )
339 {
340 precision = static_cast<int>( std::ceil( -1.0 * std::log10( std::min( width(), height() ) ) ) ) + 1;
341 // sanity check
342 if ( precision > 20 )
343 precision = 20;
344 }
345 }
346
347 if ( isNull() )
348 rep = u"Null"_s;
349 else if ( isEmpty() )
350 rep = u"Empty"_s;
351 else
352 rep = u"%1,%2,%3 : %4,%5,%6"_s
353 .arg( mBounds2d.xMinimum(), 0, 'f', precision )
354 .arg( mBounds2d.yMinimum(), 0, 'f', precision )
355 .arg( mZmin, 0, 'f', precision )
356 .arg( mBounds2d.xMaximum(), 0, 'f', precision )
357 .arg( mBounds2d.yMaximum(), 0, 'f', precision )
358 .arg( mZmax, 0, 'f', precision );
359
360 QgsDebugMsgLevel( u"Extents : %1"_s.arg( rep ), 4 );
361
362 return rep;
363}
364
365QVector<QgsVector3D> QgsBox3D::corners() const
366{
367 return
368 {
369 QgsVector3D( mBounds2d.xMinimum(), mBounds2d.yMinimum(), mZmin ),
370 QgsVector3D( mBounds2d.xMinimum(), mBounds2d.yMaximum(), mZmin ),
371 QgsVector3D( mBounds2d.xMaximum(), mBounds2d.yMinimum(), mZmin ),
372 QgsVector3D( mBounds2d.xMaximum(), mBounds2d.yMaximum(), mZmin ),
373
374 QgsVector3D( mBounds2d.xMinimum(), mBounds2d.yMinimum(), mZmax ),
375 QgsVector3D( mBounds2d.xMinimum(), mBounds2d.yMaximum(), mZmax ),
376 QgsVector3D( mBounds2d.xMaximum(), mBounds2d.yMinimum(), mZmax ),
377 QgsVector3D( mBounds2d.xMaximum(), mBounds2d.yMaximum(), mZmax )
378 };
379}
380
382{
383 return QgsBox3D( mBounds2d.xMinimum() - v.x(), mBounds2d.yMinimum() - v.y(), mZmin - v.z(),
384 mBounds2d.xMaximum() - v.x(), mBounds2d.yMaximum() - v.y(), mZmax - v.z() );
385}
386
388{
389 return QgsBox3D( mBounds2d.xMinimum() + v.x(), mBounds2d.yMinimum() + v.y(), mZmin + v.z(),
390 mBounds2d.xMaximum() + v.x(), mBounds2d.yMaximum() + v.y(), mZmax + v.z() );
391}
392
394{
395 mBounds2d.set( mBounds2d.xMinimum() - v.x(), mBounds2d.yMinimum() - v.y(),
396 mBounds2d.xMaximum() - v.x(), mBounds2d.yMaximum() - v.y() );
397 mZmin -= v.z();
398 mZmax -= v.z();
399 return *this;
400}
401
403{
404 mBounds2d.set( mBounds2d.xMinimum() + v.x(), mBounds2d.yMinimum() + v.y(),
405 mBounds2d.xMaximum() + v.x(), mBounds2d.yMaximum() + v.y() );
406 mZmin += v.z();
407 mZmax += v.z();
408 return *this;
409}
double yMaximum() const
Returns the maximum y value.
Definition qgsbox3d.h:233
QgsBox3D operator-(const QgsVector3D &v) const
Returns a box offset from this one in the direction of the reversed vector.
Definition qgsbox3d.cpp:381
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:331
void scale(double scaleFactor, const QgsPoint &center=QgsPoint())
Scale the rectangle around a center QgsPoint.
Definition qgsbox3d.cpp:276
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:145
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:150
double xMinimum() const
Returns the minimum x value.
Definition qgsbox3d.h:198
bool contains(const QgsBox3D &other) const
Returns true when box contains other box.
Definition qgsbox3d.cpp:167
double zMaximum() const
Returns the maximum z value.
Definition qgsbox3d.h:261
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:205
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:214
bool is2d() const
Returns true if the box can be considered a 2-dimensional box, i.e.
Definition qgsbox3d.cpp:140
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:390
QVector< QgsVector3D > corners() const
Returns an array of all box corners as 3D vectors.
Definition qgsbox3d.cpp:365
QgsBox3D operator+(const QgsVector3D &v) const
Returns a box offset from this one in the direction of the vector.
Definition qgsbox3d.cpp:387
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:168
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:280
QgsBox3D & operator+=(const QgsVector3D &v)
Moves this box in the direction of the vector.
Definition qgsbox3d.cpp:402
QgsBox3D intersect(const QgsBox3D &other) const
Returns the intersection of this box and another 3D box.
Definition qgsbox3d.cpp:131
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:307
double zMinimum() const
Returns the minimum z value.
Definition qgsbox3d.h:254
double yMinimum() const
Returns the minimum y value.
Definition qgsbox3d.h:226
double height() const
Returns the height of the box.
Definition qgsbox3d.h:287
QgsBox3D & operator-=(const QgsVector3D &v)
Moves this box in the direction of the reversed vector.
Definition qgsbox3d.cpp:393
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:316
bool operator==(const QgsBox3D &other) const
Definition qgsbox3d.cpp:269
bool isEmpty() const
Returns true if the box is empty.
Definition qgsbox3d.cpp:326
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:52
double z() const
Returns Z coordinate.
Definition qgsvector3d.h:54
double x() const
Returns X coordinate.
Definition qgsvector3d.h:50
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6935
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63