Python 3.x 循环以计算起点和终点角度之间的坐标
我有一个手机发射塔信息的数据集,如你所见。lat和lon字段是风塔的位置 我的目标是通过计算从起始角到结束角的每个坐标来发现这些塔所覆盖的区域,每次计算时将角度增加1。Python 3.x 循环以计算起点和终点角度之间的坐标,python-3.x,Python 3.x,我有一个手机发射塔信息的数据集,如你所见。lat和lon字段是风塔的位置 我的目标是通过计算从起始角到结束角的每个坐标来发现这些塔所覆盖的区域,每次计算时将角度增加1。 我知道给定角度和半径的坐标的计算公式。我的问题是,无法创建一个循环来计算每个id的每个坐标。如果这是您需要的,这里是我的计算面积解决方案。对于每个塔,我计算的面积为Pi*半径^2*abs(结束角-开始角)/360。这只是一个简单的公式 如果您需要遍历其中的所有点,那么我编写了下一个代码 它以1度的角度和1米的半径进行步进。并将
我知道给定角度和半径的坐标的计算公式。我的问题是,无法创建一个循环来计算每个id的每个坐标。如果这是您需要的,这里是我的计算面积解决方案。对于每个塔,我计算的面积为
Pi*半径^2*abs(结束角-开始角)/360
。这只是一个简单的公式
如果您需要遍历其中的所有点,那么我编写了下一个代码
它以1度的角度和1米的半径进行步进。并将以米表示的圆形扇形点坐标转换为以度表示的lat/lon坐标,因此我在Dist()
函数中使用它来计算lat/lon距离压缩比,以校正lon的距离(我们越靠近两极,lon距离就越小于lat,我们越靠近赤道,lon距离就越接近lat,并且在赤道上相等),lat距离不需要校正(lat的每1度都是111km
)
我的步进迭代是不均匀的,这意味着我会在每一个地方迭代1度角和1米半径,这意味着如果你有塔楼半径50和角度80度,那么你将有正好50*80=4000点迭代。如果你需要区域均匀迭代,告诉我,我会更改代码,或者你可以自己做,你只需要在外环和内环中,通过1米半径的T,应该通过角度进行迭代,但在较大半径处,角度步数应该更多,在较小半径处,角度步数应该更少,这样你就可以均匀填充。你必须说出你需要什么
接下来的代码需要使用python-mpipinstall-numpy-tqdm
安装3个包tqdm
只是进度条实现
如果您需要处理大量数据,而纯python代码太慢,我可以扩展我的解决方案,使用numpy
数组,这样会更快
第一个简化的、缓慢的、具有非均匀步进的旧版本代码可以是
更新!我已经实现了第二个版本,它更高级,运行速度更快(对重型部件使用numpy
),并且在扇区上以统一的步长创建网格(以米为单位的步长由脚本开头的mdist
值控制)。Main函数GenPoints()
是一个生成器,它迭代解析CSV,并为每个塔楼扇区的网格生成(返回)点,如(lon,lat)numpy数组,还附加了这些塔的已解析数据帧。还将绘图结果实现为图像文件。下面是两个绘图结果。正如您所看到的,第二个结果是椭球体,这是因为该塔位于60度纬度,其中对象水平拉伸
及
接下来是版本2代码。您还可以:
测试文件:
id,lat,lon,radius,start_angle,end_angle
1,2.1,3.7,30.5,50.3,100.1
2,60.0,5.8,10.6,80.4,30.2
代码:
导入数学、系统、操作系统
作为pd导入熊猫,作为np导入numpy,作为TQM导入
ifname='test.csv'
mdist=1.#网格覆盖塔扇形区域内各点之间的最小距离(米)
ofname='test{i}.png'#输出图形的文件名
def GenPoints():
pi=math.pi
asteps=360*2#沿整圈的步数,360*2对应于0.5度的精度。
lat_deg2m=111000
latlon_比_度_步数=100
fdtype=np.64
def LonLatDist(p1、p2):
#地球上两点之间的精确距离,点由(lon,lat)元组给出。
#看https://www.movable-type.co.uk/scripts/latlong.html
lon1,lat1=p1[:2]
lon2,lat2=p2[:2]
R=6371000米
#φ,以弧度表示的林
phi1=lat1*pi/180
phi2=lat2*pi/180
dphi=(lat2-lat1)*π/180
dlam=(lon2-lon1)*pi/180
a=abs(数学sin(dphi/2))**2+数学cos(phi1)*数学cos(phi2)*abs(数学sin(dlam/2))**2
c=2*math.atan2(math.sqrt(a),math.sqrt(1-a))
d=R*c(以米为单位)
返回d
def法兰(启动、停止、步骤):
x=开始
当x0:
a=2*math.asin(mdist/(2*r))#r*2*sin(a/2)=mdist
n=数学楼层(2*pi/a)
其他:
n=1
as_uu=np.linspace(0,4*pi,2*n,端点=False)
idx=np.concatenate((
np.searchsorted(如u,np.linspace(0,4*pi,2*asteps,endpoint=False),side=right),
数组([2*n],dtype=np.int64),
))
xs=r*np.cos(as_u2;)
ys=r*np.sin(as_u2;)
dat['idx']=np.concatenate((dat['idx'],idx[None,:]+dat['pts'].shape[0]))
dat['pts']=np.concatenate((dat['pts'],np.vstack((xs,ys)).transpose())
断言dat['idx'][-1,-1]==dat['pts']。形状[0]
断言0。每个塔的面积不是等于
id,lat,lon,radius,start_angle,end_angle
1,2.1,3.7,30.5,50.3,100.1
2,60.0,5.8,10.6,80.4,30.2
import math, sys, os
import pandas as pd, numpy as np, tqdm
ifname = 'test.csv'
mdist = 1. # Minimal distance in meters between points in grid covering tower's sector
ofname = 'test{i}.png' # Outpu file names for drawing
def GenPoints():
pi = math.pi
asteps = 360 * 2 # Number of steps along full circle, 360 * 2 corresponds to precision of 0.5 degree.
lat_deg2m = 111000
latlon_ratio_deg_steps = 100
fdtype = np.float64
def LonLatDist(p1, p2):
# Exact distance between two points on Earth, points given by (lon, lat) tuple.
# See https://www.movable-type.co.uk/scripts/latlong.html
lon1, lat1 = p1[:2]
lon2, lat2 = p2[:2]
R = 6371000 # metres
# phi, lam in radians
phi1 = lat1 * pi / 180
phi2 = lat2 * pi / 180
dphi = (lat2 - lat1) * pi / 180
dlam = (lon2 - lon1) * pi / 180
a = abs(math.sin(dphi / 2)) ** 2 + math.cos(phi1) * math.cos(phi2) * abs(math.sin(dlam / 2)) ** 2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
d = R * c # in metres
return d
def frange(start, stop, step):
x = start
while x < stop:
yield x
x += step
class dict2obj(object):
def __init__(self, dict_):
self.__dict__.update(dict_)
def multi_arange(a):
steps = a[:,2]
lens = ((a[:,1]-a[:,0]) + steps-1)//steps
b = np.repeat(steps, lens)
ends = (lens-1)*steps + a[:,0]
b[0] = a[0,0]
b[lens[:-1].cumsum()] = a[1:,0] - ends[:-1]
return b.cumsum()
def GetPts(*, re, ab, ae, dat = {'pts': np.zeros([0, 2], dtype = fdtype), 'idx': np.zeros([0, 2 * asteps + 1], dtype = np.int64)}):
while (dat['idx'].shape[0] - 1) * mdist < re:
r = dat['idx'].shape[0] * mdist
if dat['idx'].shape[0] > 0:
a = 2 * math.asin(mdist / (2 * r)) # r*2*sin(a/2) = mdist
n = math.floor(2 * pi / a)
else:
n = 1
as_ = np.linspace(0., 4 * pi, 2 * n, endpoint = False)
idx = np.concatenate((
np.searchsorted(as_, np.linspace(0., 4 * pi, 2 * asteps, endpoint = False), side = 'right'),
np.array([2 * n], dtype = np.int64),
))
xs = r * np.cos(as_)
ys = r * np.sin(as_)
dat['idx'] = np.concatenate((dat['idx'], idx[None, :] + dat['pts'].shape[0]))
dat['pts'] = np.concatenate((dat['pts'], np.vstack((xs, ys)).transpose()))
assert dat['idx'][-1, -1] == dat['pts'].shape[0]
assert 0. <= ab <= ae <= 4 * pi, (ab, ae)
ire = round(float(re / mdist))
iab, iae = [round(float(a / (2 * pi / asteps))) for a in [ab, ae]]
pb, pe = [dat['idx'][:ire + 1, ia] for ia in [iab, iae + 1]]
#return np.concatenate([dat['pts'][b : e, :] for b, e in zip(np.nditer(pb), np.nditer(pe))])
return dat['pts'][multi_arange(np.vstack((pb, pe, np.ones_like(pb))).T), :]
def Deg2Rad(a):
return a * pi / 180.
def GetLLRatio(*, lat, dat = {'tab': None}):
if dat['tab'] is None:
dat['tab'] = np.array([
LonLatDist((-shift, clat), (shift, clat)) / LonLatDist((0., clat - shift), (0., clat + shift))
for ilat in range(0, 90 * latlon_ratio_deg_steps) for shift, clat in [(0.00001, ilat / latlon_ratio_deg_steps)]
], dtype = fdtype)
assert -90. <= lat <= 90., lat
return dat['tab'][min(90 * latlon_ratio_deg_steps - 1, round(float(abs(lat) * latlon_ratio_deg_steps)))]
fsize = os.path.getsize(ifname)
area = 0.
with open(ifname, 'rb', buffering = 1 << 16) as fin, tqdm.tqdm(total = fsize, ascii = True, unit = 'B') as prctr:
for idf, df in enumerate(pd.read_csv(fin, iterator = True, chunksize = 1 << 4)):
if idf == 0:
# id,lat,lon,radius,start_angle,end_angle
cols = dict2obj({e : ie for ie, e in enumerate(df.columns.values.tolist())})
istart = df.index[0]
a = df.values.astype(np.float64)
area += np.sum(a[:, cols.radius] * a[:, cols.radius] * ((a[:, cols.end_angle] - a[:, cols.start_angle]) % 360.)) * pi / 360.
for i in range(a.shape[0]):
row = a[i, :]
pts = GetPts(
re = row[cols.radius],
ab = Deg2Rad(row[cols.start_angle]),
ae = Deg2Rad(row[cols.end_angle] + (0., 360.)[int(row[cols.start_angle] >= row[cols.end_angle])]),
)
lats = pts[:, 1] / lat_deg2m + row[cols.lat]
lons = pts[:, 0] / (lat_deg2m * GetLLRatio(lat = row[cols.lat])) + row[cols.lon]
yield {
'idx': istart + i,
'data': df.iloc[i : i + 1, :],
'points': np.vstack((lons, lats)).transpose(),
}
prctr.update(fin.tell() - prctr.n)
prctr.update(fsize - prctr.n)
def Draw():
import PIL.Image, PIL.ImageDraw
swidth = 1048
sradius = 10
antialias_mult = 1 # Degree of antialiasing, 1 - Not antialiased, 2 - Some antialiasing, 4 - Good antialiasing
for iv, v in enumerate(GenPoints()):
ps = v['points']
xmin, xmax = np.amin(ps[:, 0]), np.amax(ps[:, 0])
ymin, ymax = np.amin(ps[:, 1]), np.amax(ps[:, 1])
sheight = math.ceil(swidth * (ymax - ymin) / (xmax - xmin))
assert antialias_mult in [1, 2, 4, 8], antialias_mult
width = swidth * antialias_mult
radius = sradius * antialias_mult
height = sheight * antialias_mult
img = PIL.Image.new('RGB', (width, height))
imgd = PIL.ImageDraw.Draw(img)
for i, (x, y) in enumerate(zip(np.nditer(ps[:, 0]), np.nditer(ps[:, 1]))):
imgd.ellipse([
(width - 2 * radius) * (x - xmin) / (xmax - xmin),
(height - 2 * radius) * (ymax - y) / (ymax - ymin),
(width - 2 * radius) * (x - xmin) / (xmax - xmin) + 2 * radius,
(height - 2 * radius) * (ymax - y) / (ymax - ymin) + 2 * radius,
], fill = (round(255 * (1 - i / ps.shape[0] * 0.9)),) * 3, outline = 'black')
if antialias_mult > 1:
img = img.resize([swidth, sheight], PIL.Image.LANCZOS)
img.save(ofname.format(i = iv))
def TestFast():
print(len(list(GenPoints())))
Draw()
#TestFast()