QGIS API Documentation 4.3.0-Master (8c22baaae17)
Loading...
Searching...
No Matches
qgschunknode.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgschunknode.cpp
3 --------------------------------------
4 Date : July 2017
5 Copyright : (C) 2017 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgschunknode.h"
17
18#include "qgschunkedentity.h"
19#include "qgschunklist_p.h"
20
21#include <Qt3DCore/QEntity>
22
24
25QgsChunkNode::QgsChunkNode( const QgsChunkNodeId &nodeId, const QgsBox3D &box3D, float error, QgsChunkNode *parent )
26 : mBox3D( box3D )
27 , mError( error )
28 , mNodeId( nodeId )
29 , mParent( parent )
30{}
31
32QgsChunkNode::~QgsChunkNode()
33{
34 Q_ASSERT( mState == Skeleton );
35 Q_ASSERT( !mLoaderQueueEntry );
36 Q_ASSERT( !mReplacementQueueEntry );
37 Q_ASSERT( !mEntity ); // should be deleted when removed from replacement queue
38
39 qDeleteAll( mChildren );
40}
41
42bool QgsChunkNode::allChildChunksResident( QTime currentTime ) const
43{
44 Q_ASSERT( mChildrenPopulated );
45 for ( int i = 0; i < childCount(); ++i )
46 {
47 if ( mChildren[i]->mHasData && !mChildren[i]->mEntity )
48 return false; // no there yet
49 Q_UNUSED( currentTime ) // seems we do not need this extra time (it just brings extra problems)
50 //if (children[i]->entityCreatedTime.msecsTo(currentTime) < 100)
51 // return false; // allow some time for upload of stuff within Qt3D (TODO: better way to check it is ready?)
52 }
53 return true;
54}
55
56void QgsChunkNode::populateChildren( const QVector<QgsChunkNode *> &children )
57{
58 Q_ASSERT( !mChildrenPopulated );
59 mChildrenPopulated = true;
60 mChildren = children;
61 mCreatingChildren = false;
62}
63
64int QgsChunkNode::level() const
65{
66 int lvl = 0;
67 QgsChunkNode *p = mParent;
68 while ( p )
69 {
70 ++lvl;
71 p = p->mParent;
72 }
73 return lvl;
74}
75
76QList<QgsChunkNode *> QgsChunkNode::descendants()
77{
78 QList<QgsChunkNode *> lst;
79 lst << this;
80
81 for ( int i = 0; i < childCount(); ++i )
82 {
83 lst << mChildren[i]->descendants();
84 }
85
86 return lst;
87}
88
89void QgsChunkNode::setQueuedForLoad( QgsChunkListEntry *entry )
90{
91 Q_ASSERT( mState == Skeleton );
92 Q_ASSERT( !mLoaderQueueEntry );
93 Q_ASSERT( !mLoaderJob );
94
95 mState = QgsChunkNode::QueuedForLoad;
96 mLoaderQueueEntry = entry;
97}
98
99void QgsChunkNode::cancelQueuedForLoad()
100{
101 Q_ASSERT( mState == QueuedForLoad );
102 Q_ASSERT( mLoaderQueueEntry );
103
104 delete mLoaderQueueEntry;
105 mLoaderQueueEntry = nullptr;
106
107 mState = QgsChunkNode::Skeleton;
108}
109
110void QgsChunkNode::setLoading( QgsChunkQueueJob &job )
111{
112 Q_ASSERT( mState == QueuedForLoad );
113 Q_ASSERT( !mLoaderJob );
114 Q_ASSERT( mLoaderQueueEntry );
115
116 mState = Loading;
117 mLoaderJob = &job;
118 mLoaderQueueEntry = nullptr;
119}
120
121void QgsChunkNode::cancelLoading()
122{
123 Q_ASSERT( mState == QgsChunkNode::Loading );
124 Q_ASSERT( mLoaderJob );
125 Q_ASSERT( !mLoaderQueueEntry );
126 Q_ASSERT( !mEntity );
127 Q_ASSERT( !mReplacementQueueEntry );
128
129 mLoaderJob = nullptr; // not owned by chunk node
130
131 mState = QgsChunkNode::Skeleton;
132}
133
134void QgsChunkNode::setLoaded( Qt3DCore::QEntity *newEntity )
135{
136 Q_ASSERT( mState == QgsChunkNode::Loading );
137 Q_ASSERT( mLoaderJob );
138 Q_ASSERT( !mLoaderQueueEntry );
139 Q_ASSERT( !mReplacementQueueEntry );
140
141 mEntity = newEntity;
142 mEntityCreatedTime = QTime::currentTime();
143
144 mLoaderJob = nullptr; // not owned by chunk node
145
146 mState = QgsChunkNode::Loaded;
147 mReplacementQueueEntry = new QgsChunkListEntry( this );
148}
149
150void QgsChunkNode::unloadChunk()
151{
152 Q_ASSERT( mState == QgsChunkNode::Loaded );
153 Q_ASSERT( mEntity );
154 Q_ASSERT( mReplacementQueueEntry );
155
156 delete mEntity;
157 mEntity = nullptr;
158
159 delete mReplacementQueueEntry;
160 mReplacementQueueEntry = nullptr;
161 mState = QgsChunkNode::Skeleton;
162}
163
164void QgsChunkNode::setQueuedForUpdate( QgsChunkListEntry *entry )
165{
166 Q_ASSERT( mState == QgsChunkNode::Loaded );
167 Q_ASSERT( mEntity );
168 Q_ASSERT( mReplacementQueueEntry );
169 Q_ASSERT( !mLoaderQueueEntry );
170 Q_ASSERT( !mUpdateJob );
171
172 mState = QueuedForUpdate;
173 mLoaderQueueEntry = entry;
174}
175
176void QgsChunkNode::cancelQueuedForUpdate()
177{
178 Q_ASSERT( mState == QueuedForUpdate );
179 Q_ASSERT( mEntity );
180 Q_ASSERT( mLoaderQueueEntry );
181 Q_ASSERT( !mUpdateJob );
182
183 mState = Loaded;
184
185 delete mLoaderQueueEntry;
186 mLoaderQueueEntry = nullptr;
187}
188
189void QgsChunkNode::setUpdating( QgsChunkQueueJob &job )
190{
191 Q_ASSERT( mState == QgsChunkNode::QueuedForUpdate );
192 Q_ASSERT( mEntity );
193 Q_ASSERT( mReplacementQueueEntry );
194 Q_ASSERT( mLoaderQueueEntry );
195 Q_ASSERT( !mUpdateJob );
196
197 mState = Updating;
198 mUpdateJob = &job;
199 mLoaderQueueEntry = nullptr;
200}
201
202void QgsChunkNode::cancelUpdating()
203{
204 Q_ASSERT( mState == QgsChunkNode::Updating );
205 Q_ASSERT( mUpdateJob );
206 Q_ASSERT( !mLoaderQueueEntry );
207
208 mUpdateJob = nullptr; // not owned by chunk node
209
210 mState = Loaded;
211}
212
213void QgsChunkNode::setUpdated()
214{
215 Q_ASSERT( mState == QgsChunkNode::Updating );
216 Q_ASSERT( mUpdateJob );
217 Q_ASSERT( !mLoaderQueueEntry );
218 Q_ASSERT( mReplacementQueueEntry );
219
220 mUpdateJob = nullptr; // not owned by chunk node
221
222 mState = QgsChunkNode::Loaded;
223}
224
225bool QgsChunkNode::creatingChildren() const
226{
227 return mCreatingChildren;
228}
229
230void QgsChunkNode::setCreatingChildren( bool val )
231{
232 mCreatingChildren = val;
233}
234
235void QgsChunkNode::replaceEntity( Qt3DCore::QEntity *newEntity )
236{
237 Q_ASSERT( mState == QgsChunkNode::Updating );
238 Q_ASSERT( mUpdateJob );
239 Q_ASSERT( mEntity );
240 Q_ASSERT( newEntity );
241
242 mEntity->deleteLater();
243 mEntity = newEntity;
244}
245
246void QgsChunkNode::setExactBox3D( const QgsBox3D &box3D )
247{
248 mBox3D = box3D;
249
250 // TODO: propagate better estimate to children?
251}
252
253void QgsChunkNode::updateParentBoundingBoxesRecursively() const
254{
255 QgsChunkNode *currentNode = parent();
256 while ( currentNode )
257 {
258 QgsChunkNode *const *currentNodeChildren = currentNode->children();
259 double xMin = std::numeric_limits<double>::max();
260 double xMax = -std::numeric_limits<double>::max();
261 double yMin = std::numeric_limits<double>::max();
262 double yMax = -std::numeric_limits<double>::max();
263 double zMin = std::numeric_limits<double>::max();
264 double zMax = -std::numeric_limits<double>::max();
265
266 for ( int i = 0; i < currentNode->childCount(); ++i )
267 {
268 const QgsBox3D childBox3D = currentNodeChildren[i]->box3D();
269
270 // Nodes without data have an empty bbox and should be skipped
271 if ( childBox3D.isEmpty() )
272 continue;
273
274 if ( childBox3D.xMinimum() < xMin )
275 xMin = childBox3D.xMinimum();
276 if ( childBox3D.yMinimum() < yMin )
277 yMin = childBox3D.yMinimum();
278 if ( childBox3D.zMinimum() < zMin )
279 zMin = childBox3D.zMinimum();
280 if ( childBox3D.xMaximum() > xMax )
281 xMax = childBox3D.xMaximum();
282 if ( childBox3D.yMaximum() > yMax )
283 yMax = childBox3D.yMaximum();
284 if ( childBox3D.zMaximum() > zMax )
285 zMax = childBox3D.zMaximum();
286 }
287
288 // QgsBox3D is normalized in its constructor, so that min values are always smaller than max.
289 // If all child bboxes were empty, we can end up with min > max, so let's have an empty bbox instead.
290 const QgsBox3D currentNodeBox3D = xMin > xMax || yMin > yMax || zMin > zMax ? QgsBox3D() : QgsBox3D( xMin, yMin, zMin, xMax, yMax, zMax );
291
292 currentNode->setExactBox3D( currentNodeBox3D );
293 currentNode = currentNode->parent();
294 }
295}
296
A 3-dimensional box composed of x, y, z coordinates.
Definition qgsbox3d.h:45
double yMaximum() const
Returns the maximum y value.
Definition qgsbox3d.h:240
double xMinimum() const
Returns the minimum x value.
Definition qgsbox3d.h:205
double zMaximum() const
Returns the maximum z value.
Definition qgsbox3d.h:268
double xMaximum() const
Returns the maximum x value.
Definition qgsbox3d.h:212
double zMinimum() const
Returns the minimum z value.
Definition qgsbox3d.h:261
double yMinimum() const
Returns the minimum y value.
Definition qgsbox3d.h:233
bool isEmpty() const
Returns true if the box is empty.
Definition qgsbox3d.cpp:321