1 /***************************************************************************
2                          qgsmeshdatasetgroupstore.cpp
3                          ---------------------
4     begin                : June 2020
5     copyright            : (C) 2020 by Vincent Cloarec
6     email                : vcloarec 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 "qgsmeshdatasetgroupstore.h"
19 #include "qgsmeshlayer.h"
20 #include "qgsmeshlayerutils.h"
21 #include "qgsapplication.h"
22 #include "qgsmeshvirtualdatasetgroup.h"
23 #include "qgslogger.h"
24 
datasetGroupIndexes() const25 QList<int> QgsMeshDatasetGroupStore::datasetGroupIndexes() const
26 {
27   return mRegistery.keys();
28 }
29 
enabledDatasetGroupIndexes() const30 QList<int> QgsMeshDatasetGroupStore::enabledDatasetGroupIndexes() const
31 {
32   return mDatasetGroupTreeRootItem->enabledDatasetGroupIndexes();
33 }
34 
datasetGroupCount() const35 int QgsMeshDatasetGroupStore::datasetGroupCount() const
36 {
37   return mRegistery.count();
38 }
39 
extraDatasetGroupCount() const40 int QgsMeshDatasetGroupStore::extraDatasetGroupCount() const
41 {
42   return mExtraDatasets->datasetGroupCount();
43 }
44 
QgsMeshDatasetGroupStore(QgsMeshLayer * layer)45 QgsMeshDatasetGroupStore::QgsMeshDatasetGroupStore( QgsMeshLayer *layer ):
46   mLayer( layer ),
47   mExtraDatasets( new QgsMeshExtraDatasetStore ),
48   mDatasetGroupTreeRootItem( new QgsMeshDatasetGroupTreeItem )
49 {}
50 
setPersistentProvider(QgsMeshDataProvider * provider,const QStringList & extraDatasetUri)51 void QgsMeshDatasetGroupStore::setPersistentProvider( QgsMeshDataProvider *provider, const QStringList &extraDatasetUri )
52 {
53   removePersistentProvider();
54   mPersistentProvider = provider;
55   if ( !mPersistentProvider )
56     return;
57   for ( const QString &uri : extraDatasetUri )
58     mPersistentProvider->addDataset( uri );
59 
60   onPersistentDatasetAdded( mPersistentProvider->datasetGroupCount() );
61 
62   checkDatasetConsistency( mPersistentProvider );
63   removeUnregisteredItemFromTree();
64 
65   //Once everything is in place, initialize the extra dataset groups
66   if ( mExtraDatasets )
67   {
68     const int groupCount = mExtraDatasets->datasetGroupCount();
69     for ( int i = 0; i < groupCount; ++i )
70       if ( mExtraDatasets->datasetGroup( i ) )
71         mExtraDatasets->datasetGroup( i )->initialize();
72   }
73 
74   mExtraDatasets->updateTemporalCapabilities();
75 
76   connect( mPersistentProvider, &QgsMeshDataProvider::datasetGroupsAdded, this, &QgsMeshDatasetGroupStore::onPersistentDatasetAdded );
77 }
78 
datasetGroup(int index) const79 QgsMeshDatasetGroupStore::DatasetGroup QgsMeshDatasetGroupStore::datasetGroup( int index ) const
80 {
81   if ( mRegistery.contains( index ) )
82     return mRegistery[index];
83   else
84     return DatasetGroup{nullptr, -1};
85 }
86 
addPersistentDatasets(const QString & path)87 bool QgsMeshDatasetGroupStore::addPersistentDatasets( const QString &path )
88 {
89   if ( !mPersistentProvider )
90     return false;
91   return mPersistentProvider->addDataset( path ) ;
92 }
93 
addDatasetGroup(QgsMeshDatasetGroup * group)94 bool QgsMeshDatasetGroupStore::addDatasetGroup( QgsMeshDatasetGroup *group )
95 {
96   if ( !mExtraDatasets && !mLayer )
97     return false;
98 
99   switch ( group->dataType() )
100   {
101     case QgsMeshDatasetGroupMetadata::DataOnFaces:
102       if ( ! group->checkValueCountPerDataset( mLayer->meshFaceCount() ) )
103         return false;
104       break;
105     case QgsMeshDatasetGroupMetadata::DataOnVertices:
106       if ( ! group->checkValueCountPerDataset( mLayer->meshVertexCount() ) )
107         return false;
108       break;
109     case QgsMeshDatasetGroupMetadata::DataOnVolumes:
110       return false; // volume not supported for extra dataset
111       break;
112     case QgsMeshDatasetGroupMetadata::DataOnEdges:
113       if ( ! group->checkValueCountPerDataset( mLayer->meshEdgeCount() ) )
114         return false;
115       break;
116   }
117 
118   int nativeIndex = mExtraDatasets->addDatasetGroup( group );
119   int groupIndex = registerDatasetGroup( DatasetGroup{mExtraDatasets.get(), nativeIndex} );
120   QList<int> groupIndexes;
121   groupIndexes.append( groupIndex );
122   createDatasetGroupTreeItems( groupIndexes );
123   syncItemToDatasetGroup( groupIndex );
124 
125   emit datasetGroupsAdded( groupIndexes );
126 
127   return true;
128 }
129 
resetDatasetGroupTreeItem()130 void QgsMeshDatasetGroupStore::resetDatasetGroupTreeItem()
131 {
132   mDatasetGroupTreeRootItem.reset( new QgsMeshDatasetGroupTreeItem );
133   createDatasetGroupTreeItems( datasetGroupIndexes() );
134   QList<int> groupIndexes = datasetGroupIndexes();
135   for ( int groupIndex : groupIndexes )
136     syncItemToDatasetGroup( groupIndex );
137 }
138 
datasetGroupTreeItem() const139 QgsMeshDatasetGroupTreeItem *QgsMeshDatasetGroupStore::datasetGroupTreeItem() const
140 {
141   return mDatasetGroupTreeRootItem.get();
142 }
143 
setDatasetGroupTreeItem(QgsMeshDatasetGroupTreeItem * rootItem)144 void QgsMeshDatasetGroupStore::setDatasetGroupTreeItem( QgsMeshDatasetGroupTreeItem *rootItem )
145 {
146   if ( rootItem )
147     mDatasetGroupTreeRootItem.reset( rootItem->clone() );
148   else
149     mDatasetGroupTreeRootItem.reset();
150 
151   unregisterGroupNotPresentInTree();
152 }
153 
datasetGroupMetadata(const QgsMeshDatasetIndex & index) const154 QgsMeshDatasetGroupMetadata QgsMeshDatasetGroupStore::datasetGroupMetadata( const QgsMeshDatasetIndex &index ) const
155 {
156   QgsMeshDatasetGroupStore::DatasetGroup  group = datasetGroup( index.group() );
157   if ( group.first )
158     return group.first->datasetGroupMetadata( group.second );
159   else
160     return QgsMeshDatasetGroupMetadata();
161 }
162 
datasetCount(int groupIndex) const163 int QgsMeshDatasetGroupStore::datasetCount( int groupIndex ) const
164 {
165   QgsMeshDatasetGroupStore::DatasetGroup  group = datasetGroup( groupIndex );
166   if ( group.first )
167     return group.first->datasetCount( group.second );
168   else
169     return 0;
170 }
171 
datasetMetadata(const QgsMeshDatasetIndex & index) const172 QgsMeshDatasetMetadata QgsMeshDatasetGroupStore::datasetMetadata( const QgsMeshDatasetIndex &index ) const
173 {
174   QgsMeshDatasetGroupStore::DatasetGroup  group = datasetGroup( index.group() );
175   if ( group.first )
176     return group.first->datasetMetadata( QgsMeshDatasetIndex( group.second, index.dataset() ) );
177   else
178     return QgsMeshDatasetMetadata();
179 }
180 
datasetValue(const QgsMeshDatasetIndex & index,int valueIndex) const181 QgsMeshDatasetValue QgsMeshDatasetGroupStore::datasetValue( const QgsMeshDatasetIndex &index, int valueIndex ) const
182 {
183   QgsMeshDatasetGroupStore::DatasetGroup  group = datasetGroup( index.group() );
184   if ( group.first )
185     return group.first->datasetValue( QgsMeshDatasetIndex( group.second, index.dataset() ), valueIndex );
186   else
187     return QgsMeshDatasetValue();
188 }
189 
datasetValues(const QgsMeshDatasetIndex & index,int valueIndex,int count) const190 QgsMeshDataBlock QgsMeshDatasetGroupStore::datasetValues( const QgsMeshDatasetIndex &index, int valueIndex, int count ) const
191 {
192   QgsMeshDatasetGroupStore::DatasetGroup  group = datasetGroup( index.group() );
193   if ( group.first )
194     return group.first->datasetValues( QgsMeshDatasetIndex( group.second, index.dataset() ), valueIndex, count );
195   else
196     return QgsMeshDataBlock();
197 }
198 
dataset3dValues(const QgsMeshDatasetIndex & index,int faceIndex,int count) const199 QgsMesh3dDataBlock QgsMeshDatasetGroupStore::dataset3dValues( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
200 {
201   QgsMeshDatasetGroupStore::DatasetGroup  group = datasetGroup( index.group() );
202   if ( group.first )
203     return group.first->dataset3dValues( QgsMeshDatasetIndex( group.second, index.dataset() ), faceIndex, count );
204   else
205     return QgsMesh3dDataBlock();
206 }
207 
areFacesActive(const QgsMeshDatasetIndex & index,int faceIndex,int count) const208 QgsMeshDataBlock QgsMeshDatasetGroupStore::areFacesActive( const QgsMeshDatasetIndex &index, int faceIndex, int count ) const
209 {
210   QgsMeshDatasetGroupStore::DatasetGroup  group = datasetGroup( index.group() );
211   if ( group.first )
212     return group.first->areFacesActive( QgsMeshDatasetIndex( group.second, index.dataset() ), faceIndex, count );
213   else
214     return QgsMeshDataBlock();
215 }
216 
isFaceActive(const QgsMeshDatasetIndex & index,int faceIndex) const217 bool QgsMeshDatasetGroupStore::isFaceActive( const QgsMeshDatasetIndex &index, int faceIndex ) const
218 {
219   QgsMeshDatasetGroupStore::DatasetGroup  group = datasetGroup( index.group() );
220   if ( group.first )
221     return group.first->isFaceActive( QgsMeshDatasetIndex( group.second, index.dataset() ), faceIndex );
222   else
223     return false;
224 }
225 
datasetIndexAtTime(qint64 time,int groupIndex,QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod method) const226 QgsMeshDatasetIndex QgsMeshDatasetGroupStore::datasetIndexAtTime(
227   qint64 time,
228   int groupIndex, QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod method ) const
229 {
230   QgsMeshDatasetGroupStore::DatasetGroup  group = datasetGroup( groupIndex );
231   if ( !group.first )
232     return QgsMeshDatasetIndex();
233 
234   const QDateTime &referenceTime = mPersistentProvider ? mPersistentProvider->temporalCapabilities()->referenceTime() : QDateTime();
235 
236   return QgsMeshDatasetIndex( groupIndex,
237                               group.first->datasetIndexAtTime( referenceTime, group.second, time, method ).dataset() );
238 }
239 
datasetIndexInTimeInterval(qint64 time1,qint64 time2,int groupIndex) const240 QList<QgsMeshDatasetIndex> QgsMeshDatasetGroupStore::datasetIndexInTimeInterval(
241   qint64 time1,
242   qint64 time2,
243   int groupIndex ) const
244 {
245   const QgsMeshDatasetGroupStore::DatasetGroup  group = datasetGroup( groupIndex );
246   if ( !group.first )
247     return QList<QgsMeshDatasetIndex>();
248 
249   const QDateTime &referenceTime = mPersistentProvider ? mPersistentProvider->temporalCapabilities()->referenceTime() : QDateTime();
250 
251   const QList<QgsMeshDatasetIndex> datasetIndexes = group.first->datasetIndexInTimeInterval( referenceTime, group.second, time1, time2 );
252 
253   QList<QgsMeshDatasetIndex> ret;
254   ret.reserve( datasetIndexes.count() );
255 
256   for ( const QgsMeshDatasetIndex &sourceDatasetIndex : datasetIndexes )
257     ret.append( QgsMeshDatasetIndex( groupIndex, sourceDatasetIndex.dataset() ) );
258 
259   return ret;
260 }
261 
datasetRelativeTime(const QgsMeshDatasetIndex & index) const262 qint64 QgsMeshDatasetGroupStore::datasetRelativeTime( const QgsMeshDatasetIndex &index ) const
263 {
264   QgsMeshDatasetGroupStore::DatasetGroup  group = datasetGroup( index.group() );
265   if ( !group.first || group.second < 0 )
266     return INVALID_MESHLAYER_TIME;
267 
268   QgsMeshDatasetIndex nativeIndex( group.second, index.dataset() );
269 
270   if ( group.first == mPersistentProvider )
271     return mPersistentProvider->temporalCapabilities()->datasetTime( nativeIndex );
272   else if ( group.first == mExtraDatasets.get() )
273     return mExtraDatasets->datasetRelativeTime( nativeIndex );
274 
275   return INVALID_MESHLAYER_TIME;
276 
277 }
278 
hasTemporalCapabilities() const279 bool QgsMeshDatasetGroupStore::hasTemporalCapabilities() const
280 {
281   return ( mPersistentProvider && mPersistentProvider->temporalCapabilities()->hasTemporalCapabilities() ) ||
282          ( mExtraDatasets && mExtraDatasets->hasTemporalCapabilities() );
283 }
284 
writeXml(QDomDocument & doc,const QgsReadWriteContext & context)285 QDomElement QgsMeshDatasetGroupStore::writeXml( QDomDocument &doc, const QgsReadWriteContext &context )
286 {
287   Q_UNUSED( context );
288   QDomElement storeElement = doc.createElement( QStringLiteral( "mesh-dataset-groups-store" ) );
289   storeElement.appendChild( mDatasetGroupTreeRootItem->writeXml( doc, context ) );
290 
291   QMap < int, DatasetGroup>::const_iterator it = mRegistery.constBegin();
292   while ( it != mRegistery.constEnd() )
293   {
294     QDomElement elemDataset;
295     if ( it.value().first == mPersistentProvider )
296     {
297       elemDataset = doc.createElement( QStringLiteral( "mesh-dataset" ) );
298       elemDataset.setAttribute( QStringLiteral( "global-index" ), it.key() );
299       elemDataset.setAttribute( QStringLiteral( "source-type" ), QStringLiteral( "persitent-provider" ) );
300       elemDataset.setAttribute( QStringLiteral( "source-index" ), it.value().second );
301     }
302     else if ( it.value().first == mExtraDatasets.get() )
303     {
304       QgsMeshDatasetGroupTreeItem *item = mDatasetGroupTreeRootItem->childFromDatasetGroupIndex( it.key() );
305       if ( item )
306       {
307         elemDataset = mExtraDatasets->writeXml( it.value().second, doc, context );
308         if ( !elemDataset.isNull() )
309           elemDataset.setAttribute( QStringLiteral( "global-index" ), it.key() );
310       }
311     }
312 
313     if ( !elemDataset.isNull() )
314       storeElement.appendChild( elemDataset );
315     ++it;
316   }
317 
318   return storeElement;
319 }
320 
readXml(const QDomElement & storeElem,const QgsReadWriteContext & context)321 void QgsMeshDatasetGroupStore::readXml( const QDomElement &storeElem, const QgsReadWriteContext &context )
322 {
323   Q_UNUSED( context );
324   mRegistery.clear();
325   QDomElement datasetElem = storeElem.firstChildElement( "mesh-dataset" );
326   QMap<int, QgsMeshDatasetGroup *> extraDatasetGroups;
327   while ( !datasetElem.isNull() )
328   {
329     int globalIndex = datasetElem.attribute( QStringLiteral( "global-index" ) ).toInt();
330     int sourceIndex = -1;
331     QgsMeshDatasetSourceInterface *source = nullptr;
332     const QString sourceType = datasetElem.attribute( QStringLiteral( "source-type" ) );
333     if ( sourceType == QLatin1String( "persitent-provider" ) )
334     {
335       source = mPersistentProvider;
336       sourceIndex = datasetElem.attribute( QStringLiteral( "source-index" ) ).toInt();
337       mPersistentExtraDatasetGroupIndexes.append( globalIndex );
338     }
339     else if ( sourceType == QLatin1String( "virtual" ) )
340     {
341       source = mExtraDatasets.get();
342       QString name = datasetElem.attribute( QStringLiteral( "name" ) );
343       QString formula = datasetElem.attribute( QStringLiteral( "formula" ) );
344       qint64 startTime = datasetElem.attribute( QStringLiteral( "start-time" ) ).toLongLong();
345       qint64 endTime = datasetElem.attribute( QStringLiteral( "end-time" ) ).toLongLong();
346 
347       QgsMeshDatasetGroup *dsg = new QgsMeshVirtualDatasetGroup( name, formula, mLayer, startTime, endTime );
348       extraDatasetGroups[globalIndex] = dsg;
349       sourceIndex = mExtraDatasets->addDatasetGroup( dsg );
350     }
351     else
352     {
353       QgsDebugMsg( QStringLiteral( "Unhandled source-type: %1." ).arg( sourceType ) );
354     }
355     if ( source )
356     {
357       mRegistery[globalIndex] = DatasetGroup{source, sourceIndex};
358     }
359 
360     datasetElem = datasetElem.nextSiblingElement( QStringLiteral( "mesh-dataset" ) );
361   }
362 
363   QDomElement rootTreeItemElem = storeElem.firstChildElement( QStringLiteral( "mesh-dataset-group-tree-item" ) );
364   if ( !rootTreeItemElem.isNull() )
365     setDatasetGroupTreeItem( new QgsMeshDatasetGroupTreeItem( rootTreeItemElem, context ) );
366 }
367 
globalDatasetGroupIndexInSource(QgsMeshDatasetSourceInterface * source,int nativeGroupIndex) const368 int QgsMeshDatasetGroupStore::globalDatasetGroupIndexInSource( QgsMeshDatasetSourceInterface *source, int nativeGroupIndex ) const
369 {
370   for ( QMap<int, DatasetGroup>::const_iterator it = mRegistery.cbegin(); it != mRegistery.cend(); ++it )
371   {
372     if ( it.value().first == source && it.value().second == nativeGroupIndex )
373       return it.key();
374   }
375 
376   return -1;
377 }
378 
saveDatasetGroup(QString filePath,int groupIndex,QString driver)379 bool QgsMeshDatasetGroupStore::saveDatasetGroup( QString filePath, int groupIndex, QString driver )
380 {
381   DatasetGroup group = datasetGroup( groupIndex );
382 
383   bool fail = true;
384   if ( group.first && group.second >= 0 )
385     fail = mPersistentProvider->persistDatasetGroup( filePath, driver, group.first, group.second );
386 
387   if ( !fail )
388   {
389     eraseDatasetGroup( group );
390     group.first = mPersistentProvider;
391     group.second = mPersistentProvider->datasetGroupCount() - 1;
392     mRegistery[groupIndex] = group;
393     //update the item type
394     if ( mDatasetGroupTreeRootItem )
395     {
396       QgsMeshDatasetGroupTreeItem *item = mDatasetGroupTreeRootItem->childFromDatasetGroupIndex( groupIndex );
397       if ( item )
398         item->setPersistentDatasetGroup( filePath );
399     }
400   }
401 
402   return fail;
403 }
404 
onPersistentDatasetAdded(int count)405 void QgsMeshDatasetGroupStore::onPersistentDatasetAdded( int count )
406 {
407   Q_ASSERT( mPersistentProvider );
408 
409   int providerTotalCount = mPersistentProvider->datasetGroupCount();
410   int providerBeginIndex = mPersistentProvider->datasetGroupCount() - count;
411   QList<int> newGroupIndexes;
412   for ( int i = providerBeginIndex; i < providerTotalCount; ++i )
413   {
414     if ( i < mPersistentExtraDatasetGroupIndexes.count() )
415       mRegistery[mPersistentExtraDatasetGroupIndexes.at( i )] = DatasetGroup( mPersistentProvider, i );
416     else
417       newGroupIndexes.append( registerDatasetGroup( DatasetGroup{mPersistentProvider, i} ) );
418   }
419 
420   if ( !newGroupIndexes.isEmpty() )
421   {
422     createDatasetGroupTreeItems( newGroupIndexes );
423     mPersistentExtraDatasetGroupIndexes.append( newGroupIndexes );
424 
425     for ( int groupIndex : std::as_const( newGroupIndexes ) )
426       syncItemToDatasetGroup( groupIndex );
427 
428     emit datasetGroupsAdded( newGroupIndexes );
429   }
430 }
431 
removePersistentProvider()432 void QgsMeshDatasetGroupStore::removePersistentProvider()
433 {
434   if ( !mPersistentProvider )
435     return;
436 
437   disconnect( mPersistentProvider, &QgsMeshDataProvider::datasetGroupsAdded, this, &QgsMeshDatasetGroupStore::onPersistentDatasetAdded );
438 
439   QMap < int, DatasetGroup>::iterator it = mRegistery.begin();
440   while ( it != mRegistery.end() )
441   {
442     if ( it.value().first == mPersistentProvider )
443       it = mRegistery.erase( it );
444     else
445       ++it;
446   }
447 
448   mPersistentProvider = nullptr;
449 }
450 
newIndex()451 int QgsMeshDatasetGroupStore::newIndex()
452 {
453   int index = 0;
454   QMap < int, DatasetGroup>::iterator it = mRegistery.begin();
455   while ( it != mRegistery.end() )
456   {
457     if ( index <= it.key() )
458       index = it.key() + 1;
459     ++it;
460   }
461   return index;
462 }
463 
registerDatasetGroup(const QgsMeshDatasetGroupStore::DatasetGroup & group)464 int QgsMeshDatasetGroupStore::registerDatasetGroup( const QgsMeshDatasetGroupStore::DatasetGroup &group )
465 {
466   int groupIndex = newIndex();
467   mRegistery[newIndex()] = group;
468   return groupIndex;
469 }
470 
eraseDatasetGroup(const QgsMeshDatasetGroupStore::DatasetGroup & group)471 void QgsMeshDatasetGroupStore::eraseDatasetGroup( const QgsMeshDatasetGroupStore::DatasetGroup &group )
472 {
473   if ( group.first == mPersistentProvider )
474     return; //removing persistent dataset group from the store is not allowed
475   else if ( group.first == mExtraDatasets.get() )
476     eraseExtraDataset( group.second );
477 }
478 
eraseExtraDataset(int indexInExtraStore)479 void QgsMeshDatasetGroupStore::eraseExtraDataset( int indexInExtraStore )
480 {
481   mExtraDatasets->removeDatasetGroup( indexInExtraStore );
482 
483   //search dataset with index greater than indexInExtraStore and decrement it
484   QMap < int, DatasetGroup>::iterator it = mRegistery.begin();
485   while ( it != mRegistery.end() )
486   {
487     int localIndex = it.value().second;
488     if ( it.value().first == mExtraDatasets.get() && localIndex > indexInExtraStore )
489       it->second = localIndex - 1;
490     ++it;
491   }
492 }
493 
nativeIndexToGroupIndex(QgsMeshDatasetSourceInterface * source,int nativeIndex)494 int QgsMeshDatasetGroupStore::nativeIndexToGroupIndex( QgsMeshDatasetSourceInterface *source, int nativeIndex )
495 {
496   QMap < int, DatasetGroup>::const_iterator it = mRegistery.constBegin();
497   while ( it != mRegistery.constEnd() )
498   {
499     if ( it.value() == DatasetGroup{source, nativeIndex} )
500       return it.key();
501     ++it;
502   }
503   return -1;
504 }
505 
checkDatasetConsistency(QgsMeshDatasetSourceInterface * source)506 void QgsMeshDatasetGroupStore::checkDatasetConsistency( QgsMeshDatasetSourceInterface *source )
507 {
508   // check if datasets of source are present, if not, add them
509   QList<int> indexes;
510   for ( int i = 0; i < source->datasetGroupCount(); ++i )
511     if ( nativeIndexToGroupIndex( source, i ) == -1 )
512       indexes.append( registerDatasetGroup( DatasetGroup{source, i} ) );
513 
514   if ( !indexes.isEmpty() )
515     createDatasetGroupTreeItems( indexes );
516 
517   for ( int globalIndex : mRegistery.keys() )
518   {
519     if ( mRegistery.value( globalIndex ).first == source )
520       syncItemToDatasetGroup( globalIndex );
521   }
522 }
523 
removeUnregisteredItemFromTree()524 void QgsMeshDatasetGroupStore::removeUnregisteredItemFromTree()
525 {
526   QList<QgsMeshDatasetGroupTreeItem *> itemsToCheck;
527   QList<int> indexItemToRemove;
528   for ( int i = 0; i < mDatasetGroupTreeRootItem->childCount(); ++i )
529     itemsToCheck.append( mDatasetGroupTreeRootItem->child( i ) );
530 
531   while ( !itemsToCheck.isEmpty() )
532   {
533     QgsMeshDatasetGroupTreeItem *item = itemsToCheck.takeFirst();
534     int globalIndex = item->datasetGroupIndex();
535     if ( !mRegistery.contains( globalIndex ) )
536       indexItemToRemove.append( globalIndex );
537     for ( int i = 0; i < item->childCount(); ++i )
538       itemsToCheck.append( item->child( i ) );
539   }
540 
541   for ( int i : indexItemToRemove )
542   {
543     QgsMeshDatasetGroupTreeItem *item = mDatasetGroupTreeRootItem->childFromDatasetGroupIndex( i );
544     if ( item )
545       item->parentItem()->removeChild( item );
546   }
547 }
548 
unregisterGroupNotPresentInTree()549 void QgsMeshDatasetGroupStore::unregisterGroupNotPresentInTree()
550 {
551   if ( !mDatasetGroupTreeRootItem )
552   {
553     mRegistery.clear();
554     return;
555   }
556 
557   QMap < int, DatasetGroup>::iterator it = mRegistery.begin();
558   while ( it != mRegistery.end() )
559   {
560     DatasetGroup datasetGroup = it.value();
561     int globalIndex = it.key();
562     if ( ! mDatasetGroupTreeRootItem->childFromDatasetGroupIndex( globalIndex ) // Not in the tree item
563          && datasetGroup.first != mPersistentProvider ) // and not persistent
564     {
565       it = mRegistery.erase( it ); //remove from registery
566       eraseDatasetGroup( datasetGroup ); //remove from where the dataset group is stored
567     }
568     else
569       ++it;
570   }
571 }
572 
syncItemToDatasetGroup(int groupIndex)573 void QgsMeshDatasetGroupStore::syncItemToDatasetGroup( int groupIndex )
574 {
575   if ( !mDatasetGroupTreeRootItem )
576     return;
577   DatasetGroup group = datasetGroup( groupIndex );
578   QgsMeshDatasetGroupTreeItem *item = mDatasetGroupTreeRootItem->childFromDatasetGroupIndex( groupIndex );
579   if ( group.first == mPersistentProvider && mPersistentProvider )
580   {
581     QgsMeshDatasetGroupMetadata meta = mPersistentProvider->datasetGroupMetadata( group.second );
582     if ( item )
583       item->setPersistentDatasetGroup( meta.uri() );
584   }
585   else if ( group.first == mExtraDatasets.get() )
586   {
587     if ( item )
588       item->setDatasetGroup( mExtraDatasets->datasetGroup( group.second ) );
589   }
590 }
591 
createDatasetGroupTreeItems(const QList<int> & indexes)592 void QgsMeshDatasetGroupStore::createDatasetGroupTreeItems( const QList<int> &indexes )
593 {
594   QMap<QString, QgsMeshDatasetGroupTreeItem *> mNameToItem;
595 
596   for ( int i = 0; i < indexes.count(); ++i )
597   {
598     int groupIndex = indexes.at( i );
599     const QgsMeshDatasetGroupMetadata meta = datasetGroupMetadata( groupIndex );
600     const QString name = meta.name();
601     const QStringList subdatasets = name.split( '/' );
602 
603     QString displayName = name;
604     QgsMeshDatasetGroupTreeItem *parent = mDatasetGroupTreeRootItem.get();
605 
606     if ( subdatasets.size() == 2 )
607     {
608       auto it = mNameToItem.find( subdatasets[0] );
609       if ( it == mNameToItem.end() )
610         QgsDebugMsg( QStringLiteral( "Unable to find parent group for %1." ).arg( name ) );
611       else
612       {
613         displayName = subdatasets[1];
614         parent = it.value();
615       }
616     }
617     else if ( subdatasets.size() != 1 )
618       QgsDebugMsg( QStringLiteral( "Ignoring too deep child group name %1." ).arg( name ) );
619 
620     QgsMeshDatasetGroupTreeItem *item = new QgsMeshDatasetGroupTreeItem( displayName, name, meta.isVector(), groupIndex );
621     parent->appendChild( item );
622     if ( mNameToItem.contains( name ) )
623       QgsDebugMsg( QStringLiteral( "Group %1 is not unique" ).arg( displayName ) );
624     mNameToItem[name] = item;
625   }
626 }
627 
addDatasetGroup(QgsMeshDatasetGroup * datasetGroup)628 int QgsMeshExtraDatasetStore::addDatasetGroup( QgsMeshDatasetGroup *datasetGroup )
629 {
630   int groupIndex = mGroups.size();
631   mGroups.push_back( std::unique_ptr<QgsMeshDatasetGroup>( datasetGroup ) );
632 
633   if ( datasetGroup->datasetCount() > 1 )
634   {
635     mTemporalCapabilities->setHasTemporalCapabilities( true );
636     for ( int i = 0; i < datasetGroup->datasetCount(); ++i )
637       mTemporalCapabilities->addDatasetTime( groupIndex, datasetGroup->datasetMetadata( i ).time() );
638   }
639 
640   return mGroups.size() - 1;
641 }
642 
removeDatasetGroup(int index)643 void QgsMeshExtraDatasetStore::removeDatasetGroup( int index )
644 {
645   if ( index < datasetGroupCount() )
646     mGroups.erase( mGroups.begin() + index );
647 
648 
649   updateTemporalCapabilities();
650 }
651 
hasTemporalCapabilities() const652 bool QgsMeshExtraDatasetStore::hasTemporalCapabilities() const
653 {
654   return mTemporalCapabilities->hasTemporalCapabilities();
655 }
656 
datasetRelativeTime(QgsMeshDatasetIndex index)657 quint64 QgsMeshExtraDatasetStore::datasetRelativeTime( QgsMeshDatasetIndex index )
658 {
659   return mTemporalCapabilities->datasetTime( index );
660 }
661 
description(int groupIndex) const662 QString QgsMeshExtraDatasetStore::description( int groupIndex ) const
663 {
664   if ( groupIndex >= 0 && groupIndex < int( mGroups.size() ) )
665     return mGroups.at( groupIndex )->description();
666   else
667     return QString();
668 }
669 
datasetGroup(int groupIndex) const670 QgsMeshDatasetGroup *QgsMeshExtraDatasetStore::datasetGroup( int groupIndex ) const
671 {
672   if ( groupIndex >= 0 && groupIndex < int( mGroups.size() ) )
673     return mGroups[groupIndex].get();
674   else
675     return nullptr;
676 }
677 
addDataset(const QString & uri)678 bool QgsMeshExtraDatasetStore::addDataset( const QString &uri )
679 {
680   Q_UNUSED( uri );
681   return false;
682 }
683 
extraDatasets() const684 QStringList QgsMeshExtraDatasetStore::extraDatasets() const
685 {
686   return QStringList();
687 }
688 
datasetGroupCount() const689 int QgsMeshExtraDatasetStore::datasetGroupCount() const
690 {
691   return mGroups.size();
692 }
693 
datasetCount(int groupIndex) const694 int QgsMeshExtraDatasetStore::datasetCount( int groupIndex ) const
695 {
696   if ( groupIndex >= 0 && groupIndex < datasetGroupCount() )
697     return mGroups.at( groupIndex )->datasetCount();
698   else
699     return 0;
700 }
701 
datasetGroupMetadata(int groupIndex) const702 QgsMeshDatasetGroupMetadata QgsMeshExtraDatasetStore::datasetGroupMetadata( int groupIndex ) const
703 {
704   if ( groupIndex >= 0 && groupIndex < datasetGroupCount() )
705     return mGroups.at( groupIndex )->groupMetadata();
706   else
707     return QgsMeshDatasetGroupMetadata();
708 }
709 
datasetMetadata(QgsMeshDatasetIndex index) const710 QgsMeshDatasetMetadata QgsMeshExtraDatasetStore::datasetMetadata( QgsMeshDatasetIndex index ) const
711 {
712   int groupIndex = index.group();
713   if ( index.isValid() && groupIndex < datasetGroupCount() )
714   {
715     int datasetIndex = index.dataset();
716     const QgsMeshDatasetGroup *group = mGroups.at( groupIndex ).get();
717     if ( datasetIndex < group->datasetCount() )
718       return group->datasetMetadata( datasetIndex );
719   }
720   return QgsMeshDatasetMetadata();
721 }
722 
datasetValue(QgsMeshDatasetIndex index,int valueIndex) const723 QgsMeshDatasetValue QgsMeshExtraDatasetStore::datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const
724 {
725   int groupIndex = index.group();
726   if ( index.isValid() && groupIndex < datasetGroupCount() )
727   {
728     const QgsMeshDatasetGroup *group = mGroups.at( groupIndex ).get();
729     int datasetIndex = index.dataset();
730     if ( datasetIndex < group->datasetCount() )
731       return group->dataset( datasetIndex )->datasetValue( valueIndex );
732   }
733 
734   return QgsMeshDatasetValue();
735 }
736 
datasetValues(QgsMeshDatasetIndex index,int valueIndex,int count) const737 QgsMeshDataBlock QgsMeshExtraDatasetStore::datasetValues( QgsMeshDatasetIndex index, int valueIndex, int count ) const
738 {
739   int groupIndex = index.group();
740   if ( index.isValid() && groupIndex < datasetGroupCount() )
741   {
742     const QgsMeshDatasetGroup *group = mGroups.at( groupIndex ).get();
743     int datasetIndex = index.dataset();
744     if ( datasetIndex < group->datasetCount() )
745       return group->dataset( datasetIndex )->datasetValues( group->isScalar(), valueIndex, count );
746   }
747 
748   return QgsMeshDataBlock();
749 }
750 
dataset3dValues(QgsMeshDatasetIndex index,int faceIndex,int count) const751 QgsMesh3dDataBlock QgsMeshExtraDatasetStore::dataset3dValues( QgsMeshDatasetIndex index, int faceIndex, int count ) const
752 {
753   // Not supported for now
754   Q_UNUSED( index )
755   Q_UNUSED( faceIndex )
756   Q_UNUSED( count )
757   return QgsMesh3dDataBlock();
758 }
759 
isFaceActive(QgsMeshDatasetIndex index,int faceIndex) const760 bool QgsMeshExtraDatasetStore::isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const
761 {
762   int groupIndex = index.group();
763   if ( index.isValid() && groupIndex < datasetGroupCount() )
764   {
765     const QgsMeshDatasetGroup *group = mGroups.at( groupIndex ).get();
766     int datasetIndex = index.dataset();
767     if ( datasetIndex < group->datasetCount() )
768       return group->dataset( datasetIndex )->isActive( faceIndex );
769   }
770 
771   return false;
772 }
773 
areFacesActive(QgsMeshDatasetIndex index,int faceIndex,int count) const774 QgsMeshDataBlock QgsMeshExtraDatasetStore::areFacesActive( QgsMeshDatasetIndex index, int faceIndex, int count ) const
775 {
776   int groupIndex = index.group();
777   if ( index.isValid() && groupIndex < datasetGroupCount() )
778   {
779     const QgsMeshDatasetGroup *group = mGroups.at( groupIndex ).get();
780     int datasetIndex = index.dataset();
781     if ( datasetIndex < group->datasetCount() )
782       return group->dataset( datasetIndex )->areFacesActive( faceIndex, count );
783   }
784   return QgsMeshDataBlock();
785 }
786 
persistDatasetGroup(const QString & outputFilePath,const QString & outputDriver,const QgsMeshDatasetGroupMetadata & meta,const QVector<QgsMeshDataBlock> & datasetValues,const QVector<QgsMeshDataBlock> & datasetActive,const QVector<double> & times)787 bool QgsMeshExtraDatasetStore::persistDatasetGroup( const QString &outputFilePath,
788     const QString &outputDriver,
789     const QgsMeshDatasetGroupMetadata &meta,
790     const QVector<QgsMeshDataBlock> &datasetValues,
791     const QVector<QgsMeshDataBlock> &datasetActive,
792     const QVector<double> &times )
793 {
794   Q_UNUSED( outputFilePath )
795   Q_UNUSED( outputDriver )
796   Q_UNUSED( meta )
797   Q_UNUSED( datasetValues )
798   Q_UNUSED( datasetActive )
799   Q_UNUSED( times )
800   return true; // not implemented/supported
801 }
802 
persistDatasetGroup(const QString & outputFilePath,const QString & outputDriver,QgsMeshDatasetSourceInterface * source,int datasetGroupIndex)803 bool QgsMeshExtraDatasetStore::persistDatasetGroup( const QString &outputFilePath,
804     const QString &outputDriver,
805     QgsMeshDatasetSourceInterface *source,
806     int datasetGroupIndex )
807 {
808   Q_UNUSED( outputFilePath )
809   Q_UNUSED( outputDriver )
810   Q_UNUSED( source )
811   Q_UNUSED( datasetGroupIndex )
812   return true; // not implemented/supported
813 }
814 
writeXml(int groupIndex,QDomDocument & doc,const QgsReadWriteContext & context)815 QDomElement QgsMeshExtraDatasetStore::writeXml( int groupIndex, QDomDocument &doc, const QgsReadWriteContext &context )
816 {
817   if ( groupIndex >= 0 && groupIndex < int( mGroups.size() ) && mGroups[groupIndex] )
818     return mGroups[groupIndex]->writeXml( doc, context );
819   else
820     return QDomElement();
821 }
822 
updateTemporalCapabilities()823 void QgsMeshExtraDatasetStore::updateTemporalCapabilities()
824 {
825   //update temporal capabilitie
826   mTemporalCapabilities->clear();
827   bool hasTemporal = false;
828   for ( size_t g = 0; g < mGroups.size(); ++g )
829   {
830     const QgsMeshDatasetGroup *group = mGroups[g].get();
831     hasTemporal |= group->datasetCount() > 1;
832     for ( int i = 0; i < group->datasetCount(); ++i )
833       mTemporalCapabilities->addDatasetTime( g, group->datasetMetadata( i ).time() );
834   }
835 
836   mTemporalCapabilities->setHasTemporalCapabilities( hasTemporal );
837 }
838