Skip to content

Commit af0f61e

Browse files
committed
OGR provider - virtual sublayers for each geometry type in multi geometry layers, fixes #7895
1 parent 4f46379 commit af0f61e

File tree

6 files changed

+176
-31
lines changed

6 files changed

+176
-31
lines changed

src/app/qgisapp.cpp

+13-3
Original file line numberDiff line numberDiff line change
@@ -2847,19 +2847,29 @@ void QgisApp::loadOGRSublayers( QString layertype, QString uri, QStringList list
28472847
for ( int i = 0; i < list.size(); i++ )
28482848
{
28492849
QString composedURI;
2850+
QString layerName = list.at( i ).split( ':' ).value( 0 );
2851+
QString layerType = list.at( i ).split( ':' ).value( 1 );
2852+
28502853
if ( layertype != "GRASS" )
28512854
{
2852-
composedURI = uri + "|layername=" + list.at( i );
2855+
composedURI = uri + "|layername=" + layerName;
28532856
}
28542857
else
28552858
{
2856-
composedURI = uri + "|layerindex=" + list.at( i );
2859+
composedURI = uri + "|layerindex=" + layerName;
2860+
}
2861+
2862+
if ( !layerType.isEmpty() )
2863+
{
2864+
composedURI += "|geometrytype=" + layerType;
28572865
}
28582866

28592867
// addVectorLayer( composedURI, list.at( i ), "ogr" );
28602868

28612869
QgsDebugMsg( "Creating new vector layer using " + composedURI );
2862-
QgsVectorLayer *layer = new QgsVectorLayer( composedURI, list.at( i ), "ogr" );
2870+
QString name = list.at( i );
2871+
name.replace( ":", " " );
2872+
QgsVectorLayer *layer = new QgsVectorLayer( composedURI, name, "ogr" );
28632873
if ( layer && layer->isValid() )
28642874
{
28652875
myList << layer;

src/gui/qgssublayersdialog.cpp

+18-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ QgsSublayersDialog::QgsSublayersDialog( ProviderType providerType, QString name,
3232
{
3333
setWindowTitle( tr( "Select vector layers to add..." ) );
3434
layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" )
35-
<< tr( "Nb of features" ) << tr( "Geometry type" ) );
35+
<< tr( "Number of features" ) << tr( "Geometry type" ) );
3636
}
3737
else if ( providerType == QgsSublayersDialog::Gdal )
3838
{
@@ -69,7 +69,23 @@ QStringList QgsSublayersDialog::selectionNames()
6969
QStringList list;
7070
for ( int i = 0; i < layersTable->selectedItems().size(); i++ )
7171
{
72-
list << layersTable->selectedItems().at( i )->text( 1 );
72+
// If there are more sub layers of the same name (virtual for geometry types),
73+
// add geometry type
74+
75+
QString name = layersTable->selectedItems().at( i )->text( 1 );
76+
int count = 0;
77+
for ( int j = 0; j < layersTable->topLevelItemCount(); j++ )
78+
{
79+
if ( layersTable->topLevelItem( j )->text( 1 ) == name )
80+
{
81+
count++;
82+
}
83+
}
84+
if ( count > 1 )
85+
{
86+
name += ":" + layersTable->selectedItems().at( i )->text( 3 );
87+
}
88+
list << name;
7389
}
7490
return list;
7591
}

src/gui/qgssublayersdialog.h

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class GUI_EXPORT QgsSublayersDialog : public QDialog, private Ui::QgsSublayersDi
3737
~QgsSublayersDialog();
3838

3939
void populateLayerTable( QStringList theList, QString delim = ":" );
40+
// Returns list of selected layers, if there are more layers with the same name,
41+
// geometry type is appended separated by semicolon, example: <layer>:<geometryType>
4042
QStringList selectionNames();
4143
QList<int> selectionIndexes();
4244

src/providers/ogr/qgsogrfeatureiterator.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature )
204204

205205
bool fetchGeom = !( mRequest.flags() & QgsFeatureRequest::NoGeometry );
206206
bool useIntersect = mRequest.flags() & QgsFeatureRequest::ExactIntersect;
207-
if ( fetchGeom || useIntersect )
207+
bool geometryTypeFilter = P->mOgrGeometryTypeFilter != wkbUnknown;
208+
if ( fetchGeom || useIntersect || geometryTypeFilter )
208209
{
209210
OGRGeometryH geom = OGR_F_GetGeometryRef( fet );
210211

@@ -217,7 +218,8 @@ bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature )
217218
feature.setGeometryAndOwnership( wkb, OGR_G_WkbSize( geom ) );
218219
}
219220

