按经纬度将城市划分为矩阵
Posted
技术标签:
【中文标题】按经纬度将城市划分为矩阵【英文标题】:Dividing City by Longitude and Latitude into Matrix 【发布时间】:2018-03-24 17:50:29 【问题描述】:您如何根据经度和纬度坐标将旧金山等城市划分为大小相等的块?这样做的目的是,当我收到城市中某个位置的坐标时,我想将其自动分配到这些街区之一中。
【问题讨论】:
How to create a Grid is the viewing area of a map的可能重复 相关问题:Grid on top of Google maps produces gaps in squares How do I create a grid in google maps api v3 的可能副本 也考虑实现自己的 Geohash 或使用公开可用的库。 【参考方案1】:这里是公开可用的 python 库模块 Geohash (https://github.com/vinsci/geohash) 的简单使用。
python hashmap(字典)用于将 Geohash 字符串映射到已添加到由 Geohash 表示的区域(“块”)中的 lat/lng 点列表。通过计算位置的 Geohash 并访问该条目的哈希图以检索该“块”的所有条目来执行查询。
### Add position to Geohash
### Each hash mapping contains a list of points in the "block"
###
def addToGeohash(m, latitude, longitude):
p = (latitude, longitude)
ph = encode(p[0],p[1],5)
if ph not in m:
m[ph] = []
m[ph].append(p)
return
### Get positions in same "block" or empty list if none found
###
def getFromGeohash(m, latitude, longitude):
p = (latitude, longitude)
ph = encode(p[0],p[1],5)
print ("query hash: " + ph)
if ph in m:
return m[ph]
return []
### Test
m = dict()
# Add 2 points in general area (1st near vista del mar)
addToGeohash(m, 37.779914,-122.509431)
addToGeohash(m, 37.780546,-122.366189)
# Query a point 769 meters from vista del mar point
n = getFromGeohash(m, 37.779642,-122.502993)
print ("Length of hashmap: "+str(len(m)))
print ("Contents of map : "+str(m))
print ("Query result : ")
print (n)
默认精度为 12 个字符(示例中使用了 5 个),会影响字典映射效率或“块”大小。
请注意,使用基于 lat/lng 的方法是一种非线性方法,因此在广阔的区域或靠近两极的地方不会是“大小相等的块”。然而, 在 San Fransisco 区域内,如果具有足够的精度,这种非线性会显着降低。
输出
query hash: 9q8yu
Length of hashmap: 2
Contents of map : '9q8yu': [(37.779914, -122.509431)], '9q8yz': [(37.780546, -122.366189)]
Query result :
[(37.779914, -122.509431)]
要了解各种精度的块大小,请使用 link 并输入例如 37.779914,-122.509431 和 5 的精度。试验精度。
以下是精度为 5-8 的近似框尺寸:
5 ≤ 4.89km × 4.89km
6 ≤ 1.22km × 0.61km
7 ≤ 153m × 153m
8 ≤ 38.2m × 19.1m
Geohash 的一个有趣功能主要(并且始终与 SanFran 区域一起使用)是您可以通过操纵最后一个字符轻松找到 8 个相邻的邻居。因此,您可以用最少的努力使用更高的精度(例如 8)并将其减小到 7 到 8 之间的大小。
【讨论】:
【参考方案2】:天真的方法是在整个城市(您想要覆盖的区域)周围找到一个足够大的矩形,然后通过所需的块数可以推断出矩形边缘有多少部分,这应该是一个相当基本的数学 给定一个点,您可以以非常快速的方式将其分配给它的块(只需检查它的 lan 并长时间查看它在网格中的位置)
【讨论】:
【参考方案3】:多年来,我编写了该算法的不同版本。花了很多时间思考这个问题。涉及两个问题:
-
将二维坐标映射到一维值。 (从根本上说,为了达到最佳效果,您必须知道两个维度的界限)
将覆盖球体的平面大致切割成“正方形”。 (当您靠近两极时,正方形的大小会有所不同。此外,它们实际上从来都不是正方形,但地球是如此之大,这通常无关紧要)
这是我编写的一些符合我的目的的代码。需要考虑的几点:
这会创建您指定的固定大小的块。 python Geohash 库做了一件很酷的事情,可以截断散列以产生更大尺寸的散列。该算法不会这样做,但另一方面,您可以(大致)指定所需的块大小。 这实际上创建了二维坐标,我将其视为一维字符串。我这样做是因为它对我来说已经足够好了,而且我可以轻松地操纵字符串数据,以一种清晰且有意义的方式获取相邻的块。例如哈希:“-23,407”是中心点以西 23 个块和以北 407 个块。所以如果你想向东移动一个街区,你只需在 -23 上加 1:“-22,407”。 我在这里使用的中心点是华盛顿特区的中部。您可以使用中心点 0,0,或旧金山的中部或其他。但不要在两极附近使用中心点:-90,-180。因为当算法以公里为单位计算经度偏移时,它将计算(-90,您的经度)和(-90,-180)之间的距离。这些点在南极(我认为是南极?),距离将无限小,因为在两极,所有这些块都非常小。这是散列点的主要算法:
# Define center point
CENTER_LAT = 38.893
CENTER_LNG = -77.084
def geohash(lat, lng, BLOCK_SIZE_KM=.05):
# Get Latitude Offset
lat_distance = haversine_km(
(CENTER_LAT, CENTER_LNG),
(lat, CENTER_LNG)
)
if lat < CENTER_LAT:
lat_distance = lat_distance*-1
lat_offset = int(lat_distance/BLOCK_SIZE_KM)
# Get Longitude offset
lng_distance = haversine_km(
(CENTER_LAT, CENTER_LNG),
(CENTER_LAT, lng)
)
if lng < CENTER_LNG:
lng_distance = lng_distance*-1
lng_offset = int(lng_distance/BLOCK_SIZE_KM)
block_str = '%s,%s' % (lat_offset, lng_offset)
return block_str
我包含了这些帮助函数来计算两个坐标之间的距离:
def haversine_km(origin, destination):
return haversine(origin, destination, 6371)
def haversine(origin, destination, radius):
lat1, lon1 = origin
lat2, lon2 = destination
lat1 = float(lat1)
lon1 = float(lon1)
lat2 = float(lat2)
lon2 = float(lon2)
dlat = math.radians(lat2-lat1)
dlon = math.radians(lon2-lon1)
a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(lat1)) \
* math.cos(math.radians(lat2)) * math.sin(dlon/2) * math.sin(dlon/2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
d = radius * c
return d
【讨论】:
以上是关于按经纬度将城市划分为矩阵的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 bing 将城市/州转换为地理位置(纬度/经度)?