Skip to content

Commit 2f44d52

Browse files
authoredOct 5, 2017
Merge pull request #5298 from manisandro/ogr_tin_triangle
[Feature][OGR] Support Triangle, TIN and PolyhedralSurface geometry types by mapping them to Polygon and MultiPolygon respectively
2 parents a725dae + de126a1 commit 2f44d52

File tree

7 files changed

+123
-8
lines changed

7 files changed

+123
-8
lines changed
 

‎src/app/qgisapp.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4358,13 +4358,13 @@ void QgisApp::askUserForOGRSublayers( QgsVectorLayer *layer )
43584358

43594359
QStringList elements = sublayer.split( QStringLiteral( ":" ) );
43604360
// merge back parts of the name that may have been split
4361-
while ( elements.size() > 4 )
4361+
while ( elements.size() > 5 )
43624362
{
43634363
elements[1] += ":" + elements[2];
43644364
elements.removeAt( 2 );
43654365
}
43664366

4367-
if ( elements.count() == 4 )
4367+
if ( elements.count() >= 4 )
43684368
{
43694369
QgsSublayersDialog::LayerDefinition def;
43704370
def.layerId = elements[0].toInt();

‎src/core/geometry/qgsgeometryfactory.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "qgsmultipoint.h"
2828
#include "qgsmultipolygon.h"
2929
#include "qgsmultisurface.h"
30+
#include "qgstriangle.h"
3031
#include "qgswkbtypes.h"
3132
#include "qgslogger.h"
3233

@@ -241,6 +242,8 @@ std::unique_ptr<QgsAbstractGeometry> QgsGeometryFactory::geomFromWkbType( QgsWkb
241242
return std::unique_ptr<QgsAbstractGeometry>( new QgsMultiSurface() );
242243
case QgsWkbTypes::GeometryCollection:
243244
return std::unique_ptr<QgsAbstractGeometry>( new QgsGeometryCollection() );
245+
case QgsWkbTypes::Triangle:
246+
return std::unique_ptr<QgsAbstractGeometry>( new QgsTriangle() );
244247
default:
245248
return nullptr;
246249
}

‎src/core/geometry/qgstriangle.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,7 @@ bool QgsTriangle::fromWkb( QgsConstWkbPtr &wkbPtr )
161161

162162
QgsLineString *line = new QgsLineString();
163163
line->fromWkbPoints( ringType, wkbPtr );
164-
if ( !mExteriorRing )
165-
{
166-
mExteriorRing.reset( line );
167-
}
164+
mExteriorRing.reset( line );
168165

169166
return true;
170167
}
@@ -257,7 +254,7 @@ bool QgsTriangle::insertVertex( QgsVertexId position, const QgsPoint &vertex )
257254
Q_UNUSED( vertex );
258255
return false;
259256
}
260-
#include <iostream>
257+
261258
bool QgsTriangle::moveVertex( QgsVertexId vId, const QgsPoint &newPos )
262259
{
263260
if ( !mExteriorRing || vId.part != 0 || vId.ring != 0 || vId.vertex < 0 || vId.vertex > 4 )

‎src/core/qgsogrutils.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,64 @@ QgsGeometry QgsOgrUtils::ogrGeometryToQgsGeometry( OGRGeometryH geom )
221221
unsigned char *wkb = new unsigned char[memorySize];
222222
OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb );
223223