220-
if ( useIntersect && ( !feature.geometry() || !feature.geometry()->intersects( mRequest.filterRect() ) ) )
221+
if (( useIntersect && ( !feature.geometry() || !feature.geometry()->intersects( mRequest.filterRect() ) ) )
222+
|| ( geometryTypeFilter && ( !feature.geometry() || feature.geometry()->wkbType() != ( QGis::WkbType )P->mOgrGeometryTypeFilter ) ) )
221223
{
222224
OGR_F_Destroy( fet );
223225
return false;

src/providers/ogr/qgsogrprovider.cpp

+133-24
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri )
205205
, extent_( 0 )
206206
, ogrLayer( 0 )
207207
, ogrOrigLayer( 0 )
208+
, mOgrGeometryTypeFilter( wkbUnknown )
208209
, ogrDriver( 0 )
209210
, valid( false )
210211
, featuresCounted( -1 )
@@ -267,6 +268,11 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri )
267268
{
268269
mSubsetString = value;
269270
}
271+
272+
if ( field == "geometrytype" )
273+
{
274+
mOgrGeometryTypeFilter = ogrWkbGeometryTypeFromName( value );
275+
}
270276
}
271277
}
272278

@@ -424,6 +430,11 @@ bool QgsOgrProvider::setSubsetString( QString theSQL, bool updateFeatureCount )
424430
uri += QString( "|subset=%1" ).arg( mSubsetString );
425431
}
426432

433+
if ( mOgrGeometryTypeFilter != wkbUnknown )
434+
{
435+
uri += QString( "|geometrytype=%1" ).arg( ogrWkbGeometryTypeName( mOgrGeometryTypeFilter ) );
436+
}
437+
427438
setDataSourceUri( uri );
428439

429440
OGR_L_ResetReading( ogrLayer );
@@ -454,8 +465,54 @@ QString QgsOgrProvider::subsetString()
454465
return mSubsetString;
455466
}
456467

