Skip to content
Permalink
Browse files

Add a bounding box intersection test to QgsGeometry

We only previously had methods for exact intersections - this
commit adds a new QgsGeometry.boundingBoxIntersects() method
which can be used to test if just the bounding boxes of
geometries/rectangles intersect.

It's fast, and doesn't care about invalid geometries (unlike
the exact intersects checks)
  • Loading branch information
nyalldawson committed Feb 20, 2018
1 parent 9471c5d commit 3ffbd84f5f0f003f8f873115ee5a3832ddc1c8f4
@@ -755,14 +755,48 @@ were found.
.. versionadded:: 3.0
%End

bool intersects( const QgsRectangle &r ) const;
bool intersects( const QgsRectangle &rectangle ) const;
%Docstring
Tests for intersection with a rectangle (uses GEOS)
Returns true if this geometry exactly intersects with a ``rectangle``. This test is exact
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.

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

bool intersects( const QgsGeometry &geometry ) const;
%Docstring
Tests for intersection with a geometry (uses GEOS)
Returns true if this geometry exactly intersects with another ``geometry``. This test is exact
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.

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

bool boundingBoxIntersects( const QgsRectangle &rectangle ) const;
%Docstring
Returns true if the bounding box of this geometry intersects with a ``rectangle``. Since this
test only considers the bounding box of the geometry, is is very fast to calculate and handles invalid
geometries.

.. seealso:: :py:func:`intersects`

.. versionadded:: 3.0
%End

bool boundingBoxIntersects( const QgsGeometry &geometry ) const;
%Docstring
Returns true if the bounding box of this geometry intersects with the bounding box of another ``geometry``. Since this
test only considers the bounding box of the geometries, is is very fast to calculate and handles invalid
geometries.

.. seealso:: :py:func:`intersects`

.. versionadded:: 3.0
%End

bool contains( const QgsPointXY *p ) const;
@@ -1106,6 +1106,26 @@ bool QgsGeometry::intersects( const QgsGeometry &geometry ) const
return geos.intersects( geometry.d->geometry.get(), &mLastError );
}

bool QgsGeometry::boundingBoxIntersects( const QgsRectangle &rectangle ) const
{
if ( !d->geometry )
{
return false;
}

return d->geometry->boundingBox().intersects( rectangle );
}

bool QgsGeometry::boundingBoxIntersects( const QgsGeometry &geometry ) const
{
if ( !d->geometry || geometry.isNull() )
{
return false;
}

return d->geometry->boundingBox().intersects( geometry.constGet()->boundingBox() );
}

bool QgsGeometry::contains( const QgsPointXY *p ) const
{
if ( !d->geometry || !p )
@@ -798,12 +798,50 @@ class CORE_EXPORT QgsGeometry
*/
bool removeDuplicateNodes( double epsilon = 4 * DBL_EPSILON, bool useZValues = false );

//! Tests for intersection with a rectangle (uses GEOS)
bool intersects( const QgsRectangle &r ) const;
/**
* Returns true if this geometry exactly intersects with a \a rectangle. This test is exact
* 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.
*
* \see boundingBoxIntersects()
*/
bool intersects( const QgsRectangle &rectangle ) const;

//! Tests for intersection with a geometry (uses GEOS)
/**
* Returns true if this geometry exactly intersects with another \a geometry. This test is exact
* 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.
*
* \see boundingBoxIntersects()
*/
bool intersects( const QgsGeometry &geometry ) const;

/**
* Returns true if the bounding box of this geometry intersects with a \a rectangle. Since this
* test only considers the bounding box of the geometry, is is very fast to calculate and handles invalid
* geometries.
*
* \see intersects()
*
* \since QGIS 3.0
*/
bool boundingBoxIntersects( const QgsRectangle &rectangle ) const;

/**
* Returns true if the bounding box of this geometry intersects with the bounding box of another \a geometry. Since this
* test only considers the bounding box of the geometries, is is very fast to calculate and handles invalid
* geometries.
*
* \see intersects()
*
* \since QGIS 3.0
*/
bool boundingBoxIntersects( const QgsGeometry &geometry ) const;

//! Tests for containment of a point (uses GEOS)
bool contains( const QgsPointXY *p ) const;

@@ -4286,6 +4286,33 @@ def testHausdorffDensify(self):
self.assertAlmostEqual(o, exp, 5,
"mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format(t[0], t[1], exp, o))

def testBoundingBoxIntersects(self):
tests = [
["LINESTRING (0 0, 100 100)", "LINESTRING (90 0, 100 0)", True],
["LINESTRING (0 0, 100 100)", "LINESTRING (101 0, 102 0)", False],
["POINT(20 1)", "LINESTRING( 0 0, 100 100 )", True],
["POINT(20 1)", "POINT(21 1)", False],
["POINT(20 1)", "POINT(20 1)", True]
]
for t in tests:
g1 = QgsGeometry.fromWkt(t[0])
g2 = QgsGeometry.fromWkt(t[1])
res = g1.boundingBoxIntersects(g2)
self.assertEqual(res, t[2], "mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format(g1.asWkt(), g2.asWkt(), t[2], res))

def testBoundingBoxIntersectsRectangle(self):
tests = [
["LINESTRING (0 0, 100 100)", QgsRectangle(90, 0, 100, 10), True],
["LINESTRING (0 0, 100 100)", QgsRectangle(101, 0, 102, 10), False],
["POINT(20 1)", QgsRectangle(0, 0, 100, 100), True],
["POINT(20 1)", QgsRectangle(21, 1, 21, 1), False],
["POINT(20 1)", QgsRectangle(20, 1, 20, 1), True]
]
for t in tests:
g1 = QgsGeometry.fromWkt(t[0])
res = g1.boundingBoxIntersects(t[1])
self.assertEqual(res, t[2], "mismatch for {} to {}, expected:\n{}\nGot:\n{}\n".format(g1.asWkt(), t[1].toString(), t[2], res))

def renderGeometry(self, geom, use_pen, as_polygon=False, as_painter_path=False):
image = QImage(200, 200, QImage.Format_RGB32)
image.fill(QColor(0, 0, 0))

0 comments on commit 3ffbd84

Please sign in to comment.
You can’t perform that action at this time.