Skip to content
Permalink
Browse files
fix detecting 3D geometry for OGR (#46034)
  • Loading branch information
vcloarec committed Nov 18, 2021
1 parent 345dbd6 commit c80ec66ce71e7dcc7483f5cd2841bc66d6982f30
Showing with 1,626 additions and 5 deletions.
  1. +9 −3 src/core/providers/ogr/qgsogrproviderutils.cpp
  2. +41 −2 tests/src/python/test_provider_ogr.py
  3. +1,576 −0 tests/testdata/points_lines_3d.dxf
@@ -2474,16 +2474,21 @@ QList< QgsProviderSublayerDetails > QgsOgrProviderUtils::querySubLayerList( int
// Add virtual sublayers for supported geometry types if layer type is unknown
// Count features for geometry types
QMap<OGRwkbGeometryType, int> fCount;
QSet<OGRwkbGeometryType> fHasZ;
// TODO: avoid reading attributes, setRelevantFields cannot be called here because it is not constant

layer->ResetReading();
gdal::ogr_feature_unique_ptr fet;
while ( fet.reset( layer->GetNextFeature() ), fet )
{
const OGRwkbGeometryType gType = QgsOgrProviderUtils::ogrWkbSingleFlatten( resolveGeometryTypeForFeature( fet.get(), driverName ) );
OGRwkbGeometryType gType = resolveGeometryTypeForFeature( fet.get(), driverName );
if ( gType != wkbNone )
{
bool hasZ = wkbHasZ( gType );
gType = QgsOgrProviderUtils::ogrWkbSingleFlatten( gType );
fCount[gType] = fCount.value( gType ) + 1;
if ( hasZ )
fHasZ.insert( gType );
}

if ( feedback && feedback->isCanceled() )
@@ -2554,7 +2559,7 @@ QList< QgsProviderSublayerDetails > QgsOgrProviderUtils::querySubLayerList( int
}
}
details.setFeatureCount( fCount.value( countIt.key() ) );
details.setWkbType( QgsOgrUtils::ogrGeometryTypeToQgsWkbType( ( bIs25D ) ? wkbSetZ( countIt.key() ) : countIt.key() ) );
details.setWkbType( QgsOgrUtils::ogrGeometryTypeToQgsWkbType( ( bIs25D || fHasZ.contains( countIt.key() ) ) ? wkbSetZ( countIt.key() ) : countIt.key() ) );
details.setGeometryColumnName( geometryColumnName );
details.setDescription( longDescription );
details.setProviderKey( QStringLiteral( "ogr" ) );
@@ -2565,7 +2570,8 @@ QList< QgsProviderSublayerDetails > QgsOgrProviderUtils::querySubLayerList( int
// in the uri for the sublayers (otherwise we'll be forced to re-do this iteration whenever
// the uri from the sublayer is used to construct an actual vector layer)
if ( details.wkbType() != QgsWkbTypes::Unknown )
parts.insert( QStringLiteral( "geometryType" ), ogrWkbGeometryTypeName( countIt.key() ) );
parts.insert( QStringLiteral( "geometryType" ),
ogrWkbGeometryTypeName( ( bIs25D || fHasZ.contains( countIt.key() ) ) ? wkbSetZ( countIt.key() ) : countIt.key() ) );
else
parts.remove( QStringLiteral( "geometryType" ) );

@@ -1723,13 +1723,21 @@ def test_provider_sublayer_details(self):
self.assertEqual(res[0].layerNumber(), 0)
self.assertEqual(res[0].name(), "multipatch")
self.assertEqual(res[0].description(), '')
self.assertEqual(res[0].uri(), TEST_DATA_DIR + "/multipatch.shp|geometrytype=Polygon")
self.assertEqual(res[0].uri(), TEST_DATA_DIR + "/multipatch.shp|geometrytype=Polygon25D")
self.assertEqual(res[0].providerKey(), "ogr")
self.assertEqual(res[0].type(), QgsMapLayerType.VectorLayer)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.Polygon)
self.assertEqual(res[0].wkbType(), QgsWkbTypes.PolygonZ)
self.assertEqual(res[0].geometryColumnName(), '')
self.assertEqual(res[0].driverName(), 'ESRI Shapefile')

# check a feature
vl = res[0].toLayer(options)
self.assertTrue(vl.isValid())
feature = next(vl.getFeatures())
self.assertEqual(feature.geometry().wkbType(), QgsWkbTypes.MultiPolygonZ)
self.assertEqual(feature.geometry().asWkt(), 'MultiPolygonZ (((0 0 0, 0 1 0, 1 1 0, 0 0 0)),((0 0 0, 1 1 0, 1 0 0,'
' 0 0 0)),((0 0 0, 0 -1 0, 1 -1 0, 0 0 0)),((0 0 0, 1 -1 0, 1 0 0, 0 0 0)))')

# single layer geopackage -- sublayers MUST have the layerName set on the uri,
# in case more layers are added in future to the gpkg
res = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'curved_polys.gpkg'))
@@ -2463,6 +2471,37 @@ def test_provider_feature_iterator_options(self):
f = vl.getFeature(2)
self.assertEqual(f.geometry().asWkt(), 'Point (2 2)')

def test_provider_dxf_3d(self):
"""Test issue GH #45938"""

metadata = QgsProviderRegistry.instance().providerMetadata('ogr')
layers = metadata.querySublayers(os.path.join(TEST_DATA_DIR, 'points_lines_3d.dxf'),
Qgis.SublayerQueryFlag.ResolveGeometryType)

options = QgsProviderSublayerDetails.LayerOptions(QgsCoordinateTransformContext())

for ld in layers:
if ld.wkbType() == QgsWkbTypes.PointZ:
point_layer = ld.toLayer(options)
if ld.wkbType() == QgsWkbTypes.LineStringZ:
polyline_layer = ld.toLayer(options)

self.assertTrue(point_layer.isValid())
self.assertEqual(point_layer.featureCount(), 11)
feature = next(point_layer.getFeatures())
self.assertTrue(feature.isValid())
self.assertEqual(feature.geometry().wkbType(), QgsWkbTypes.Point25D)
self.assertEqual(feature.geometry().asWkt(),
'PointZ (635660.10747100005391985 1768912.79759799991734326 3.36980799999999991)')

self.assertTrue(polyline_layer.isValid())
self.assertEqual(polyline_layer.featureCount(), 2)
feature = next(polyline_layer.getFeatures())
self.assertTrue(feature.isValid())
self.assertEqual(feature.geometry().wkbType(), QgsWkbTypes.LineString25D)
self.assertEqual(feature.geometry().vertexAt(1).asWkt(),
'PointZ (635660.11699699994642287 1768910.93880999996326864 3.33884099999999995)')


if __name__ == '__main__':
unittest.main()
Loading

0 comments on commit c80ec66

Please sign in to comment.