468+
QString QgsOgrProvider::ogrWkbGeometryTypeName( OGRwkbGeometryType type ) const
469+
{
470+
QString geom;
471+
switch ( type )
472+
{
473+
case wkbUnknown: geom = "Unknown"; break;
474+
case wkbPoint: geom = "Point"; break;
475+
case wkbLineString: geom = "LineString"; break;
476+
case wkbPolygon: geom = "Polygon"; break;
477+
case wkbMultiPoint: geom = "MultiPoint"; break;
478+
case wkbMultiLineString: geom = "MultiLineString"; break;
479+
case wkbMultiPolygon: geom = "MultiPolygon"; break;
480+
case wkbGeometryCollection: geom = "GeometryCollection"; break;
481+
case wkbNone: geom = "None"; break;
482+
case wkbPoint25D: geom = "Point25D"; break;
483+
case wkbLineString25D: geom = "LineString25D"; break;
484+
case wkbPolygon25D: geom = "Polygon25D"; break;
485+
case wkbMultiPoint25D: geom = "MultiPoint25D"; break;
486+
case wkbMultiLineString25D: geom = "MultiLineString25D"; break;
487+
case wkbMultiPolygon25D: geom = "MultiPolygon25D"; break;
488+
default: geom = QString( "Unknown WKB: %1" ).arg( type );
489+
}
490+
return geom;
491+
}
492+
493+
OGRwkbGeometryType QgsOgrProvider::ogrWkbGeometryTypeFromName( QString typeName ) const
494+
{
495+
if ( typeName == "Point" ) return wkbPoint;
496+
else if ( typeName == "LineString" ) return wkbLineString;
497+
else if ( typeName == "Polygon" ) return wkbPolygon;
498+
else if ( typeName == "MultiPoint" ) return wkbMultiPoint;
499+
else if ( typeName == "MultiLineString" ) return wkbMultiLineString;
500+
else if ( typeName == "MultiPolygon" ) return wkbMultiPolygon;
501+
else if ( typeName == "GeometryCollection" ) return wkbGeometryCollection;
502+
else if ( typeName == "None" ) return wkbNone;
503+
else if ( typeName == "Point25D" ) return wkbPoint25D;
504+
else if ( typeName == "LineString25D" ) return wkbLineString25D;
505+
else if ( typeName == "Polygon25D" ) return wkbPolygon25D;
506+
else if ( typeName == "MultiPoint25D" ) return wkbMultiPoint25D;
507+
else if ( typeName == "MultiLineString25D" ) return wkbMultiLineString25D;
508+
else if ( typeName == "MultiPolygon25D" ) return wkbMultiPolygon25D;
509+
else if ( typeName == "GeometryCollection25D" ) return wkbGeometryCollection25D;
510+
return wkbUnknown;
511+
}
512+
457513
QStringList QgsOgrProvider::subLayers() const
458514
{
515+
QgsDebugMsg( "Entered." );
459516
if ( !valid )
460517
{
461518
return QStringList();
@@ -471,29 +528,47 @@ QStringList QgsOgrProvider::subLayers() const
471528
QString theLayerName = FROM8( OGR_FD_GetName( fdef ) );
472529
OGRwkbGeometryType layerGeomType = OGR_FD_GetGeomType( fdef );
473530

474-
int theLayerFeatureCount = OGR_L_GetFeatureCount( layer, 0 );
475-
476-
QString geom;
477-
switch ( layerGeomType )
531+
if ( layerGeomType != wkbUnknown )
478532
{
479-
case wkbUnknown: geom = "Unknown"; break;
480-
case wkbPoint: geom = "Point"; break;
481-
case wkbLineString: geom = "LineString"; break;
482-
case wkbPolygon: geom = "Polygon"; break;
483-
case wkbMultiPoint: geom = "MultiPoint"; break;
484-
case wkbMultiLineString: geom = "MultiLineString"; break;
485-
case wkbGeometryCollection: geom = "GeometryCollection"; break;
486-
case wkbNone: geom = "None"; break;
487-
case wkbPoint25D: geom = "Point25D"; break;
488-
case wkbLineString25D: geom = "LineString25D"; break;
489-
case wkbPolygon25D: geom = "Polygon25D"; break;
490-
case wkbMultiPoint25D: geom = "MultiPoint25D"; break;
491-
case wkbMultiLineString25D: geom = "MultiLineString25D"; break;
492-
case wkbMultiPolygon25D: geom = "MultiPolygon25D"; break;
493-
default: geom = QString( "Unknown WKB: %1" ).arg( layerGeomType );
533+
int theLayerFeatureCount = OGR_L_GetFeatureCount( layer, 0 );
534+
535+
QString geom = ogrWkbGeometryTypeName( layerGeomType );
536+
537+
mSubLayerList << QString( "%1:%2:%3:%4" ).arg( i ).arg( theLayerName ).arg( theLayerFeatureCount == -1 ? tr( "Unknown" ) : QString::number( theLayerFeatureCount ) ).arg( geom );
538+
QgsDebugMsg( "Unknown geometry type, count features for each geometry type" );
494539
}
540+
else
541+
{
542+
// Add virtual sublayers for supported geometry types if layer type is unknown
543+
// Count features for geometry types
544+
QMap<OGRwkbGeometryType, int> fCount;
545+
// TODO: avoid reading attributes, setRelevantFields cannot be called here because it is not constant
546+
//setRelevantFields( true, QgsAttributeList() );
547+
OGR_L_ResetReading( ogrLayer );
548+
OGRFeatureH fet;
549+
while (( fet = OGR_L_GetNextFeature( ogrLayer ) ) )
550+
{
551+
if ( !fet ) continue;
552+
OGRGeometryH geom = OGR_F_GetGeometryRef( fet );
553+
if ( geom )
554+
{
555+
OGRwkbGeometryType gType = OGR_G_GetGeometryType( geom );
556+
fCount[gType] = fCount.value( gType ) + 1;
557+
}
558+
OGR_F_Destroy( fet );
559+
}
560+
OGR_L_ResetReading( ogrLayer );
561+
int i = 0;
562+
foreach ( OGRwkbGeometryType gType, fCount.keys() )
563+
{
564+
QString geom = ogrWkbGeometryTypeName( gType );
495565

496-
mSubLayerList << QString( "%1:%2:%3:%4" ).arg( i ).arg( theLayerName ).arg( theLayerFeatureCount == -1 ? tr( "Unknown" ) : QString::number( theLayerFeatureCount ) ).arg( geom );
566+
QString sl = QString( "%1:%2:%3:%4" ).arg( i ).arg( theLayerName ).arg( fCount.value( gType ) ).arg( geom );
567+
QgsDebugMsg( "sub layer: " + sl );
568+
mSubLayerList << sl;
569+
i++;
570+
}
571+
}
497572
}
498573

499574
return mSubLayerList;
@@ -528,7 +603,9 @@ int QgsOgrProvider::getOgrGeomType( OGRLayerH ogrLayer )
528603
geomType = OGR_FD_GetGeomType( fdef );
529604

530605
//Some ogr drivers (e.g. GML) are not able to determine the geometry type of a layer like this.
531-
//In such cases, we examine the first feature
606+
//In such cases, we use virtual sublayers for each geometry (originally the type was
607+
// guessed from the first feature which resulted in loss of other formats)
608+
/*
532609
if ( geomType == wkbUnknown )
533610
{
534611
OGR_L_ResetReading( ogrLayer );
@@ -544,6 +621,7 @@ int QgsOgrProvider::getOgrGeomType( OGRLayerH ogrLayer )
544621
}
545622
OGR_L_ResetReading( ogrLayer );
546623
}
624+
*/
547625
}
548626
return geomType;
549627
}
@@ -553,7 +631,14 @@ void QgsOgrProvider::loadFields()
553631
//the attribute fields need to be read again when the encoding changes
554632
mAttributeFields.clear();
555633