224+
// Read original geometry type
225+
uint32_t origGeomType;
226+
memcpy( &origGeomType, wkb + 1, sizeof( uint32_t ) );
227+
bool hasZ = ( origGeomType >= 1000 && origGeomType < 2000 ) || ( origGeomType >= 3000 && origGeomType < 4000 );
228+
bool hasM = ( origGeomType >= 2000 && origGeomType < 3000 ) || ( origGeomType >= 3000 && origGeomType < 4000 );
229+
230+
// PolyhedralSurface and TINs are not supported, map them to multipolygons...
231+
if ( origGeomType % 1000 == 16 ) // is TIN, TINZ, TINM or TINZM
232+
{
233+
// TIN has the same wkb layout as a multipolygon, just need to overwrite the geom types...
234+
int nDims = 2 + hasZ + hasM;
235+
uint32_t newMultiType = static_cast<uint32_t>( QgsWkbTypes::zmType( QgsWkbTypes::MultiPolygon, hasZ, hasM ) );
236+
uint32_t newSingleType = static_cast<uint32_t>( QgsWkbTypes::zmType( QgsWkbTypes::Polygon, hasZ, hasM ) );
237+
unsigned char *wkbptr = wkb;
238+
239+
// Endianness
240+
wkbptr += 1;
241+
242+
// Overwrite geom type
243+
memcpy( wkbptr, &newMultiType, sizeof( uint32_t ) );
244+
wkbptr += 4;
245+
246+
// Geom count
247+
uint32_t numGeoms;
248+
memcpy( &numGeoms, wkb + 5, sizeof( uint32_t ) );
249+
wkbptr += 4;
250+
251+
// For each part, overwrite the geometry type to polygon (Z|M)
252+
for ( uint32_t i = 0; i < numGeoms; ++i )
253+
{
254+
// Endianness
255+
wkbptr += 1;
256+
257+
// Overwrite geom type
258+
memcpy( wkbptr, &newSingleType, sizeof( uint32_t ) );
259+
wkbptr += sizeof( uint32_t );
260+
261+
// skip coordinates
262+
uint32_t nRings;
263+
memcpy( &nRings, wkbptr, sizeof( uint32_t ) );
264+
wkbptr += sizeof( uint32_t );
265+
266+
for ( uint32_t j = 0; j < nRings; ++j )
267+
{
268+
uint32_t nPoints;
269+
memcpy( &nPoints, wkbptr, sizeof( uint32_t ) );
270+
wkbptr += sizeof( uint32_t ) + sizeof( double ) * nDims * nPoints;
271+
}
272+
}
273+
}
274+
else if ( origGeomType % 1000 == 15 ) // PolyhedralSurface, PolyhedralSurfaceZ, PolyhedralSurfaceM or PolyhedralSurfaceZM
275+
{
276+
// PolyhedralSurface has the same wkb layout as a MultiPolygon, just need to overwrite the geom type...
277+
uint32_t newType = static_cast<uint32_t>( QgsWkbTypes::zmType( QgsWkbTypes::MultiPolygon, hasZ, hasM ) );
278+
// Overwrite geom type
279+
memcpy( wkb + 1, &newType, sizeof( uint32_t ) );
280+
}
281+
224282
QgsGeometry g;
225283
g.fromWkb( wkb, memorySize );
226284
return g;

‎src/core/symbology/qgssymbol.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,7 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
775775
}
776776
break;
777777
case QgsWkbTypes::Polygon:
778+
case QgsWkbTypes::Triangle:
778779
{
779780
QPolygonF pts;
780781
QList<QPolygonF> holes;

‎src/providers/ogr/qgsogrprovider.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,17 @@ QStringList QgsOgrProvider::subLayers() const
765765
fCount[wkbUnknown] = 0;
766766
}
767767

768+
// List TIN and PolyhedralSurface as MultiPolygon
769+
if ( fCount.contains( wkbTIN ) )
770+
{
771+
fCount[wkbMultiPolygon] = fCount.value( wkbMultiPolygon ) + fCount[wkbTIN];
772+
fCount.remove( wkbTIN );
773+
}
774+
if ( fCount.contains( wkbPolyhedralSurface ) )
775+
{
776+
fCount[wkbMultiPolygon] = fCount.value( wkbMultiPolygon ) + fCount[wkbPolyhedralSurface];
777+
fCount.remove( wkbPolyhedralSurface );
778+
}
768779
// When there are CurvePolygons, promote Polygons
769780
if ( fCount.contains( wkbPolygon ) && fCount.contains( wkbCurvePolygon ) )
770781
{
@@ -1164,6 +1175,14 @@ QgsWkbTypes::Type QgsOgrProvider::wkbType() const
11641175
{
11651176
wkb = QgsWkbTypes::multiType( wkb );
11661177
}
1178+
if ( wkb % 1000 == 15 ) // is PolyhedralSurface, PolyhedralSurfaceZ, PolyhedralSurfaceM or PolyhedralSurfaceZM => map to MultiPolygon
1179+
{
1180+
wkb = static_cast<QgsWkbTypes::Type>( wkb - 9 );
1181+
}
1182+
else if ( wkb % 1000 == 16 ) // is TIN, TINZ, TINM or TINZM => map to MultiPolygon
1183+
{
1184+
wkb = static_cast<QgsWkbTypes::Type>( wkb - 10 );
1185+
}
11671186
return wkb;
11681187
}
11691188

