1 /***************************************************************************
2                              qgsbox3d.h
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 #ifndef QGSBOX3D_H
19 #define QGSBOX3D_H
20 
21 #include "qgis_core.h"
22 #include "qgsrectangle.h"
23 
24 #include <QVector3D>
25 
26 class QgsPoint;
27 
28 /**
29  * \ingroup core
30  * \brief A 3-dimensional box composed of x, y, z coordinates.
31  *
32  * A box composed of x/y/z minimum and maximum values. It is often used to return the 3D
33  * extent of a geometry or collection of geometries.
34  *
35  * \see QgsRectangle
36  * \since QGIS 3.0
37  */
38 class CORE_EXPORT QgsBox3d
39 {
40   public:
41 
42     /**
43      * Constructor for QgsBox3D which accepts the ranges of x/y/z coordinates.
44      */
45     QgsBox3d( double xmin = 0, double ymin = 0, double zmin = 0, double xmax = 0, double ymax = 0, double zmax = 0 ) SIP_HOLDGIL;
46 
47     /**
48      * Constructs a QgsBox3D from two points representing opposite corners of the box.
49      * The box is normalized after construction.
50      */
51     QgsBox3d( const QgsPoint &p1, const QgsPoint &p2 ) SIP_HOLDGIL;
52 
53     /**
54      * Constructs a QgsBox3D from a rectangle.
55      * Z Minimum and Z Maximum are set to 0.0.
56      */
57     QgsBox3d( const QgsRectangle &rect ) SIP_HOLDGIL;
58 
59     /**
60      * Sets the minimum \a x value.
61      * \see xMinimum()
62      * \see setXMaximum()
63      */
64     void setXMinimum( double x ) SIP_HOLDGIL;
65 
66     /**
67      * Sets the maximum \a x value.
68      * \see xMaximum()
69      * \see setXMinimum()
70      */
71     void setXMaximum( double x ) SIP_HOLDGIL;
72 
73     /**
74      * Returns the minimum x value.
75      * \see setXMinimum()
76      * \see xMaximum()
77      */
xMinimum()78     double xMinimum() const SIP_HOLDGIL { return mBounds2d.xMinimum(); }
79 
80     /**
81      * Returns the maximum x value.
82      * \see setXMaximum()
83      * \see xMinimum()
84      */
xMaximum()85     double xMaximum() const SIP_HOLDGIL { return mBounds2d.xMaximum(); }
86 
87     /**
88      * Sets the minimum \a y value.
89      * \see yMinimum()
90      * \see setYMaximum()
91      */
92     void setYMinimum( double y ) SIP_HOLDGIL;
93 
94     /**
95      * Sets the maximum \a y value.
96      * \see yMaximum()
97      * \see setYMinimum()
98      */
99     void setYMaximum( double y ) SIP_HOLDGIL;
100 
101     /**
102      * Returns the minimum y value.
103      * \see setYMinimum()
104      * \see yMaximum()
105      */
yMinimum()106     double yMinimum() const SIP_HOLDGIL { return mBounds2d.yMinimum(); }
107 
108     /**
109      * Returns the maximum y value.
110      * \see setYMaximum()
111      * \see yMinimum()
112      */
yMaximum()113     double yMaximum() const SIP_HOLDGIL { return mBounds2d.yMaximum(); }
114 
115     /**
116      * Sets the minimum \a z value.
117      * \see zMinimum()
118      * \see setZMaximum()
119      */
120     void setZMinimum( double z ) SIP_HOLDGIL;
121 
122     /**
123      * Sets the maximum \a z value.
124      * \see zMaximum()
125      * \see setZMinimum()
126      */
127     void setZMaximum( double z ) SIP_HOLDGIL;
128 
129     /**
130      * Returns the minimum z value.
131      * \see setZMinimum()
132      * \see zMaximum()
133      */
zMinimum()134     double zMinimum() const SIP_HOLDGIL { return mZmin; }
135 
136     /**
137      * Returns the maximum z value.
138      * \see setZMaximum()
139      * \see zMinimum()
140      */
zMaximum()141     double zMaximum() const SIP_HOLDGIL { return mZmax; }
142 
143     /**
144      * Normalize the box so it has non-negative width/height/depth.
145      */
146     void normalize();
147 
148     /**
149      * Returns the width of the box.
150      * \see height()
151      * \see depth()
152      */
width()153     double width() const SIP_HOLDGIL { return mBounds2d.width(); }
154 
155     /**
156      * Returns the height of the box.
157      * \see width()
158      * \see depth()
159      */
height()160     double height() const SIP_HOLDGIL { return mBounds2d.height(); }
161 
162     /**
163      * Returns the depth of the box.
164      * \see width()
165      * \see height()
166      */
depth()167     double depth() const SIP_HOLDGIL { return mZmax - mZmin; }
168 
169     /**
170      * Returns the volume of the box.
171      */
volume()172     double volume() const SIP_HOLDGIL { return mBounds2d.area() * ( mZmax - mZmin ); }
173 
174     /**
175      * Returns the intersection of this box and another 3D box.
176      */
177     QgsBox3d intersect( const QgsBox3d &other ) const;
178 
179     /**
180      * Returns TRUE if the box can be considered a 2-dimensional box, i.e.
181      * it has equal minimum and maximum z values.
182      */
183     bool is2d() const SIP_HOLDGIL;
184 
185     /**
186      * Returns TRUE if box intersects with another box.
187      */
188     bool intersects( const QgsBox3d &other ) const;
189 
190     /**
191      * Returns TRUE when box contains other box.
192      */
193     bool contains( const QgsBox3d &other ) const;
194 
195     /**
196      * Returns TRUE when box contains a \a point.
197      *
198      * If the point is a 2D point (no z-coordinate), then the containment test
199      * will be performed on the x/y extent of the box only.
200      */
201     bool contains( const QgsPoint &point ) const;
202 
203     /**
204      * Converts the box to a 2D rectangle.
205      */
toRectangle()206     QgsRectangle toRectangle() const { return mBounds2d; }
207 
208     /**
209      * Returns the smallest distance between the box and the point \a point
210      * (returns 0 if the point is inside the box)
211      *
212      * \since QGIS 3.18
213      */
214     double distanceTo( const  QVector3D &point ) const;
215 
216     bool operator==( const QgsBox3d &other ) const;
217 
218   private:
219 
220     QgsRectangle mBounds2d;
221     double mZmin = 0.0;
222     double mZmax = 0.0;
223 
224 };
225 
226 #endif // QGSBOX3D_H
227