mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-17 00:04:02 -04:00
Add method to find distance from a point to a poylgon's boundary
This commit is contained in:
parent
1d3f1f07e8
commit
d5c307eb05
@ -35,4 +35,12 @@ class QgsPolygonV2: public QgsCurvePolygon
|
||||
virtual void setExteriorRing( QgsCurve* ring /Transfer/ );
|
||||
|
||||
virtual QgsAbstractGeometry* boundary() const /Factory/;
|
||||
|
||||
/**
|
||||
* Returns the distance from a point to the boundary of the polygon (either the
|
||||
* exterior ring or any closer interior rings). The returned distance will be
|
||||
* negative if the point lies outside the polygon.
|
||||
* @note added in QGIS 3.0
|
||||
*/
|
||||
double pointDistanceToBoundary( double x, double y ) const;
|
||||
};
|
||||
|
@ -261,6 +261,40 @@ QgsAbstractGeometry* QgsPolygonV2::boundary() const
|
||||
}
|
||||
}
|
||||
|
||||
double QgsPolygonV2::pointDistanceToBoundary( double x, double y ) const
|
||||
{
|
||||
if ( !mExteriorRing )
|
||||
return std::numeric_limits< double >::quiet_NaN();
|
||||
|
||||
bool inside = false;
|
||||
double minimumDistance = DBL_MAX;
|
||||
double minDistX = 0.0;
|
||||
double minDistY = 0.0;
|
||||
|
||||
int numRings = mInteriorRings.size() + 1;
|
||||
for ( int ringIndex = 0; ringIndex < numRings; ++ringIndex )
|
||||
{
|
||||
const QgsLineString* ring = static_cast< const QgsLineString* >( ringIndex == 0 ? mExteriorRing : mInteriorRings.at( ringIndex - 1 ) );
|
||||
|
||||
int len = ring->numPoints() - 1; //assume closed
|
||||
for ( int i = 0, j = len - 1; i < len; j = i++ )
|
||||
{
|
||||
double aX = ring->xAt( i );
|
||||
double aY = ring->yAt( i );
|
||||
double bX = ring->xAt( j );
|
||||
double bY = ring->yAt( j );
|
||||
|
||||
if ((( aY > y ) != ( bY > y ) ) &&
|
||||
( x < ( bX - aX ) * ( y - aY ) / ( bY - aY ) + aX ) )
|
||||
inside = !inside;
|
||||
|
||||
minimumDistance = qMin( minimumDistance, QgsGeometryUtils::sqrDistToLine( x, y, aX, aY, bX, bY, minDistX, minDistY, 4 * DBL_EPSILON ) );
|
||||
}
|
||||
}
|
||||
|
||||
return ( inside ? 1 : -1 ) * sqrt( minimumDistance );
|
||||
}
|
||||
|
||||
QgsPolygonV2* QgsPolygonV2::surfaceToPolygon() const
|
||||
{
|
||||
return clone();
|
||||
|
@ -60,5 +60,13 @@ class CORE_EXPORT QgsPolygonV2: public QgsCurvePolygon
|
||||
|
||||
virtual QgsAbstractGeometry* boundary() const override;
|
||||
|
||||
/**
|
||||
* Returns the distance from a point to the boundary of the polygon (either the
|
||||
* exterior ring or any closer interior rings). The returned distance will be
|
||||
* negative if the point lies outside the polygon.
|
||||
* @note added in QGIS 3.0
|
||||
*/
|
||||
double pointDistanceToBoundary( double x, double y ) const;
|
||||
|
||||
};
|
||||
#endif // QGSPOLYGONV2_H
|
||||
|
@ -3026,6 +3026,29 @@ void TestQgsGeometry::polygon()
|
||||
QCOMPARE( lineBoundary->zAt( 3 ), 10.0 );
|
||||
delete boundary;
|
||||
|
||||
// point distance to boundary
|
||||
|
||||
QgsLineString pd1;
|
||||
pd1.setPoints( QList<QgsPointV2>() << QgsPointV2( 0, 0 ) << QgsPointV2( 1, 0 ) << QgsPointV2( 1, 1 ) << QgsPointV2( 0, 1 ) << QgsPointV2( 0, 0 ) );
|
||||
QgsPolygonV2 pd;
|
||||
// no meaning, but let's not crash
|
||||
( void )pd.pointDistanceToBoundary( 0, 0 );
|
||||
|
||||
pd.setExteriorRing( pd1.clone() );
|
||||
QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0, 0.5 ), 0.0, 0.0000000001 );
|
||||
QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0.1, 0.5 ), 0.1, 0.0000000001 );
|
||||
QGSCOMPARENEAR( pd.pointDistanceToBoundary( -0.1, 0.5 ), -0.1, 0.0000000001 );
|
||||
// with a ring
|
||||
QgsLineString pdRing1;
|
||||
pdRing1.setPoints( QList<QgsPointV2>() << QgsPointV2( 0.1, 0.1 ) << QgsPointV2( 0.2, 0.1 ) << QgsPointV2( 0.2, 0.6 ) << QgsPointV2( 0.1, 0.6 ) << QgsPointV2( 0.1, 0.1 ) );
|
||||
pd.setInteriorRings( QList< QgsCurve* >() << pdRing1.clone() );
|
||||
QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0, 0.5 ), 0.0, 0.0000000001 );
|
||||
QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0.1, 0.5 ), 0.0, 0.0000000001 );
|
||||
QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0.01, 0.5 ), 0.01, 0.0000000001 );
|
||||
QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0.08, 0.5 ), 0.02, 0.0000000001 );
|
||||
QGSCOMPARENEAR( pd.pointDistanceToBoundary( 0.12, 0.5 ), -0.02, 0.0000000001 );
|
||||
QGSCOMPARENEAR( pd.pointDistanceToBoundary( -0.1, 0.5 ), -0.1, 0.0000000001 );
|
||||
|
||||
}
|
||||
|
||||
void TestQgsGeometry::multiPoint()
|
||||
|
Loading…
x
Reference in New Issue
Block a user