Skip to content
Permalink
Browse files

Optimise QgsGeometry::asMultiPolygon/asPolygon

These methods were very expensive, involving a temporary allocation
of list of lists of temporary points

Rework with direct iteration of input points instead to speed up
this conversion.
  • Loading branch information
nyalldawson committed Feb 23, 2021
1 parent b04fe1f commit 885387f5ba7bc6a7f471afaa1602312bbb952e49
Showing with 45 additions and 22 deletions.
  1. +45 −21 src/core/geometry/qgsgeometry.cpp
  2. +0 −1 src/core/geometry/qgsgeometry.h
@@ -1720,19 +1720,20 @@ QgsMultiPolygonXY QgsGeometry::asMultiPolygon() const
return QgsMultiPolygonXY();
}

QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( d->geometry.get() );
const QgsGeometryCollection *geomCollection = qgsgeometry_cast<const QgsGeometryCollection *>( d->geometry.get() );
if ( !geomCollection )
{
return QgsMultiPolygonXY();
}

int nPolygons = geomCollection->numGeometries();
const int nPolygons = geomCollection->numGeometries();
if ( nPolygons < 1 )
{
return QgsMultiPolygonXY();
}

QgsMultiPolygonXY mp;
mp.reserve( nPolygons );
for ( int i = 0; i < nPolygons; ++i )
{
const QgsPolygon *polygon = qgsgeometry_cast<const QgsPolygon *>( geomCollection->geometryN( i ) );
@@ -1751,7 +1752,7 @@ QgsMultiPolygonXY QgsGeometry::asMultiPolygon() const

QgsPolygonXY poly;
convertPolygon( *polygon, poly );
mp.append( poly );
mp.push_back( poly );
}
return mp;
}
@@ -3043,32 +3044,55 @@ void QgsGeometry::convertPointList( const QgsPointSequence &input, QVector<QgsPo
}
}

void QgsGeometry::convertToPolyline( const QgsPointSequence &input, QgsPolylineXY &output )
void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
{
output.clear();
output.resize( input.size() );

for ( int i = 0; i < input.size(); ++i )
auto convertRing = []( const QgsCurve * ring ) -> QgsPolylineXY
{
const QgsPoint &pt = input.at( i );
output[i].setX( pt.x() );
output[i].setY( pt.y() );
}
}
QgsPolylineXY res;
bool doSegmentation = ( QgsWkbTypes::flatType( ring->wkbType() ) == QgsWkbTypes::CompoundCurve
|| QgsWkbTypes::flatType( ring->wkbType() ) == QgsWkbTypes::CircularString );
std::unique_ptr< QgsLineString > segmentizedLine;
const QgsLineString *line = nullptr;
if ( doSegmentation )
{
segmentizedLine.reset( ring->curveToLine() );
line = segmentizedLine.get();
}
else
{
line = qgsgeometry_cast<const QgsLineString *>( ring );
if ( !line )
{
return res;
}
}

void QgsGeometry::convertPolygon( const QgsPolygon &input, QgsPolygonXY &output )
{
output.clear();
QgsCoordinateSequence coords = input.coordinateSequence();
if ( coords.empty() )
int nVertices = line->numPoints();
res.resize( nVertices );
QgsPointXY *data = res.data();
const double *xData = line->xData();
const double *yData = line->yData();
for ( int i = 0; i < nVertices; ++i )
{
data->setX( *xData++ );
data->setY( *yData++ );
data++;
}
return res;
};

if ( const QgsCurve *exterior = input.exteriorRing() )
{
return;
output.push_back( convertRing( exterior ) );
}
const QgsRingSequence &rings = coords[0];
output.resize( rings.size() );
for ( int i = 0; i < rings.size(); ++i )

const int interiorRingCount = input.numInteriorRings();
output.reserve( output.size() + interiorRingCount );
for ( int n = 0; n < interiorRingCount; ++n )
{
convertToPolyline( rings[i], output[i] );
output.push_back( convertRing( input.interiorRing( n ) ) );
}
}

@@ -2489,7 +2489,6 @@ class CORE_EXPORT QgsGeometry
*/
void reset( std::unique_ptr< QgsAbstractGeometry > newGeometry );

static void convertToPolyline( const QgsPointSequence &input, QgsPolylineXY &output );
static void convertPolygon( const QgsPolygon &input, QgsPolygonXY &output );

//! Try to convert the geometry to a point

0 comments on commit 885387f

Please sign in to comment.