From 3f62cd46e792c224b678d1736e65e5c7f5398067 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 29 Feb 2016 15:39:49 +1100 Subject: [PATCH] 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. --- src/core/CMakeLists.txt | 1 + src/core/qgsogrutils.cpp | 315 ++++++++++++++ src/core/qgsogrutils.cpp.bom | 203 +++++++++ src/core/qgsogrutils.h | 108 +++++ .../ogr/qgsogrexpressioncompiler.cpp | 2 +- src/providers/ogr/qgsogrfeatureiterator.cpp | 75 +--- src/providers/ogr/qgsogrprovider.cpp | 14 +- src/providers/ogr/qgsogrprovider.h | 2 +- tests/src/core/CMakeLists.txt | 1 + tests/src/core/testqgsogrutils.cpp | 389 ++++++++++++++++++ tests/testdata/ogr_types.dat | Bin 0 -> 355 bytes tests/testdata/ogr_types.id | Bin 0 -> 4 bytes tests/testdata/ogr_types.map | Bin 0 -> 3584 bytes tests/testdata/ogr_types.tab | 13 + 14 files changed, 1046 insertions(+), 77 deletions(-) create mode 100644 src/core/qgsogrutils.cpp create mode 100644 src/core/qgsogrutils.cpp.bom create mode 100644 src/core/qgsogrutils.h create mode 100644 tests/src/core/testqgsogrutils.cpp create mode 100644 tests/testdata/ogr_types.dat create mode 100644 tests/testdata/ogr_types.id create mode 100644 tests/testdata/ogr_types.map create mode 100644 tests/testdata/ogr_types.tab diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e9b41942295..95227e6d853 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -154,6 +154,7 @@ SET(QGIS_CORE_SRCS qgsobjectcustomproperties.cpp qgsofflineediting.cpp qgsogcutils.cpp + qgsogrutils.cpp qgsowsconnection.cpp qgspaintenginehack.cpp qgspallabeling.cpp diff --git a/src/core/qgsogrutils.cpp b/src/core/qgsogrutils.cpp new file mode 100644 index 00000000000..164981f8222 --- /dev/null +++ b/src/core/qgsogrutils.cpp @@ -0,0 +1,315 @@ +/*************************************************************************** + qgsogrutils.cpp + --------------- + begin : February 2016 + copyright : (C) 2016 Nyall Dawson + email : nyall dot dawson at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsogrutils.h" +#include "qgsapplication.h" +#include "qgslogger.h" +#include "qgsgeometry.h" +#include +#include + +#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800 +#define TO8(x) (x).toUtf8().constData() +#define TO8F(x) (x).toUtf8().constData() +#define FROM8(x) QString::fromUtf8(x) +#else +#define TO8(x) (x).toLocal8Bit().constData() +#define TO8F(x) QFile::encodeName( x ).constData() +#define FROM8(x) QString::fromLocal8Bit(x) +#endif + +QgsFeature QgsOgrUtils::readOgrFeature( OGRFeatureH ogrFet, const QgsFields& fields, QTextCodec* encoding ) +{ + QgsFeature feature; + if ( !ogrFet ) + { + feature.setValid( false ); + return feature; + } + + feature.setFeatureId( OGR_F_GetFID( ogrFet ) ); + feature.setValid( true ); + + if ( !readOgrFeatureGeometry( ogrFet, feature ) ) + { + feature.setValid( false ); + } + + if ( !readOgrFeatureAttributes( ogrFet, fields, feature, encoding ) ) + { + feature.setValid( false ); + } + + return feature; +} + +QgsFields QgsOgrUtils::readOgrFields( OGRFeatureH ogrFet, QTextCodec* encoding ) +{ + QgsFields fields; + + if ( !ogrFet ) + return fields; + + int fieldCount = OGR_F_GetFieldCount( ogrFet ); + for ( int i = 0; i < fieldCount; ++i ) + { + OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, i ); + if ( !fldDef ) + { + fields.append( QgsField() ); + continue; + } + + QString name = encoding->toUnicode( OGR_Fld_GetNameRef( fldDef ) ); + QVariant::Type varType; + switch ( OGR_Fld_GetType( fldDef ) ) + { + case OFTInteger: + varType = QVariant::Int; + break; +#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000 + case OFTInteger64: + varType = QVariant::LongLong; + break; +#endif + case OFTReal: + varType = QVariant::Double; + break; +#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1400 + case OFTDate: + varType = QVariant::Date; + break; + case OFTTime: + varType = QVariant::Time; + break; + case OFTDateTime: + varType = QVariant::DateTime; + break; + case OFTString: +#endif + default: + varType = QVariant::String; // other unsupported, leave it as a string + } + fields.append( QgsField( name, varType ) ); + } + return fields; +} + +QVariant QgsOgrUtils::getOgrFeatureAttribute( OGRFeatureH ogrFet, const QgsFields& fields, int attIndex, QTextCodec* encoding , bool* ok ) +{ + if ( !ogrFet || attIndex < 0 || attIndex >= fields.count() ) + { + if ( ok ) + *ok = false; + return QVariant(); + } + + OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, attIndex ); + + if ( ! fldDef ) + { + if ( ok ) + *ok = false; + + QgsDebugMsg( "ogrFet->GetFieldDefnRef(attindex) returns NULL" ); + return QVariant(); + } + + QVariant value; + + if ( ok ) + *ok = true; + + if ( OGR_F_IsFieldSet( ogrFet, attIndex ) ) + { + switch ( fields.at( attIndex ).type() ) + { + case QVariant::String: + value = QVariant( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) ); + break; + case QVariant::Int: + value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) ); + break; +#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000 + case QVariant::LongLong: + value = QVariant( OGR_F_GetFieldAsInteger64( ogrFet, attIndex ) ); + break; +#endif + case QVariant::Double: + value = QVariant( OGR_F_GetFieldAsDouble( ogrFet, attIndex ) ); + break; + case QVariant::Date: + case QVariant::DateTime: + case QVariant::Time: + { + int year, month, day, hour, minute, second, tzf; + + OGR_F_GetFieldAsDateTime( ogrFet, attIndex, &year, &month, &day, &hour, &minute, &second, &tzf ); + if ( fields.at( attIndex ).type() == QVariant::Date ) + value = QDate( year, month, day ); + else if ( fields.at( attIndex ).type() == QVariant::Time ) + value = QTime( hour, minute, second ); + else + value = QDateTime( QDate( year, month, day ), QTime( hour, minute, second ) ); + } + break; + default: + Q_ASSERT_X( false, "QgsOgrUtils::getOgrFeatureAttribute", "unsupported field type" ); + if ( ok ) + *ok = false; + } + } + else + { + value = QVariant( QString::null ); + } + + return value; +} + +bool QgsOgrUtils::readOgrFeatureAttributes( OGRFeatureH ogrFet, const QgsFields& fields, QgsFeature& feature, QTextCodec* encoding ) +{ + // read all attributes + feature.initAttributes( fields.count() ); + feature.setFields( fields ); + + if ( !ogrFet ) + return false; + + bool ok = false; + for ( int idx = 0; idx < fields.count(); ++idx ) + { + QVariant value = getOgrFeatureAttribute( ogrFet, fields, idx, encoding, &ok ); + if ( ok ) + { + feature.setAttribute( idx, value ); + } + } + return true; +} + +bool QgsOgrUtils::readOgrFeatureGeometry( OGRFeatureH ogrFet, QgsFeature& feature ) +{ + if ( !ogrFet ) + return false; + + OGRGeometryH geom = OGR_F_GetGeometryRef( ogrFet ); + if ( !geom ) + feature.setGeometry( nullptr ); + else + feature.setGeometry( ogrGeometryToQgsGeometry( geom ) ); + + return true; +} + +QgsGeometry* QgsOgrUtils::ogrGeometryToQgsGeometry( OGRGeometryH geom ) +{ + if ( !geom ) + return nullptr; + + // get the wkb representation + int memorySize = OGR_G_WkbSize( geom ); + unsigned char *wkb = new unsigned char[memorySize]; + OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb ); + + QgsGeometry *g = new QgsGeometry(); + g->fromWkb( wkb, memorySize ); + return g; +} + +QgsFeatureList QgsOgrUtils::stringToFeatureList( const QString& string, const QgsFields& fields, QTextCodec* encoding ) +{ + QgsFeatureList features; + if ( string.isEmpty() ) + return features; + + QString randomFileName = QString( "/vsimem/%1" ).arg( QUuid::createUuid() ); + + // create memory file system object from string buffer + QByteArray ba = string.toUtf8(); + VSIFCloseL( VSIFileFromMemBuffer( TO8( randomFileName ), reinterpret_cast< GByte* >( ba.data() ), + static_cast< vsi_l_offset >( ba.size() ), FALSE ) ); + + OGRDataSourceH hDS = OGROpen( TO8( randomFileName ), false, nullptr ); + if ( !hDS ) + { + VSIUnlink( TO8( randomFileName ) ); + return features; + } + + OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS, 0 ); + if ( !ogrLayer ) + { + OGR_DS_Destroy( hDS ); + VSIUnlink( TO8( randomFileName ) ); + return features; + } + + OGRFeatureH oFeat; + while (( oFeat = OGR_L_GetNextFeature( ogrLayer ) ) ) + { + QgsFeature feat = readOgrFeature( oFeat, fields, encoding ); + if ( feat.isValid() ) + features << feat; + + OGR_F_Destroy( oFeat ); + } + + OGR_DS_Destroy( hDS ); + VSIUnlink( "/vsimem/clipboard.dat" ); + + return features; +} + +QgsFields QgsOgrUtils::stringToFields( const QString& string, QTextCodec* encoding ) +{ + QgsFields fields; + if ( string.isEmpty() ) + return fields; + + QString randomFileName = QString( "/vsimem/%1" ).arg( QUuid::createUuid() ); + + // create memory file system object from buffer + QByteArray ba = string.toUtf8(); + VSIFCloseL( VSIFileFromMemBuffer( TO8( randomFileName ), reinterpret_cast< GByte* >( ba.data() ), + static_cast< vsi_l_offset >( ba.size() ), FALSE ) ); + + OGRDataSourceH hDS = OGROpen( TO8( randomFileName ), false, nullptr ); + if ( !hDS ) + { + VSIUnlink( TO8( randomFileName ) ); + return fields; + } + + OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS, 0 ); + if ( !ogrLayer ) + { + OGR_DS_Destroy( hDS ); + VSIUnlink( TO8( randomFileName ) ); + return fields; + } + + OGRFeatureH oFeat; + //read in the first feature only + if (( oFeat = OGR_L_GetNextFeature( ogrLayer ) ) ) + { + fields = readOgrFields( oFeat, encoding ); + OGR_F_Destroy( oFeat ); + } + + OGR_DS_Destroy( hDS ); + VSIUnlink( TO8( randomFileName ) ); + return fields; +} diff --git a/src/core/qgsogrutils.cpp.bom b/src/core/qgsogrutils.cpp.bom new file mode 100644 index 00000000000..2e4ba969c07 --- /dev/null +++ b/src/core/qgsogrutils.cpp.bom @@ -0,0 +1,203 @@ +/*************************************************************************** + qgsogrutils.cpp + --------------- + begin : February 2016 + copyright : (C) 2016 Nyall Dawson + email : nyall dot dawson at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsogrutils.h" +#include "qgsapplication.h" +#include "qgslogger.h" +#include "qgsgeometry.h" +#include + +QgsFeature QgsOgrUtils::readOgrFeature(OGRFeatureH ogrFet, const QgsFields& fields, QTextCodec* encoding) +{ + QgsFeature feature; + feature.setFeatureId( OGR_F_GetFID( ogrFet ) ); + feature.setValid( true ); + + if ( !readOgrFeatureGeometry( ogrFet, feature ) ) + { + feature.setValid( false ); + } + + if ( !readOgrFeatureAttributes( ogrFet, fields, feature, encoding ) ) + { + feature.setValid( false ); + } + + return feature; +} + +QgsFields QgsOgrUtils::readOgrFields( OGRFeatureH ogrFet, QTextCodec* encoding ) +{ + QgsFields fields; + + if ( !ogrFet ) + return fields; + + int fieldCount = OGR_F_GetFieldCount( fet ); + for ( int i = 0; i < fieldCount; ++i ) + { + OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, i ); + if ( !fldDef ) + { + fields.append( QgsField() ); + continue; + } + + QString name = encoding->toUnicode( OGR_Fld_GetNameRef( fldDef ) ); + QVariant::Type varType; + switch ( OGR_Fld_GetType( fldDef ) ) + { + case OFTInteger: + varType = QVariant::Int; + break; + #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000 + case OFTInteger64: + varType = QVariant::LongLong; + break; + #endif + case OFTReal: + varType = QVariant::Double; + break; + #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1400 + case OFTDate: + varType = QVariant::Date; + break; + case OFTTime: + varType = QVariant::Time; + break; + case OFTDateTime: + varType = QVariant::DateTime; + break; + case OFTString: + #endif + default: + varType = QVariant::String; // other unsupported, leave it as a string + } + fields.append( QgsField( name, varType ) ); + } + return fields; +} + +QVariant QgsOgrUtils::getOgrFeatureAttribute(OGRFeatureH ogrFet, const QgsFields& fields, int attIndex, QTextCodec* encoding , bool* ok) +{ + OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, attIndex ); + + if ( ! fldDef ) + { + if ( ok ) + *ok = false; + + QgsDebugMsg( "ogrFet->GetFieldDefnRef(attindex) returns NULL" ); + return QVariant(); + } + + QVariant value; + + if ( ok ) + *ok = true; + + if ( OGR_F_IsFieldSet( ogrFet, attIndex ) ) + { + switch ( fields.at( attIndex ).type() ) + { + case QVariant::String: + value = QVariant( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) ); + break; + case QVariant::Int: + value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) ); + break; +#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000 + case QVariant::LongLong: + value = QVariant( OGR_F_GetFieldAsInteger64( ogrFet, attIndex ) ); + break; +#endif + case QVariant::Double: + value = QVariant( OGR_F_GetFieldAsDouble( ogrFet, attIndex ) ); + break; + case QVariant::Date: + case QVariant::DateTime: + case QVariant::Time: + { + int year, month, day, hour, minute, second, tzf; + + OGR_F_GetFieldAsDateTime( ogrFet, attIndex, &year, &month, &day, &hour, &minute, &second, &tzf ); + if ( fields.at( attIndex ).type() == QVariant::Date ) + value = QDate( year, month, day ); + else if ( fields.at( attIndex ).type() == QVariant::Time ) + value = QTime( hour, minute, second ); + else + value = QDateTime( QDate( year, month, day ), QTime( hour, minute, second ) ); + } + break; + default: + Q_ASSERT_X( false, "QgsOgrUtils::getOgrFeatureAttribute", "unsupported field type" ); + if ( ok ) + *ok = false; + } + } + else + { + value = QVariant( QString::null ); + } + + return value; +} + +bool QgsOgrUtils::readOgrFeatureAttributes(OGRFeatureH ogrFet, const QgsFields& fields, QgsFeature& feature, QTextCodec* encoding ) +{ + // read all attributes + feature.initAttributes( fields.count() ); + feature.setFields( fields ); + + bool ok = false; + for ( int idx = 0; idx < fields.count(); ++idx ) + { + QVariant value = getOgrFeatureAttribute( ogrFet, fields, idx, encoding, &ok ); + if ( ok ) + { + feature.setAttribute( idx, value ); + } + } + return true; +} + +bool QgsOgrUtils::readOgrFeatureGeometry( OGRFeatureH ogrFet, QgsFeature& feature ) +{ + if ( !ogrFet ) + return false; + + OGRGeometryH geom = OGR_F_GetGeometryRef( ogrFet ); + if ( !geom ) + feature.setGeometry( nullptr ); + else + feature.setGeometry( ogrGeometryToQgsGeometry( geom ) ); + + return true; +} + +QgsGeometry* QgsOgrUtils::ogrGeometryToQgsGeometry( OGRGeometryH geom ) +{ + if ( !geom ) + return nullptr; + + // get the wkb representation + int memorySize = OGR_G_WkbSize( geom ); + unsigned char *wkb = new unsigned char[memorySize]; + OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb ); + + QgsGeometry *g = new QgsGeometry(); + g->fromWkb( wkb, memorySize ); + return g; +} diff --git a/src/core/qgsogrutils.h b/src/core/qgsogrutils.h new file mode 100644 index 00000000000..4c4e48ca85c --- /dev/null +++ b/src/core/qgsogrutils.h @@ -0,0 +1,108 @@ +/*************************************************************************** + qgsogrutils.h + ------------- + begin : February 2016 + copyright : (C) 2016 Nyall Dawson + email : nyall dot dawson at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSOGRUTILS_H +#define QGSOGRUTILS_H + +#include "qgsfeature.h" + +#include +#include "cpl_conv.h" +#include "cpl_string.h" + +/** \ingroup core + * \class QgsOgrUtils + * \brief Utilities for working with OGR features and layers + * + * Contains helper utilities for assisting work with both OGR features and layers. + * \note Added in version 2.16 + * \note not available in Python bindings + */ +class CORE_EXPORT QgsOgrUtils +{ + public: + + /** Reads an OGR feature and converts it to a QgsFeature. + * @param ogrFet OGR feature handle + * @param fields fields collection corresponding to feature + * @param encoding text encoding + * @return valid feature if read was successful + */ + static QgsFeature readOgrFeature( OGRFeatureH ogrFet, const QgsFields &fields, QTextCodec* encoding ); + + /** Reads an OGR feature and returns a corresponding fields collection. + * @param ogrFet OGR feature handle + * @param encoding text encoding + * @returns fields collection if read was successful + */ + static QgsFields readOgrFields( OGRFeatureH ogrFet, QTextCodec* encoding ); + + /** Retrieves an attribute value from an OGR feature. + * @param ogrFet OGR feature handle + * @param fields fields collection corresponding to feature + * @param attIndex index of attribute to retreive + * @param encoding text encoding + * @param ok optional storage for success of retrieval + * @returns attribute converted to a QVariant object + * @see readOgrFeatureAttributes() + */ + static QVariant getOgrFeatureAttribute( OGRFeatureH ogrFet, const QgsFields &fields, int attIndex, QTextCodec* encoding, bool* ok = 0 ); + + /** Reads all attributes from an OGR feature into a QgsFeature. + * @param ogrFet OGR feature handle + * @param fields fields collection corresponding to feature + * @param feature QgsFeature to store attributes in + * @param encoding text encoding + * @returns true if attribute read was successful + * @see getOgrFeatureAttribute() + */ + static bool readOgrFeatureAttributes( OGRFeatureH ogrFet, const QgsFields &fields, QgsFeature& feature, QTextCodec* encoding ); + + /** Reads the geometry from an OGR feature into a QgsFeature. + * @param ogrFet OGR feature handle + * @param feature QgsFeature to store geometry in + * @returns true if geometry read was successful + * @see readOgrFeatureAttributes() + * @see ogrGeometryToQgsGeometry() + */ + static bool readOgrFeatureGeometry( OGRFeatureH ogrFet, QgsFeature& feature ); + + /** Converts an OGR geometry representation to a QgsGeometry object + * @param geom OGR geometry handle + * @returns new QgsGeometry object, if conversion was successful + * @see readOgrFeatureGeometry() + */ + static QgsGeometry* ogrGeometryToQgsGeometry( OGRGeometryH geom ); + + /** Attempts to parse a string representing a collection of features using OGR. For example, this method can be + * used to convert a GeoJSON encoded collection to a list of QgsFeatures. + * @param string string to parse + * @param fields fields collection to use for parsed features (@see stringToFields()) + * @param encoding text encoding + * @returns list of parsed features, or an empty list if no features could be parsed + * @see stringToFields() + */ + static QgsFeatureList stringToFeatureList( const QString& string, const QgsFields& fields, QTextCodec* encoding ); + + /** Attempts to retrieve the fields from a string representing a collection of features using OGR. + * @param string string to parse + * @param encoding text encoding + * @returns retrieved fields collection, or an empty list if no fields could be determined from the string + * @see stringToFeatureList() + */ + static QgsFields stringToFields( const QString& string, QTextCodec* encoding ); +}; + +#endif // QGSOGRUTILS_H diff --git a/src/providers/ogr/qgsogrexpressioncompiler.cpp b/src/providers/ogr/qgsogrexpressioncompiler.cpp index e729a24e22f..851b6ef3325 100644 --- a/src/providers/ogr/qgsogrexpressioncompiler.cpp +++ b/src/providers/ogr/qgsogrexpressioncompiler.cpp @@ -95,5 +95,5 @@ QString QgsOgrExpressionCompiler::quotedIdentifier( const QString& identifier ) QString QgsOgrExpressionCompiler::quotedValue( const QVariant& value, bool& ok ) { ok = true; - return QgsOgrUtils::quotedValue( value ); + return QgsOgrProviderUtils::quotedValue( value ); } diff --git a/src/providers/ogr/qgsogrfeatureiterator.cpp b/src/providers/ogr/qgsogrfeatureiterator.cpp index 4dcb06ae308..1417b04b3ef 100644 --- a/src/providers/ogr/qgsogrfeatureiterator.cpp +++ b/src/providers/ogr/qgsogrfeatureiterator.cpp @@ -18,6 +18,7 @@ #include "qgsogrgeometrysimplifier.h" #include "qgsogrexpressioncompiler.h" +#include "qgsogrutils.h" #include "qgsapplication.h" #include "qgsgeometry.h" #include "qgslogger.h" @@ -56,7 +57,7 @@ QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource* source, bool if ( !mSource->mSubsetString.isEmpty() ) { - ogrLayer = QgsOgrUtils::setSubsetString( ogrLayer, mConn->ds, mSource->mEncoding, mSource->mSubsetString ); + ogrLayer = QgsOgrProviderUtils::setSubsetString( ogrLayer, mConn->ds, mSource->mEncoding, mSource->mSubsetString ); mSubsetStringSet = true; } @@ -69,7 +70,7 @@ QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource* source, bool // filter if we choose to ignore them (fixes #11223) if (( mSource->mDriverName != "VRT" && mSource->mDriverName != "OGR_VRT" ) || mRequest.filterRect().isNull() ) { - QgsOgrUtils::setRelevantFields( ogrLayer, mSource->mFields.count(), mFetchGeometry, attrs ); + QgsOgrProviderUtils::setRelevantFields( ogrLayer, mSource->mFields.count(), mFetchGeometry, attrs ); } // spatial query to select features @@ -265,57 +266,10 @@ bool QgsOgrFeatureIterator::close() void QgsOgrFeatureIterator::getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex ) { - OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, attindex ); - - if ( ! fldDef ) - { - QgsDebugMsg( "ogrFet->GetFieldDefnRef(attindex) returns NULL" ); + bool ok = false; + QVariant value = QgsOgrUtils::getOgrFeatureAttribute( ogrFet, mSource->mFields, attindex, mSource->mEncoding, &ok ); + if ( !ok ) return; - } - - QVariant value; - - if ( OGR_F_IsFieldSet( ogrFet, attindex ) ) - { - switch ( mSource->mFields.at( attindex ).type() ) - { - case QVariant::String: - value = QVariant( mSource->mEncoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attindex ) ) ); - break; - case QVariant::Int: - value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attindex ) ); - break; -#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000 - case QVariant::LongLong: - value = QVariant( OGR_F_GetFieldAsInteger64( ogrFet, attindex ) ); - break; -#endif - case QVariant::Double: - value = QVariant( OGR_F_GetFieldAsDouble( ogrFet, attindex ) ); - break; - case QVariant::Date: - case QVariant::DateTime: - case QVariant::Time: - { - int year, month, day, hour, minute, second, tzf; - - OGR_F_GetFieldAsDateTime( ogrFet, attindex, &year, &month, &day, &hour, &minute, &second, &tzf ); - if ( mSource->mFields.at( attindex ).type() == QVariant::Date ) - value = QDate( year, month, day ); - else if ( mSource->mFields.at( attindex ).type() == QVariant::Time ) - value = QTime( hour, minute, second ); - else - value = QDateTime( QDate( year, month, day ), QTime( hour, minute, second ) ); - } - break; - default: - assert( 0 && "unsupported field type" ); - } - } - else - { - value = QVariant( QString::null ); - } f.setAttribute( attindex, value ); } @@ -338,22 +292,7 @@ bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature ) if ( mGeometrySimplifier ) mGeometrySimplifier->simplifyGeometry( geom ); - // get the wkb representation - int memorySize = OGR_G_WkbSize( geom ); - unsigned char *wkb = new unsigned char[memorySize]; - OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb ); - - QgsGeometry* geometry = feature.geometry(); - if ( !geometry ) - { - QgsGeometry *g = new QgsGeometry(); - g->fromWkb( wkb, memorySize ); - feature.setGeometry( g ); - } - else - { - geometry->fromWkb( wkb, memorySize ); - } + feature.setGeometry( QgsOgrUtils::ogrGeometryToQgsGeometry( geom ) ); } else feature.setGeometry( nullptr ); diff --git a/src/providers/ogr/qgsogrprovider.cpp b/src/providers/ogr/qgsogrprovider.cpp index ab907d7330c..d1deb7dc6b4 100644 --- a/src/providers/ogr/qgsogrprovider.cpp +++ b/src/providers/ogr/qgsogrprovider.cpp @@ -784,11 +784,11 @@ QString QgsOgrProvider::storageType() const void QgsOgrProvider::setRelevantFields( OGRLayerH ogrLayer, bool fetchGeometry, const QgsAttributeList &fetchAttributes ) { - QgsOgrUtils::setRelevantFields( ogrLayer, mAttributeFields.count(), fetchGeometry, fetchAttributes ); + QgsOgrProviderUtils::setRelevantFields( ogrLayer, mAttributeFields.count(), fetchGeometry, fetchAttributes ); } -void QgsOgrUtils::setRelevantFields( OGRLayerH ogrLayer, int fieldCount, bool fetchGeometry, const QgsAttributeList &fetchAttributes ) +void QgsOgrProviderUtils::setRelevantFields( OGRLayerH ogrLayer, int fieldCount, bool fetchGeometry, const QgsAttributeList &fetchAttributes ) { #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800 if ( OGR_L_TestCapability( ogrLayer, OLCIgnoreFields ) ) @@ -2535,7 +2535,7 @@ QVariant QgsOgrProvider::maximumValue( int index ) QByteArray QgsOgrProvider::quotedIdentifier( QByteArray field ) const { - return QgsOgrUtils::quotedIdentifier( field, ogrDriverName ); + return QgsOgrProviderUtils::quotedIdentifier( field, ogrDriverName ); } void QgsOgrProvider::forceReload() @@ -2543,7 +2543,7 @@ void QgsOgrProvider::forceReload() QgsOgrConnPool::instance()->invalidateConnections( filePath() ); } -QByteArray QgsOgrUtils::quotedIdentifier( QByteArray field, const QString& ogrDriverName ) +QByteArray QgsOgrProviderUtils::quotedIdentifier( QByteArray field, const QString& ogrDriverName ) { if ( ogrDriverName == "MySQL" ) { @@ -2560,7 +2560,7 @@ QByteArray QgsOgrUtils::quotedIdentifier( QByteArray field, const QString& ogrDr } } -QString QgsOgrUtils::quotedValue( const QVariant& value ) +QString QgsOgrProviderUtils::quotedValue( const QVariant& value ) { if ( value.isNull() ) return "NULL"; @@ -2698,10 +2698,10 @@ OGRwkbGeometryType QgsOgrProvider::ogrWkbSingleFlatten( OGRwkbGeometryType type OGRLayerH QgsOgrProvider::setSubsetString( OGRLayerH layer, OGRDataSourceH ds ) { - return QgsOgrUtils::setSubsetString( layer, ds, mEncoding, mSubsetString ); + return QgsOgrProviderUtils::setSubsetString( layer, ds, mEncoding, mSubsetString ); } -OGRLayerH QgsOgrUtils::setSubsetString( OGRLayerH layer, OGRDataSourceH ds, QTextCodec* encoding, const QString& subsetString ) +OGRLayerH QgsOgrProviderUtils::setSubsetString( OGRLayerH layer, OGRDataSourceH ds, QTextCodec* encoding, const QString& subsetString ) { QByteArray layerName = OGR_FD_GetName( OGR_L_GetLayerDefn( layer ) ); OGRSFDriverH ogrDriver = OGR_DS_GetDriver( ds ); diff --git a/src/providers/ogr/qgsogrprovider.h b/src/providers/ogr/qgsogrprovider.h index 101c85902a3..1904607ca78 100644 --- a/src/providers/ogr/qgsogrprovider.h +++ b/src/providers/ogr/qgsogrprovider.h @@ -359,7 +359,7 @@ class QgsOgrProvider : public QgsVectorDataProvider }; -class QgsOgrUtils +class QgsOgrProviderUtils { public: static void setRelevantFields( OGRLayerH ogrLayer, int fieldCount, bool fetchGeometry, const QgsAttributeList &fetchAttributes ); diff --git a/tests/src/core/CMakeLists.txt b/tests/src/core/CMakeLists.txt index 9c69357363c..724a54f3f91 100644 --- a/tests/src/core/CMakeLists.txt +++ b/tests/src/core/CMakeLists.txt @@ -151,6 +151,7 @@ ADD_QGIS_TEST(maptopixeltest testqgsmaptopixel.cpp) ADD_QGIS_TEST(markerlinessymboltest testqgsmarkerlinesymbol.cpp) ADD_QGIS_TEST(networkcontentfetcher testqgsnetworkcontentfetcher.cpp ) ADD_QGIS_TEST(ogcutilstest testqgsogcutils.cpp) +ADD_QGIS_TEST(ogrutilstest testqgsogrutils.cpp) ADD_QGIS_TEST(painteffectregistrytest testqgspainteffectregistry.cpp) ADD_QGIS_TEST(painteffecttest testqgspainteffect.cpp) ADD_QGIS_TEST(pallabelingtest testqgspallabeling.cpp) diff --git a/tests/src/core/testqgsogrutils.cpp b/tests/src/core/testqgsogrutils.cpp new file mode 100644 index 00000000000..b66a78c4292 --- /dev/null +++ b/tests/src/core/testqgsogrutils.cpp @@ -0,0 +1,389 @@ +/*************************************************************************** + testqgsogrutils.cpp + ------------------- + Date : February 2016 + Copyright : (C) 2016 Nyall Dawson + Email : nyall dot dawson at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include +#include "cpl_conv.h" +#include "cpl_string.h" + +#include "qgsgeometry.h" +#include "qgsogrutils.h" +#include "qgsapplication.h" +#include "qgspointv2.h" + +#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800 +#define TO8(x) (x).toUtf8().constData() +#define TO8F(x) (x).toUtf8().constData() +#define FROM8(x) QString::fromUtf8(x) +#else +#define TO8(x) (x).toLocal8Bit().constData() +#define TO8F(x) QFile::encodeName( x ).constData() +#define FROM8(x) QString::fromLocal8Bit(x) +#endif + +class TestQgsOgrUtils: public QObject +{ + Q_OBJECT + + private slots: + void initTestCase();// will be called before the first testfunction is executed. + void cleanupTestCase();// will be called after the last testfunction was executed. + void init();// will be called before each testfunction is executed. + void cleanup();// will be called after every testfunction. + void ogrGeometryToQgsGeometry(); + void readOgrFeatureGeometry(); + void getOgrFeatureAttribute(); + void readOgrFeatureAttributes(); + void readOgrFeature(); + void readOgrFields(); + void stringToFeatureList(); + void stringToFields(); + + private: + + QString mTestDataDir; + QString mTestFile; +}; + +void TestQgsOgrUtils::initTestCase() +{ + QString myDataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt + mTestDataDir = myDataDir + '/'; + + mTestFile = mTestDataDir + "ogr_types.tab"; + + QgsApplication::init(); + QgsApplication::initQgis(); + QgsApplication::registerOgrDrivers(); +} + +void TestQgsOgrUtils::cleanupTestCase() +{ + QgsApplication::exitQgis(); +} + +void TestQgsOgrUtils::init() +{ + +} + +void TestQgsOgrUtils::cleanup() +{ + +} + +void TestQgsOgrUtils::ogrGeometryToQgsGeometry() +{ + // test with null geometry + QVERIFY( !QgsOgrUtils::ogrGeometryToQgsGeometry( nullptr ) ); + + // get a geometry from line file, test + OGRDataSourceH hDS = OGROpen( TO8F( mTestFile ), false, nullptr ); + QVERIFY( hDS ); + OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS, 0 ); + QVERIFY( ogrLayer ); + OGRFeatureH oFeat; + oFeat = OGR_L_GetNextFeature( ogrLayer ); + QVERIFY( oFeat ); + OGRGeometryH ogrGeom = OGR_F_GetGeometryRef( oFeat ); + QVERIFY( ogrGeom ); + + QScopedPointer< QgsGeometry > geom( QgsOgrUtils::ogrGeometryToQgsGeometry( ogrGeom ) ); + QVERIFY( geom.data() ); + QCOMPARE( geom->geometry()->wkbType(), QgsWKBTypes::LineString ); + QCOMPARE( geom->geometry()->nCoordinates(), 71 ); + + OGR_F_Destroy( oFeat ); + OGR_DS_Destroy( hDS ); +} + +void TestQgsOgrUtils::readOgrFeatureGeometry() +{ + QgsFeature f; + + // null geometry + QgsOgrUtils::readOgrFeatureGeometry( nullptr, f ); + QVERIFY( !f.constGeometry() ); + + //real geometry + // get a geometry from line file, test + OGRDataSourceH hDS = OGROpen( TO8F( mTestFile ), false, nullptr ); + QVERIFY( hDS ); + OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS, 0 ); + QVERIFY( ogrLayer ); + OGRFeatureH oFeat; + oFeat = OGR_L_GetNextFeature( ogrLayer ); + QVERIFY( oFeat ); + + QgsOgrUtils::readOgrFeatureGeometry( oFeat, f ); + QVERIFY( f.constGeometry() ); + QCOMPARE( f.constGeometry()->geometry()->wkbType(), QgsWKBTypes::LineString ); + QCOMPARE( f.constGeometry()->geometry()->nCoordinates(), 71 ); + + OGR_F_Destroy( oFeat ); + OGR_DS_Destroy( hDS ); +} + +void TestQgsOgrUtils::getOgrFeatureAttribute() +{ + QgsFeature f; + QgsFields fields; + + // null feature + bool ok = false; + QVariant val = QgsOgrUtils::getOgrFeatureAttribute( nullptr, fields, 0, QTextCodec::codecForName( "System" ), &ok ); + QVERIFY( !ok ); + QVERIFY( !val.isValid() ); + + //real feature + //get a feature from line file, test + OGRDataSourceH hDS = OGROpen( TO8F( mTestFile ), false, nullptr ); + QVERIFY( hDS ); + OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS, 0 ); + QVERIFY( ogrLayer ); + OGRFeatureH oFeat; + oFeat = OGR_L_GetNextFeature( ogrLayer ); + QVERIFY( oFeat ); + + fields.append( QgsField( "int_field", QVariant::Int ) ); + fields.append( QgsField( "dbl_field", QVariant::Double ) ); + fields.append( QgsField( "date_field", QVariant::Date ) ); + fields.append( QgsField( "time_field", QVariant::Time ) ); + fields.append( QgsField( "datetime_field", QVariant::DateTime ) ); + fields.append( QgsField( "string_field", QVariant::String ) ); + + // attribute index out of range + val = QgsOgrUtils::getOgrFeatureAttribute( oFeat, fields, -1, QTextCodec::codecForName( "System" ), &ok ); + QVERIFY( !ok ); + QVERIFY( !val.isValid() ); + val = QgsOgrUtils::getOgrFeatureAttribute( oFeat, fields, 100, QTextCodec::codecForName( "System" ), &ok ); + QVERIFY( !ok ); + QVERIFY( !val.isValid() ); + + val = QgsOgrUtils::getOgrFeatureAttribute( oFeat, fields, 0, QTextCodec::codecForName( "System" ), &ok ); + QVERIFY( ok ); + QVERIFY( val.isValid() ); + QCOMPARE( val, QVariant( 5 ) ); + + val = QgsOgrUtils::getOgrFeatureAttribute( oFeat, fields, 1, QTextCodec::codecForName( "System" ), &ok ); + QVERIFY( ok ); + QVERIFY( val.isValid() ); + QCOMPARE( val, QVariant( 8.9 ) ); + + val = QgsOgrUtils::getOgrFeatureAttribute( oFeat, fields, 2, QTextCodec::codecForName( "System" ), &ok ); + QVERIFY( ok ); + QVERIFY( val.isValid() ); + QCOMPARE( val, QVariant( QDate( 2005, 01, 05 ) ) ); + + val = QgsOgrUtils::getOgrFeatureAttribute( oFeat, fields, 3, QTextCodec::codecForName( "System" ), &ok ); + QVERIFY( ok ); + QVERIFY( val.isValid() ); + QCOMPARE( val, QVariant( QTime( 8, 11, 01 ) ) ); + + val = QgsOgrUtils::getOgrFeatureAttribute( oFeat, fields, 4, QTextCodec::codecForName( "System" ), &ok ); + QVERIFY( ok ); + QVERIFY( val.isValid() ); + QCOMPARE( val, QVariant( QDateTime( QDate( 2005, 3, 5 ), QTime( 6, 45, 0 ) ) ) ); + + val = QgsOgrUtils::getOgrFeatureAttribute( oFeat, fields, 5, QTextCodec::codecForName( "System" ), &ok ); + QVERIFY( ok ); + QVERIFY( val.isValid() ); + QCOMPARE( val, QVariant( "a string" ) ); + + OGR_F_Destroy( oFeat ); + OGR_DS_Destroy( hDS ); +} + +void TestQgsOgrUtils::readOgrFeatureAttributes() +{ + QgsFeature f; + QgsFields fields; + + // null feature + QVERIFY( !QgsOgrUtils::readOgrFeatureAttributes( nullptr, fields, f, QTextCodec::codecForName( "System" ) ) ); + + //real feature + //get a feature from line file, test + OGRDataSourceH hDS = OGROpen( TO8F( mTestFile ), false, nullptr ); + QVERIFY( hDS ); + OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS, 0 ); + QVERIFY( ogrLayer ); + OGRFeatureH oFeat; + oFeat = OGR_L_GetNextFeature( ogrLayer ); + QVERIFY( oFeat ); + + fields.append( QgsField( "int_field", QVariant::Int ) ); + fields.append( QgsField( "dbl_field", QVariant::Double ) ); + fields.append( QgsField( "date_field", QVariant::Date ) ); + fields.append( QgsField( "time_field", QVariant::Time ) ); + fields.append( QgsField( "datetime_field", QVariant::DateTime ) ); + fields.append( QgsField( "string_field", QVariant::String ) ); + + QVERIFY( QgsOgrUtils::readOgrFeatureAttributes( oFeat, fields, f, QTextCodec::codecForName( "System" ) ) ); + QCOMPARE( f.attribute( "int_field" ), QVariant( 5 ) ); + QCOMPARE( f.attribute( "dbl_field" ), QVariant( 8.9 ) ); + QCOMPARE( f.attribute( "date_field" ), QVariant( QDate( 2005, 01, 05 ) ) ); + QCOMPARE( f.attribute( "time_field" ), QVariant( QTime( 8, 11, 01 ) ) ); + QCOMPARE( f.attribute( "datetime_field" ), QVariant( QDateTime( QDate( 2005, 3, 5 ), QTime( 6, 45, 0 ) ) ) ); + QCOMPARE( f.attribute( "string_field" ), QVariant( "a string" ) ); + + OGR_F_Destroy( oFeat ); + OGR_DS_Destroy( hDS ); +} + +void TestQgsOgrUtils::readOgrFeature() +{ + QgsFields fields; + + // null feature + QgsFeature f = QgsOgrUtils::readOgrFeature( nullptr, fields, QTextCodec::codecForName( "System" ) ); + QVERIFY( !f.isValid() ); + + //real feature + //get a feature from line file, test + OGRDataSourceH hDS = OGROpen( TO8F( mTestFile ), false, nullptr ); + QVERIFY( hDS ); + OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS, 0 ); + QVERIFY( ogrLayer ); + OGRFeatureH oFeat; + oFeat = OGR_L_GetNextFeature( ogrLayer ); + QVERIFY( oFeat ); + + fields.append( QgsField( "int_field", QVariant::Int ) ); + fields.append( QgsField( "dbl_field", QVariant::Double ) ); + fields.append( QgsField( "date_field", QVariant::Date ) ); + fields.append( QgsField( "time_field", QVariant::Time ) ); + fields.append( QgsField( "datetime_field", QVariant::DateTime ) ); + fields.append( QgsField( "string_field", QVariant::String ) ); + + f = QgsOgrUtils::readOgrFeature( oFeat, fields, QTextCodec::codecForName( "System" ) ); + QVERIFY( f.isValid() ); + QCOMPARE( f.id(), 1LL ); + QCOMPARE( f.attribute( "int_field" ), QVariant( 5 ) ); + QCOMPARE( f.attribute( "dbl_field" ), QVariant( 8.9 ) ); + QCOMPARE( f.attribute( "date_field" ), QVariant( QDate( 2005, 01, 05 ) ) ); + QCOMPARE( f.attribute( "time_field" ), QVariant( QTime( 8, 11, 01 ) ) ); + QCOMPARE( f.attribute( "datetime_field" ), QVariant( QDateTime( QDate( 2005, 3, 5 ), QTime( 6, 45, 0 ) ) ) ); + QCOMPARE( f.attribute( "string_field" ), QVariant( "a string" ) ); + QVERIFY( f.constGeometry() ); + QCOMPARE( f.constGeometry()->geometry()->wkbType(), QgsWKBTypes::LineString ); + QCOMPARE( f.constGeometry()->geometry()->nCoordinates(), 71 ); + + OGR_F_Destroy( oFeat ); + OGR_DS_Destroy( hDS ); +} + +void TestQgsOgrUtils::readOgrFields() +{ + // null feature + QgsFields f = QgsOgrUtils::readOgrFields( nullptr, QTextCodec::codecForName( "System" ) ); + QCOMPARE( f.count(), 0 ); + + //real feature + //get a feature from line file, test + OGRDataSourceH hDS = OGROpen( TO8F( mTestFile ), false, nullptr ); + QVERIFY( hDS ); + OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS, 0 ); + QVERIFY( ogrLayer ); + OGRFeatureH oFeat; + oFeat = OGR_L_GetNextFeature( ogrLayer ); + QVERIFY( oFeat ); + + f = QgsOgrUtils::readOgrFields( oFeat, QTextCodec::codecForName( "System" ) ); + QCOMPARE( f.count(), 6 ); + QCOMPARE( f.at( 0 ).name(), QString( "int_field" ) ); + QCOMPARE( f.at( 0 ).type(), QVariant::Int ); + QCOMPARE( f.at( 1 ).name(), QString( "dbl_field" ) ); + QCOMPARE( f.at( 1 ).type(), QVariant::Double ); + QCOMPARE( f.at( 2 ).name(), QString( "date_field" ) ); + QCOMPARE( f.at( 2 ).type(), QVariant::Date ); + QCOMPARE( f.at( 3 ).name(), QString( "time_field" ) ); + QCOMPARE( f.at( 3 ).type(), QVariant::Time ); + QCOMPARE( f.at( 4 ).name(), QString( "datetime_field" ) ); + QCOMPARE( f.at( 4 ).type(), QVariant::DateTime ); + QCOMPARE( f.at( 5 ).name(), QString( "string_field" ) ); + QCOMPARE( f.at( 5 ).type(), QVariant::String ); + + OGR_F_Destroy( oFeat ); + OGR_DS_Destroy( hDS ); +} + +void TestQgsOgrUtils::stringToFeatureList() +{ + QgsFields fields; + fields.append( QgsField( "name", QVariant::String ) ); + + //empty string + QgsFeatureList features = QgsOgrUtils::stringToFeatureList( "", fields, QTextCodec::codecForName( "System" ) ); + QVERIFY( features.isEmpty() ); + // bad string + features = QgsOgrUtils::stringToFeatureList( "asdasdas", fields, QTextCodec::codecForName( "System" ) ); + QVERIFY( features.isEmpty() ); + + // geojson string with 1 feature + features = QgsOgrUtils::stringToFeatureList( "{\n\"type\": \"Feature\",\"geometry\": {\"type\": \"Point\",\"coordinates\": [125, 10]},\"properties\": {\"name\": \"Dinagat Islands\"}}", fields, QTextCodec::codecForName( "System" ) ); + QCOMPARE( features.length(), 1 ); + QVERIFY( features.at( 0 ).constGeometry() && !features.at( 0 ).constGeometry()->isEmpty() ); + QCOMPARE( features.at( 0 ).constGeometry()->geometry()->wkbType(), QgsWKBTypes::Point ); + const QgsPointV2* point = dynamic_cast< QgsPointV2* >( features.at( 0 ).constGeometry()->geometry() ); + QCOMPARE( point->x(), 125.0 ); + QCOMPARE( point->y(), 10.0 ); + QCOMPARE( features.at( 0 ).attribute( "name" ).toString(), QString( "Dinagat Islands" ) ); + + // geojson string with 2 features + features = QgsOgrUtils::stringToFeatureList( "{ \"type\": \"FeatureCollection\",\"features\":[{\n\"type\": \"Feature\",\"geometry\": {\"type\": \"Point\",\"coordinates\": [125, 10]},\"properties\": {\"name\": \"Dinagat Islands\"}}," + " {\n\"type\": \"Feature\",\"geometry\": {\"type\": \"Point\",\"coordinates\": [110, 20]},\"properties\": {\"name\": \"Henry Gale Island\"}}]}", fields, QTextCodec::codecForName( "System" ) ); + QCOMPARE( features.length(), 2 ); + QVERIFY( features.at( 0 ).constGeometry() && !features.at( 0 ).constGeometry()->isEmpty() ); + QCOMPARE( features.at( 0 ).constGeometry()->geometry()->wkbType(), QgsWKBTypes::Point ); + point = dynamic_cast< QgsPointV2* >( features.at( 0 ).constGeometry()->geometry() ); + QCOMPARE( point->x(), 125.0 ); + QCOMPARE( point->y(), 10.0 ); + QCOMPARE( features.at( 0 ).attribute( "name" ).toString(), QString( "Dinagat Islands" ) ); + QVERIFY( features.at( 1 ).constGeometry() && !features.at( 1 ).constGeometry()->isEmpty() ); + QCOMPARE( features.at( 1 ).constGeometry()->geometry()->wkbType(), QgsWKBTypes::Point ); + point = dynamic_cast< QgsPointV2* >( features.at( 1 ).constGeometry()->geometry() ); + QCOMPARE( point->x(), 110.0 ); + QCOMPARE( point->y(), 20.0 ); + QCOMPARE( features.at( 1 ).attribute( "name" ).toString(), QString( "Henry Gale Island" ) ); +} + +void TestQgsOgrUtils::stringToFields() +{ + //empty string + QgsFields fields = QgsOgrUtils::stringToFields( "", QTextCodec::codecForName( "System" ) ); + QCOMPARE( fields.count(), 0 ); + // bad string + fields = QgsOgrUtils::stringToFields( "asdasdas", QTextCodec::codecForName( "System" ) ); + QCOMPARE( fields.count(), 0 ); + + // geojson string + fields = QgsOgrUtils::stringToFields( "{\n\"type\": \"Feature\",\"geometry\": {\"type\": \"Point\",\"coordinates\": [125, 10]},\"properties\": {\"name\": \"Dinagat Islands\",\"height\":5.5}}", QTextCodec::codecForName( "System" ) ); + QCOMPARE( fields.count(), 2 ); + QCOMPARE( fields.at( 0 ).name(), QString( "name" ) ); + QCOMPARE( fields.at( 0 ).type(), QVariant::String ); + QCOMPARE( fields.at( 1 ).name(), QString( "height" ) ); + QCOMPARE( fields.at( 1 ).type(), QVariant::Double ); +} + + + +QTEST_MAIN( TestQgsOgrUtils ) +#include "testqgsogrutils.moc" diff --git a/tests/testdata/ogr_types.dat b/tests/testdata/ogr_types.dat new file mode 100644 index 0000000000000000000000000000000000000000..36941925d8c5ac7657e3dfe4dab3961d74500599 GIT binary patch literal 355 zcmZQh=Hz5#U|@L2&X zc;!=o`XOo{_M@9$TvC*omkzQ4A`f&Y3gA^>1@h0H0RcsatL%)d99;()ud*|C&7Kx!BnGJu2(FG#eZMb8nL1_^=qK+pgt zM~Tr8pi>AiF{m+ISkC^-Hi{s~G6FH`f6L@}d1S>Pi*YN$EI7@}e zWtQ;IZ96oX&OQ|R>A;}P6kH|uQ}d7k(@i0bpItVlOace=f8J0xXZm)@_UHO2E2eN? zCotXr%M(n$IU4p;P1usDeNNQR#C!`TGp59!!YyV@(F$o`T1GVgr%j+SQx-$v&&`}h zOsA?!!RFuPtoXU0N}q{IqxNU-YaJ%h?e#xdmS{6=>}>|S=U+wZ&rc$nOxIR-{LDD3 z&SX?R_2-#y%1r5{OTq3>KDPGf*TV`-|L1J{nNuUrbnX0>pUZE^F`0So1k*7Y`@r;f zyF*}q!;*gp*LiR@xEFWeTN$R9o>yR6w(&EVmb~=) zr=fxZ)BG&fU!d@_cI5me^+=Uz)oh7h_gmGNn0M&@+Lf-zWSwgI3*?^sWY=Gy@Ln$9 z3#Q-BjsFF5|DW2dU!d^5z*zPR6dqD`4ZlF)yWm>qufMJ~OwW_&{Cdvr1gC#~n)eG- zf1NE`^-C$mk?GTv^}qP9+A-N&+zD3S#(U%!DBPJD9KdNx>B(`hc^5s;{Q|{bu(@*~V`NjCvm}$j=zhL==PJF))zO(_?lir4QnDr#pQ|hRJv