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