简体   繁体   English

用指定半径的圆点填充经度/纬度图的最有效方法是什么?

[英]What's the most efficient way to fill a longitude / latitude map with circular points of specified radius?

So I'm trying to get around restrictions on a certain company's API that provides data on places of interest. 因此,我试图绕过某些公司API的限制,这些API提供有关景点的数据。 The API doesn't allow me to collect results for an entire state. API不允许我收集整个状态的结果。 Instead, I must specify Lat/Lon coordinates and gather the nearby places in a circular 1 to 50000m radius. 相反,我必须指定纬度/经度坐标,并以1到50000m的圆形半径收集附近的位置。 This API also only returns 60 results at a time, regardless of how many reside in the location specified. 该API一次一次仅返回60个结果,无论指定位置中有多少个结果。 I'm aware I will encounter more than 60 places at specified locations, but I'm planning to recursively bisect and process each of these cases. 我知道我会在指定位置遇到60多个地方,但是我打算递归地将这些情况一分为二并进行处理。

I'd like to use New York State as my first test case. 我想将纽约州作为我的第一个测试用例。

I'm using a shapefile from https://www.arcgis.com/home/item.html?id=b07a9393ecbd430795a6f6218443dccc to get the shape of NY, and shapely to determine whether my point is inside the border. 我正在使用来自https://www.arcgis.com/home/item.html?id=b07a9393ecbd430795a6f6218443dccc的shapefile获取NY的形状,并确定我的点是否在边界内。

import geopandas as gpd
from shapely.geometry import Point, Polygon

usa = gpd.read_file('states_21basic/states.shp')
polygon = usa[usa.STATE_ABBR == 'NY']['geometry'].values[0]
point = Point(-74.005974,40.712776) # create point
print(polygon.contains(point)) # check if polygon contains point

It's been suggested I try a flood fill algorithm, but I'm not exactly sure how to get a list of spaced out coordinates from it (to minimize API calls) and how to ensure that every part is covered, even in weird shapes like NY. 有人建议我尝试使用泛洪填充算法,但是我不确定如何从中获取间隔坐标列表(以最小化API调用),以及如何确保每个部分都被覆盖,即使是像NY这样的怪异形状。

My main goal is to collect all the places whilst minimizing API calls. 我的主要目标是收集所有位置,同时尽量减少API调用。 I'm not really expecting any code, just an idea of how to tackle this. 我并不是真的希望有任何代码,只是关于如何解决这个问题的想法。

**Unfortunately, I have been removed from the company and won't be able to mark answers as accepted **很遗憾,我已经从公司除名,无法将答案标记为已接受

Your problem might have a good solution not a perfect solution. 您的问题可能有一个好的解决方案,而不是一个完美的解决方案。 I worked with maps for a long time and mostly all of them are complex themselves. 我在地图上工作了很长时间,而且大多数地图本身都很复杂。 You have another level of complexity which is an external dependency you cannot control. 您还有另一种复杂性,这是您无法控制的外部依赖性。 I had to do something similar at a lower level querying Google Maps to obtain sites on a small area (no more than 20 meters) to try to match the closest place to where I was in terms of geolocation. 我必须在较低级别执行类似的操作,以查询Google Maps以获得较小区域(不超过20米)的站点,以尝试将最接近的地理位置与我所在的地理位置相匹配。 First, you need to make an assumption and try it. 首先,您需要做一个假设并尝试一下。 The assumption could be to only use 100 meters radius which more or less cover one block. 假设可能仅使用100米半径,或多或少覆盖一个街区。 The second problem you have is density. 您遇到的第二个问题是密度。 You can explore a map with zero places of interest for a while (New York has a lot of open areas that might not have nearly anything around). 您可以在一段时间内探索零兴趣点的地图(纽约有很多空旷的地方,周围可能几乎没有任何东西)。

