QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 <QTextCodec>
21 #include <QUuid>
22 
23 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800
24 #define TO8(x) (x).toUtf8().constData()
25 #define TO8F(x) (x).toUtf8().constData()
26 #define FROM8(x) QString::fromUtf8(x)
27 #else
28 #define TO8(x) (x).toLocal8Bit().constData()
29 #define TO8F(x) QFile::encodeName( x ).constData()
30 #define FROM8(x) QString::fromLocal8Bit(x)
31 #endif
32 
33 // Starting with GDAL 2.2, there are 2 concepts: unset fields and null fields
34 // whereas previously there was only unset fields. For QGIS purposes, both
35 // states (unset/null) are equivalent.
36 #ifndef OGRNullMarker
37 #define OGR_F_IsFieldSetAndNotNull OGR_F_IsFieldSet
38 #endif
39 
40 QgsFeature QgsOgrUtils::readOgrFeature( OGRFeatureH ogrFet, const QgsFields& fields, QTextCodec* encoding )
41 {
42  QgsFeature feature;
43  if ( !ogrFet )
44  {
45  feature.setValid( false );
46  return feature;
47  }
48 
49  feature.setFeatureId( OGR_F_GetFID( ogrFet ) );
50  feature.setValid( true );
51 
52  if ( !readOgrFeatureGeometry( ogrFet, feature ) )
53  {
54  feature.setValid( false );
55  }
56 
57  if ( !readOgrFeatureAttributes( ogrFet, fields, feature, encoding ) )
58  {
59  feature.setValid( false );
60  }
61 
62  return feature;
63 }
64 
65 QgsFields QgsOgrUtils::readOgrFields( OGRFeatureH ogrFet, QTextCodec* encoding )
66 {
67  QgsFields fields;
68 
69  if ( !ogrFet )
70  return fields;
71 
72  int fieldCount = OGR_F_GetFieldCount( ogrFet );
73  for ( int i = 0; i < fieldCount; ++i )
74  {
75  OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, i );
76  if ( !fldDef )
77  {
78  fields.append( QgsField() );
79  continue;
80  }
81 
82  QString name = encoding ? encoding->toUnicode( OGR_Fld_GetNameRef( fldDef ) ) : QString::fromUtf8( OGR_Fld_GetNameRef( fldDef ) );
83  QVariant::Type varType;
84  switch ( OGR_Fld_GetType( fldDef ) )
85  {
86  case OFTInteger:
87  varType = QVariant::Int;
88  break;
89 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000
90  case OFTInteger64:
91  varType = QVariant::LongLong;
92  break;
93 #endif
94  case OFTReal:
95  varType = QVariant::Double;
96  break;
97 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1400
98  case OFTDate:
99  varType = QVariant::Date;
100  break;
101  case OFTTime:
102  varType = QVariant::Time;
103  break;
104  case OFTDateTime:
105  varType = QVariant::DateTime;
106  break;
107  case OFTString:
108 #endif
109  default:
110  varType = QVariant::String; // other unsupported, leave it as a string
111  }
112  fields.append( QgsField( name, varType ) );
113  }
114  return fields;
115 }
116 
117 QVariant QgsOgrUtils::getOgrFeatureAttribute( OGRFeatureH ogrFet, const QgsFields& fields, int attIndex, QTextCodec* encoding , bool* ok )
118 {
119  if ( !ogrFet || attIndex < 0 || attIndex >= fields.count() )
120  {
121  if ( ok )
122  *ok = false;
123  return QVariant();
124  }
125 
126  OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, attIndex );
127 
128  if ( ! fldDef )
129  {
130  if ( ok )
131  *ok = false;
132 
133  QgsDebugMsg( "ogrFet->GetFieldDefnRef(attindex) returns NULL" );
134  return QVariant();
135  }
136 
137  QVariant value;
138 
139  if ( ok )
140  *ok = true;
141 
142  if ( OGR_F_IsFieldSetAndNotNull( ogrFet, attIndex ) )
143  {
144  switch ( fields.at( attIndex ).type() )
145  {
146  case QVariant::String:
147  {
148  if ( encoding )
149  value = QVariant( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
150  else
151  value = QVariant( QString::fromUtf8( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
152  break;
153  }
154  case QVariant::Int:
155  value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) );
156  break;
157 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000
158  case QVariant::LongLong:
159  value = QVariant( OGR_F_GetFieldAsInteger64( ogrFet, attIndex ) );
160  break;
161 #endif
162  case QVariant::Double:
163  value = QVariant( OGR_F_GetFieldAsDouble( ogrFet, attIndex ) );
164  break;
165  case QVariant::Date:
166  case QVariant::DateTime:
167  case QVariant::Time:
168  {
169  int year, month, day, hour, minute, second, tzf;
170 
171  OGR_F_GetFieldAsDateTime( ogrFet, attIndex, &year, &month, &day, &hour, &minute, &second, &tzf );
172  if ( fields.at( attIndex ).type() == QVariant::Date )
173  value = QDate( year, month, day );
174  else if ( fields.at( attIndex ).type() == QVariant::Time )
175  value = QTime( hour, minute, second );
176  else
177  value = QDateTime( QDate( year, month, day ), QTime( hour, minute, second ) );
178  }
179  break;
180  default:
181  Q_ASSERT_X( false, "QgsOgrUtils::getOgrFeatureAttribute", "unsupported field type" );
182  if ( ok )
183  *ok = false;
184  }
185  }
186  else
187  {
188  value = QVariant( QString::null );
189  }
190 
191  return value;
192 }
193 
194 bool QgsOgrUtils::readOgrFeatureAttributes( OGRFeatureH ogrFet, const QgsFields& fields, QgsFeature& feature, QTextCodec* encoding )
195 {
196  // read all attributes
197  feature.initAttributes( fields.count() );
198  feature.setFields( fields );
199 
200  if ( !ogrFet )
201  return false;
202 
203  bool ok = false;
204  for ( int idx = 0; idx < fields.count(); ++idx )
205  {
206  QVariant value = getOgrFeatureAttribute( ogrFet, fields, idx, encoding, &ok );
207  if ( ok )
208  {
209  feature.setAttribute( idx, value );
210  }
211  }
212  return true;
213 }
214 
215 bool QgsOgrUtils::readOgrFeatureGeometry( OGRFeatureH ogrFet, QgsFeature& feature )
216 {
217  if ( !ogrFet )
218  return false;
219 
220  OGRGeometryH geom = OGR_F_GetGeometryRef( ogrFet );
221  if ( !geom )
222  feature.setGeometry( nullptr );
223  else
224  feature.setGeometry( ogrGeometryToQgsGeometry( geom ) );
225 
226  return true;
227 }
228 
230 {
231  if ( !geom )
232  return nullptr;
233 
234  // get the wkb representation
235  int memorySize = OGR_G_WkbSize( geom );
236  unsigned char *wkb = new unsigned char[memorySize];
237  OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb );
238 
239  QgsGeometry *g = new QgsGeometry();
240  g->fromWkb( wkb, memorySize );
241  return g;
242 }
243 
245 {
246  QgsFeatureList features;
247  if ( string.isEmpty() )
248  return features;
249 
250  QString randomFileName = QString( "/vsimem/%1" ).arg( QUuid::createUuid().toString() );
251 
252  // create memory file system object from string buffer
253  QByteArray ba = string.toUtf8();
254  VSIFCloseL( VSIFileFromMemBuffer( TO8( randomFileName ), reinterpret_cast< GByte* >( ba.data() ),
255  static_cast< vsi_l_offset >( ba.size() ), FALSE ) );
256 
257  OGRDataSourceH hDS = OGROpen( TO8( randomFileName ), false, nullptr );
258  if ( !hDS )
259  {
260  VSIUnlink( TO8( randomFileName ) );
261  return features;
262  }
263 
264  OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS, 0 );
265  if ( !ogrLayer )
266  {
267  OGR_DS_Destroy( hDS );
268  VSIUnlink( TO8( randomFileName ) );
269  return features;
270  }
271 
272  OGRFeatureH oFeat;
273  while (( oFeat = OGR_L_GetNextFeature( ogrLayer ) ) )
274  {
275  QgsFeature feat = readOgrFeature( oFeat, fields, encoding );
276  if ( feat.isValid() )
277  features << feat;
278 
279  OGR_F_Destroy( oFeat );
280  }
281 
282  OGR_DS_Destroy( hDS );
283  VSIUnlink( TO8( randomFileName ) );
284 
285  return features;
286 }
287 
289 {
290  QgsFields fields;
291  if ( string.isEmpty() )
292  return fields;
293 
294  QString randomFileName = QString( "/vsimem/%1" ).arg( QUuid::createUuid().toString() );
295 
296  // create memory file system object from buffer
297  QByteArray ba = string.toUtf8();
298  VSIFCloseL( VSIFileFromMemBuffer( TO8( randomFileName ), reinterpret_cast< GByte* >( ba.data() ),
299  static_cast< vsi_l_offset >( ba.size() ), FALSE ) );
300 
301  OGRDataSourceH hDS = OGROpen( TO8( randomFileName ), false, nullptr );
302  if ( !hDS )
303  {
304  VSIUnlink( TO8( randomFileName ) );
305  return fields;
306  }
307 
308  OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS, 0 );
309  if ( !ogrLayer )
310  {
311  OGR_DS_Destroy( hDS );
312  VSIUnlink( TO8( randomFileName ) );
313  return fields;
314  }
315 
316  OGRFeatureH oFeat;
317  //read in the first feature only
318  if (( oFeat = OGR_L_GetNextFeature( ogrLayer ) ) )
319  {
320  fields = readOgrFields( oFeat, encoding );
321  OGR_F_Destroy( oFeat );
322  }
323 
324  OGR_DS_Destroy( hDS );
325  VSIUnlink( TO8( randomFileName ) );
326  return fields;
327 }
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:199
#define TO8(x)
Definition: qgsogrutils.cpp:28
static QVariant getOgrFeatureAttribute(OGRFeatureH ogrFet, const QgsFields &fields, int attIndex, QTextCodec *encoding, bool *ok=0)
Retrieves an attribute value from an OGR feature.
static bool readOgrFeatureAttributes(OGRFeatureH ogrFet, const QgsFields &fields, QgsFeature &feature, QTextCodec *encoding)
Reads all attributes from an OGR feature into a QgsFeature.
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:33
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: qgsfield.h:252
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:222
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
static QgsFields readOgrFields(OGRFeatureH ogrFet, QTextCodec *encoding)
Reads an OGR feature and returns a corresponding fields collection.
Definition: qgsogrutils.cpp:65
#define OGR_F_IsFieldSetAndNotNull
Definition: qgsogrutils.cpp:37
static endian_t endian()
Returns whether this machine uses big or little endian.
int count() const
Return number of items.
Definition: qgsfield.cpp:402
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:422
void setGeometry(const QgsGeometry &geom)
Set this feature&#39;s geometry from another QgsGeometry object.
Definition: qgsfeature.cpp:124
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields, QTextCodec *encoding)
Attempts to parse a string representing a collection of features using OGR.
QString fromUtf8(const char *str, int size)
void setFeatureId(QgsFeatureId id)
Sets the feature ID for this feature.
Definition: qgsfeature.cpp:101
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:213
static QgsFeature readOgrFeature(OGRFeatureH ogrFet, const QgsFields &fields, QTextCodec *encoding)
Reads an OGR feature and converts it to a QgsFeature.
Definition: qgsogrutils.cpp:40
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Append a field. The field must have unique name, otherwise it is rejected (returns false) ...
Definition: qgsfield.cpp:346
static QgsGeometry * ogrGeometryToQgsGeometry(OGRGeometryH geom)
Converts an OGR geometry representation to a QgsGeometry object.
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:44
Q_DECL_DEPRECATED 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:173
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:204
char * data()
int size() const
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.
Definition: qgsfield.cpp:97
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toUnicode(const QByteArray &a) const
QUuid createUuid()