Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Better docs and examples for QgsGeometryEngine class
  • Loading branch information
nyalldawson committed Jun 16, 2021
1 parent 7263d67 commit 480c2eb
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 6 deletions.
87 changes: 85 additions & 2 deletions python/core/auto_generated/geometry/qgsgeometry.sip.in
Expand Up @@ -1081,6 +1081,13 @@ and can be slow for complex geometries.
The GEOS library is used to perform the intersection test. Geometries which are not
valid may return incorrect results.

.. note::

For performance critical code, or when testing for intersection against many different
geometries, consider using :py:class:`QgsGeometryEngine` instead. This approach can be many orders of magnitude
faster than calling :py:func:`~QgsGeometry.intersects` directly. See :py:func:`~QgsGeometry.createGeometryEngine` for details on how to use the
:py:class:`QgsGeometryEngine` class.

.. seealso:: :py:func:`boundingBoxIntersects`
%End

Expand Down Expand Up @@ -1115,42 +1122,83 @@ Returns ``True`` if the geometry contains the point ``p``.
%Docstring
Returns ``True`` if the geometry completely contains another ``geometry``.

.. note::

For performance critical code, or when testing for contains against many different
geometries, consider using :py:class:`QgsGeometryEngine` instead. This approach can be many orders of magnitude
faster than calling :py:func:`~QgsGeometry.contains` directly. See :py:func:`~QgsGeometry.createGeometryEngine` for details on how to use the
:py:class:`QgsGeometryEngine` class.

.. versionadded:: 1.5
%End

bool disjoint( const QgsGeometry &geometry ) const;
%Docstring
Returns ``True`` if the geometry is disjoint of another ``geometry``.

.. note::

For performance critical code, or when testing for disjoint against many different
geometries, consider using :py:class:`QgsGeometryEngine` instead. This approach can be many orders of magnitude
faster than calling :py:func:`~QgsGeometry.disjoint` directly. See :py:func:`~QgsGeometry.createGeometryEngine` for details on how to use the
:py:class:`QgsGeometryEngine` class.

.. versionadded:: 1.5
%End

bool touches( const QgsGeometry &geometry ) const;
%Docstring
Returns ``True`` if the geometry touches another ``geometry``.

.. note::

For performance critical code, or when testing for touches against many different
geometries, consider using :py:class:`QgsGeometryEngine` instead. This approach can be many orders of magnitude
faster than calling :py:func:`~QgsGeometry.touches` directly. See :py:func:`~QgsGeometry.createGeometryEngine` for details on how to use the
:py:class:`QgsGeometryEngine` class.

.. versionadded:: 1.5
%End

bool overlaps( const QgsGeometry &geometry ) const;
%Docstring
Returns ``True`` if the geometry overlaps another ``geometry``.

.. note::

For performance critical code, or when testing for overlaps against many different
geometries, consider using :py:class:`QgsGeometryEngine` instead. This approach can be many orders of magnitude
faster than calling :py:func:`~QgsGeometry.overlaps` directly. See :py:func:`~QgsGeometry.createGeometryEngine` for details on how to use the
:py:class:`QgsGeometryEngine` class.

.. versionadded:: 1.5
%End

bool within( const QgsGeometry &geometry ) const;
%Docstring
Returns ``True`` if the geometry is completely within another ``geometry``.

.. note::

For performance critical code, or when testing for within against many different
geometries, consider using :py:class:`QgsGeometryEngine` instead. This approach can be many orders of magnitude
faster than calling :py:func:`~QgsGeometry.within` directly. See :py:func:`~QgsGeometry.createGeometryEngine` for details on how to use the
:py:class:`QgsGeometryEngine` class.

.. versionadded:: 1.5
%End


bool crosses( const QgsGeometry &geometry ) const;
%Docstring
Returns ``True`` if the geometry crosses another ``geometry``.

.. note::

For performance critical code, or when testing for crosses against many different
geometries, consider using :py:class:`QgsGeometryEngine` instead. This approach can be many orders of magnitude
faster than calling :py:func:`~QgsGeometry.crosses` directly. See :py:func:`~QgsGeometry.createGeometryEngine` for details on how to use the
:py:class:`QgsGeometryEngine` class.