556-
geomType = getOgrGeomType( ogrLayer );
634+
if ( mOgrGeometryTypeFilter != wkbUnknown )
635+
{
636+
geomType = mOgrGeometryTypeFilter;
637+
}
638+
else
639+
{
640+
geomType = getOgrGeomType( ogrLayer );
641+
}
557642
OGRFeatureDefnH fdef = OGR_L_GetLayerDefn( ogrLayer );
558643
if ( fdef )
559644
{
@@ -733,7 +818,7 @@ QGis::WkbType QgsOgrProvider::geometryType() const
733818
}
734819

735820
/**
736-
* Return the feature type
821+
* Return the feature count
737822
*/
738823
long QgsOgrProvider::featureCount() const
739824
{
@@ -2190,7 +2275,31 @@ void QgsOgrProvider::recalculateFeatureCount()
21902275

21912276
// feature count returns number of features within current spatial filter
21922277
// so we remove it if there's any and then put it back
2193-
featuresCounted = OGR_L_GetFeatureCount( ogrLayer, true );
2278+
if ( mOgrGeometryTypeFilter == wkbUnknown )
2279+
{
2280+
featuresCounted = OGR_L_GetFeatureCount( ogrLayer, true );
2281+
}
2282+
else
2283+
{
2284+
featuresCounted = 0;
2285+
OGR_L_ResetReading( ogrLayer );
2286+
setRelevantFields( true, QgsAttributeList() );
2287+
OGR_L_ResetReading( ogrLayer );
2288+
OGRFeatureH fet;
2289+
while (( fet = OGR_L_GetNextFeature( ogrLayer ) ) )
2290+
{
2291+
if ( !fet ) continue;
2292+
OGRGeometryH geom = OGR_F_GetGeometryRef( fet );
2293+
if ( geom )
2294+
{
2295+
OGRwkbGeometryType gType = OGR_G_GetGeometryType( geom );
2296+
if ( gType == mOgrGeometryTypeFilter ) featuresCounted++;
2297+
}
2298+
OGR_F_Destroy( fet );
2299+
}
2300+
OGR_L_ResetReading( ogrLayer );
2301+
2302+
}
21942303

21952304
if ( filter )
21962305
{

src/providers/ogr/qgsogrprovider.h

+6
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ class QgsOgrProvider : public QgsVectorDataProvider
262262

263263
private:
264264
unsigned char *getGeometryPointer( OGRFeatureH fet );
265+
QString ogrWkbGeometryTypeName( OGRwkbGeometryType type ) const;
266+
OGRwkbGeometryType ogrWkbGeometryTypeFromName( QString typeName ) const;
265267
QgsFields mAttributeFields;
266268
OGRDataSourceH ogrDataSource;
267269
void *extent_;
@@ -281,6 +283,10 @@ class QgsOgrProvider : public QgsVectorDataProvider
281283
//! layer index
282284
int mLayerIndex;
283285

286+
/** Optional geometry type for layers with multiple geometries,
287+
* otherwise wkbUnknown */
288+
OGRwkbGeometryType mOgrGeometryTypeFilter;
289+
284290
//! current spatial filter
285291
QgsRectangle mFetchRect;
286292

0 commit comments

Comments
 (0)