‎tests/src/python/test_provider_ogr.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import sys
1818
import tempfile
1919

20-
from qgis.core import QgsVectorLayer, QgsVectorDataProvider, QgsWkbTypes, QgsFeature
20+
from qgis.core import QgsVectorLayer, QgsVectorDataProvider, QgsWkbTypes, QgsFeature, QgsFeatureRequest
2121
from qgis.testing import (
2222
start_app,
2323
unittest
@@ -255,6 +255,43 @@ def testGdbFilter(self):
255255
while it.nextFeature(f):
256256
self.assertTrue(f.attribute("text") == "shape 2")
257257

258+
def testTriangleTINPolyhedralSurface(self):
259+
""" Test support for Triangles (mapped to Polygons) """
260+
testsets = (
261+
("Triangle((0 0, 0 1, 1 1, 0 0))", QgsWkbTypes.Triangle, "Triangle ((0 0, 0 1, 1 1, 0 0))"),
262+
("Triangle Z((0 0 1, 0 1 2, 1 1 3, 0 0 1))", QgsWkbTypes.TriangleZ, "TriangleZ ((0 0 1, 0 1 2, 1 1 3, 0 0 1))"),
263+
("Triangle M((0 0 4, 0 1 5, 1 1 6, 0 0 4))", QgsWkbTypes.TriangleM, "TriangleM ((0 0 4, 0 1 5, 1 1 6, 0 0 4))"),
264+
("Triangle ZM((0 0 0 1, 0 1 2 3, 1 1 4 5, 0 0 0 1))", QgsWkbTypes.TriangleZM, "TriangleZM ((0 0 0 1, 0 1 2 3, 1 1 4 5, 0 0 0 1))"),
265+
266+
("TIN (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))", QgsWkbTypes.MultiPolygon, "MultiPolygon (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))"),
267+
("TIN Z(((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))", QgsWkbTypes.MultiPolygonZ, "MultiPolygonZ (((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))"),
268+
("TIN M(((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))", QgsWkbTypes.MultiPolygonM, "MultiPolygonM (((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))"),
269+
("TIN ZM(((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))", QgsWkbTypes.MultiPolygonZM, "MultiPolygonZM (((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))"),
270+
271+
("PolyhedralSurface (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))", QgsWkbTypes.MultiPolygon, "MultiPolygon (((0 0, 0 1, 1 1, 0 0)),((0 0, 1 0, 1 1, 0 0)))"),
272+
("PolyhedralSurface Z(((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))", QgsWkbTypes.MultiPolygonZ, "MultiPolygonZ (((0 0 0, 0 1 1, 1 1 1, 0 0 0)),((0 0 0, 1 0 0, 1 1 1, 0 0 0)))"),
273+
("PolyhedralSurface M(((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))", QgsWkbTypes.MultiPolygonM, "MultiPolygonM (((0 0 0, 0 1 2, 1 1 3, 0 0 0)),((0 0 0, 1 0 4, 1 1 3, 0 0 0)))"),
274+
("PolyhedralSurface ZM(((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))", QgsWkbTypes.MultiPolygonZM, "MultiPolygonZM (((0 0 0 0, 0 1 1 2, 1 1 1 3, 0 0 0 0)),((0 0 0 0, 1 0 0 4, 1 1 1 3, 0 0 0 0)))")
275+
)
276+
for row in testsets:
277+
datasource = os.path.join(self.basetestpath, 'test.csv')
278+
with open(datasource, 'wt') as f:
279+
f.write('id,WKT\n')
280+
f.write('1,"%s"' % row[0])
281+
282+
vl = QgsVectorLayer(datasource, 'test', 'ogr')
283+
self.assertTrue(vl.isValid())
284+
self.assertEqual(vl.wkbType(), row[1])
285+
286+
f = QgsFeature()
287+
self.assertTrue(vl.getFeatures(QgsFeatureRequest(1)).nextFeature(f))
288+
self.assertTrue(f.geometry())
289+
self.assertEqual(f.geometry().geometry().asWkt(), row[2])
290+
291+
"""PolyhedralSurface, Tin => mapped to MultiPolygon
292+
Triangle => mapped to Polygon
293+
"""
294+
258295

259296
if __name__ == '__main__':
260297
unittest.main()

0 commit comments

Comments
 (0)