QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgsmeshmemorydataprovider.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmeshmemorydataprovider.cpp
3  -----------------------------
4  begin : April 2018
5  copyright : (C) 2018 by Peter Petrik
6  email : zilolv 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  ***************************************************************************/
18 
20 #include "qgsmeshlayerutils.h"
21 #include "qgstriangularmesh.h"
22 #include <cstring>
23 
24 static const QString TEXT_PROVIDER_KEY = QStringLiteral( "mesh_memory" );
25 static const QString TEXT_PROVIDER_DESCRIPTION = QStringLiteral( "Mesh memory provider" );
26 
27 bool QgsMeshMemoryDataProvider::isValid() const
28 {
29  return true;
30 }
31 
32 QString QgsMeshMemoryDataProvider::name() const
33 {
34  return TEXT_PROVIDER_KEY;
35 }
36 
37 QString QgsMeshMemoryDataProvider::description() const
38 {
39  return TEXT_PROVIDER_DESCRIPTION;
40 }
41 
43 {
45 }
46 
47 QgsMeshMemoryDataProvider::QgsMeshMemoryDataProvider( const QString &uri, const ProviderOptions &options )
48  : QgsMeshDataProvider( uri, options )
49 {
50  mIsValid = splitMeshSections( uri );
51 }
52 
53 QString QgsMeshMemoryDataProvider::providerKey()
54 {
55  return TEXT_PROVIDER_KEY;
56 }
57 
58 QString QgsMeshMemoryDataProvider::providerDescription()
59 {
60  return TEXT_PROVIDER_DESCRIPTION;
61 }
62 
63 QgsMeshMemoryDataProvider *QgsMeshMemoryDataProvider::createProvider( const QString &uri, const ProviderOptions &options )
64 {
65  return new QgsMeshMemoryDataProvider( uri, options );
66 }
67 
68 bool QgsMeshMemoryDataProvider::splitMeshSections( const QString &uri )
69 {
70  const QStringList sections = uri.split( QStringLiteral( "---" ), QString::SkipEmptyParts );
71  if ( sections.size() != 2 )
72  {
73  setError( QgsError( tr( "Invalid mesh definition, does not contain 2 sections" ),
74  QStringLiteral( "Mesh Memory Provider" ) ) );
75  return false;
76  }
77 
78  if ( addMeshVertices( sections[0] ) )
79  return addMeshFaces( sections[1] );
80  else
81  return false;
82 }
83 
84 bool QgsMeshMemoryDataProvider::addMeshVertices( const QString &def )
85 {
86  QVector<QgsMeshVertex> vertices;
87 
88  const QStringList verticesCoords = def.split( '\n', QString::SkipEmptyParts );
89  for ( int i = 0; i < verticesCoords.size(); ++i )
90  {
91  const QStringList coords = verticesCoords[i].split( ',', QString::SkipEmptyParts );
92  if ( coords.size() != 2 )
93  {
94  setError( QgsError( tr( "Invalid mesh definition, vertex definition does not contain x, y" ),
95  QStringLiteral( "Mesh Memory Provider" ) ) );
96  return false;
97  }
98  double x = coords.at( 0 ).toDouble();
99  double y = coords.at( 1 ).toDouble();
100  QgsMeshVertex vertex( x, y );
101  vertices.push_back( vertex );
102  }
103 
104  mVertices = vertices;
105  return true;
106 }
107 
108 bool QgsMeshMemoryDataProvider::addMeshFaces( const QString &def )
109 {
110  QVector<QgsMeshFace> faces;
111 
112  const QStringList facesVertices = def.split( '\n', QString::SkipEmptyParts );
113  for ( int i = 0; i < facesVertices.size(); ++i )
114  {
115  const QStringList vertices = facesVertices[i].split( ',', QString::SkipEmptyParts );
116  if ( vertices.size() < 3 )
117  {
118  setError( QgsError( tr( "Invalid mesh definition, face must contain at least 3 vertices" ),
119  QStringLiteral( "Mesh Memory Provider" ) ) );
120  return false;
121  }
122  QgsMeshFace face;
123  for ( int j = 0; j < vertices.size(); ++j )
124  {
125  int vertex_id = vertices[j].toInt();
126  if ( vertex_id < 0 )
127  {
128  setError( QgsError( tr( "Invalid mesh definition, vertex index must be positive value" ),
129  QStringLiteral( "Mesh Memory Provider" ) ) );
130  return false;
131  }
132  if ( mVertices.size() < vertex_id )
133  {
134  setError( QgsError( tr( "Invalid mesh definition, missing vertex id defined in face" ),
135  QStringLiteral( "Mesh Memory Provider" ) ) );
136  return false;
137  }
138 
139  face.push_back( vertex_id );
140  }
141  faces.push_back( face );
142  }
143 
144  mFaces = faces;
145  return true;
146 }
147 
148 
149 bool QgsMeshMemoryDataProvider::splitDatasetSections( const QString &uri, QgsMeshMemoryDatasetGroup &datasetGroup )
150 {
151  const QStringList sections = uri.split( QStringLiteral( "---" ), QString::SkipEmptyParts );
152 
153  bool success = sections.size() > 2;
154  if ( !success )
155  {
156  setError( QgsError( tr( "Invalid dataset definition, does not contain 3+ sections" ),
157  QStringLiteral( "Mesh Memory Provider" ) ) );
158  }
159 
160  if ( success )
161  success = setDatasetGroupType( sections[0], datasetGroup );
162  if ( success )
163  success = addDatasetGroupMetadata( sections[1], datasetGroup );
164 
165  for ( int i = 2; i < sections.size(); ++i )
166  {
167  if ( !success )
168  break;
169  std::shared_ptr<QgsMeshMemoryDataset> dataset = std::make_shared<QgsMeshMemoryDataset>();
170  success = addDatasetValues( sections[i], dataset, datasetGroup.isScalar );
171  if ( success )
172  success = checkDatasetValidity( dataset, datasetGroup.type == QgsMeshDatasetGroupMetadata::DataOnVertices );
173  if ( success )
174  datasetGroup.datasets.push_back( dataset );
175  }
176 
177  return success;
178 }
179 
180 bool QgsMeshMemoryDataProvider::setDatasetGroupType( const QString &def, QgsMeshMemoryDatasetGroup &datasetGroup )
181 {
182  const QStringList types = def.split( ' ', QString::SkipEmptyParts );
183 
184  if ( types.size() != 3 )
185  {
186  setError( QgsError( tr( "Invalid type definition, must be Vertex/Face Vector/Scalar Name" ),
187  QStringLiteral( "Mesh Memory Provider" ) ) );
188  return false;
189  }
190 
191  if ( 0 == QString::compare( types[0].trimmed(), QStringLiteral( "vertex" ), Qt::CaseInsensitive ) )
193  else
194  datasetGroup.type = QgsMeshDatasetGroupMetadata::DataOnFaces;
195 
196  datasetGroup.isScalar = 0 == QString::compare( types[1].trimmed(), QStringLiteral( "scalar" ), Qt::CaseInsensitive );
197  datasetGroup.name = types[2].trimmed();
198 
199  return true;
200 }
201 
202 bool QgsMeshMemoryDataProvider::addDatasetGroupMetadata( const QString &def, QgsMeshMemoryDatasetGroup &datasetGroup )
203 {
204  const QStringList metadataLines = def.split( '\n', QString::SkipEmptyParts );
205  for ( int i = 0; i < metadataLines.size(); ++i )
206  {
207  const QStringList keyVal = metadataLines[i].split( ':', QString::SkipEmptyParts );
208  if ( keyVal.size() != 2 )
209  {
210  setError( QgsError( tr( "Invalid dataset definition, dataset metadata does not contain key: value" ),
211  QStringLiteral( "Mesh Memory Provider" ) ) );
212  return false;
213  }
214 
215  datasetGroup.metadata.insert( keyVal.at( 0 ).trimmed(), keyVal.at( 1 ).trimmed() );
216  }
217  return true;
218 }
219 
220 bool QgsMeshMemoryDataProvider::addDatasetValues( const QString &def, std::shared_ptr<QgsMeshMemoryDataset> &dataset, bool isScalar )
221 {
222  const QStringList valuesLines = def.split( '\n', QString::SkipEmptyParts );
223  // first line is time
224  if ( valuesLines.size() < 2 )
225  {
226  setError( QgsError( tr( "Invalid dataset definition, must contain at least 1 line (time)" ),
227  QStringLiteral( "Mesh Memory Provider" ) ) );
228  return false;
229  }
230 
231  dataset->time = valuesLines[0].toDouble();
232 
233  for ( int i = 1; i < valuesLines.size(); ++i )
234  {
235  const QStringList values = valuesLines[i].split( ',', QString::SkipEmptyParts );
236  QgsMeshDatasetValue point;
237 
238  if ( isScalar )
239  {
240  if ( values.size() != 1 )
241  {
242  setError( QgsError( tr( "Invalid dataset definition, dataset scalar values must be x" ),
243  QStringLiteral( "Mesh Memory Provider" ) ) );
244  return false;
245  }
246  else
247  {
248  point.setX( values[0].toDouble() );
249  }
250  }
251  else
252  {
253  if ( values.size() < 2 )
254  {
255  setError( QgsError( tr( "Invalid dataset definition, dataset vector values must be x, y" ),
256  QStringLiteral( "Mesh Memory Provider" ) ) );
257  return false;
258  }
259  else
260  {
261  point.setX( values[0].toDouble() );
262  point.setY( values[1].toDouble() );
263  }
264  }
265 
266  dataset->values.push_back( point );
267  }
268  return true;
269 }
270 
271 bool QgsMeshMemoryDataProvider::checkDatasetValidity( std::shared_ptr<QgsMeshMemoryDataset> &dataset, bool isOnVertices )
272 {
273  bool valid = true;
274 
275  if ( isOnVertices )
276  {
277  if ( dataset->values.count() != vertexCount() )
278  {
279  valid = false;
280  setError( QgsError( tr( "Dataset defined on vertices has {} values, but mesh {}" ).arg( dataset->values.count(), vertexCount() ),
281  QStringLiteral( "Mesh Memory Provider" ) ) );
282  }
283  }
284  else
285  {
286  // on faces
287  if ( dataset->values.count() != faceCount() )
288  {
289  valid = false;
290  setError( QgsError( tr( "Dataset defined on faces has {} values, but mesh {}" ).arg( dataset->values.count(), faceCount() ),
291  QStringLiteral( "Mesh Memory Provider" ) ) );
292  }
293  }
294 
295  dataset->valid = valid;
296  return valid;
297 }
298 
299 int QgsMeshMemoryDataProvider::vertexCount() const
300 {
301  return mVertices.size();
302 }
303 
304 int QgsMeshMemoryDataProvider::faceCount() const
305 {
306  return mFaces.size();
307 }
308 
309 void QgsMeshMemoryDataProvider::populateMesh( QgsMesh *mesh ) const
310 {
311  if ( mesh )
312  {
313  mesh->faces = mFaces;
314  mesh->vertices = mVertices;
315  }
316 }
317 
318 QgsRectangle QgsMeshMemoryDataProvider::extent() const
319 {
320  return calculateExtent( );
321 }
322 
323 bool QgsMeshMemoryDataProvider::addDataset( const QString &uri )
324 {
325  QgsMeshMemoryDatasetGroup group;
326 
327  bool valid = false;
328  if ( mIsValid )
329  {
330  valid = splitDatasetSections( uri, group );
331  }
332  else
333  {
334  setError( QgsError( tr( "Unable to add dataset group to invalid mesh" ),
335  QStringLiteral( "Mesh Memory Provider" ) ) );
336  }
337 
338  calculateMinMaxForDatasetGroup( group );
339  mDatasetGroups.push_back( group );
340 
341  if ( valid )
342  {
343  mExtraDatasetUris << uri;
344  emit datasetGroupsAdded( 1 );
345  emit dataChanged();
346  }
347 
348  return valid;
349 }
350 
351 QStringList QgsMeshMemoryDataProvider::extraDatasets() const
352 {
353  return mExtraDatasetUris;
354 }
355 
356 int QgsMeshMemoryDataProvider::datasetGroupCount() const
357 {
358  return mDatasetGroups.count();
359 }
360 
361 int QgsMeshMemoryDataProvider::datasetCount( int groupIndex ) const
362 {
363  if ( ( groupIndex >= 0 ) && ( groupIndex < datasetGroupCount() ) )
364  return mDatasetGroups[groupIndex].datasets.count();
365  else
366  return 0;
367 }
368 
369 QgsMeshDatasetGroupMetadata QgsMeshMemoryDataProvider::datasetGroupMetadata( int groupIndex ) const
370 {
371  if ( ( groupIndex >= 0 ) && ( groupIndex < datasetGroupCount() ) )
372  {
373  return mDatasetGroups[groupIndex].groupMetadata();
374  }
375  else
376  {
378  }
379 }
380 
381 QgsMeshDatasetGroupMetadata QgsMeshMemoryDatasetGroup::groupMetadata() const
382 {
384  name,
385  isScalar,
387  minimum,
388  maximum,
389  metadata
390  );
391 }
392 
393 int QgsMeshMemoryDatasetGroup::datasetCount() const
394 {
395  return datasets.size();
396 }
397 
398 void QgsMeshMemoryDatasetGroup::addDataset( std::shared_ptr<QgsMeshMemoryDataset> dataset )
399 {
400  datasets.push_back( dataset );
401 }
402 
403 void QgsMeshMemoryDatasetGroup::clearDatasets()
404 {
405  datasets.clear();
406 }
407 
408 std::shared_ptr<const QgsMeshMemoryDataset> QgsMeshMemoryDatasetGroup::constDataset( int index ) const
409 {
410  return datasets[index];
411 }
412 
413 QgsMeshDatasetMetadata QgsMeshMemoryDataProvider::datasetMetadata( QgsMeshDatasetIndex index ) const
414 {
415  if ( ( index.group() >= 0 ) && ( index.group() < datasetGroupCount() ) &&
416  ( index.dataset() >= 0 ) && ( index.dataset() < datasetCount( index.group() ) )
417  )
418  {
419  const QgsMeshMemoryDatasetGroup &grp = mDatasetGroups.at( index.group() );
420  QgsMeshDatasetMetadata metadata(
421  grp.datasets[index.dataset()]->time,
422  grp.datasets[index.dataset()]->valid,
423  grp.datasets[index.dataset()]->minimum,
424  grp.datasets[index.dataset()]->maximum
425  );
426  return metadata;
427  }
428  else
429  {
430  return QgsMeshDatasetMetadata();
431  }
432 }
433 
434 QgsMeshDatasetValue QgsMeshMemoryDataProvider::datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const
435 {
436  if ( ( index.group() >= 0 ) && ( index.group() < datasetGroupCount() ) &&
437  ( index.dataset() >= 0 ) && ( index.dataset() < datasetCount( index.group() ) ) &&
438  ( valueIndex >= 0 ) && ( valueIndex < mDatasetGroups[index.group()].datasets[index.dataset()]->values.count() ) )
439  {
440  return mDatasetGroups[index.group()].datasets[index.dataset()]->values[valueIndex];
441  }
442  else
443  {
444  return QgsMeshDatasetValue();
445  }
446 }
447 
448 QgsMeshDataBlock QgsMeshMemoryDataProvider::datasetValues( QgsMeshDatasetIndex index, int valueIndex, int count ) const
449 {
450  if ( ( index.group() >= 0 ) && ( index.group() < datasetGroupCount() ) )
451  {
452  const QgsMeshMemoryDatasetGroup group = mDatasetGroups[index.group()];
453  bool isScalar = group.isScalar;
454  if ( ( index.dataset() >= 0 ) && ( index.dataset() < group.datasets.size() ) )
455  {
456  return group.datasets[index.dataset()]->datasetValues( isScalar, valueIndex, count );
457  }
458  else
459  {
460  return QgsMeshDataBlock();
461  }
462  }
463  else
464  {
465  return QgsMeshDataBlock();
466  }
467 }
468 
469 QgsMeshDataBlock QgsMeshMemoryDataset::datasetValues( bool isScalar, int valueIndex, int count ) const
470 {
472  double *buf = static_cast<double *>( ret.buffer() );
473 
474  for ( int i = 0; i < count; ++i )
475  {
476  int idx = valueIndex + i;
477  if ( ( idx < 0 ) || ( idx >= values.size() ) )
478  return ret;
479 
480  QgsMeshDatasetValue val = values[ valueIndex + i ];
481  if ( isScalar )
482  buf[i] = val.x();
483  else
484  {
485  buf[2 * i] = val.x();
486  buf[2 * i + 1] = val.y();
487  }
488  }
489  return ret;
490 }
491 
492 bool QgsMeshMemoryDataProvider::isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const
493 {
494  if ( mDatasetGroups[index.group()].datasets[index.dataset()]->active.isEmpty() )
495  return true;
496  else
497  return mDatasetGroups[index.group()].datasets[index.dataset()]->active[faceIndex];
498 }
499 
500 QgsMeshDataBlock QgsMeshMemoryDataProvider::areFacesActive( QgsMeshDatasetIndex index, int faceIndex, int count ) const
501 {
502  if ( ( index.group() >= 0 ) && ( index.group() < datasetGroupCount() ) )
503  {
504  const QgsMeshMemoryDatasetGroup group = mDatasetGroups[index.group()];
505  if ( ( index.dataset() >= 0 ) && ( index.dataset() < group.datasets.size() ) )
506  {
507  return group.datasets[index.dataset()]->areFacesActive( faceIndex, count );
508  }
509  else
510  {
511  return QgsMeshDataBlock();
512  }
513  }
514  else
515  {
516  return QgsMeshDataBlock();
517  }
518 }
519 
520 QgsMeshDataBlock QgsMeshMemoryDataset::areFacesActive( int faceIndex, int count ) const
521 {
523  if ( active.isEmpty() ||
524  ( faceIndex < 0 ) ||
525  ( faceIndex + count > active.size() )
526  )
527  memset( ret.buffer(), 1, static_cast<size_t>( count ) * sizeof( int ) );
528  else
529  memcpy( ret.buffer(),
530  active.data() + faceIndex,
531  static_cast<size_t>( count ) * sizeof( int ) );
532 
533  return ret;
534 }
535 
536 bool QgsMeshMemoryDataProvider::persistDatasetGroup( const QString &path,
537  const QgsMeshDatasetGroupMetadata &meta,
538  const QVector<QgsMeshDataBlock> &datasetValues,
539  const QVector<QgsMeshDataBlock> &datasetActive,
540  const QVector<double> &times )
541 {
542  Q_UNUSED( path )
543  Q_UNUSED( meta )
544  Q_UNUSED( datasetValues )
545  Q_UNUSED( datasetActive )
546  Q_UNUSED( times )
547  return true; // not implemented/supported
548 }
549 
550 void QgsMeshMemoryDataProvider::calculateMinMaxForDatasetGroup( QgsMeshMemoryDatasetGroup &grp ) const
551 {
552  double min = std::numeric_limits<double>::max();
553  double max = std::numeric_limits<double>::min();
554 
555  int count = grp.datasets.size();
556  for ( int i = 0; i < count; ++i )
557  {
558  calculateMinMaxForDataset( grp.datasets[i] );
559  min = std::min( min, grp.datasets[i]->minimum );
560  max = std::max( max, grp.datasets[i]->maximum );
561  }
562 
563  grp.minimum = min;
564  grp.maximum = max;
565 }
566 
567 void QgsMeshMemoryDataProvider::calculateMinMaxForDataset( std::shared_ptr<QgsMeshMemoryDataset> &dataset ) const
568 {
569  double min = std::numeric_limits<double>::max();
570  double max = std::numeric_limits<double>::min();
571 
572  if ( !dataset->valid )
573  {
574  return;
575  }
576 
577  bool firstIteration = true;
578  for ( int i = 0; i < dataset->values.size(); ++i )
579  {
580  double v = dataset->values[i].scalar();
581 
582  if ( std::isnan( v ) )
583  continue;
584  if ( firstIteration )
585  {
586  firstIteration = false;
587  min = v;
588  max = v;
589  }
590  else
591  {
592  if ( v < min )
593  {
594  min = v;
595  }
596  if ( v > max )
597  {
598  max = v;
599  }
600  }
601  }
602 
603  dataset->minimum = min;
604  dataset->maximum = max;
605 }
606 
607 QgsRectangle QgsMeshMemoryDataProvider::calculateExtent() const
608 {
609  QgsRectangle rec;
610  rec.setMinimal();
611  for ( const QgsMeshVertex &v : mVertices )
612  {
613  rec.setXMinimum( std::min( rec.xMinimum(), v.x() ) );
614  rec.setYMinimum( std::min( rec.yMinimum(), v.y() ) );
615  rec.setXMaximum( std::max( rec.xMaximum(), v.x() ) );
616  rec.setYMaximum( std::max( rec.yMaximum(), v.y() ) );
617  }
618  return rec;
619 }
620 
621 
622 QgsMeshMemoryDatasetGroup::QgsMeshMemoryDatasetGroup( const QString &nm ):
623  name( nm )
624 {
625 }
626 
627 QgsMeshMemoryDatasetGroup::QgsMeshMemoryDatasetGroup() = default;
628 QgsMeshMemoryDataset::QgsMeshMemoryDataset() = default;
629 
A rectangle specified with double values.
Definition: qgsrectangle.h:41
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
Definition: qgsrectangle.h:151
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:135
int dataset() const
Returns a dataset index within group()
Vector double pairs (x1, y1, x2, y2, ... )
QgsMeshDataBlock is a block of integers/doubles that can be used to retrieve: active flags (e...
void setY(double y)
Sets Y value.
const QgsCoordinateReferenceSystem & crs
int group() const
Returns a group index.
double y() const
Returns y value.
QVector< QgsMeshVertex > vertices
vertices
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:140
Integer boolean flag whether face is active.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
Base class for providing data for QgsMeshLayer.
Mesh - vertices and faces.
QgsError is container for error messages (report).
Definition: qgserror.h:80
QgsMeshDatasetGroupMetadata is a collection of dataset group metadata such as whether the data is vec...
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:145
QVector< int > QgsMeshFace
List of vertex indexes.
This class represents a coordinate reference system (CRS).
QgsMeshDatasetIndex is index that identifies the dataset group (e.g.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QVector< QgsMeshFace > faces
faces
QgsMeshDatasetValue represents single dataset value.
QgsMeshDatasetMetadata is a collection of mesh dataset metadata such as whether the data is valid or ...
void setX(double x)
Sets X value.
double x() const
Returns x value.
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:130