mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-09 00:08:52 -04:00
Expose GEOS constrainedDelaunayTriangulation to QgsGeometry
Allows calling this method when QGIS is built against supported GEOS versions (>= 3.11)
This commit is contained in:
parent
fa6c41fd74
commit
45e51c2a55
@ -1807,7 +1807,24 @@ If ``edgesOnly`` is ``True`` than line string boundary geometries will be return
|
|||||||
instead of polygons.
|
instead of polygons.
|
||||||
An empty geometry will be returned if the diagram could not be calculated.
|
An empty geometry will be returned if the diagram could not be calculated.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`constrainedDelaunayTriangulation`
|
||||||
|
|
||||||
.. versionadded:: 3.0
|
.. versionadded:: 3.0
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsGeometry constrainedDelaunayTriangulation() const throw( QgsNotSupportedException );
|
||||||
|
%Docstring
|
||||||
|
Returns a constrained Delaunay triangulation for the vertices of the geometry.
|
||||||
|
|
||||||
|
An empty geometry will be returned if the triangulation could not be calculated.
|
||||||
|
|
||||||
|
This method requires a QGIS build based on GEOS 3.11 or later.
|
||||||
|
|
||||||
|
:raises QgsNotSupportedException: on QGIS builds based on GEOS 3.10 or earlier.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`delaunayTriangulation`
|
||||||
|
|
||||||
|
.. versionadded:: 3.36
|
||||||
%End
|
%End
|
||||||
|
|
||||||
Qgis::CoverageValidityResult validateCoverage( double gapWidth, QgsGeometry *invalidEdges /Out/ = 0 ) const throw( QgsNotSupportedException );
|
Qgis::CoverageValidityResult validateCoverage( double gapWidth, QgsGeometry *invalidEdges /Out/ = 0 ) const throw( QgsNotSupportedException );
|
||||||
|
@ -1807,7 +1807,24 @@ If ``edgesOnly`` is ``True`` than line string boundary geometries will be return
|
|||||||
instead of polygons.
|
instead of polygons.
|
||||||
An empty geometry will be returned if the diagram could not be calculated.
|
An empty geometry will be returned if the diagram could not be calculated.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`constrainedDelaunayTriangulation`
|
||||||
|
|
||||||
.. versionadded:: 3.0
|
.. versionadded:: 3.0
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsGeometry constrainedDelaunayTriangulation() const throw( QgsNotSupportedException );
|
||||||
|
%Docstring
|
||||||
|
Returns a constrained Delaunay triangulation for the vertices of the geometry.
|
||||||
|
|
||||||
|
An empty geometry will be returned if the triangulation could not be calculated.
|
||||||
|
|
||||||
|
This method requires a QGIS build based on GEOS 3.11 or later.
|
||||||
|
|
||||||
|
:raises QgsNotSupportedException: on QGIS builds based on GEOS 3.10 or earlier.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`delaunayTriangulation`
|
||||||
|
|
||||||
|
.. versionadded:: 3.36
|
||||||
%End
|
%End
|
||||||
|
|
||||||
Qgis::CoverageValidityResult validateCoverage( double gapWidth, QgsGeometry *invalidEdges /Out/ = 0 ) const throw( QgsNotSupportedException );
|
Qgis::CoverageValidityResult validateCoverage( double gapWidth, QgsGeometry *invalidEdges /Out/ = 0 ) const throw( QgsNotSupportedException );
|
||||||
|
@ -2641,6 +2641,20 @@ QgsGeometry QgsGeometry::delaunayTriangulation( double tolerance, bool edgesOnly
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsGeometry QgsGeometry::constrainedDelaunayTriangulation() const
|
||||||
|
{
|
||||||
|
if ( !d->geometry )
|
||||||
|
{
|
||||||
|
return QgsGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsGeos geos( d->geometry.get() );
|
||||||
|
mLastError.clear();
|
||||||
|
QgsGeometry result( geos.constrainedDelaunayTriangulation() );
|
||||||
|
result.mLastError = mLastError;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
QgsGeometry QgsGeometry::unionCoverage() const
|
QgsGeometry QgsGeometry::unionCoverage() const
|
||||||
{
|
{
|
||||||
if ( !d->geometry )
|
if ( !d->geometry )
|
||||||
|
@ -1829,10 +1829,26 @@ class CORE_EXPORT QgsGeometry
|
|||||||
* If \a edgesOnly is TRUE than line string boundary geometries will be returned
|
* If \a edgesOnly is TRUE than line string boundary geometries will be returned
|
||||||
* instead of polygons.
|
* instead of polygons.
|
||||||
* An empty geometry will be returned if the diagram could not be calculated.
|
* An empty geometry will be returned if the diagram could not be calculated.
|
||||||
|
*
|
||||||
|
* \see constrainedDelaunayTriangulation()
|
||||||
* \since QGIS 3.0
|
* \since QGIS 3.0
|
||||||
*/
|
*/
|
||||||
QgsGeometry delaunayTriangulation( double tolerance = 0.0, bool edgesOnly = false ) const;
|
QgsGeometry delaunayTriangulation( double tolerance = 0.0, bool edgesOnly = false ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a constrained Delaunay triangulation for the vertices of the geometry.
|
||||||
|
*
|
||||||
|
* An empty geometry will be returned if the triangulation could not be calculated.
|
||||||
|
*
|
||||||
|
* This method requires a QGIS build based on GEOS 3.11 or later.
|
||||||
|
*
|
||||||
|
* \throws QgsNotSupportedException on QGIS builds based on GEOS 3.10 or earlier.
|
||||||
|
* \see delaunayTriangulation()
|
||||||
|
*
|
||||||
|
* \since QGIS 3.36
|
||||||
|
*/
|
||||||
|
QgsGeometry constrainedDelaunayTriangulation() const SIP_THROW( QgsNotSupportedException );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyze a coverage (represented as a collection of polygonal geometry with exactly matching edge
|
* Analyze a coverage (represented as a collection of polygonal geometry with exactly matching edge
|
||||||
* geometry) to find places where the assumption of exactly matching edges is not met.
|
* geometry) to find places where the assumption of exactly matching edges is not met.
|
||||||
|
@ -3066,6 +3066,40 @@ QgsGeometry QgsGeos::delaunayTriangulation( double tolerance, bool edgesOnly, QS
|
|||||||
CATCH_GEOS_WITH_ERRMSG( QgsGeometry() )
|
CATCH_GEOS_WITH_ERRMSG( QgsGeometry() )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<QgsAbstractGeometry> QgsGeos::constrainedDelaunayTriangulation( QString *errorMsg ) const
|
||||||
|
{
|
||||||
|
#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
|
||||||
|
( void )errorMsg;
|
||||||
|
throw QgsNotSupportedException( QObject::tr( "Calculating constrainedDelaunayTriangulation requires a QGIS build based on GEOS 3.11 or later" ) );
|
||||||
|
#else
|
||||||
|
if ( !mGeos )
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
geos::unique_ptr geos;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
geos.reset( GEOSConstrainedDelaunayTriangulation_r( geosinit()->ctxt, mGeos.get() ) );
|
||||||
|
|
||||||
|
if ( !geos || GEOSisEmpty_r( geosinit()->ctxt, geos.get() ) != 0 )
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr< QgsAbstractGeometry > res = fromGeos( geos.get() );
|
||||||
|
if ( const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( res.get() ) )
|
||||||
|
{
|
||||||
|
return std::unique_ptr< QgsAbstractGeometry >( collection->extractPartsByType( Qgis::WkbType::Polygon, true ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CATCH_GEOS_WITH_ERRMSG( nullptr )
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
//! Extract coordinates of linestring's endpoints. Returns false on error.
|
//! Extract coordinates of linestring's endpoints. Returns false on error.
|
||||||
static bool _linestringEndpoints( const GEOSGeometry *linestring, double &x1, double &y1, double &x2, double &y2 )
|
static bool _linestringEndpoints( const GEOSGeometry *linestring, double &x1, double &y1, double &x2, double &y2 )
|
||||||
|
@ -547,10 +547,25 @@ class CORE_EXPORT QgsGeos: public QgsGeometryEngine
|
|||||||
* If \a edgesOnly is TRUE than line string boundary geometries will be returned
|
* If \a edgesOnly is TRUE than line string boundary geometries will be returned
|
||||||
* instead of polygons.
|
* instead of polygons.
|
||||||
* An empty geometry will be returned if the diagram could not be calculated.
|
* An empty geometry will be returned if the diagram could not be calculated.
|
||||||
|
* \see constrainedDelaunayTriangulation()
|
||||||
* \since QGIS 3.0
|
* \since QGIS 3.0
|
||||||
*/
|
*/
|
||||||
QgsGeometry delaunayTriangulation( double tolerance = 0.0, bool edgesOnly = false, QString *errorMsg = nullptr ) const;
|
QgsGeometry delaunayTriangulation( double tolerance = 0.0, bool edgesOnly = false, QString *errorMsg = nullptr ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a constrained Delaunay triangulation for the vertices of the geometry.
|
||||||
|
*
|
||||||
|
* An empty geometry will be returned if the triangulation could not be calculated.
|
||||||
|
*
|
||||||
|
* This method requires a QGIS build based on GEOS 3.11 or later.
|
||||||
|
*
|
||||||
|
* \throws QgsNotSupportedException on QGIS builds based on GEOS 3.10 or earlier.
|
||||||
|
* \see delaunayTriangulation()
|
||||||
|
*
|
||||||
|
* \since QGIS 3.36
|
||||||
|
*/
|
||||||
|
std::unique_ptr< QgsAbstractGeometry > constrainedDelaunayTriangulation( QString *errorMsg = nullptr ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a possibly concave geometry that encloses the input geometry.
|
* Returns a possibly concave geometry that encloses the input geometry.
|
||||||
*
|
*
|
||||||
|
@ -7545,6 +7545,31 @@ class TestQgsGeometry(QgisTestCase):
|
|||||||
self.assertEqual(res_isClockwise, False)
|
self.assertEqual(res_isClockwise, False)
|
||||||
self.assertEqual(res_isCounterClockwise, True)
|
self.assertEqual(res_isCounterClockwise, True)
|
||||||
|
|
||||||
|
@unittest.skipIf(Qgis.geosVersionInt() < 31100, "GEOS 3.11 required")
|
||||||
|
def testConstrainedDelaunayTriangulation(self):
|
||||||
|
"""
|
||||||
|
Test QgsGeometry.constrainedDelaunayTriangulation
|
||||||
|
"""
|
||||||
|
empty = QgsGeometry()
|
||||||
|
o = empty.constrainedDelaunayTriangulation()
|
||||||
|
self.assertFalse(o)
|
||||||
|
line = QgsGeometry.fromWkt('LineString EMPTY')
|
||||||
|
o = line.constrainedDelaunayTriangulation()
|
||||||
|
self.assertFalse(o)
|
||||||
|
|
||||||
|
input = QgsGeometry.fromWkt("MULTIPOINT ((10 10), (10 20), (20 20))")
|
||||||
|
o = input.constrainedDelaunayTriangulation()
|
||||||
|
self.assertTrue(o.isNull())
|
||||||
|
|
||||||
|
input = QgsGeometry.fromWkt(
|
||||||
|
"POLYGON ((42 30, 41.96 29.61, 41.85 29.23, 41.66 28.89, 41.41 28.59, 41.11 28.34, 40.77 28.15, 40.39 28.04, 40 28, 39.61 28.04, 39.23 28.15, 38.89 28.34, 38.59 28.59, 38.34 28.89, 38.15 29.23, 38.04 29.61, 38 30, 38.04 30.39, 38.15 30.77, 38.34 31.11, 38.59 31.41, 38.89 31.66, 39.23 31.85, 39.61 31.96, 40 32, 40.39 31.96, 40.77 31.85, 41.11 31.66, 41.41 31.41, 41.66 31.11, 41.85 30.77, 41.96 30.39, 42 30))")
|
||||||
|
o = input.constrainedDelaunayTriangulation()
|
||||||
|
o.normalize()
|
||||||
|
self.assertEqual(
|
||||||
|
o.asWkt(2),
|
||||||
|
"MultiPolygon (((41.96 29.61, 41.96 30.39, 42 30, 41.96 29.61)),((41.66 31.11, 41.85 30.77, 41.96 30.39, 41.66 31.11)),((41.66 28.89, 41.96 29.61, 41.85 29.23, 41.66 28.89)),((41.41 31.41, 41.96 30.39, 41.96 29.61, 41.41 31.41)),((41.41 31.41, 41.66 31.11, 41.96 30.39, 41.41 31.41)),((41.41 28.59, 41.96 29.61, 41.66 28.89, 41.41 28.59)),((41.41 28.59, 41.41 31.41, 41.96 29.61, 41.41 28.59)),((40.39 31.96, 41.11 31.66, 41.41 31.41, 40.39 31.96)),((40.39 31.96, 40.77 31.85, 41.11 31.66, 40.39 31.96)),((40.39 28.04, 41.41 28.59, 41.11 28.34, 40.39 28.04)),((40.39 28.04, 41.11 28.34, 40.77 28.15, 40.39 28.04)),((39.61 31.96, 40.39 31.96, 41.41 31.41, 39.61 31.96)),((39.61 31.96, 40 32, 40.39 31.96, 39.61 31.96)),((39.61 28.04, 40.39 28.04, 40 28, 39.61 28.04)),((38.89 31.66, 39.23 31.85, 39.61 31.96, 38.89 31.66)),((38.89 28.34, 39.61 28.04, 39.23 28.15, 38.89 28.34)),((38.59 31.41, 41.41 31.41, 41.41 28.59, 38.59 31.41)),((38.59 31.41, 39.61 31.96, 41.41 31.41, 38.59 31.41)),((38.59 31.41, 38.89 31.66, 39.61 31.96, 38.59 31.41)),((38.59 28.59, 41.41 28.59, 40.39 28.04, 38.59 28.59)),((38.59 28.59, 40.39 28.04, 39.61 28.04, 38.59 28.59)),((38.59 28.59, 39.61 28.04, 38.89 28.34, 38.59 28.59)),((38.59 28.59, 38.59 31.41, 41.41 28.59, 38.59 28.59)),((38.04 30.39, 38.59 31.41, 38.59 28.59, 38.04 30.39)),((38.04 30.39, 38.34 31.11, 38.59 31.41, 38.04 30.39)),((38.04 30.39, 38.15 30.77, 38.34 31.11, 38.04 30.39)),((38.04 29.61, 38.59 28.59, 38.34 28.89, 38.04 29.61)),((38.04 29.61, 38.34 28.89, 38.15 29.23, 38.04 29.61)),((38.04 29.61, 38.04 30.39, 38.59 28.59, 38.04 29.61)),((38 30, 38.04 30.39, 38.04 29.61, 38 30)))"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user