Python 如何在没有GeoDjango的情况下搜索多边形内的点

Python 如何在没有GeoDjango的情况下搜索多边形内的点,python,django,geolocation,geodjango,Python,Django,Geolocation,Geodjango,情况如下: 每个供应商都有一些服务区域,用户使用谷歌地图(多边形)定义这些区域 我需要将这些数据存储在数据库中,并在此基础上进行简单(但快速)的查询 查询应类似于:“列出服务区域包含x,y的所有供应商”或“其中多边形(服务区域)x,y在其中?” 此时,我找到了GeoDjango,它看起来是这个问题的一个非常复杂的解决方案。要使用它,我需要一个非常复杂的设置,我找不到任何最近的(好的)教程 我提出了这个解决方案: 将每个多边形作为Json存储到数据库中 应用一种方法来确定某个x,y是否属于任

情况如下:

  • 每个供应商都有一些服务区域,用户使用谷歌地图(多边形)定义这些区域
  • 我需要将这些数据存储在数据库中,并在此基础上进行简单(但快速)的查询
  • 查询应类似于:“列出服务区域包含x,y的所有供应商”或“其中多边形(服务区域)x,y在其中?”
此时,我找到了GeoDjango,它看起来是这个问题的一个非常复杂的解决方案。要使用它,我需要一个非常复杂的设置,我找不到任何最近的(好的)教程

我提出了这个解决方案:

  • 将每个多边形作为Json存储到数据库中
  • 应用一种方法来确定某个x,y是否属于任何多边形
这个解决方案的问题非常明显:考虑到我需要计算每个多边形,执行查询可能需要太长时间

最后:我正在为这个问题寻找另一个解决方案,我希望找到一些在我当前运行的服务器中没有安装GeoDjango的东西

确定某个点是否在多边形内不是问题(我发现了几个例子);问题在于,从DB中检索每个多边形并对其进行求值并不会缩放。为了解决这个问题,我需要以一种可以快速查询的方式存储多边形。

我的方法

  • 求多边形的质心
  • 存储在数据库中
  • 查找顶点到质心的最长距离(毕达格)
  • 存储为半径
  • 使用质心和半径作为边界框搜索数据库
  • 如果有一个或多个结果,请在结果多边形上使用多边形中的点

  • 此解决方案使您能够在GeoDjango之外存储多边形,以显著加快多边形中的点查询

    在我的例子中,我需要找到我的numpy数组的坐标是否位于存储在geodjango db(陆地/水掩蔽)中的多边形中。这需要迭代数组中的每个坐标组合,以测试它是在多边形内部还是外部。由于我的阵列很大,使用geodjango需要很长时间

    使用django的GEOSGeometry.contains,我的命令如下所示:

    import numpy as np
    from django.contrib.gis.geos import Point
    
    my_polygon = model.geometry  # get model multipolygon field
    lat_lon = zip(latitude.flat, longitude.flat)  # zip coordinate arrays to tuple
    mask = np.array([my_polygon.contains(Point(l)) for l in lon_lat])  # boolean mask
    
    对于大型阵列,这需要20秒或更长时间。我尝试了在数组上应用geometry.contains()函数的不同方法(例如np.vectorize),但这并没有带来任何改进。然后我意识到是Django包含查找花费了太长的时间。我还将几何体转换为shapely多边形,并测试了shapely的多边形。包含函数-没有差异或更糟

    解决方案在于使用isInside方法绕过GeoDjango。首先,我创建了一个函数,用于从Geos Multipolygon创建多边形对象

    from Polygon import Polygon
    
    def multipolygon_to_polygon(multipolygon):
        """
        Convert a Geos Multipolygon to python Polygon
        """
    
        polygon = multipolygon[0] # select first polygon object
        nrings = polygon.num_interior_rings # get number of rings in polygon
    
        poly = Polygon()  
        poly.addContour(polygon[0].coords)  # Add first ring coordinates tuple
    
        # Add subsequent rings
        if nrings > 0:
            for i in range(nrings):
                print("Adding ring %s" % str(i+1))
                hole = True
                poly.addContour(polygon[i+1].coords, hole)
    
        return poly
    
    把这个应用到我的问题上

    my_polygon = model.geometry  # get model multipolygon field
    polygon = multipolygon_to_polygon(my_polygon)  # convert to python Polygon
    lat_lon = zip(bands['latitude'].flat, bands['longitude'].flat)  # points tuple
    land_mask = array([not polygon.isInside(ll[1], ll[0]) for ll in lat_lon])
    
    这使得速度提高了约20倍。希望这对别人有帮助


    Python2.7.

    您不会仅仅为此使用GeoDjango。你可以改用Shapely。但是你同时问了很多问题。问题是如何在数据库中存储数据?或者如何找到一个点是否在多边形中?tx@AntonisChristofides!我添加了更多细节。问题不在于确定点是否在多边形内,但我需要以这样一种方式存储多边形,我可以快速查询其中的几个。现在清楚了吗?看起来Shapely并没有解决这个问题,也许你需要的是PostGIS。这是一个老问题,但添加了这个注释,因为它仍然在这里突出显示。使用geodjango肯定没有您尝试过的基于json的方法那么复杂。空间数据库是专门为查找空间关系而设计的。这是一个地狱很多代码由很多有才华的人。如果你想用JSON复制它,你会非常痛苦。我刚刚发现了Geos准备的几何图形。这使得像.contains这样的操作更快,并且只需要一行简单的代码:my_polygon=my_polygon.prepared,然后再执行.contains操作。这将产生与上述替代解决方案相当的速度。见: