QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgsogrutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsogrutils.cpp
3  ---------------
4  begin : February 2016
5  copyright : (C) 2016 Nyall Dawson
6  email : nyall dot dawson 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 "qgsogrutils.h"
17 #include "qgsapplication.h"
18 #include "qgslogger.h"
19 #include "qgsgeometry.h"
20 #include "qgsfields.h"
21 #include "qgslinestring.h"
22 #include "qgsmultipoint.h"
23 #include "qgsmultilinestring.h"
24 #include <QTextCodec>
25 #include <QUuid>
26 #include <cpl_error.h>
27 #include <QJsonDocument>
28 
29 // Starting with GDAL 2.2, there are 2 concepts: unset fields and null fields
30 // whereas previously there was only unset fields. For QGIS purposes, both
31 // states (unset/null) are equivalent.
32 #ifndef OGRNullMarker
33 #define OGR_F_IsFieldSetAndNotNull OGR_F_IsFieldSet
34 #endif
35 
36 
37 
38 void gdal::OGRDataSourceDeleter::operator()( OGRDataSourceH source )
39 {
40  OGR_DS_Destroy( source );
41 }
42 
43 
44 void gdal::OGRGeometryDeleter::operator()( OGRGeometryH geometry )
45 {
46  OGR_G_DestroyGeometry( geometry );
47 }
48 
49 void gdal::OGRFldDeleter::operator()( OGRFieldDefnH definition )
50 {
51  OGR_Fld_Destroy( definition );
52 }
53 
54 void gdal::OGRFeatureDeleter::operator()( OGRFeatureH feature )
55 {
56  OGR_F_Destroy( feature );
57 }
58 
60 {
61  GDALClose( dataset );
62 }
63 
64 void gdal::fast_delete_and_close( gdal::dataset_unique_ptr &dataset, GDALDriverH driver, const QString &path )
65 {
66  // see https://github.com/qgis/QGIS/commit/d024910490a39e65e671f2055c5b6543e06c7042#commitcomment-25194282
67  // faster if we close the handle AFTER delete, but doesn't work for windows
68 #ifdef Q_OS_WIN
69  // close dataset handle
70  dataset.reset();
71 #endif
72 
73  CPLPushErrorHandler( CPLQuietErrorHandler );
74  GDALDeleteDataset( driver, path.toUtf8().constData() );
75  CPLPopErrorHandler();
76 
77 #ifndef Q_OS_WIN
78  // close dataset handle
79  dataset.reset();
80 #endif
81 }
82 
83 
84 void gdal::GDALWarpOptionsDeleter::operator()( GDALWarpOptions *options )
85 {
86  GDALDestroyWarpOptions( options );
87 }
88 
89 QgsFeature QgsOgrUtils::readOgrFeature( OGRFeatureH ogrFet, const QgsFields &fields, QTextCodec *encoding )
90 {
91  QgsFeature feature;
92  if ( !ogrFet )
93  {
94  feature.setValid( false );
95  return feature;
96  }
97 
98  feature.setId( OGR_F_GetFID( ogrFet ) );
99  feature.setValid( true );
100 
101  if ( !readOgrFeatureGeometry( ogrFet, feature ) )
102  {
103  feature.setValid( false );
104  }
105 
106  if ( !readOgrFeatureAttributes( ogrFet, fields, feature, encoding ) )
107  {
108  feature.setValid( false );
109  }
110 
111  return feature;
112 }
113 
114 QgsFields QgsOgrUtils::readOgrFields( OGRFeatureH ogrFet, QTextCodec *encoding )
115 {
116  QgsFields fields;
117 
118  if ( !ogrFet )
119  return fields;
120 
121  int fieldCount = OGR_F_GetFieldCount( ogrFet );
122  for ( int i = 0; i < fieldCount; ++i )
123  {
124  OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, i );
125  if ( !fldDef )
126  {
127  fields.append( QgsField() );
128  continue;
129  }
130 
131  QString name = encoding ? encoding->toUnicode( OGR_Fld_GetNameRef( fldDef ) ) : QString::fromUtf8( OGR_Fld_GetNameRef( fldDef ) );
132  QVariant::Type varType;
133  switch ( OGR_Fld_GetType( fldDef ) )
134  {
135  case OFTInteger:
136  if ( OGR_Fld_GetSubType( fldDef ) == OFSTBoolean )
137  varType = QVariant::Bool;
138  else
139  varType = QVariant::Int;
140  break;
141  case OFTInteger64:
142  varType = QVariant::LongLong;
143  break;
144  case OFTReal:
145  varType = QVariant::Double;
146  break;
147  case OFTDate:
148  varType = QVariant::Date;
149  break;
150  case OFTTime:
151  varType = QVariant::Time;
152  break;
153  case OFTDateTime:
154  varType = QVariant::DateTime;
155  break;
156  case OFTString:
157 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,4,0)
158  if ( OGR_Fld_GetSubType( fldDef ) == OFSTJSON )
159  varType = QVariant::Map;
160  else
161  varType = QVariant::String;
162  break;
163 #endif
164  default:
165  varType = QVariant::String; // other unsupported, leave it as a string
166  }
167  fields.append( QgsField( name, varType ) );
168  }
169  return fields;
170 }
171 
172 QVariant QgsOgrUtils::getOgrFeatureAttribute( OGRFeatureH ogrFet, const QgsFields &fields, int attIndex, QTextCodec *encoding, bool *ok )
173 {
174  if ( !ogrFet || attIndex < 0 || attIndex >= fields.count() )
175  {
176  if ( ok )
177  *ok = false;
178  return QVariant();
179  }
180 
181  OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, attIndex );
182 
183  if ( ! fldDef )
184  {
185  if ( ok )
186  *ok = false;
187 
188  QgsDebugMsg( QStringLiteral( "ogrFet->GetFieldDefnRef(attindex) returns NULL" ) );
189  return QVariant();
190  }
191 
192  QVariant value;
193 
194  if ( ok )
195  *ok = true;
196 
197  if ( OGR_F_IsFieldSetAndNotNull( ogrFet, attIndex ) )
198  {
199  switch ( fields.at( attIndex ).type() )
200  {
201  case QVariant::String:
202  {
203  if ( encoding )
204  value = QVariant( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
205  else
206  value = QVariant( QString::fromUtf8( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
207  break;
208  }
209  case QVariant::Int:
210  value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) );
211  break;
212  case QVariant::Bool:
213  value = QVariant( bool( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) ) );
214  break;
215  case QVariant::LongLong:
216  value = QVariant( OGR_F_GetFieldAsInteger64( ogrFet, attIndex ) );
217  break;
218  case QVariant::Double:
219  value = QVariant( OGR_F_GetFieldAsDouble( ogrFet, attIndex ) );
220  break;
221  case QVariant::Date:
222  case QVariant::DateTime:
223  case QVariant::Time:
224  {
225  int year, month, day, hour, minute, second, tzf;
226 
227  OGR_F_GetFieldAsDateTime( ogrFet, attIndex, &year, &month, &day, &hour, &minute, &second, &tzf );
228  if ( fields.at( attIndex ).type() == QVariant::Date )
229  value = QDate( year, month, day );
230  else if ( fields.at( attIndex ).type() == QVariant::Time )
231  value = QTime( hour, minute, second );
232  else
233  value = QDateTime( QDate( year, month, day ), QTime( hour, minute, second ) );
234  }
235  break;
236 
237  case QVariant::ByteArray:
238  {
239  int size = 0;
240  const GByte *b = OGR_F_GetFieldAsBinary( ogrFet, attIndex, &size );
241 
242  // QByteArray::fromRawData is funny. It doesn't take ownership of the data, so we have to explicitly call
243  // detach on it to force a copy which owns the data
244  QByteArray ba = QByteArray::fromRawData( reinterpret_cast<const char *>( b ), size );
245  ba.detach();
246 
247  value = ba;
248  break;
249  }
250 
251  case QVariant::List:
252  {
253  if ( fields.at( attIndex ).subType() == QVariant::String )
254  {
255  QStringList list;
256  char **lst = OGR_F_GetFieldAsStringList( ogrFet, attIndex );
257  const int count = CSLCount( lst );
258  if ( count > 0 )
259  {
260  for ( int i = 0; i < count; i++ )
261  {
262  if ( encoding )
263  list << encoding->toUnicode( lst[i] );
264  else
265  list << QString::fromUtf8( lst[i] );
266  }
267  }
268  value = list;
269  }
270  else
271  {
272  Q_ASSERT_X( false, "QgsOgrUtils::getOgrFeatureAttribute", "unsupported field type" );
273  if ( ok )
274  *ok = false;
275  }
276  break;
277  }
278 
279  case QVariant::Map:
280  {
281  //it has to be JSON
282  //it's null if no json format
283  if ( encoding )
284  value = QJsonDocument::fromJson( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ).toUtf8() ).toVariant();
285  else
286  value = QJsonDocument::fromJson( QString::fromUtf8( OGR_F_GetFieldAsString( ogrFet, attIndex ) ).toUtf8() ).toVariant();
287  break;
288  }
289  default:
290  Q_ASSERT_X( false, "QgsOgrUtils::getOgrFeatureAttribute", "unsupported field type" );
291  if ( ok )
292  *ok = false;
293  }
294  }
295  else
296  {
297  value = QVariant( QString() );
298  }
299 
300  return value;
301 }
302 
303 bool QgsOgrUtils::readOgrFeatureAttributes( OGRFeatureH ogrFet, const QgsFields &fields, QgsFeature &feature, QTextCodec *encoding )
304 {
305  // read all attributes
306  feature.initAttributes( fields.count() );
307  feature.setFields( fields );
308 
309  if ( !ogrFet )
310  return false;
311 
312  bool ok = false;
313  for ( int idx = 0; idx < fields.count(); ++idx )
314  {
315  QVariant value = getOgrFeatureAttribute( ogrFet, fields, idx, encoding, &ok );
316  if ( ok )
317  {
318  feature.setAttribute( idx, value );
319  }
320  }
321  return true;
322 }
323 
324 bool QgsOgrUtils::readOgrFeatureGeometry( OGRFeatureH ogrFet, QgsFeature &feature )
325 {
326  if ( !ogrFet )
327  return false;
328 
329  OGRGeometryH geom = OGR_F_GetGeometryRef( ogrFet );
330  if ( !geom )
331  feature.clearGeometry();
332  else
333  feature.setGeometry( ogrGeometryToQgsGeometry( geom ) );
334 
335  return true;
336 }
337 
338 std::unique_ptr< QgsPoint > ogrGeometryToQgsPoint( OGRGeometryH geom )
339 {
340  QgsWkbTypes::Type wkbType = static_cast<QgsWkbTypes::Type>( OGR_G_GetGeometryType( geom ) );
341 
342  double x, y, z, m;
343  OGR_G_GetPointZM( geom, 0, &x, &y, &z, &m );
344  return qgis::make_unique< QgsPoint >( wkbType, x, y, z, m );
345 }
346 
347 std::unique_ptr< QgsMultiPoint > ogrGeometryToQgsMultiPoint( OGRGeometryH geom )
348 {
349  std::unique_ptr< QgsMultiPoint > mp = qgis::make_unique< QgsMultiPoint >();
350 
351  const int count = OGR_G_GetGeometryCount( geom );
352  mp->reserve( count );
353  for ( int i = 0; i < count; ++i )
354  {
355  mp->addGeometry( ogrGeometryToQgsPoint( OGR_G_GetGeometryRef( geom, i ) ).release() );
356  }
357 
358  return mp;
359 }
360 
361 std::unique_ptr< QgsLineString > ogrGeometryToQgsLineString( OGRGeometryH geom )
362 {
363  QgsWkbTypes::Type wkbType = static_cast<QgsWkbTypes::Type>( OGR_G_GetGeometryType( geom ) );
364 
365  int count = OGR_G_GetPointCount( geom );
366  QVector< double > x( count );
367  QVector< double > y( count );
368  QVector< double > z;
369  double *pz = nullptr;
370  if ( QgsWkbTypes::hasZ( wkbType ) )
371  {
372  z.resize( count );
373  pz = z.data();
374  }
375  double *pm = nullptr;
376  QVector< double > m;
377  if ( QgsWkbTypes::hasM( wkbType ) )
378  {
379  m.resize( count );
380  pm = m.data();
381  }
382  OGR_G_GetPointsZM( geom, x.data(), sizeof( double ), y.data(), sizeof( double ), pz, sizeof( double ), pm, sizeof( double ) );
383 
384  return qgis::make_unique< QgsLineString>( x, y, z, m, wkbType == QgsWkbTypes::LineString25D );
385 }
386 
387 std::unique_ptr< QgsMultiLineString > ogrGeometryToQgsMultiLineString( OGRGeometryH geom )
388 {
389  std::unique_ptr< QgsMultiLineString > mp = qgis::make_unique< QgsMultiLineString >();
390 
391  const int count = OGR_G_GetGeometryCount( geom );
392  mp->reserve( count );
393  for ( int i = 0; i < count; ++i )
394  {
395  mp->addGeometry( ogrGeometryToQgsLineString( OGR_G_GetGeometryRef( geom, i ) ).release() );
396  }
397 
398  return mp;
399 }
400 
402 {
403  switch ( ogrGeomType )
404  {
405  case wkbUnknown: return QgsWkbTypes::Type::Unknown;
406  case wkbPoint: return QgsWkbTypes::Type::Point;
407  case wkbLineString: return QgsWkbTypes::Type::LineString;
408  case wkbPolygon: return QgsWkbTypes::Type::Polygon;
409  case wkbMultiPoint: return QgsWkbTypes::Type::MultiPoint;
410  case wkbMultiLineString: return QgsWkbTypes::Type::MultiLineString;
411  case wkbMultiPolygon: return QgsWkbTypes::Type::MultiPolygon;
412  case wkbGeometryCollection: return QgsWkbTypes::Type::GeometryCollection;
413  case wkbCircularString: return QgsWkbTypes::Type::CircularString;
414  case wkbCompoundCurve: return QgsWkbTypes::Type::CompoundCurve;
415  case wkbCurvePolygon: return QgsWkbTypes::Type::CurvePolygon;
416  case wkbMultiCurve: return QgsWkbTypes::Type::MultiCurve;
417  case wkbMultiSurface: return QgsWkbTypes::Type::MultiSurface;
418  case wkbCurve: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
419  case wkbSurface: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
420  case wkbPolyhedralSurface: return QgsWkbTypes::Type::Unknown; // no actual matching
421  case wkbTIN: return QgsWkbTypes::Type::Unknown; // no actual matching
422  case wkbTriangle: return QgsWkbTypes::Type::Triangle;
423 
424  case wkbNone: return QgsWkbTypes::Type::NoGeometry;
425  case wkbLinearRing: return QgsWkbTypes::Type::LineString; // approximate match
426 
427  case wkbCircularStringZ: return QgsWkbTypes::Type::CircularStringZ;
428  case wkbCompoundCurveZ: return QgsWkbTypes::Type::CompoundCurveZ;
429  case wkbCurvePolygonZ: return QgsWkbTypes::Type::CurvePolygonZ;
430  case wkbMultiCurveZ: return QgsWkbTypes::Type::MultiCurveZ;
431  case wkbMultiSurfaceZ: return QgsWkbTypes::Type::MultiSurfaceZ;
432  case wkbCurveZ: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
433  case wkbSurfaceZ: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
434  case wkbPolyhedralSurfaceZ: return QgsWkbTypes::Type::Unknown; // no actual matching
435  case wkbTINZ: return QgsWkbTypes::Type::Unknown; // no actual matching
436  case wkbTriangleZ: return QgsWkbTypes::Type::TriangleZ;
437 
438  case wkbPointM: return QgsWkbTypes::Type::PointM;
439  case wkbLineStringM: return QgsWkbTypes::Type::LineStringM;
440  case wkbPolygonM: return QgsWkbTypes::Type::PolygonM;
441  case wkbMultiPointM: return QgsWkbTypes::Type::MultiPointM;
442  case wkbMultiLineStringM: return QgsWkbTypes::Type::MultiLineStringM;
443  case wkbMultiPolygonM: return QgsWkbTypes::Type::MultiPolygonM;
444  case wkbGeometryCollectionM: return QgsWkbTypes::Type::GeometryCollectionM;
445  case wkbCircularStringM: return QgsWkbTypes::Type::CircularStringM;
446  case wkbCompoundCurveM: return QgsWkbTypes::Type::CompoundCurveM;
447  case wkbCurvePolygonM: return QgsWkbTypes::Type::CurvePolygonM;
448  case wkbMultiCurveM: return QgsWkbTypes::Type::MultiCurveM;
449  case wkbMultiSurfaceM: return QgsWkbTypes::Type::MultiSurfaceM;
450  case wkbCurveM: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
451  case wkbSurfaceM: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
452  case wkbPolyhedralSurfaceM: return QgsWkbTypes::Type::Unknown; // no actual matching
453  case wkbTINM: return QgsWkbTypes::Type::Unknown; // no actual matching
454  case wkbTriangleM: return QgsWkbTypes::Type::TriangleM;
455 
456  case wkbPointZM: return QgsWkbTypes::Type::PointZM;
457  case wkbLineStringZM: return QgsWkbTypes::Type::LineStringZM;
458  case wkbPolygonZM: return QgsWkbTypes::Type::PolygonZM;
459  case wkbMultiPointZM: return QgsWkbTypes::Type::MultiPointZM;
460  case wkbMultiLineStringZM: return QgsWkbTypes::Type::MultiLineStringZM;
461  case wkbMultiPolygonZM: return QgsWkbTypes::Type::MultiPolygonZM;
462  case wkbGeometryCollectionZM: return QgsWkbTypes::Type::GeometryCollectionZM;
463  case wkbCircularStringZM: return QgsWkbTypes::Type::CircularStringZM;
464  case wkbCompoundCurveZM: return QgsWkbTypes::Type::CompoundCurveZM;
465  case wkbCurvePolygonZM: return QgsWkbTypes::Type::CurvePolygonZM;
466  case wkbMultiCurveZM: return QgsWkbTypes::Type::MultiCurveZM;
467  case wkbMultiSurfaceZM: return QgsWkbTypes::Type::MultiSurfaceZM;
468  case wkbCurveZM: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
469  case wkbSurfaceZM: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
470  case wkbPolyhedralSurfaceZM: return QgsWkbTypes::Type::Unknown; // no actual matching
471  case wkbTINZM: return QgsWkbTypes::Type::Unknown; // no actual matching
472  case wkbTriangleZM: return QgsWkbTypes::Type::TriangleZM;
473 
474  case wkbPoint25D: return QgsWkbTypes::Type::PointZ;
475  case wkbLineString25D: return QgsWkbTypes::Type::LineStringZ;
476  case wkbPolygon25D: return QgsWkbTypes::Type::PolygonZ;
477  case wkbMultiPoint25D: return QgsWkbTypes::Type::MultiPointZ;
478  case wkbMultiLineString25D: return QgsWkbTypes::Type::MultiLineStringZ;
479  case wkbMultiPolygon25D: return QgsWkbTypes::Type::MultiPolygonZ;
480  case wkbGeometryCollection25D: return QgsWkbTypes::Type::GeometryCollectionZ;
481  }
482 
483  // should not reach that point normally
484  return QgsWkbTypes::Type::Unknown;
485 }
486 
488 {
489  if ( !geom )
490  return QgsGeometry();
491 
492  const auto ogrGeomType = OGR_G_GetGeometryType( geom );
493  QgsWkbTypes::Type wkbType = ogrGeometryTypeToQgsWkbType( ogrGeomType );
494 
495  // optimised case for some geometry classes, avoiding wkb conversion on OGR/QGIS sides
496  // TODO - extend to other classes!
497  switch ( QgsWkbTypes::flatType( wkbType ) )
498  {
499  case QgsWkbTypes::Point:
500  {
501  return QgsGeometry( ogrGeometryToQgsPoint( geom ) );
502  }
503 
505  {
506  return QgsGeometry( ogrGeometryToQgsMultiPoint( geom ) );
507  }
508 
510  {
511  // optimised case for line -- avoid wkb conversion
512  return QgsGeometry( ogrGeometryToQgsLineString( geom ) );
513  }
514 
516  {
517  // optimised case for line -- avoid wkb conversion
519  }
520 
521  default:
522  break;
523  };
524 
525  // Fallback to inefficient WKB conversions
526 
527  if ( wkbFlatten( wkbType ) == wkbGeometryCollection )
528  {
529  // Shapefile MultiPatch can be reported as GeometryCollectionZ of TINZ
530  if ( OGR_G_GetGeometryCount( geom ) >= 1 &&
531  wkbFlatten( OGR_G_GetGeometryType( OGR_G_GetGeometryRef( geom, 0 ) ) ) == wkbTIN )
532  {
533  auto newGeom = OGR_G_ForceToMultiPolygon( OGR_G_Clone( geom ) );
534  auto ret = ogrGeometryToQgsGeometry( newGeom );
535  OGR_G_DestroyGeometry( newGeom );
536  return ret;
537  }
538  }
539 
540  // get the wkb representation
541  int memorySize = OGR_G_WkbSize( geom );
542  unsigned char *wkb = new unsigned char[memorySize];
543  OGR_G_ExportToWkb( geom, static_cast<OGRwkbByteOrder>( QgsApplication::endian() ), wkb );
544 
545  // Read original geometry type
546  uint32_t origGeomType;
547  memcpy( &origGeomType, wkb + 1, sizeof( uint32_t ) );
548  bool hasZ = ( origGeomType >= 1000 && origGeomType < 2000 ) || ( origGeomType >= 3000 && origGeomType < 4000 );
549  bool hasM = ( origGeomType >= 2000 && origGeomType < 3000 ) || ( origGeomType >= 3000 && origGeomType < 4000 );
550 
551  // PolyhedralSurface and TINs are not supported, map them to multipolygons...
552  if ( origGeomType % 1000 == 16 ) // is TIN, TINZ, TINM or TINZM
553  {
554  // TIN has the same wkb layout as a multipolygon, just need to overwrite the geom types...
555  int nDims = 2 + hasZ + hasM;
556  uint32_t newMultiType = static_cast<uint32_t>( QgsWkbTypes::zmType( QgsWkbTypes::MultiPolygon, hasZ, hasM ) );
557  uint32_t newSingleType = static_cast<uint32_t>( QgsWkbTypes::zmType( QgsWkbTypes::Polygon, hasZ, hasM ) );
558  unsigned char *wkbptr = wkb;
559 
560  // Endianness
561  wkbptr += 1;
562 
563  // Overwrite geom type
564  memcpy( wkbptr, &newMultiType, sizeof( uint32_t ) );
565  wkbptr += 4;
566 
567  // Geom count
568  uint32_t numGeoms;
569  memcpy( &numGeoms, wkb + 5, sizeof( uint32_t ) );
570  wkbptr += 4;
571 
572  // For each part, overwrite the geometry type to polygon (Z|M)
573  for ( uint32_t i = 0; i < numGeoms; ++i )
574  {
575  // Endianness
576  wkbptr += 1;
577 
578  // Overwrite geom type
579  memcpy( wkbptr, &newSingleType, sizeof( uint32_t ) );
580  wkbptr += sizeof( uint32_t );
581 
582  // skip coordinates
583  uint32_t nRings;
584  memcpy( &nRings, wkbptr, sizeof( uint32_t ) );
585  wkbptr += sizeof( uint32_t );
586 
587  for ( uint32_t j = 0; j < nRings; ++j )
588  {
589  uint32_t nPoints;
590  memcpy( &nPoints, wkbptr, sizeof( uint32_t ) );
591  wkbptr += sizeof( uint32_t ) + sizeof( double ) * nDims * nPoints;
592  }
593  }
594  }
595  else if ( origGeomType % 1000 == 15 ) // PolyhedralSurface, PolyhedralSurfaceZ, PolyhedralSurfaceM or PolyhedralSurfaceZM
596  {
597  // PolyhedralSurface has the same wkb layout as a MultiPolygon, just need to overwrite the geom type...
598  uint32_t newType = static_cast<uint32_t>( QgsWkbTypes::zmType( QgsWkbTypes::MultiPolygon, hasZ, hasM ) );
599  // Overwrite geom type
600  memcpy( wkb + 1, &newType, sizeof( uint32_t ) );
601  }
602 
603  QgsGeometry g;
604  g.fromWkb( wkb, memorySize );
605  return g;
606 }
607 
608 QgsFeatureList QgsOgrUtils::stringToFeatureList( const QString &string, const QgsFields &fields, QTextCodec *encoding )
609 {
610  QgsFeatureList features;
611  if ( string.isEmpty() )
612  return features;
613 
614  QString randomFileName = QStringLiteral( "/vsimem/%1" ).arg( QUuid::createUuid().toString() );
615 
616  // create memory file system object from string buffer
617  QByteArray ba = string.toUtf8();
618  VSIFCloseL( VSIFileFromMemBuffer( randomFileName.toUtf8().constData(), reinterpret_cast< GByte * >( ba.data() ),
619  static_cast< vsi_l_offset >( ba.size() ), FALSE ) );
620 
621  gdal::ogr_datasource_unique_ptr hDS( OGROpen( randomFileName.toUtf8().constData(), false, nullptr ) );
622  if ( !hDS )
623  {
624  VSIUnlink( randomFileName.toUtf8().constData() );
625  return features;
626  }
627 
628  OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS.get(), 0 );
629  if ( !ogrLayer )
630  {
631  hDS.reset();
632  VSIUnlink( randomFileName.toUtf8().constData() );
633  return features;
634  }
635 
637  while ( oFeat.reset( OGR_L_GetNextFeature( ogrLayer ) ), oFeat )
638  {
639  QgsFeature feat = readOgrFeature( oFeat.get(), fields, encoding );
640  if ( feat.isValid() )
641  features << feat;
642  }
643 
644  hDS.reset();
645  VSIUnlink( randomFileName.toUtf8().constData() );
646 
647  return features;
648 }
649 
650 QgsFields QgsOgrUtils::stringToFields( const QString &string, QTextCodec *encoding )
651 {
652  QgsFields fields;
653  if ( string.isEmpty() )
654  return fields;
655 
656  QString randomFileName = QStringLiteral( "/vsimem/%1" ).arg( QUuid::createUuid().toString() );
657 
658  // create memory file system object from buffer
659  QByteArray ba = string.toUtf8();
660  VSIFCloseL( VSIFileFromMemBuffer( randomFileName.toUtf8().constData(), reinterpret_cast< GByte * >( ba.data() ),
661  static_cast< vsi_l_offset >( ba.size() ), FALSE ) );
662 
663  gdal::ogr_datasource_unique_ptr hDS( OGROpen( randomFileName.toUtf8().constData(), false, nullptr ) );
664  if ( !hDS )
665  {
666  VSIUnlink( randomFileName.toUtf8().constData() );
667  return fields;
668  }
669 
670  OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS.get(), 0 );
671  if ( !ogrLayer )
672  {
673  hDS.reset();
674  VSIUnlink( randomFileName.toUtf8().constData() );
675  return fields;
676  }
677 
679  //read in the first feature only
680  if ( oFeat.reset( OGR_L_GetNextFeature( ogrLayer ) ), oFeat )
681  {
682  fields = readOgrFields( oFeat.get(), encoding );
683  }
684 
685  hDS.reset();
686  VSIUnlink( randomFileName.toUtf8().constData() );
687  return fields;
688 }
689 
690 QStringList QgsOgrUtils::cStringListToQStringList( char **stringList )
691 {
692  QStringList strings;
693 
694  // presume null terminated string list
695  for ( qgssize i = 0; stringList[i]; ++i )
696  {
697  strings.append( QString::fromUtf8( stringList[i] ) );
698  }
699 
700  return strings;
701 }
702 
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:183
void CORE_EXPORT operator()(OGRFeatureH feature)
Destroys an OGR feature, using the correct gdal calls.
Definition: qgsogrutils.cpp:54
static bool readOgrFeatureAttributes(OGRFeatureH ogrFet, const QgsFields &fields, QgsFeature &feature, QTextCodec *encoding)
Reads all attributes from an OGR feature into a QgsFeature.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:162
std::unique_ptr< QgsMultiLineString > ogrGeometryToQgsMultiLineString(OGRGeometryH geom)
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer&#39;s length...
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:571
static bool readOgrFeatureGeometry(OGRFeatureH ogrFet, QgsFeature &feature)
Reads the geometry from an OGR feature into a QgsFeature.
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:122
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:211
void CORE_EXPORT operator()(OGRDataSourceH source)
Destroys an OGR data source, using the correct gdal calls.
Definition: qgsogrutils.cpp:38
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
static QgsFields readOgrFields(OGRFeatureH ogrFet, QTextCodec *encoding)
Reads an OGR feature and returns a corresponding fields collection.
#define OGR_F_IsFieldSetAndNotNull
Definition: qgsogrutils.cpp:33
static endian_t endian()
Returns whether this machine uses big or little endian.
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:917
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
std::unique_ptr< QgsPoint > ogrGeometryToQgsPoint(OGRGeometryH geom)
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields, QTextCodec *encoding)
Attempts to parse a string representing a collection of features using OGR.
void CORE_EXPORT fast_delete_and_close(dataset_unique_ptr &dataset, GDALDriverH driver, const QString &path)
Performs a fast close of an unwanted GDAL dataset handle by deleting the underlying data store...
Definition: qgsogrutils.cpp:64
std::unique_ptr< std::remove_pointer< OGRFeatureH >::type, OGRFeatureDeleter > ogr_feature_unique_ptr
Scoped OGR feature.
Definition: qgsogrutils.h:129
std::unique_ptr< QgsMultiPoint > ogrGeometryToQgsMultiPoint(OGRGeometryH geom)
void CORE_EXPORT operator()(GDALDatasetH datasource)
Destroys an gdal dataset, using the correct gdal calls.
Definition: qgsogrutils.cpp:59
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:202
static QgsFeature readOgrFeature(OGRFeatureH ogrFet, const QgsFields &fields, QTextCodec *encoding)
Reads an OGR feature and converts it to a QgsFeature.
Definition: qgsogrutils.cpp:89
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false) ...
Definition: qgsfields.cpp:59
static QgsFields stringToFields(const QString &string, QTextCodec *encoding)
Attempts to retrieve the fields from a string representing a collection of features using OGR...
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
void setId(QgsFeatureId id)
Sets the feature ID for this feature.
Definition: qgsfeature.cpp:112
void * GDALDatasetH
static QgsGeometry ogrGeometryToQgsGeometry(OGRGeometryH geom)
Converts an OGR geometry representation to a QgsGeometry object.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
Definition: qgis.h:621
void CORE_EXPORT operator()(GDALWarpOptions *options)
Destroys GDAL warp options, using the correct gdal calls.
Definition: qgsogrutils.cpp:84
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:188
void clearGeometry()
Removes any geometry associated with the feature.
Definition: qgsfeature.cpp:151
static QVariant getOgrFeatureAttribute(OGRFeatureH ogrFet, const QgsFields &fields, int attIndex, QTextCodec *encoding, bool *ok=nullptr)
Retrieves an attribute value from an OGR feature.
std::unique_ptr< QgsLineString > ogrGeometryToQgsLineString(OGRGeometryH geom)
void CORE_EXPORT operator()(OGRGeometryH geometry)
Destroys an OGR geometry, using the correct gdal calls.
Definition: qgsogrutils.cpp:44
void CORE_EXPORT operator()(OGRFieldDefnH definition)
Destroys an OGR field definition, using the correct gdal calls.
Definition: qgsogrutils.cpp:49
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
static QgsWkbTypes::Type ogrGeometryTypeToQgsWkbType(OGRwkbGeometryType ogrGeomType)
Converts a OGRwkbGeometryType to QgsWkbTypes::Type.
static Type zmType(Type type, bool hasZ, bool hasM)
Returns the modified input geometry type according to hasZ / hasM.
Definition: qgswkbtypes.h:675
QVariant::Type subType() const
If the field is a collection, gets its element&#39;s type.
Definition: qgsfield.cpp:100
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:967
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
Definition: qgsogrutils.h:134
std::unique_ptr< std::remove_pointer< OGRDataSourceH >::type, OGRDataSourceDeleter > ogr_datasource_unique_ptr
Scoped OGR data source.
Definition: qgsogrutils.h:114
static QStringList cStringListToQStringList(char **stringList)
Converts a c string list to a QStringList.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:576
QVariant::Type type
Definition: qgsfield.h:56