Source code for stompy.spatial.gen_spatial_index
from __future__ import print_function
import numpy as np
import logging
# try again to normalize interface to spatial indices.
# no single implementation is perfect, though...
# This may transition to a factory function pattern, in
# order to allow for more flexible selection of implementation
PointIndex=None
# This is defined outside all of the conditionals as a hedge between
# (a) a factory method which can choose between implementations, and
# (b) having this class defined only once so that it can be subclassed
# if one desires.
class _PointIndexKDTree(object):
KDTree=None # This is populated on import in the factory. That's why the
# class has an underscore, i.e. don't use it directly.
def __init__(self,tuples,interleaved=False):
assert self.KDTree is not None
# stucture of tuples is [(orig_idx, [x, x, y, y], None), ... ]
cell_centers=np.zeros( (len(tuples),2), 'f8')
self.idx_to_original=np.zeros(len(cell_centers),'i4')
# note that orig_idx may not be sequential (due to deleted nodes, cells)
# so we have to map sequential indices back to original index.
for i,tup in enumerate(tuples):
cell_centers[i]= [tup[1][0],tup[1][2]]
self.idx_to_original[i]=tup[0]
self.cell_centers=cell_centers
self.rebuild()
def rebuild(self):
if len(self.cell_centers):
self._kdtree = self.KDTree(self.cell_centers)
else:
self._kdtree = None
def nearest(self,xxyy,count):
pnt=xxyy[np.array([0,2])]
if self._kdtree is not None:
distances,hits=self._kdtree.query(pnt,count)
if count==1:
# kdtree returns a single index, no list, when count==1
hits=np.array([hits])
return self.idx_to_original[hits]
else:
if len(self.cell_centers):
distances=utils.dist(pnt - self.cell_centers)
hits=np.argsort(distances)[:count]
return self.idx_to_original[hits]
else:
return []
def insert(self,idx,point_tuple):
raise NotImplementedError("KDTree in use by gen_spatial_index; insert not allowed; install rtree...")
def delete(self,idx,point_tuple):
raise NotImplementedError("KDTree in use by gen_spatial_index; delete not allowed; install rtree...")
[docs]def rect_index_class_factory(implementation='rtree'):
if implementation in ['rtree','best']:
try:
from rtree.index import Rtree
return Rtree
except ImportError:
if implementation=='rtree':
raise
# otherwise fall through to next best
raise Exception("Failed to load any spatial index based on implementation='%s'"%implementation)
[docs]def point_index_class_factory(implementation='best'):
if implementation in ['rtree','best']:
try:
from rtree.index import Rtree
# try to mimic the Rtree interface - starting by just using it...
return Rtree
except ImportError:
if implementation=='rtree':
raise
# otherwise fall through to next best
if implementation in ['qgis','best']:
try:
from . import qgis_spatialindex
return qgis_spatialindex.RtreeQgis
except ImportError:
if implementation=='qgis':
raise
# otherwise fall through to next
if implementation in ['kdtree','best']:
try:
# keep the try..except a bit tighter around the import
from scipy.spatial import KDTree
_PointIndexKDTree.KDTree=KDTree
return _PointIndexKDTree
except ImportError:
if implementation=='kdtree':
raise
raise Exception("Failed to load any spatial index based on implementation='%s'"%implementation)
try:
PointIndex=point_index_class_factory()
except ImportError:
logging.info("Spatial index not available")
PointIndex=None
try:
RectIndex=rect_index_class_factory()
except ImportError:
logging.info("Spatial index of rectangles not available")
RectIndex=None