Skip to content

Commit

Permalink
Add nearest function to STRtree (issue #668) (#672)
Browse files Browse the repository at this point in the history
* Update strtree.py

Add GEOSSTRtree_nearest_generic function from GEOS

* Update ctypes_declarations.py

Add GEOSSTRtree_nearest_generic function from GEOS

* Add files via upload

* Update test_strtree_nearest.py
  • Loading branch information
FuriousRococo authored and sgillies committed Jan 31, 2019
1 parent d7b8417 commit 4f41e54
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 0 deletions.
7 changes: 7 additions & 0 deletions shapely/ctypes_declarations.py
Expand Up @@ -509,3 +509,10 @@ def prototype(lgeos, geos_version):

lgeos.GEOSSTRtree_destroy.argtypes = [c_void_p]
lgeos.GEOSSTRtree_destroy.restype = None

if geos_version >= (3, 6, 0):
lgeos.GEOSDistanceCallback = CFUNCTYPE(c_int, c_void_p, c_void_p, c_void_p, c_void_p)

lgeos.GEOSSTRtree_nearest_generic.argtypes = [
c_void_p, py_object, c_void_p, lgeos.GEOSDistanceCallback, py_object]
lgeos.GEOSSTRtree_nearest_generic.restype = c_void_p
22 changes: 22 additions & 0 deletions shapely/strtree.py
Expand Up @@ -61,6 +61,28 @@ def callback(item, userdata):

return result

def nearest(self, geom):
if self._n_geoms == 0:
return None

envelope = geom.envelope

def callback(item1, item2, distance, userdata):
try:
geom1 = ctypes.cast(item1, ctypes.py_object).value
geom2 = ctypes.cast(item2, ctypes.py_object).value
dist = ctypes.cast(distance, ctypes.POINTER(ctypes.c_double))
lgeos.GEOSDistance(geom1._geom, geom2._geom, dist)
return 1
except:
return 0

item = lgeos.GEOSSTRtree_nearest_generic(self._tree_handle, ctypes.py_object(geom), envelope._geom, \
lgeos.GEOSDistanceCallback(callback), None)
result = ctypes.cast(item, ctypes.py_object).value

return result

if __name__ == "__main__":
import doctest
doctest.testmod()
27 changes: 27 additions & 0 deletions tests/test_strtree_nearest.py
@@ -0,0 +1,27 @@
from . import unittest

from shapely.geometry import Point, Polygon
from shapely.geos import geos_version
from shapely.strtree import STRtree

@unittest.skipIf(geos_version < (3, 6, 0), 'GEOS 3.6.0 required')
class STRTreeNearest(unittest.TestCase):
def test_nearest(self):
tree = STRtree([
Polygon([(1,0),(2,0),(2,1),(1,1)]),
Polygon([(0,2),(1,2),(1,3),(0,3)]),
Point(0,0.5)])
result = tree.nearest(Point(0,0))
self.assertEqual(result, Point(0,0.5))
result = tree.nearest(Point(0,4))
self.assertEqual(result, Polygon([(0,2),(1,2),(1,3),(0,3)]))
result = tree.nearest(Polygon([(-0.5,-0.5),(0.5,-0.5),(0.5,0.5),(-0.5,0.5)]))
self.assertEqual(result, Point(0,0.5))


def test_suite():
return unittest.TestLoader().loadTestsFromTestCase(STRTreeNearest)

if __name__ == '__main__':
unittest.main()

0 comments on commit 4f41e54

Please sign in to comment.