Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fix crash when using GEOS to calculate shortest distance to an empty
geometry

Fixes #41968
  • Loading branch information
nyalldawson committed Mar 3, 2021
1 parent 6bf836d commit 5df09f5
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 4 deletions.
12 changes: 11 additions & 1 deletion src/core/geometry/qgsgeos.cpp
Expand Up @@ -2274,7 +2274,7 @@ QgsGeometry QgsGeos::closestPoint( const QgsGeometry &other, QString *errorMsg )

QgsGeometry QgsGeos::shortestLine( const QgsGeometry &other, QString *errorMsg ) const
{
if ( !mGeos || other.isNull() )
if ( !mGeos || other.isEmpty() )
{
return QgsGeometry();
}
Expand All @@ -2284,6 +2284,9 @@ QgsGeometry QgsGeos::shortestLine( const QgsGeometry &other, QString *errorMsg )

QgsGeometry QgsGeos::shortestLine( const QgsAbstractGeometry *other, QString *errorMsg ) const
{
if ( !other || other->isEmpty() )
return QgsGeometry();

geos::unique_ptr otherGeom( asGeos( other, mPrecision ) );
if ( !otherGeom )
{
Expand All @@ -2298,6 +2301,13 @@ QgsGeometry QgsGeos::shortestLine( const QgsAbstractGeometry *other, QString *er
{
geos::coord_sequence_unique_ptr nearestCoord( GEOSNearestPoints_r( geosinit()->ctxt, mGeos.get(), otherGeom.get() ) );

if ( !nearestCoord )
{
if ( errorMsg )
*errorMsg = QStringLiteral( "GEOS returned no nearest points" );
return QgsGeometry();
}

( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 0, &nx1 );
( void )GEOSCoordSeq_getY_r( geosinit()->ctxt, nearestCoord.get(), 0, &ny1 );
( void )GEOSCoordSeq_getX_r( geosinit()->ctxt, nearestCoord.get(), 1, &nx2 );
Expand Down
7 changes: 4 additions & 3 deletions src/core/geometry/qgsinternalgeometryengine.cpp
Expand Up @@ -260,14 +260,12 @@ QgsGeometry QgsInternalGeometryEngine::poleOfInaccessibility( double precision,
int numGeom = gc->numGeometries();
double maxDist = 0;
QgsPoint bestPoint;
bool found = false;
for ( int i = 0; i < numGeom; ++i )
{
const QgsSurface *surface = qgsgeometry_cast< const QgsSurface * >( gc->geometryN( i ) );
if ( !surface )
continue;

found = true;
double dist = std::numeric_limits<double>::max();
QgsPoint p = surfacePoleOfInaccessibility( surface, precision, dist );
if ( dist > maxDist )
Expand All @@ -277,7 +275,7 @@ QgsGeometry QgsInternalGeometryEngine::poleOfInaccessibility( double precision,
}
}

if ( !found )
if ( bestPoint.isEmpty() )
return QgsGeometry();

if ( distanceFromBoundary )
Expand All @@ -292,6 +290,9 @@ QgsGeometry QgsInternalGeometryEngine::poleOfInaccessibility( double precision,

double dist = std::numeric_limits<double>::max();
QgsPoint p = surfacePoleOfInaccessibility( surface, precision, dist );
if ( p.isEmpty() )
return QgsGeometry();

if ( distanceFromBoundary )
*distanceFromBoundary = dist;
return QgsGeometry( new QgsPoint( p ) );
Expand Down
11 changes: 11 additions & 0 deletions tests/src/core/testqgsgeometry.cpp
Expand Up @@ -168,6 +168,7 @@ class TestQgsGeometry : public QObject
void differenceCheck2();
void bufferCheck();
void smoothCheck();
void shortestLineEmptyGeometry();

void unaryUnion();

Expand Down Expand Up @@ -17372,6 +17373,16 @@ void TestQgsGeometry::smoothCheck()
QCOMPARE( result.wkbType(), QgsWkbTypes::Polygon );
}

void TestQgsGeometry::shortestLineEmptyGeometry()
{
// test calculating distance to an empty geometry
// refs https://github.com/qgis/QGIS/issues/41968
QgsGeometry geom1( QgsGeometry::fromWkt( QStringLiteral( "Polygon ((0 0, 10 0, 10 10, 0 10, 0 0 ))" ) ) );
QgsGeometry geom2( new QgsPoint() );
QgsGeos geos( geom1.constGet() );
QVERIFY( geos.shortestLine( geom2.constGet() ).isNull() );
}

void TestQgsGeometry::unaryUnion()
{
//test QgsGeometry::unaryUnion with null geometry
Expand Down

0 comments on commit 5df09f5

Please sign in to comment.