mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -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 void setExteriorRing( QgsCurve* ring /Transfer/ );
|
||||||
|
|
||||||
virtual QgsAbstractGeometry* boundary() const /Factory/;
|
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
|
QgsPolygonV2* QgsPolygonV2::surfaceToPolygon() const
|
||||||
{
|
{
|
||||||
return clone();
|
return clone();
|
||||||
|
@ -60,5 +60,13 @@ class CORE_EXPORT QgsPolygonV2: public QgsCurvePolygon
|
|||||||
|
|
||||||
virtual QgsAbstractGeometry* boundary() const override;
|
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
|
#endif // QGSPOLYGONV2_H
|
||||||
|
@ -3026,6 +3026,29 @@ void TestQgsGeometry::polygon()
|
|||||||
QCOMPARE( lineBoundary->zAt( 3 ), 10.0 );
|
QCOMPARE( lineBoundary->zAt( 3 ), 10.0 );
|
||||||
delete boundary;
|
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()
|
void TestQgsGeometry::multiPoint()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user