.. versionadded:: 1.5
%End

Expand Down Expand Up @@ -2496,7 +2544,42 @@ geometry will retain the same dimensionality as the input geometry.

static QgsGeometryEngine *createGeometryEngine( const QgsAbstractGeometry *geometry ) /Factory/;
%Docstring
Creates and returns a new geometry engine
Creates and returns a new geometry engine representing the specified ``geometry``.

A geometry engine is a low-level representation of a :py:class:`QgsAbstractGeometry` object, optimised for use with external
geometry libraries such as GEOS.

:py:class:`QgsGeometryEngine` objects provide a mechanism for optimized evaluation of geometric algorithms, including spatial relationships
between geometries and operations such as buffers or clipping. :py:class:`QgsGeometryEngine` is recommended for use in any
performance critical code instead of directly using the equivalent QgsGeometry methods such as :py:func:`QgsGeometry.intersects()`.

Many methods available in the :py:class:`QgsGeometryEngine` class can benefit from pre-preparing geometries. For instance, whenever
a large number of spatial relationships will be tested (such as calling :py:func:`~QgsGeometry.intersects`, :py:func:`~QgsGeometry.within`, etc) then the
geometry should first be prepared by calling :py:func:`~QgsGeometry.prepareGeometry` before performing the tests.

Example
-------

.. code-block:: python

# polygon_geometry contains a complex polygon, with many vertices
polygon_geometry = QgsGeometry.fromWkt('Polygon((...))')

# create a QgsGeometryEngine representation of the polygon
polygon_geometry_engine = QgsGeometry.createGeometryEngine(polygon_geometry.constGet())

# since we'll be performing many intersects tests, we can speed up these tests considerably
# by first "preparing" the geometry engine
polygon_geometry_engine.prepareGeometry()

# now we are ready to quickly test intersection against many other objects
for feature in my_layer.getFeatures():
feature_geometry = feature.geometry()
# test whether the feature's geometry intersects our original complex polygon
if polygon_geometry_engine.intersects(feature_geometry.constGet()):
print('feature intersects the polygon!')

