mirror of
https://github.com/qgis/QGIS.git
synced 2025-11-22 00:14:55 -05:00
Fix unreported issue with polygon intersection resulting in a point with min_inscribed_circle_radius and expression
The issue was that in case of intersections resulting in a single point and when meausres were requires (i.e. when sorting) the circle radius test result was ignored.
This commit is contained in:
parent
10284637af
commit
c40516b06d
@ -6953,6 +6953,105 @@ static QVariant executeGeomOverlay( const QVariantList &values, const QgsExpress
|
||||
}
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// Helper functions for geometry tests
|
||||
|
||||
// Test function for linestring geometries, returns TRUE if test passes
|
||||
auto testLinestring = [ = ]( const QgsGeometry intersection, double & overlapValue ) -> bool
|
||||
{
|
||||
bool testResult { false };
|
||||
// For return measures:
|
||||
QVector<double> overlapValues;
|
||||
for ( auto it = intersection.const_parts_begin(); ! testResult && it != intersection.const_parts_end(); ++it )
|
||||
{
|
||||
const QgsCurve *geom = qgsgeometry_cast< const QgsCurve * >( *it );
|
||||
// Check min overlap for intersection (if set)
|
||||
if ( minOverlap != -1 || requireMeasures )
|
||||
{
|
||||
overlapValue = geom->length();
|
||||
overlapValues.append( overlapValue );
|
||||
if ( minOverlap != -1 )
|
||||
{
|
||||
if ( overlapValue >= minOverlap )
|
||||
{
|
||||
testResult = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! overlapValues.isEmpty() )
|
||||
{
|
||||
overlapValue = *std::max_element( overlapValues.cbegin(), overlapValues.cend() );
|
||||
}
|
||||
|
||||
return testResult;
|
||||
};
|
||||
|
||||
// Test function for polygon geometries, returns TRUE if test passes
|
||||
auto testPolygon = [ = ]( const QgsGeometry intersection, double & radiusValue, double & overlapValue ) -> bool
|
||||
{
|
||||
// overlap and inscribed circle tests must be checked both (if the values are != -1)
|
||||
bool testResult { false };
|
||||
// For return measures:
|
||||
QVector<double> overlapValues;
|
||||
QVector<double> radiusValues;
|
||||
for ( auto it = intersection.const_parts_begin(); ( ! testResult || requireMeasures ) && it != intersection.const_parts_end(); ++it )
|
||||
{
|
||||
const QgsCurvePolygon *geom = qgsgeometry_cast< const QgsCurvePolygon * >( *it );
|
||||
// Check min overlap for intersection (if set)
|
||||
if ( minOverlap != -1 || requireMeasures )
|
||||
{
|
||||
overlapValue = geom->area();
|
||||
overlapValues.append( geom->area() );
|
||||
if ( minOverlap != - 1 )
|
||||
{
|
||||
if ( overlapValue >= minOverlap )
|
||||
{
|
||||
testResult = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
|
||||
// Check min inscribed circle radius for intersection (if set)
|
||||
if ( minInscribedCircleRadius != -1 || requireMeasures )
|
||||
{
|
||||
const QgsRectangle bbox = geom->boundingBox();
|
||||
const double width = bbox.width();
|
||||
const double height = bbox.height();
|
||||
const double size = width > height ? width : height;
|
||||
const double tolerance = size / 100.0;
|
||||
radiusValue = QgsGeos( geom ).maximumInscribedCircle( tolerance )->length();
|
||||
testResult = radiusValue >= minInscribedCircleRadius;
|
||||
radiusValues.append( radiusValues );
|
||||
}
|
||||
#endif
|
||||
} // end for parts
|
||||
|
||||
// Get the max values
|
||||
if ( !radiusValues.isEmpty() )
|
||||
{
|
||||
radiusValue = *std::max_element( radiusValues.cbegin(), radiusValues.cend() );
|
||||
}
|
||||
|
||||
if ( ! overlapValues.isEmpty() )
|
||||
{
|
||||
overlapValue = *std::max_element( overlapValues.cbegin(), overlapValues.cend() );
|
||||
}
|
||||
|
||||
return testResult;
|
||||
|
||||
};
|
||||
|
||||
|
||||
bool found = false;
|
||||
int foundCount = 0;
|
||||
@ -6961,8 +7060,10 @@ static QVariant executeGeomOverlay( const QVariantList &values, const QgsExpress
|
||||
QListIterator<QgsFeature> i( features );
|
||||
while ( i.hasNext() && ( sortByMeasure || limit == -1 || foundCount < limit ) )
|
||||
{
|
||||
|
||||
QgsFeature feat2 = i.next();
|
||||
|
||||
|
||||
if ( ! relationFunction || ( geometry.*relationFunction )( feat2.geometry() ) ) // Calls the method provided as template argument for the function (e.g. QgsGeometry::intersects)
|
||||
{
|
||||
|
||||
@ -6983,57 +7084,7 @@ static QVariant executeGeomOverlay( const QVariantList &values, const QgsExpress
|
||||
{
|
||||
|
||||
// overlap and inscribed circle tests must be checked both (if the values are != -1)
|
||||
bool testResult { false };
|
||||
// For return measures:
|
||||
QVector<double> overlapValues;
|
||||
QVector<double> radiusValues;
|
||||
for ( auto it = intersection.const_parts_begin(); ( ! testResult || requireMeasures ) && it != intersection.const_parts_end(); ++it )
|
||||
{
|
||||
const QgsCurvePolygon *geom = qgsgeometry_cast< const QgsCurvePolygon * >( *it );
|
||||
// Check min overlap for intersection (if set)
|
||||
if ( minOverlap != -1 || requireMeasures )
|
||||
{
|
||||
overlapValue = geom->area();
|
||||
overlapValues.append( geom->area() );
|
||||
if ( minOverlap != - 1 )
|
||||
{
|
||||
if ( overlapValue >= minOverlap )
|
||||
{
|
||||
testResult = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
|
||||
// Check min inscribed circle radius for intersection (if set)
|
||||
if ( minInscribedCircleRadius != -1 || requireMeasures )
|
||||
{
|
||||
const QgsRectangle bbox = geom->boundingBox();
|
||||
const double width = bbox.width();
|
||||
const double height = bbox.height();
|
||||
const double size = width > height ? width : height;
|
||||
const double tolerance = size / 100.0;
|
||||
radiusValue = QgsGeos( geom ).maximumInscribedCircle( tolerance )->length();
|
||||
testResult = radiusValue >= minInscribedCircleRadius;
|
||||
radiusValues.append( radiusValues );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get the max values
|
||||
if ( !radiusValues.isEmpty() )
|
||||
{
|
||||
radiusValue = *std::max_element( radiusValues.cbegin(), radiusValues.cend() );
|
||||
}
|
||||
|
||||
if ( ! overlapValues.isEmpty() )
|
||||
{
|
||||
overlapValue = *std::max_element( overlapValues.cbegin(), overlapValues.cend() );
|
||||
}
|
||||
bool testResult { testPolygon( intersection, radiusValue, overlapValue ) };
|
||||
|
||||
if ( ! testResult && overlapOrRadiusFilter )
|
||||
{
|
||||
@ -7042,37 +7093,11 @@ static QVariant executeGeomOverlay( const QVariantList &values, const QgsExpress
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case QgsWkbTypes::GeometryType::LineGeometry:
|
||||
{
|
||||
bool testResult { false };
|
||||
// For return measures:
|
||||
QVector<double> overlapValues;
|
||||
for ( auto it = intersection.const_parts_begin(); ! testResult && it != intersection.const_parts_end(); ++it )
|
||||
{
|
||||
const QgsCurve *geom = qgsgeometry_cast< const QgsCurve * >( *it );
|
||||
// Check min overlap for intersection (if set)
|
||||
if ( minOverlap != -1 || requireMeasures )
|
||||
{
|
||||
overlapValue = geom->length();
|
||||
overlapValues.append( overlapValue );
|
||||
if ( minOverlap != -1 )
|
||||
{
|
||||
if ( overlapValue >= minOverlap )
|
||||
{
|
||||
testResult = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! overlapValues.isEmpty() )
|
||||
{
|
||||
overlapValue = *std::max_element( overlapValues.cbegin(), overlapValues.cend() );
|
||||
}
|
||||
const bool testResult { testLinestring( intersection, overlapValue ) };
|
||||
|
||||
if ( ! testResult && overlapOrRadiusFilter )
|
||||
{
|
||||
@ -7081,9 +7106,11 @@ static QVariant executeGeomOverlay( const QVariantList &values, const QgsExpress
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case QgsWkbTypes::GeometryType::PointGeometry:
|
||||
{
|
||||
if ( minOverlap != -1 || requireMeasures )
|
||||
bool testResult { false };
|
||||
if ( minOverlap != -1 || requireMeasures )
|
||||
{
|
||||
// Initially set this to 0 because it's a point intersection...
|
||||
overlapValue = 0;
|
||||
@ -7103,18 +7130,18 @@ static QVariant executeGeomOverlay( const QVariantList &values, const QgsExpress
|
||||
}
|
||||
case QgsWkbTypes::GeometryType::LineGeometry:
|
||||
{
|
||||
overlapValue = feat2.geometry().length();
|
||||
testResult = testLinestring( feat2.geometry(), overlapValue );
|
||||
break;
|
||||
}
|
||||
case QgsWkbTypes::GeometryType::PolygonGeometry:
|
||||
{
|
||||
overlapValue = feat2.geometry().area();
|
||||
testResult = testPolygon( feat2.geometry(), radiusValue, overlapValue );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( minOverlap != -1 && overlapValue < minOverlap )
|
||||
if ( ! testResult && overlapOrRadiusFilter )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -7122,6 +7149,7 @@ static QVariant executeGeomOverlay( const QVariantList &values, const QgsExpress
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case QgsWkbTypes::GeometryType::NullGeometry:
|
||||
case QgsWkbTypes::GeometryType::UnknownGeometry:
|
||||
{
|
||||
|
||||
@ -297,10 +297,12 @@ void TestQgsOverlayExpression::testOverlayMeasure_data()
|
||||
expected3.insert( QStringLiteral( "id" ), 3LL );
|
||||
expected3.insert( QStringLiteral( "result" ), 3 );
|
||||
expected3.insert( QStringLiteral( "overlap" ), 19.049688572712284 );
|
||||
expected3.insert( QStringLiteral( "radius" ), 1.3414663642343596 );
|
||||
QVariantMap expected1;
|
||||
expected1.insert( QStringLiteral( "id" ), 1LL );
|
||||
expected1.insert( QStringLiteral( "result" ), 1 );
|
||||
expected1.insert( QStringLiteral( "overlap" ), 18.569843123334977 );
|
||||
expected1.insert( QStringLiteral( "radius" ), 1.8924012738149243 );
|
||||
|
||||
QTest::newRow( "intersects multi match points return sorted" ) << "overlay_intersects('polys', sort_by_intersection_size:='des', return_details:=true, expression:=$id)" << "MULTIPOINT((-107.37 33.75), (-102.8 36.97))" << ( QVariantList() << expected3 << expected1 ) ;
|
||||
|
||||
@ -338,7 +340,6 @@ void TestQgsOverlayExpression::testOverlayMeasure_data()
|
||||
|
||||
QTest::newRow( "intersects linestring multi match measure sorted" ) << "overlay_intersects('polys', return_details:=true, sort_by_intersection_size:='des', expression:=$id)" << "LINESTRING(-102.76 33.74, -102.76 36.44)" << ( QVariantList() << expectedLine3 << expectedLine1 );
|
||||
|
||||
|
||||
// Test linestring intersections
|
||||
{
|
||||
QVariantMap expectedLine1;
|
||||
@ -351,6 +352,8 @@ void TestQgsOverlayExpression::testOverlayMeasure_data()
|
||||
expectedLine2.insert( QStringLiteral( "overlap" ), 0 );
|
||||
|
||||
QTest::newRow( "intersects linestring single match" ) << "overlay_intersects('linestrings', return_details:=true, expression:=$id)" << "LINESTRING(1.5 1, 1.5 -1)" << ( QVariantList() << expectedLine1 );
|
||||
|
||||
|
||||
QTest::newRow( "intersects linestring single match fail overlap" ) << "overlay_intersects('linestrings', min_overlap:=0.5, return_details:=true, expression:=$id)" << "LINESTRING(1.5 1, 1.5 -1)" << ( QVariantList() );
|
||||
QTest::newRow( "intersects linestring no match" ) << "overlay_intersects('linestrings', return_details:=true, expression:=$id)" << "LINESTRING(1.5 2, 1.5 1)" << ( QVariantList() );
|
||||
QTest::newRow( "intersects linestring multi match" ) << "overlay_intersects('linestrings', return_details:=true, expression:=$id)" << "LINESTRING(1.5 1, 1.5 -1, 4 -1, 4 1)" << ( QVariantList() << expectedLine1 << expectedLine2 );
|
||||
@ -381,6 +384,8 @@ void TestQgsOverlayExpression::testOverlayMeasure_data()
|
||||
QTest::newRow( "intersects points multi match" ) << "overlay_intersects('points', return_details:=true, expression:=$id)" << "POLYGON((0 -1, 3.5 -1, 3.5 1, 0 1, 0 -1))" << ( QVariantList() << expectedPoint1 << expectedPoint2 );
|
||||
}
|
||||
|
||||
// Test polygon intersection resulting in a point with min_inscribed_circle_radius and expression
|
||||
QTest::newRow( "intersects point expression no match" ) << "overlay_intersects('polys', expression:=$id, min_inscribed_circle_radius:=0.5, sort_by_intersection_size:='desc')" << "POLYGON((-90.825 34.486, -89.981 35.059, -90.009 33.992, -90.825 34.486))" << ( QVariantList() );
|
||||
}
|
||||
|
||||
void TestQgsOverlayExpression::testOverlayExpression()
|
||||
|
||||
BIN
tests/testdata/polys_overlapping_with_id.dbf
vendored
BIN
tests/testdata/polys_overlapping_with_id.dbf
vendored
Binary file not shown.
BIN
tests/testdata/polys_overlapping_with_id.shp
vendored
BIN
tests/testdata/polys_overlapping_with_id.shp
vendored
Binary file not shown.
BIN
tests/testdata/polys_overlapping_with_id.shx
vendored
BIN
tests/testdata/polys_overlapping_with_id.shx
vendored
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user