QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgschunknode_p.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgschunknode_p.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_p.h"
17 
18 #include "qgschunkedentity_p.h" // for ChunkLoader destructor
19 #include "qgschunklist_p.h"
20 #include "qgschunkloader_p.h"
21 #include <Qt3DCore/QEntity>
22 
24 
25 QgsChunkNode::QgsChunkNode( int x, int y, int z, const QgsAABB &bbox, float error, QgsChunkNode *parent )
26  : mBbox( bbox )
27  , mError( error )
28  , mTileX( x )
29  , mTileY( y )
30  , mTileZ( z )
31  , mParent( parent )
32  , mState( Skeleton )
33  , mLoaderQueueEntry( nullptr )
34  , mReplacementQueueEntry( nullptr )
35  , mLoader( nullptr )
36  , mEntity( nullptr )
37  , mUpdaterFactory( nullptr )
38  , mUpdater( nullptr )
39 {
40  for ( int i = 0; i < 4; ++i )
41  mChildren[i] = nullptr;
42 }
43 
44 QgsChunkNode::~QgsChunkNode()
45 {
46  Q_ASSERT( mState == Skeleton );
47  Q_ASSERT( !mLoaderQueueEntry );
48  Q_ASSERT( !mReplacementQueueEntry );
49  Q_ASSERT( !mLoader ); // should be deleted when removed from loader queue
50  Q_ASSERT( !mEntity ); // should be deleted when removed from replacement queue
51  Q_ASSERT( !mUpdater );
52  Q_ASSERT( !mUpdaterFactory );
53  for ( int i = 0; i < 4; ++i )
54  delete mChildren[i];
55 }
56 
57 bool QgsChunkNode::allChildChunksResident( QTime currentTime ) const
58 {
59  for ( int i = 0; i < 4; ++i )
60  {
61  if ( !mChildren[i] )
62  return false; // not even a skeleton
63  if ( mChildren[i]->mHasData && !mChildren[i]->mEntity )
64  return false; // no there yet
65  Q_UNUSED( currentTime ) // seems we do not need this extra time (it just brings extra problems)
66  //if (children[i]->entityCreatedTime.msecsTo(currentTime) < 100)
67  // return false; // allow some time for upload of stuff within Qt3D (TODO: better way to check it is ready?)
68  }
69  return true;
70 }
71 
72 void QgsChunkNode::ensureAllChildrenExist()
73 {
74  float childError = mError / 2;
75  float xc = mBbox.xCenter(), zc = mBbox.zCenter();
76  float ymin = mBbox.yMin;
77  float ymax = mBbox.yMax;
78 
79  if ( !mChildren[0] )
80  mChildren[0] = new QgsChunkNode( mTileX * 2 + 0, mTileY * 2 + 1, mTileZ + 1, QgsAABB( mBbox.xMin, ymin, mBbox.zMin, xc, ymax, zc ), childError, this );
81 
82  if ( !mChildren[1] )
83  mChildren[1] = new QgsChunkNode( mTileX * 2 + 0, mTileY * 2 + 0, mTileZ + 1, QgsAABB( mBbox.xMin, ymin, zc, xc, ymax, mBbox.zMax ), childError, this );
84 
85  if ( !mChildren[2] )
86  mChildren[2] = new QgsChunkNode( mTileX * 2 + 1, mTileY * 2 + 1, mTileZ + 1, QgsAABB( xc, ymin, mBbox.zMin, mBbox.xMax, ymax, zc ), childError, this );
87 
88  if ( !mChildren[3] )
89  mChildren[3] = new QgsChunkNode( mTileX * 2 + 1, mTileY * 2 + 0, mTileZ + 1, QgsAABB( xc, ymin, zc, mBbox.xMax, ymax, mBbox.zMax ), childError, this );
90 }
91 
92 int QgsChunkNode::level() const
93 {
94  int lvl = 0;
95  QgsChunkNode *p = mParent;
96  while ( p )
97  {
98  ++lvl;
99  p = p->mParent;
100  }
101  return lvl;
102 }
103 
104 QList<QgsChunkNode *> QgsChunkNode::descendants()
105 {
106  QList<QgsChunkNode *> lst;
107  lst << this;
108 
109  for ( int i = 0; i < 4; ++i )
110  {
111  if ( mChildren[i] )
112  lst << mChildren[i]->descendants();
113  }
114 
115  return lst;
116 }
117 
118 void QgsChunkNode::setQueuedForLoad( QgsChunkListEntry *entry )
119 {
120  Q_ASSERT( mState == Skeleton );
121  Q_ASSERT( !mLoaderQueueEntry );
122  Q_ASSERT( !mLoader );
123 
124  mState = QgsChunkNode::QueuedForLoad;
125  mLoaderQueueEntry = entry;
126 }
127 
128 void QgsChunkNode::cancelQueuedForLoad()
129 {
130  Q_ASSERT( mState == QueuedForLoad );
131  Q_ASSERT( mLoaderQueueEntry );
132 
133  delete mLoaderQueueEntry;
134  mLoaderQueueEntry = nullptr;
135 
136  mState = QgsChunkNode::Skeleton;
137 }
138 
139 void QgsChunkNode::setLoading( QgsChunkLoader *chunkLoader )
140 {
141  Q_ASSERT( mState == QueuedForLoad );
142  Q_ASSERT( !mLoader );
143  Q_ASSERT( mLoaderQueueEntry );
144 
145  mState = Loading;
146  mLoader = chunkLoader;
147  mLoaderQueueEntry = nullptr;
148 }
149 
150 void QgsChunkNode::cancelLoading()
151 {
152  Q_ASSERT( mState == QgsChunkNode::Loading );
153  Q_ASSERT( mLoader );
154  Q_ASSERT( !mLoaderQueueEntry );
155  Q_ASSERT( !mEntity );
156  Q_ASSERT( !mReplacementQueueEntry );
157 
158  mLoader = nullptr; // not owned by chunk node
159 
160  mState = QgsChunkNode::Skeleton;
161 }
162 
163 void QgsChunkNode::setLoaded( Qt3DCore::QEntity *newEntity )
164 {
165  Q_ASSERT( mState == QgsChunkNode::Loading );
166  Q_ASSERT( mLoader );
167  Q_ASSERT( !mLoaderQueueEntry );
168  Q_ASSERT( !mReplacementQueueEntry );
169 
170  mEntity = newEntity;
171  mEntityCreatedTime = QTime::currentTime();
172 
173  mLoader = nullptr; // not owned by chunk node
174 
175  mState = QgsChunkNode::Loaded;
176  mReplacementQueueEntry = new QgsChunkListEntry( this );
177 }
178 
179 void QgsChunkNode::unloadChunk()
180 {
181  Q_ASSERT( mState == QgsChunkNode::Loaded );
182  Q_ASSERT( mEntity );
183  Q_ASSERT( mReplacementQueueEntry );
184 
185  mEntity->deleteLater();
186  mEntity = nullptr;
187  delete mReplacementQueueEntry;
188  mReplacementQueueEntry = nullptr;
189  mState = QgsChunkNode::Skeleton;
190 }
191 
192 void QgsChunkNode::setQueuedForUpdate( QgsChunkListEntry *entry, QgsChunkQueueJobFactory *updateJobFactory )
193 {
194  Q_ASSERT( mState == QgsChunkNode::Loaded );
195  Q_ASSERT( mEntity );
196  Q_ASSERT( mReplacementQueueEntry );
197  Q_ASSERT( !mLoaderQueueEntry );
198  Q_ASSERT( !mUpdater );
199  Q_ASSERT( !mUpdaterFactory );
200 
201  mState = QueuedForUpdate;
202  mLoaderQueueEntry = entry;
203  mUpdaterFactory = updateJobFactory;
204 }
205 
206 void QgsChunkNode::cancelQueuedForUpdate()
207 {
208  Q_ASSERT( mState == QueuedForUpdate );
209  Q_ASSERT( mEntity );
210  Q_ASSERT( mLoaderQueueEntry );
211  Q_ASSERT( mUpdaterFactory );
212  Q_ASSERT( !mUpdater );
213 
214  mState = Loaded;
215  mUpdaterFactory = nullptr; // not owned by the node
216 
217  delete mLoaderQueueEntry;
218  mLoaderQueueEntry = nullptr;
219 }
220 
221 void QgsChunkNode::setUpdating()
222 {
223  Q_ASSERT( mState == QgsChunkNode::QueuedForUpdate );
224  Q_ASSERT( mEntity );
225  Q_ASSERT( mReplacementQueueEntry );
226  Q_ASSERT( mLoaderQueueEntry );
227  Q_ASSERT( !mUpdater );
228  Q_ASSERT( mUpdaterFactory );
229 
230  mState = Updating;
231  mUpdater = mUpdaterFactory->createJob( this );
232  mUpdaterFactory = nullptr; // not owned by the node
233  mLoaderQueueEntry = nullptr;
234 }
235 
236 void QgsChunkNode::cancelUpdating()
237 {
238  Q_ASSERT( mState == QgsChunkNode::Updating );
239  Q_ASSERT( mUpdater );
240  Q_ASSERT( !mLoaderQueueEntry );
241 
242  mUpdater = nullptr; // not owned by chunk node
243 
244  mState = Loaded;
245 }
246 
247 void QgsChunkNode::setUpdated()
248 {
249  Q_ASSERT( mState == QgsChunkNode::Updating );
250  Q_ASSERT( mUpdater );
251  Q_ASSERT( !mLoaderQueueEntry );
252  Q_ASSERT( mReplacementQueueEntry );
253 
254  mUpdater = nullptr; // not owned by chunk node
255 
256  mState = QgsChunkNode::Loaded;
257 }
258 
259 void QgsChunkNode::setExactBbox( const QgsAABB &box )
260 {
261  mBbox = box;
262 
263  // TODO: propagate better estimate to children?
264 }
265 
3 Axis-aligned bounding box - in world coords.
Definition: qgsaabb.h:30