Let's suppose you can enclose your solution in a shape. 假设您可以将解决方案围成一个形状。 Suggestion is you start from a predefined point in a dense area (Manhattan?) to maximize the algorithm findings at the beginning. 建议您从密集区域(曼哈顿?)中的预定义点开始,以在开始时最大化算法发现。 Longer it runs, closer to detect less it will get. 它运行时间越长,越接近检测到它将得到的更少。

The flood fill algorithm is good in your case but it might not be the best. 泛洪填充算法在您的情况下是好的,但可能不是最好的。 I would probably go with something more complex that follows streets for example but a first approach using flood fill will work. 例如,我可能会沿着街道走一些更复杂的东西,但是使用洪水填充的第一种方法会起作用。

"Flood filling" is like using paint, you walk in a direction; “洪水填充”就像使用油漆,您朝一个方向行走; in your case I suggest to use 8, (N, S, W, E, NW, NE, SW, SE), detect if you have "painted it" (you will need to store somewhere you've been in that position already to avoid duplicate calls, and call the API if not. Walking will open a tree of different executions, start from point A, walk N, S, E, W, NW, NE, SW, SE recursively. This recursion might be extreme in an area like New York, 100 meters each in that area will lead to several thousands level of recursion. You will require to optimize it. 在您的情况下,我建议使用8(N,S,W,E,NW,NE,SW,SE),检测是否已“绘制”(您需要将其存放在该位置的某个位置)为了避免重复调用,如果不重复调用API,Walking将打开一棵不同的执行树,从A点开始,递归地遍历N,S,E,W,NW,NE,SW,SE。像纽约这样的区域,该区域各有100米,将导致数千级递归,您需要对其进行优化。

The third thing to keep into consideration is checking if the point is outside of the polygon. 要考虑的第三件事是检查点是否在多边形之外。 This is pretty straightforward using PNPoly. 使用PNPoly非常简单。 Once you are outside the polygon, walking in that direction must stop. 一旦您位于多边形外,就必须停止在该方向上行走。

I share with you the PNPoly implementation in C# I coded for a project: 我与您分享为项目编码的C#中的PNPoly实现:

public bool IsCoordinateWithinPolygon(double latitude, double longitude, Polygon polygon)
{
    if(polygon == null || polygon.Coordinates.Count() == 0)
    {
        return false;
    }

    List<double> coordinatesY = new List<double>();
    List<double> coordinatesX = new List<double>();

    var minLatitude = double.MaxValue;
    var maxLatitude = double.MinValue;
    var minLongitude = double.MaxValue;
    var maxLongitude = double.MinValue;
    // Quick-check, determine if the coordinate is outside of the bounding rectangle
    foreach(var linearRing in polygon.Coordinates)
    {
        foreach (var coordinate in linearRing.Coordinates)
        {
            coordinatesY.Add(coordinate.Latitude);
            coordinatesX.Add(coordinate.Longitude);
            if (coordinate.Latitude < minLatitude)
            {
                minLatitude = coordinate.Latitude;
            }
            if(coordinate.Latitude > maxLatitude)
            {
                maxLatitude = coordinate.Latitude;
            }
            if(coordinate.Longitude < minLongitude)
            {
                minLongitude = coordinate.Longitude;
            }
            if(coordinate.Longitude > maxLongitude)
            {
                maxLongitude = coordinate.Longitude;
            }
        }
    }

    // Determine if the coordinate is outside the bounding box
    if( (latitude < minLatitude || latitude > maxLatitude) &&
        (longitude < minLongitude || longitude < maxLongitude))
    {
        // Out of the box
        return false;
    }

    // PNPoly Algorithm - Point Inclusion in Polygon Test 
    bool inclusion = false;
    var verty = coordinatesY.ToArray();
    var vertx = coordinatesX.ToArray();
    var nvert = vertx.Length;
    var testy = latitude;
    var testx = longitude;

    for (int i = 0, j = nvert - 1; i < nvert; j = i++)
    {
        if (((verty[i] > testy) != (verty[j] > testy)) &&
         (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]))
            inclusion = !inclusion;
    }

    return inclusion;
}

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

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