计算地图上两点距离

参考:https://blog.csdn.net/pyx6119822/article/details/52298037

# coding: utf-8

import math

# 参看:http://blog.csdn.net/zengmingen/article/details/68490497

# 大地坐标系资料WGS-84 长半径a=6378137 短半径b=6356752.3142 扁率f=1/298.2572236
# 长半径a=6378137
a = 6378137
# 短半径b=6356752.3142
b = 6356752.3142
# 扁率f=1/298.2572236
f = 1 / 298.257223563


#  角度转弧度
def rad(d):
    return d * math.pi / 180.0


# 弧度转角度
def deg(x):
    return x * 180.0 / math.pi


def computerThatLonLat(lon, lat, brng, dist):
    """
    取边界值请注意,程序未验证。实际情况出现请人工验证边界值的情况。

    :param lon: 经度, 正东为正方向。取值:[0, 360)
    :param lat: 纬度,正北为正方向。取值:[-90, 90]
    :param brng: 方位角,和真北方向的夹角,顺时针方向是正方向。取值[0, 360],正北:0,正东:90,正南:180,正西:270
    :param dist: 距离。单位:米
    :return: 一个数组:[经度,纬度]
    """

    alpha1 = rad(brng)
    sinAlpha1 = math.sin(alpha1)
    cosAlpha1 = math.cos(alpha1)
    # print("alpha1:{1}, sinAlpha1:{1}, cosAlpha1:{2}".format(alpha1, sinAlpha1, cosAlpha1))

    tanU1 = (1 - f) * math.tan(rad(lat))
    cosU1 = 1 / math.sqrt((1 + tanU1 * tanU1))
    sinU1 = tanU1 * cosU1
    sigma1 = math.atan2(tanU1, cosAlpha1)
    sinAlpha = cosU1 * sinAlpha1
    cosSqAlpha = 1 - sinAlpha * sinAlpha
    uSq = cosSqAlpha * (a * a - b * b) / (b * b)
    A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)))
    B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)))
    # print("tanU1:{0}, cosU1:{1}, sinU1:{2}, sigma1:{3}, sinAlpha:{4}, cosSqAlpha{5}, uSq:{6}, A:{7}, B:{8}".format(tanU1, cosU1, sinU1, sigma1, sinAlpha, cosSqAlpha, uSq, A, B))

    cos2SigmaM = 0
    sinSigma = 0
    cosSigma = 0
    sigma = dist / (b * A)
    sigmaP = 2 * math.pi

    while math.fabs(sigma - sigmaP) > 1e-12:
        cos2SigmaM = math.cos(2 * sigma1 + sigma)
        sinSigma = math.sin(sigma)
        cosSigma = math.cos(sigma)

        deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (
            cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (
                -3 + 4 * cos2SigmaM * cos2SigmaM)))

        sigmaP = sigma
        sigma = dist / (b * A) + deltaSigma

    tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1
    # print("sinU1:{0}, tmp:{1}".format(sinU1, tmp))
    lat2 = math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
                      (1 - f) * math.sqrt(sinAlpha * sinAlpha + tmp * tmp))

    lambdas = math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1)
    C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha))
    L = lambdas - (1 - C) * f * sinAlpha * (
        sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)))
    revAz = math.atan2(sinAlpha, -tmp)

    # print("revAz:{0}.".format(revAz))
    # print("lon:{0}, lat:{1}.".format(lon+deg(L), deg(lat2) ))
    return [lon + deg(L), deg(lat2)]


"""
lon = 0
lat = 0
brng = 90
dist = 2000000

print(computerThatLonLat(lon, lat, brng, dist))
"""


def getRightUp(lon, lat, dist):
    res = computerThatLonLat(lon, lat, 90, dist)
    res = computerThatLonLat(res[0], res[1], 0, dist)
    return res


def getLeftBottom(lon, lat, dist):
    res = computerThatLonLat(lon, lat, 270, dist)
    res = computerThatLonLat(res[0], res[1], 180, dist)
    return res


def getRectangle(clon, clat, n, m):
    ru = getRightUp(clon, clat, 1.0 * n * m / 2.0)
    lb = getLeftBottom(clon, clat, 1.0 * n * m / 2.0)
    return [lb, ru]


clon = 0
clat = 0
n = 100
m = 100

# print(getRectangle(clon, clat, n, m))

"""
if __name__ == "__main__":
    if len(sys.argv) != 5:
        print("please input 4 parameter: centerlon centerlat n(一行格子个数) m(单个格子的宽度,单位:米).")
    else:
        print(getRectangle(float(sys.argv[1]), float(sys.argv[2]), float(sys.argv[3]), float(sys.argv[4])))
"""


# 参考:http://blog.csdn.net/zhuqiuhui/article/details/53180395

# 计算方位角
def getDegree(latA, lonA, latB, lonB):
    """
    Args:
        point p1(latA, lonA)
        point p2(latB, lonB)
    Returns:
        bearing between the two GPS points,
        default: the basis of heading direction is north
    """
    radLatA = rad(latA)
    radLonA = rad(lonA)
    radLatB = rad(latB)
    radLonB = rad(lonB)
    dLon = radLonB - radLonA
    y = math.sin(dLon) * math.cos(radLatB)
    x = math.cos(radLatA) * math.sin(radLatB) - math.sin(radLatA) * math.cos(radLatB) * math.cos(dLon)
    brng = deg(math.atan2(y, x))
    brng = (brng + 360) % 360
    return brng


# print(getDegree(39.997559, 116.537327, 39.944033, 116.474661))


# 计算距离
def getDistance(latA, lonA, latB, lonB):
    ra = 6378140  # radius of equator: meter
    rb = 6356755  # radius of polar: meter
    flatten = (ra - rb) / ra  # Partial rate of the earth
    # change angle to radians
    radLatA = rad(latA)
    radLonA = rad(lonA)
    radLatB = rad(latB)
    radLonB = rad(lonB)

    pA = math.atan(rb / ra * math.tan(radLatA))
    pB = math.atan(rb / ra * math.tan(radLatB))
    x = math.acos(math.sin(pA) * math.sin(pB) + math.cos(pA) * math.cos(pB) * math.cos(radLonA - radLonB))
    c1 = (math.sin(x) - x) * (math.sin(pA) + math.sin(pB)) ** 2 / math.cos(x / 2) ** 2
    c2 = (math.sin(x) + x) * (math.sin(pA) - math.sin(pB)) ** 2 / math.sin(x / 2) ** 2
    dr = flatten / 8 * (c1 - c2)
    distance = ra * (x + dr)
    return distance


# print(getDistance(-0.0452184737581234, -0.04491576420631404, 0.04521847375812339, 0.044915764206314046))

"""
inputf = open("outputj.txt")


exps = 1e-10

for i in range(0,360):
    for j in range(-90,91):
        res = computerThatLonLat(i,j,brng, dist)
        line = inputf.readline().lower().strip().split(",")

        if math.fabs(res[0] - float(line[0])) > exps or math.fabs(res[1] - float(line[1])) > exps or math.fabs(res[2] - float(line[2])) > exps :
            print(i,j)
            print(res)
            print(line)

        if math.fabs(getDegree(j,i, res[2], res[1]) - 63) > 2:
            print(i,j)
        if math.fabs(getDistance(j,i,res[2],res[1]) - 47 ) > 2:
            print("aaaa",i,j)

"""

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值