Skip to content

Commit 3f62cd4

Browse files
committedMar 1, 2016
New class QgsOgrUtils w/helper functions for working with OGR features
Also includes handy function for converting a string to a QgsFeatureList or QgsFields by using OGR to parse the string. This allows eg conversion of GeoJSON to QgsFeatures.
1 parent 3f80649 commit 3f62cd4

14 files changed

+1046
-77
lines changed
 

‎src/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ SET(QGIS_CORE_SRCS
154154
qgsobjectcustomproperties.cpp
155155
qgsofflineediting.cpp
156156
qgsogcutils.cpp
157+
qgsogrutils.cpp
157158
qgsowsconnection.cpp
158159
qgspaintenginehack.cpp
159160
qgspallabeling.cpp

‎src/core/qgsogrutils.cpp

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
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+
QgsFeature QgsOgrUtils::readOgrFeature( OGRFeatureH ogrFet, const QgsFields& fields, QTextCodec* encoding )
34+
{
35+
QgsFeature feature;
36+
if ( !ogrFet )
37+
{
38+
feature.setValid( false );
39+
return feature;
40+
}
41+
42+
feature.setFeatureId( OGR_F_GetFID( ogrFet ) );
43+
feature.setValid( true );
44+
45+
if ( !readOgrFeatureGeometry( ogrFet, feature ) )
46+
{
47+
feature.setValid( false );
48+
}
49+
50+
if ( !readOgrFeatureAttributes( ogrFet, fields, feature, encoding ) )
51+
{
52+
feature.setValid( false );
53+
}
54+
55+
return feature;
56+
}
57+
58+
QgsFields QgsOgrUtils::readOgrFields( OGRFeatureH ogrFet, QTextCodec* encoding )
59+
{
60+
QgsFields fields;
61+
62+
if ( !ogrFet )
63+
return fields;
64+
65+
int fieldCount = OGR_F_GetFieldCount( ogrFet );
66+
for ( int i = 0; i < fieldCount; ++i )
67+
{
68+
OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, i );
69+
if ( !fldDef )
70+
{
71+
fields.append( QgsField() );
72+
continue;
73+
}
74+
75+
QString name = encoding->toUnicode( OGR_Fld_GetNameRef( fldDef ) );
76+
QVariant::Type varType;
77+
switch ( OGR_Fld_GetType( fldDef ) )
78+
{
79+
case OFTInteger:
80+
varType = QVariant::Int;
81+
break;
82+
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000
83+
case OFTInteger64:
84+
varType = QVariant::LongLong;
85+
break;
86+
#endif
87+
case OFTReal:
88+
varType = QVariant::Double;
89+
break;
90+
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1400
91+
case OFTDate:
92+
varType = QVariant::Date;
93+
break;
94+
case OFTTime:
95+
varType = QVariant::Time;
96+
break;
97+
case OFTDateTime:
98+
varType = QVariant::DateTime;
99+
break;
100+
case OFTString:
101+
#endif
102+
default:
103+
varType = QVariant::String; // other unsupported, leave it as a string
104+
}
105+
fields.append( QgsField( name, varType ) );
106+
}
107+
return fields;
108+
}
109+
110+
QVariant QgsOgrUtils::getOgrFeatureAttribute( OGRFeatureH ogrFet, const QgsFields& fields, int attIndex, QTextCodec* encoding , bool* ok )
111+
{
112+
if ( !ogrFet || attIndex < 0 || attIndex >= fields.count() )
113+
{
114+
if ( ok )
115+
*ok = false;
116+
return QVariant();
117+
}
118+
119+
OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, attIndex );
120+
121+
if ( ! fldDef )
122+
{
123+
if ( ok )
124+
*ok = false;
125+
126+
QgsDebugMsg( "ogrFet->GetFieldDefnRef(attindex) returns NULL" );
127+
return QVariant();
128+
}
129+
130+
QVariant value;
131+
132+
if ( ok )
133+
*ok = true;
134+
135+
if ( OGR_F_IsFieldSet( ogrFet, attIndex ) )
136+
{
137+
switch ( fields.at( attIndex ).type() )
138+
{
139+
case QVariant::String:
140+
value = QVariant( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
141+
break;
142+
case QVariant::Int:
143+
value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) );
144+
break;
145+
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000
146+
case QVariant::LongLong:
147+
value = QVariant( OGR_F_GetFieldAsInteger64( ogrFet, attIndex ) );
148+
break;
149+
#endif
150+
case QVariant::Double:
151+
value = QVariant( OGR_F_GetFieldAsDouble( ogrFet, attIndex ) );
152+
break;
153+
case QVariant::Date:
154+
case QVariant::DateTime:
155+
case QVariant::Time:
156+
{
157+
int year, month, day, hour, minute, second, tzf;
158+
159+
OGR_F_GetFieldAsDateTime( ogrFet, attIndex, &year, &month, &day, &hour, &minute, &second, &tzf );
160+
if ( fields.at( attIndex ).type() == QVariant::Date )
161+
value = QDate( year, month, day );
162+
else if ( fields.at( attIndex ).type() == QVariant::Time )
163+
value = QTime( hour, minute, second );
164+
else
165+
value = QDateTime( QDate( year, month, day ), QTime( hour, minute, second ) );
166+
}
167+
break;
168+
default:
169+
Q_ASSERT_X( false, "QgsOgrUtils::getOgrFeatureAttribute", "unsupported field type" );
170+
if ( ok )
171+
*ok = false;
172+
}
173+
}
174+
else
175+
{
176+
value = QVariant( QString::null );
177+
}
178+
179+
return value;
180+
}
181+
182+
bool QgsOgrUtils::readOgrFeatureAttributes( OGRFeatureH ogrFet, const QgsFields& fields, QgsFeature& feature, QTextCodec* encoding )
183+
{
184+
// read all attributes
185+
feature.initAttributes( fields.count() );
186+
feature.setFields( fields );
187+
188+
if ( !ogrFet )
189+
return false;
190+
191+
bool ok = false;
192+
for ( int idx = 0; idx < fields.count(); ++idx )
193+
{
194+
QVariant value = getOgrFeatureAttribute( ogrFet, fields, idx, encoding, &ok );
195+
if ( ok )
196+
{
197+
feature.setAttribute( idx, value );
198+
}
199+
}
200+
return true;
201+
}
202+
203+
bool QgsOgrUtils::readOgrFeatureGeometry( OGRFeatureH ogrFet, QgsFeature& feature )
204+
{
205+
if ( !ogrFet )
206+
return false;
207+
208+
OGRGeometryH geom = OGR_F_GetGeometryRef( ogrFet );
209+
if ( !geom )
210+
feature.setGeometry( nullptr );
211+
else
212+
feature.setGeometry( ogrGeometryToQgsGeometry( geom ) );
213+
214+
return true;
215+
}
216+
217+
QgsGeometry* QgsOgrUtils::ogrGeometryToQgsGeometry( OGRGeometryH geom )
218+
{
219+
if ( !geom )
220+
return nullptr;
221+
222+
// get the wkb representation
223+
int memorySize = OGR_G_WkbSize( geom );
224+
unsigned char *wkb = new unsigned char[memorySize];
225+
OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb );
226+
227+
QgsGeometry *g = new QgsGeometry();
228+
g->fromWkb( wkb, memorySize );
229+
return g;
230+
}
231+
232+
QgsFeatureList QgsOgrUtils::stringToFeatureList( const QString& string, const QgsFields& fields, QTextCodec* encoding )
233+
{
234+
QgsFeatureList features;
235+
if ( string.isEmpty() )
236+
return features;
237+
238+
QString randomFileName = QString( "/vsimem/%1" ).arg( QUuid::createUuid() );
239+
240+
// create memory file system object from string buffer
241+
QByteArray ba = string.toUtf8();
242+
VSIFCloseL( VSIFileFromMemBuffer( TO8( randomFileName ), reinterpret_cast< GByte* >( ba.data() ),
243+
static_cast< vsi_l_offset >( ba.size() ), FALSE ) );
244+
245+
OGRDataSourceH hDS = OGROpen( TO8( randomFileName ), false, nullptr );
246+
if ( !hDS )
247+
{
248+
VSIUnlink( TO8( randomFileName ) );
249+
return features;
250+
}
251+
252+
OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS, 0 );
253+
if ( !ogrLayer )
254+
{
255+
OGR_DS_Destroy( hDS );
256+
VSIUnlink( TO8( randomFileName ) );
257+
return features;
258+
}
259+
260+
OGRFeatureH oFeat;
261+
while (( oFeat = OGR_L_GetNextFeature( ogrLayer ) ) )
262+
{
263+
QgsFeature feat = readOgrFeature( oFeat, fields, encoding );
264+
if ( feat.isValid() )
265+
features << feat;
266+
267+
OGR_F_Destroy( oFeat );
268+
}
269+
270+
OGR_DS_Destroy( hDS );
271+
VSIUnlink( "/vsimem/clipboard.dat" );
272+
273+
return features;
274+
}
275+
276+
QgsFields QgsOgrUtils::stringToFields( const QString& string, QTextCodec* encoding )
277+
{
278+
QgsFields fields;
279+
if ( string.isEmpty() )
280+
return fields;
281+
282+
QString randomFileName = QString( "/vsimem/%1" ).arg( QUuid::createUuid() );
283+
284+
// create memory file system object from buffer
285+
QByteArray ba = string.toUtf8();
286+
VSIFCloseL( VSIFileFromMemBuffer( TO8( randomFileName ), reinterpret_cast< GByte* >( ba.data() ),
287+
static_cast< vsi_l_offset >( ba.size() ), FALSE ) );
288+
289+
OGRDataSourceH hDS = OGROpen( TO8( randomFileName ), false, nullptr );
290+
if ( !hDS )
291+
{
292+
VSIUnlink( TO8( randomFileName ) );
293+
return fields;
294+
}
295+
296+
OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS, 0 );
297+
if ( !ogrLayer )
298+
{
299+
OGR_DS_Destroy( hDS );
300+
VSIUnlink( TO8( randomFileName ) );
301+
return fields;
302+
}
303+
304+
OGRFeatureH oFeat;
305+
//read in the first feature only
306+
if (( oFeat = OGR_L_GetNextFeature( ogrLayer ) ) )
307+
{
308+
fields = readOgrFields( oFeat, encoding );
309+
OGR_F_Destroy( oFeat );
310+
}
311+
312+
OGR_DS_Destroy( hDS );
313+
VSIUnlink( TO8( randomFileName ) );
314+
return fields;
315+
}

0 commit comments

Comments
 (0)
Please sign in to comment.