简体   繁体   English

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

[英]How to search point inside polygon without GeoDjango

The situation follows:情况如下:

  • Each supplier has some service areas, which the user have defined using GoogleMaps (polygons).每个供应商都有一些服务区域,用户使用 GoogleMaps(多边形)定义了这些区域。
  • I need to store this data in the DB and make simple (but fast) queries over this.我需要将此数据存储在数据库中并对此进行简单(但快速)的查询。
  • Queries should looks like: "List all suppliers with service area containing x,y" or "In which polygons (service areas) x,y are inside?"查询应如下所示:“列出服务区包含 x,y 的所有供应商”或“x,y 位于哪些多边形(服务区)内?”

At this time, I've found GeoDjango which looks a very complex solution to this problem.这个时候,我找到了 GeoDjango,它看起来是一个非常复杂的解决这个问题的方法。 To use it, I need a quite complex setup and I couldn't find any recent (and good) tutorial.要使用它,我需要一个非常复杂的设置,而且我找不到任何最近的(好的)教程。

I came with this solution:我带来了这个解决方案:

  • Store every polygon as a Json into the database将每个多边形作为 Json 存储到数据库中
  • Apply a method to determine if some x,y belongs to any polygon应用一种方法来确定某个 x,y 是否属于任何多边形

The problem with this solution is quite obvious: Queries may take too long to execute, considering I need to evaluate every polygon.这个解决方案的问题很明显:考虑到我需要评估每个多边形,查询可能需要很长时间才能执行。

Finally: I'm looking for another solution for this problem, and I hope find something that doesn't have setup GeoDjango in my currently running server最后:我正在为这个问题寻找另一种解决方案,我希望找到在我当前运行的服务器中没有设置 GeoDjango 的东西

Determine wheter some point is inside a polygon is not a problem (I found several examples);确定某个点是否在多边形内不是问题(我找到了几个例子); the problem is that retrieve every single polygon from DB and evaluate it does not scale.问题是从数据库中检索每个多边形并对其进行评估不能缩放。 To solve that, I need to store the polygon in such way I can query it fast.为了解决这个问题,我需要以可以快速查询的方式存储多边形。

My approach.我的方法。

  1. Find centroid of polygon C++ code .找到多边形C++ 代码的质心。
  2. Store in database存储在数据库中
  3. Find longest distance from vertex to centroid (pythag)找到从顶点到质心的最长距离(pythag)
  4. Store as radius存储为半径
  5. Search database using centroid & radius as bounding box使用质心和半径作为边界框搜索数据库
  6. If 1 or more result use point in polygon on resultant polygons如果 1 个或多个结果在结果多边形上使用多边形中的点

This solution enables you to store polygons outside of GeoDjango to dramatically speed up point in polygon queries.此解决方案使您能够在 GeoDjango 之外存储多边形,以显着加快多边形查询的速度。

In my case, I needed to find whether the coordinates of my numpy arrays where inside a polygon stored in my geodjango db (land/water masking).就我而言,我需要找出我的 numpy 数组的坐标是否在存储在我的 geodjango db(陆地/水掩蔽)中的多边形内。 This required iterating over every coordinate combination in my arrays to test if it was inside or outside the polygon.这需要迭代数组中的每个坐标组合以测试它是在多边形内部还是外部。 As my arrays are large, this was taking a very long time using geodjango.由于我的数组很大,因此使用 geodjango 需要很长时间。

Using django's GEOSGeometry.contains my command looked something like this:使用 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

This was taking 20 s or more on large arrays.这在大型阵列上需要 20 秒或更长时间。 I tried different ways of applying the geometry.contains() function over the array (eg np.vectorize) but this did not lead to any improvements.我尝试了在数组上应用 geometry.contains() 函数的不同方法(例如 np.vectorize),但这并没有带来任何改进。 I then realised it was the Django contains lookup which was taking too long.然后我意识到这是 Django contains 查找花费了太长时间。 I also converted the geometry to a shapely polygon and tested shapely's polygon.contains function - no difference or worse.我还将几何图形转换为匀称的多边形并测试了匀称的多边形.contains 函数 - 没有区别或更糟。

The solution lay in bypassing GeoDjango by using Polygon isInside method.解决方案在于使用Polygon isInside 方法绕过 GeoDjango。 First I created a function to create a Polygon object from my Geos Multipolygon.首先,我创建了一个函数来从我的 Geos Multipolygon 创建一个 Polygon 对象。

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

Applying this to my problem将此应用于我的问题

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])

This resulted in a roughly 20X improvement in speed.这导致速度提高了大约 20 倍。 Hope this helps someone.希望这可以帮助某人。

Python 2.7.蟒蛇 2.7。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM