QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 
21 static const QString TEXT_PROVIDER_KEY = QStringLiteral( "mesh_memory" );
22 static const QString TEXT_PROVIDER_DESCRIPTION = QStringLiteral( "Mesh memory provider" );
23 
24 bool QgsMeshMemoryDataProvider::isValid() const
25 {
26  return true;
27 }
28 
29 QString QgsMeshMemoryDataProvider::name() const
30 {
31  return TEXT_PROVIDER_KEY;
32 }
33 
34 QString QgsMeshMemoryDataProvider::description() const
35 {
36  return TEXT_PROVIDER_DESCRIPTION;
37 }
38 
40 {
42 }
43 
44 QgsMeshMemoryDataProvider::QgsMeshMemoryDataProvider( const QString &uri, const ProviderOptions &options )
45  : QgsMeshDataProvider( uri, options )
46 {
47  mIsValid = splitMeshSections( uri );
48 }
49 
50 QString QgsMeshMemoryDataProvider::providerKey()
51 {
52  return TEXT_PROVIDER_KEY;
53 }
54 
55 QString QgsMeshMemoryDataProvider::providerDescription()
56 {
57  return TEXT_PROVIDER_DESCRIPTION;
58 }
59 
60 QgsMeshMemoryDataProvider *QgsMeshMemoryDataProvider::createProvider( const QString &uri, const ProviderOptions &options )
61 {
62  return new QgsMeshMemoryDataProvider( uri, options );
63 }
64 
65 bool QgsMeshMemoryDataProvider::splitMeshSections( const QString &uri )
66 {
67  const QStringList sections = uri.split( QStringLiteral( "---" ), QString::SkipEmptyParts );
68  if ( sections.size() != 2 )
69  {
70  setError( QgsError( tr( "Invalid mesh definition, does not contain 2 sections" ),
71  QStringLiteral( "Mesh Memory Provider" ) ) );
72  return false;
73  }
74 
75  if ( addMeshVertices( sections[0] ) )
76  return addMeshFaces( sections[1] );
77  else
78  return false;
79 }
80 
81 bool QgsMeshMemoryDataProvider::addMeshVertices( const QString &def )
82 {
83  QVector<QgsMeshVertex> vertices;
84 
85  const QStringList verticesCoords = def.split( '\n', QString::SkipEmptyParts );
86  for ( int i = 0; i < verticesCoords.size(); ++i )
87  {
88  const QStringList coords = verticesCoords[i].split( ',', QString::SkipEmptyParts );
89  if ( coords.size() != 2 )
90  {
91  setError( QgsError( tr( "Invalid mesh definition, vertex definition does not contain x, y" ),
92  QStringLiteral( "Mesh Memory Provider" ) ) );
93  return false;
94  }
95  double x = coords.at( 0 ).toDouble();
96  double y = coords.at( 1 ).toDouble();
97  QgsMeshVertex vertex( x, y );
98  vertices.push_back( vertex );
99  }
100 
101  mVertices = vertices;
102  return true;
103 }
104 
105 bool QgsMeshMemoryDataProvider::addMeshFaces( const QString &def )
106 {
107  QVector<QgsMeshFace> faces;
108 
109  const QStringList facesVertices = def.split( '\n', QString::SkipEmptyParts );
110  for ( int i = 0; i < facesVertices.size(); ++i )
111  {
112  const QStringList vertices = facesVertices[i].split( ',', QString::SkipEmptyParts );
113  if ( vertices.size() < 3 )
114  {
115  setError( QgsError( tr( "Invalid mesh definition, face must contain at least 3 vertices" ),
116  QStringLiteral( "Mesh Memory Provider" ) ) );
117  return false;
118  }
119  QgsMeshFace face;
120  for ( int j = 0; j < vertices.size(); ++j )
121  {
122  int vertex_id = vertices[j].toInt();
123  if ( vertex_id < 0 )
124  {
125  setError( QgsError( tr( "Invalid mesh definition, vertex index must be positive value" ),
126  QStringLiteral( "Mesh Memory Provider" ) ) );
127  return false;
128  }
129  if ( mVertices.size() < vertex_id )
130  {
131  setError( QgsError( tr( "Invalid mesh definition, missing vertex id defined in face" ),
132  QStringLiteral( "Mesh Memory Provider" ) ) );
133  return false;
134  }
135 
136  face.push_back( vertex_id );
137  }
138  faces.push_back( face );
139  }
140 
141  mFaces = faces;
142  return true;
143 }
144 
145 
146 bool QgsMeshMemoryDataProvider::splitDatasetSections( const QString &uri, QgsMeshMemoryDatasetGroup &datasetGroup )
147 {
148  const QStringList sections = uri.split( QStringLiteral( "---" ), QString::SkipEmptyParts );
149 
150  bool success = sections.size() > 2;
151  if ( !success )
152  {
153  setError( QgsError( tr( "Invalid dataset definition, does not contain 3+ sections" ),
154  QStringLiteral( "Mesh Memory Provider" ) ) );
155  }
156 
157  if ( success )
158  success = setDatasetGroupType( sections[0], datasetGroup );
159  if ( success )
160  success = addDatasetGroupMetadata( sections[1], datasetGroup );
161 
162  for ( int i = 2; i < sections.size(); ++i )
163  {
164  if ( !success )
165  break;
166  QgsMeshMemoryDataset dataset;
167  success = addDatasetValues( sections[i], dataset, datasetGroup.isScalar );
168  if ( success )
169  success = checkDatasetValidity( dataset, datasetGroup.isOnVertices );
170  if ( success )
171  datasetGroup.datasets.push_back( dataset );
172  }
173 
174  return success;
175 }
176 
177 bool QgsMeshMemoryDataProvider::setDatasetGroupType( const QString &def, QgsMeshMemoryDatasetGroup &datasetGroup )
178 {
179  const QStringList types = def.split( ' ', QString::SkipEmptyParts );
180 
181  if ( types.size() != 3 )
182  {
183  setError( QgsError( tr( "Invalid type definition, must be Vertex/Face Vector/Scalar Name" ),
184  QStringLiteral( "Mesh Memory Provider" ) ) );
185  return false;
186  }
187 
188  datasetGroup.isOnVertices = 0 == QString::compare( types[0].trimmed(), QStringLiteral( "vertex" ), Qt::CaseInsensitive );
189  datasetGroup.isScalar = 0 == QString::compare( types[1].trimmed(), QStringLiteral( "scalar" ), Qt::CaseInsensitive );
190  datasetGroup.name = types[2].trimmed();
191 
192  return true;
193 }
194 
195 bool QgsMeshMemoryDataProvider::addDatasetGroupMetadata( const QString &def, QgsMeshMemoryDatasetGroup &datasetGroup )
196 {
197  const QStringList metadataLines = def.split( '\n', QString::SkipEmptyParts );
198  for ( int i = 0; i < metadataLines.size(); ++i )
199  {
200  const QStringList keyVal = metadataLines[i].split( ':', QString::SkipEmptyParts );
201  if ( keyVal.size() != 2 )
202  {
203  setError( QgsError( tr( "Invalid dataset definition, dataset metadata does not contain key: value" ),
204  QStringLiteral( "Mesh Memory Provider" ) ) );
205  return false;
206  }
207 
208  datasetGroup.metadata.insert( keyVal.at( 0 ).trimmed(), keyVal.at( 1 ).trimmed() );
209  }
210  return true;
211 }
212 
213 bool QgsMeshMemoryDataProvider::addDatasetValues( const QString &def, QgsMeshMemoryDataset &dataset, bool isScalar )
214 {
215  const QStringList valuesLines = def.split( '\n', QString::SkipEmptyParts );
216  // first line is time
217  if ( valuesLines.size() < 2 )
218  {
219  setError( QgsError( tr( "Invalid dataset definition, must contain at least 1 line (time)" ),
220  QStringLiteral( "Mesh Memory Provider" ) ) );
221  return false;
222  }
223 
224  dataset.time = valuesLines[0].toDouble();
225 
226  for ( int i = 1; i < valuesLines.size(); ++i )
227  {
228  const QStringList values = valuesLines[i].split( ',', QString::SkipEmptyParts );
229  QgsMeshDatasetValue point;
230 
231  if ( isScalar )
232  {
233  if ( values.size() != 1 )
234  {
235  setError( QgsError( tr( "Invalid dataset definition, dataset scalar values must be x" ),
236  QStringLiteral( "Mesh Memory Provider" ) ) );
237  return false;
238  }
239  else
240  {
241  point.setX( values[0].toDouble() );
242  }
243  }
244  else
245  {
246  if ( values.size() < 2 )
247  {
248  setError( QgsError( tr( "Invalid dataset definition, dataset vector values must be x, y" ),
249  QStringLiteral( "Mesh Memory Provider" ) ) );
250  return false;
251  }
252  else
253  {
254  point.setX( values[0].toDouble() );
255  point.setY( values[1].toDouble() );
256  }
257  }
258 
259  dataset.values.push_back( point );
260  }
261  return true;
262 }
263 
264 bool QgsMeshMemoryDataProvider::checkDatasetValidity( QgsMeshMemoryDataset &dataset, bool isOnVertices )
265 {
266  bool valid = true;
267 
268  if ( isOnVertices )
269  {
270  if ( dataset.values.count() != vertexCount() )
271  {
272  valid = false;
273  setError( QgsError( tr( "Dataset defined on vertices has {} values, but mesh {}" ).arg( dataset.values.count(), vertexCount() ),
274  QStringLiteral( "Mesh Memory Provider" ) ) );
275  }
276  }
277  else
278  {
279  // on faces
280  if ( dataset.values.count() != faceCount() )
281  {
282  valid = false;
283  setError( QgsError( tr( "Dataset defined on faces has {} values, but mesh {}" ).arg( dataset.values.count(), faceCount() ),
284  QStringLiteral( "Mesh Memory Provider" ) ) );
285  }
286  }
287 
288  dataset.valid = valid;
289  return valid;
290 }
291 
292 int QgsMeshMemoryDataProvider::vertexCount() const
293 {
294  return mVertices.size();
295 }
296 
297 int QgsMeshMemoryDataProvider::faceCount() const
298 {
299  return mFaces.size();
300 }
301 
302 QgsMeshVertex QgsMeshMemoryDataProvider::vertex( int index ) const
303 {
304  Q_ASSERT( vertexCount() > index );
305  return mVertices[index];
306 }
307 
308 QgsMeshFace QgsMeshMemoryDataProvider::face( int index ) const
309 {
310  Q_ASSERT( faceCount() > index );
311  return mFaces[index];
312 }
313 
314 bool QgsMeshMemoryDataProvider::addDataset( const QString &uri )
315 {
316  QgsMeshMemoryDatasetGroup group;
317 
318  bool valid = false;
319  if ( mIsValid )
320  {
321  valid = splitDatasetSections( uri, group );
322  }
323  else
324  {
325  setError( QgsError( tr( "Unable to add dataset group to invalid mesh" ),
326  QStringLiteral( "Mesh Memory Provider" ) ) );
327  }
328 
329  mDatasetGroups.push_back( group );
330 
331  if ( valid )
332  {
333  mExtraDatasetUris << uri;
334  emit datasetGroupsAdded( 1 );
335  emit dataChanged();
336  }
337 
338  return valid;
339 }
340 
341 QStringList QgsMeshMemoryDataProvider::extraDatasets() const
342 {
343  return mExtraDatasetUris;
344 }
345 
346 int QgsMeshMemoryDataProvider::datasetGroupCount() const
347 {
348  return mDatasetGroups.count();
349 }
350 
351 int QgsMeshMemoryDataProvider::datasetCount( int groupIndex ) const
352 {
353  if ( ( groupIndex >= 0 ) && ( groupIndex < datasetGroupCount() ) )
354  return mDatasetGroups[groupIndex].datasets.count();
355  else
356  return 0;
357 }
358 
359 QgsMeshDatasetGroupMetadata QgsMeshMemoryDataProvider::datasetGroupMetadata( int groupIndex ) const
360 {
361  if ( ( groupIndex >= 0 ) && ( groupIndex < datasetGroupCount() ) )
362  {
364  mDatasetGroups[groupIndex].name,
365  mDatasetGroups[groupIndex].isScalar,
366  mDatasetGroups[groupIndex].isOnVertices,
367  mDatasetGroups[groupIndex].metadata
368  );
369  return metadata;
370  }
371  else
372  {
374  }
375 }
376 
377 QgsMeshDatasetMetadata QgsMeshMemoryDataProvider::datasetMetadata( QgsMeshDatasetIndex index ) const
378 {
379  if ( ( index.group() >= 0 ) && ( index.group() < datasetGroupCount() ) &&
380  ( index.dataset() >= 0 ) && ( index.dataset() < datasetCount( index.group() ) )
381  )
382  {
383  const QgsMeshMemoryDatasetGroup &grp = mDatasetGroups.at( index.group() );
384  QgsMeshDatasetMetadata metadata(
385  grp.datasets[index.dataset()].time,
386  grp.datasets[index.dataset()].valid
387  );
388  return metadata;
389  }
390  else
391  {
392  return QgsMeshDatasetMetadata();
393  }
394 }
395 
396 QgsMeshDatasetValue QgsMeshMemoryDataProvider::datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const
397 {
398  if ( ( index.group() >= 0 ) && ( index.group() < datasetGroupCount() ) &&
399  ( index.dataset() >= 0 ) && ( index.dataset() < datasetCount( index.group() ) ) &&
400  ( valueIndex >= 0 ) && ( valueIndex < mDatasetGroups[index.group()].datasets[index.dataset()].values.count() ) )
401  {
402  return mDatasetGroups[index.group()].datasets[index.dataset()].values[valueIndex];
403  }
404  else
405  {
406  return QgsMeshDatasetValue();
407  }
408 }
409 
410 bool QgsMeshMemoryDataProvider::isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const
411 {
412  Q_UNUSED( index );
413  Q_UNUSED( faceIndex );
414  return true;
415 }
416 
417 
int dataset() const
Returns a dataset index within group()
void setY(double y)
Sets Y value.
const QgsCoordinateReferenceSystem & crs
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
Base class for providing data for QgsMeshLayer.
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...
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.
int group() const
Returns a group index.
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.