QGIS API Documentation 3.39.0-Master (52f98f8c831)
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 "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
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 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:5465
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
int precision