:py:class:`QgsGeometryEngine` operations are backed by the GEOS library (https://trac.osgeo.org/geos/).
%End

static void convertPointList( const QVector<QgsPointXY> &input, QgsPointSequence &output );
Expand Down
37 changes: 36 additions & 1 deletion python/core/auto_generated/geometry/qgsgeometryengine.sip.in
Expand Up @@ -13,7 +13,42 @@
class QgsGeometryEngine
{
%Docstring(signature="appended")
Contains geometry relation and modification algorithms.
A geometry engine is a low-level representation of a :py:class:`QgsAbstractGeometry` object, optimised for use with external
geometry libraries such as GEOS.

:py:class:`QgsGeometryEngine` objects provide a mechanism for optimized evaluation of geometric algorithms, including spatial relationships
between geometries and operations such as buffers or clipping.

:py:class:`QgsGeometryEngine` objects are not created directly, but are instead created by calling :py:func:`QgsGeometry.createGeometryEngine()`.

Many methods available in the :py:class:`QgsGeometryEngine` class can benefit from pre-preparing geometries. For instance, whenever
a large number of spatial relationships will be tested (such as calling :py:func:`~intersects`, :py:func:`~within`, etc) then the
geometry should first be prepared by calling :py:func:`~prepareGeometry` before performing the tests.

Example
-------

.. code-block:: python

# polygon_geometry contains a complex polygon, with many vertices
polygon_geometry = QgsGeometry.fromWkt('Polygon((...))')

# create a QgsGeometryEngine representation of the polygon
polygon_geometry_engine = QgsGeometry.createGeometryEngine(polygon_geometry.constGet())

# since we'll be performing many intersects tests, we can speed up these tests considerably
# by first "preparing" the geometry engine
polygon_geometry_engine.prepareGeometry()

# now we are ready to quickly test intersection against many other objects
for feature in my_layer.getFeatures():
feature_geometry = feature.geometry()
# test whether the feature's geometry intersects our original complex polygon
if polygon_geometry_engine.intersects(feature_geometry.constGet()):
print('feature intersects the polygon!')

:py:class:`QgsGeometryEngine` operations are backed by the GEOS library (https://trac.osgeo.org/geos/).


.. versionadded:: 2.10
%End
Expand Down
78 changes: 76 additions & 2 deletions src/core/geometry/qgsgeometry.h
Expand Up @@ -1114,6 +1114,11 @@ class CORE_EXPORT QgsGeometry
* The GEOS library is used to perform the intersection test. Geometries which are not
* valid may return incorrect results.
*
* \note For performance critical code, or when testing for intersection against many different
* geometries, consider using QgsGeometryEngine instead. This approach can be many orders of magnitude
* faster than calling intersects() directly. See createGeometryEngine() for details on how to use the
* QgsGeometryEngine class.
*
* \see boundingBoxIntersects()
*/
bool intersects( const QgsGeometry &geometry ) const;
Expand Down Expand Up @@ -1147,37 +1152,72 @@ class CORE_EXPORT QgsGeometry

/**
* Returns TRUE if the geometry completely contains another \a geometry.
*
* \note For performance critical code, or when testing for contains against many different
* geometries, consider using QgsGeometryEngine instead. This approach can be many orders of magnitude
* faster than calling contains() directly. See createGeometryEngine() for details on how to use the
* QgsGeometryEngine class.
*
* \since QGIS 1.5
*/
bool contains( const QgsGeometry &geometry ) const;

/**
* Returns TRUE if the geometry is disjoint of another \a geometry.
*
* \note For performance critical code, or when testing for disjoint against many different
* geometries, consider using QgsGeometryEngine instead. This approach can be many orders of magnitude
* faster than calling disjoint() directly. See createGeometryEngine() for details on how to use the
* QgsGeometryEngine class.
*
* \since QGIS 1.5
*/
bool disjoint( const QgsGeometry &geometry ) const;

/**
* Returns TRUE if the geometry touches another \a geometry.
*
* \note For performance critical code, or when testing for touches against many different
* geometries, consider using QgsGeometryEngine instead. This approach can be many orders of magnitude
* faster than calling touches() directly. See createGeometryEngine() for details on how to use the
* QgsGeometryEngine class.
*
* \since QGIS 1.5
*/
bool touches( const QgsGeometry &geometry ) const;

/**
* Returns TRUE if the geometry overlaps another \a geometry.
*
* \note For performance critical code, or when testing for overlaps against many different
* geometries, consider using QgsGeometryEngine instead. This approach can be many orders of magnitude
* faster than calling overlaps() directly. See createGeometryEngine() for details on how to use the
* QgsGeometryEngine class.
*
* \since QGIS 1.5
*/
bool overlaps( const QgsGeometry &geometry ) const;

/**
* Returns TRUE if the geometry is completely within another \a geometry.
*
* \note For performance critical code, or when testing for within against many different
* geometries, consider using QgsGeometryEngine instead. This approach can be many orders of magnitude
* faster than calling within() directly. See createGeometryEngine() for details on how to use the
* QgsGeometryEngine class.
*
* \since QGIS 1.5
*/
bool within( const QgsGeometry &geometry ) const;


/**
* Returns TRUE if the geometry crosses another \a geometry.
*
* \note For performance critical code, or when testing for crosses against many different
* geometries, consider using QgsGeometryEngine instead. This approach can be many orders of magnitude
* faster than calling crosses() directly. See createGeometryEngine() for details on how to use the
* QgsGeometryEngine class.
*
* \since QGIS 1.5
*/
bool crosses( const QgsGeometry &geometry ) const;
Expand Down Expand Up @@ -2626,7 +2666,41 @@ class CORE_EXPORT QgsGeometry
double minimumDistance = -1.0, double maxAngle = 180.0 ) const;

/**
* Creates and returns a new geometry engine
* Creates and returns a new geometry engine representing the specified \a geometry.
*
* A geometry engine is a low-level representation of a QgsAbstractGeometry object, optimised for use with external
* geometry libraries such as GEOS.
*
* QgsGeometryEngine objects provide a mechanism for optimized evaluation of geometric algorithms, including spatial relationships
* between geometries and operations such as buffers or clipping. QgsGeometryEngine is recommended for use in any
* performance critical code instead of directly using the equivalent QgsGeometry methods such as QgsGeometry::intersects().
*
* Many methods available in the QgsGeometryEngine class can benefit from pre-preparing geometries. For instance, whenever
* a large number of spatial relationships will be tested (such as calling intersects(), within(), etc) then the
* geometry should first be prepared by calling prepareGeometry() before performing the tests.
*
* ### Example
*
* \code{.py}
* # polygon_geometry contains a complex polygon, with many vertices
* polygon_geometry = QgsGeometry.fromWkt('Polygon((...))')
*
* # create a QgsGeometryEngine representation of the polygon
* polygon_geometry_engine = QgsGeometry.createGeometryEngine(polygon_geometry.constGet())
*
* # since we'll be performing many intersects tests, we can speed up these tests considerably
* # by first "preparing" the geometry engine
* polygon_geometry_engine.prepareGeometry()
*
* # now we are ready to quickly test intersection against many other objects
* for feature in my_layer.getFeatures():
* feature_geometry = feature.geometry()
* # test whether the feature's geometry intersects our original complex polygon
* if polygon_geometry_engine.intersects(feature_geometry.constGet()):
* print('feature intersects the polygon!')
* \endcode
*
* QgsGeometryEngine operations are backed by the GEOS library (https://trac.osgeo.org/geos/).
*/
static QgsGeometryEngine *createGeometryEngine( const QgsAbstractGeometry *geometry ) SIP_FACTORY;

Expand Down
36 changes: 35 additions & 1 deletion src/core/geometry/qgsgeometryengine.h
Expand Up @@ -28,7 +28,41 @@ class QgsAbstractGeometry;
/**
* \ingroup core
* \class QgsGeometryEngine
* \brief Contains geometry relation and modification algorithms.
* \brief A geometry engine is a low-level representation of a QgsAbstractGeometry object, optimised for use with external
* geometry libraries such as GEOS.
*
* QgsGeometryEngine objects provide a mechanism for optimized evaluation of geometric algorithms, including spatial relationships
* between geometries and operations such as buffers or clipping.
*
* QgsGeometryEngine objects are not created directly, but are instead created by calling QgsGeometry::createGeometryEngine().
*
* Many methods available in the QgsGeometryEngine class can benefit from pre-preparing geometries. For instance, whenever
* a large number of spatial relationships will be tested (such as calling intersects(), within(), etc) then the
* geometry should first be prepared by calling prepareGeometry() before performing the tests.
*
* ### Example
*
* \code{.py}
* # polygon_geometry contains a complex polygon, with many vertices
* polygon_geometry = QgsGeometry.fromWkt('Polygon((...))')
*
* # create a QgsGeometryEngine representation of the polygon
* polygon_geometry_engine = QgsGeometry.createGeometryEngine(polygon_geometry.constGet())
*
* # since we'll be performing many intersects tests, we can speed up these tests considerably
* # by first "preparing" the geometry engine
* polygon_geometry_engine.prepareGeometry()
*
* # now we are ready to quickly test intersection against many other objects
* for feature in my_layer.getFeatures():
* feature_geometry = feature.geometry()
* # test whether the feature's geometry intersects our original complex polygon
* if polygon_geometry_engine.intersects(feature_geometry.constGet()):
* print('feature intersects the polygon!')
* \endcode
*
* QgsGeometryEngine operations are backed by the GEOS library (https://trac.osgeo.org/geos/).
*
* \since QGIS 2.10
*/
class CORE_EXPORT QgsGeometryEngine
Expand Down

0 comments on commit 480c2eb

Please sign in to comment.