将纬度和经度转换为 3D 空间中的点

Posted

技术标签:

【中文标题】将纬度和经度转换为 3D 空间中的点【英文标题】:Convert Latitude and Longitude to point in 3D space 【发布时间】:2012-05-06 20:07:34 【问题描述】:

我需要将纬度和经度值转换为 3 维空间中的一个点。我已经尝试了大约 2 个小时,但我没有得到正确的结果。

Equirectangular 坐标来自openflights.org。我尝试了几种 cossin 的组合,但结果看起来并不像我们心爱的小地球。


在下面,您可以看到应用Wikipedia 建议的转换的结果。我想可以从上下文中猜出c4d.Vector 是什么。

def llarToWorld(latit, longit, altid, rad):
    x = math.sin(longit) * math.cos(latit)
    z = math.sin(longit) * math.sin(latit)
    y = math.cos(longit)
    v = c4d.Vector(x, y, z)
    v = v * altid + v * rad
    return v

红色:X,绿色:Y,蓝色:Z

确实可以识别北美和南美,尤其是墨西哥湾周围的土地。但是,它看起来有点压扁,有点放错地方了..


由于结果看起来有些旋转,我想,我尝试交换纬度和经度。但是这个结果有点尴尬。

def llarToWorld(latit, longit, altid, rad):
    temp = latit
    latit = longit
    longit = temp
    x = math.sin(longit) * math.cos(latit)
    z = math.sin(longit) * math.sin(latit)
    y = math.cos(longit)
    v = c4d.Vector(x, y, z)
    v = v * altid + v * rad
    return v


这是没有转换值的结果。

def llarToWorld(latit, longit, altid, rad):
    return c4d.Vector(math.degrees(latit), math.degrees(longit), altid)


问题:如何正确转换经纬度?


解决方案

感谢 TreyA,我在 mathworks.com 上找到了 this 页面。执行它的代码如下:

def llarToWorld(lat, lon, alt, rad):
    # see: http://www.mathworks.de/help/toolbox/aeroblks/llatoecefposition.html
    f  = 0                              # flattening
    ls = atan((1 - f)**2 * tan(lat))    # lambda

    x = rad * cos(ls) * cos(lon) + alt * cos(lat) * cos(lon)
    y = rad * cos(ls) * sin(lon) + alt * cos(lat) * sin(lon)
    z = rad * sin(ls) + alt * sin(lat)

    return c4d.Vector(x, y, z)

实际上,我切换了yz,因为那时地球是旋转的,但是,它起作用了!结果是这样的:

【问题讨论】:

altid 是海拔高度,但rad 是什么?那是地球的半径吗? altidrad 是否使用相同的单位(英尺)?如果您只使用半径(即仅v = v * rad)怎么办? 还可以查看谷歌搜索“lla to ecef” - 以地球为中心的纬度/经度/高度,固定地球。 @TreyA 完美,谢谢!发现这个:mathworks.de/help/toolbox/aeroblks/llatoecefposition.html 这是正确的公式。 :) 如果您想要代表,您可以将您的评论作为答案,这样我也可以将我的问题标记为已回答。 【参考方案1】:

我已经重新格式化了之前在这里提到的代码,但更重要的是,您遗漏了 Niklas R 提供的链接中提到的一些方程式

def LLHtoECEF(lat, lon, alt):
    # see http://www.mathworks.de/help/toolbox/aeroblks/llatoecefposition.html

    rad = np.float64(6378137.0)        # Radius of the Earth (in meters)
    f = np.float64(1.0/298.257223563)  # Flattening factor WGS84 Model
    cosLat = np.cos(lat)
    sinLat = np.sin(lat)
    FF     = (1.0-f)**2
    C      = 1/np.sqrt(cosLat**2 + FF * sinLat**2)
    S      = C * FF

    x = (rad * C + alt)*cosLat * np.cos(lon)
    y = (rad * C + alt)*cosLat * np.sin(lon)
    z = (rad * S + alt)*sinLat

    return (x, y, z)

比较输出:查找加利福尼亚州洛杉矶的 ECEF(34.0522,-118.40806,0 海拔) 我的代码: X = -2516715.36114 米或 -2516.715 公里 Y = -4653003.08089 米或 -4653.003 公里 Z = 3551245.35929 米或 3551.245 公里

您的代码: X = -2514072.72181 米或-2514.072 公里 Y = -4648117.26458 米或-4648.117 公里 Z = 3571424.90261 米或 3571.424 公里

虽然在您的地球自转环境中,您的函数会生成正确的地理区域以供显示,但它不会给出正确的 ECEF 等效坐标。正如您所看到的,一些参数的差异高达 20 KM,这是一个相当大的错误。

扁平化因子,f 取决于您为转换假设的模型。典型,型号为WGS 84;但是,还有其他型号。

就我个人而言,我喜欢在海军研究生院使用this link 来检查我的转化情况。

【讨论】:

这可行,但您首先需要将角度转换为弧度。纬度/经度值通常以度数形式提供。 正如@TomislavMuic 所指出的,您必须在使用上述 sn-p 之前将 degree lat lon 转换为弧度。为此,只需使用 math.radians() 函数。【参考方案2】:

你没有按照***的建议去做。请仔细阅读。

他们说:

x = r cos(phi) sin(theta)
y = r sin(phi) sin(theta)
z = r cos(theta)

然后:

theta == latitude
phi == longitude

在你的情况下,r = 半径 + 高度

所以你应该使用:

r = radius + altitude
x = r cos(long) sin(lat)
y = r sin(long) sin(lat)
z = r cos(lat)

请注意,最后一个条目是cos(lat)(您使用的是经度)。

【讨论】:

不幸的是,这与像素 #2 显示的结果相同.. :( 不,不是。 lat/long 仅交换 z。你把它们都换了。 嗯,不完全一样,但和第二张图差不多。交换纬度和经度时,它与第一张图片非常相似。我通过搜索lla to ecef(感谢 TreyA)找到的链接非常完美。见:mathworks.de/help/toolbox/aeroblks/llatoecefposition.html 应该是x = r cos(long) cos(lat) y = r sin(long) cos(lat) z = r sin(lat)。请注意 lat 与 xy 平面的角度,而不是与***建议的 z 轴的角度。【参考方案3】:

正如 TreyA 所说,LLA to ECEF 是解决方案。见http://www.mathworks.de/help/toolbox/aeroblks/llatoecefposition.html

【讨论】:

以上是关于将纬度和经度转换为 3D 空间中的点的主要内容,如果未能解决你的问题,请参考以下文章

从任何点将米转换为纬度经度

将纬度/经度转换为美国州

我们如何将纬度和经度转换为网站中的地址?

通过R中的sf将经度和纬度序列转换为多边形

R - 如何将纬度和经度坐标转换为地址/人类可读的位置?

将地址转换为经度和纬度