Mapping 从经度\纬度转换为笛卡尔坐标

Mapping 从经度\纬度转换为笛卡尔坐标,mapping,geometry,geospatial,Mapping,Geometry,Geospatial,我有一些以地球为中心的坐标点,如纬度和经度() 如何将它们转换为原点位于地球中心的笛卡尔坐标(x,y,z)?以下是我找到的答案: 为了使定义完整,在笛卡尔坐标系中: x轴穿过长纬度(0,0),因此经度0与赤道相交 y轴穿过(0,90) z轴穿过两极 转换为: x = R * cos(lat) * cos(lon) y = R * cos(lat) * sin(lon) z = R *sin(lat) 其中R为(例如6371 km) 如果三角函数需要弧度(它们可能需要弧度),则需要首先将

我有一些以地球为中心的坐标点,如纬度和经度()


如何将它们转换为原点位于地球中心的笛卡尔坐标(x,y,z)?

以下是我找到的答案:

为了使定义完整,在笛卡尔坐标系中:

  • x轴穿过长纬度(0,0),因此经度0与赤道相交
  • y轴穿过(0,90)
  • z轴穿过两极
转换为:

x = R * cos(lat) * cos(lon)

y = R * cos(lat) * sin(lon)

z = R *sin(lat)
其中R为(例如6371 km)

如果三角函数需要弧度(它们可能需要弧度),则需要首先将经度和纬度转换为弧度。显然,您需要的是十进制表示,而不是度\分\秒(请参阅关于转换)

反向转换公式:

   lat = asin(z / R)
   lon = atan2(y, x)
asin当然是正弦弧。不要忘记将弧度转换回度


给出了c#代码(注意它与公式非常不同),并给出了一些解释和图表,说明了为什么这是正确的,

为什么要实现一些已经实现并经过测试验证的东西

例如,C#具有JTS拓扑套件的.NET端口

具体来说,您的计算有一个严重的缺陷。地球不是一个完美的球体,地球半径的近似值可能无法精确测量


如果在某些情况下可以使用自制函数,那么GIS就是一个很好的例子,在这个领域,人们更喜欢使用可靠的、经过测试的库。

我最近使用 WGS-84数据上的“哈弗斯公式”,是“哈弗斯定律”的一个衍生物,结果非常令人满意

是的,WGS-84假设地球是一个椭球体,但我相信使用类似“哈弗森公式”的方法只能得到大约0.5%的平均误差,在你的情况下,这可能是一个可接受的误差量。你总是会有一定的误差,除非你说的是几英尺的距离,甚至理论上还有地球的曲率。。。如果您需要更严格的WGS-84兼容方法,请检查“Vincenty公式”

我知道starblue从何而来,但好的软件工程通常是权衡取舍,所以这一切都取决于您所做工作所需的准确性。例如,在某些情况下,根据“曼哈顿距离公式”计算的结果与根据“距离公式”计算的结果相比可能更好,因为计算成本更低。想一想“哪一点最近?”这样的场景,你不需要精确的距离测量

关于“哈弗森公式”,它很容易实现,也很好,因为它使用的是“球面三角法”,而不是基于二维三角法的“余弦定律”,因此你可以在精度和复杂性之间取得很好的平衡


一位名叫Chris的先生有一本很棒的书,解释了您感兴趣的一些概念,并演示了各种编程实现;这应该也能回答您的x/y转换问题。

如果您关心基于椭球体而不是球体获取坐标,请看一看-它给出了公式。具有转换所需的WGS84常量


其中的公式还考虑了相对于参考椭球面的高度(如果您从GPS设备获取高度数据,则非常有用)。

GPS(WGS84)
转换为笛卡尔坐标的理论

以下是我正在使用的内容:

  • GPS(WGS84)和笛卡尔坐标中的经度相同
  • 纬度需要通过WGS 84椭球参数转换,半长轴为6378137 m,并且
  • 展平的倒数为298.257223563
我附加了一个我编写的VB代码:

请注意,
h
高度高于
WGS 84椭球体

通常
GPS
会给我们提供
H
以上的
MSL
高度。 必须使用位势模型将
MSL
高度转换为
WGS 84椭球体上方的高度
h
(Lemoine等人,1998)。
这是通过以15弧分的空间分辨率插值大地水准面高度文件的栅格来完成的

或者,如果您有某个级别的专业人员
GPS
具有高度
H
(msl,高于平均海平面的高度)和
起伏
,则
大地水准面
和从内部表格输出的所选基准的
椭球面(m)
之间的关系。您可以获得
H=H(msl)+起伏

通过笛卡尔坐标到XYZ:

x = R * cos(lat) * cos(lon)

y = R * cos(lat) * sin(lon)

z = R *sin(lat)
该软件提供了一个命令行程序,可以进行转换,例如

LAT=40
LON=-110
echo $LON $LAT | cs2cs +proj=latlong +datum=WGS84 +to +proj=geocent +datum=WGS84

它还提供了一个。特别是,函数
pj_geodetic_to_geocentric
将进行转换,而无需首先设置投影对象。

您可以在Java上以这种方式进行转换

public List<Double> convertGpsToECEF(double lat, double longi, float alt) {

    double a=6378.1;
    double b=6356.8;
    double N;
    double e= 1-(Math.pow(b, 2)/Math.pow(a, 2));
    N= a/(Math.sqrt(1.0-(e*Math.pow(Math.sin(Math.toRadians(lat)), 2))));
    double cosLatRad=Math.cos(Math.toRadians(lat));
    double cosLongiRad=Math.cos(Math.toRadians(longi));
    double sinLatRad=Math.sin(Math.toRadians(lat));
    double sinLongiRad=Math.sin(Math.toRadians(longi));
    double x =(N+0.001*alt)*cosLatRad*cosLongiRad;
    double y =(N+0.001*alt)*cosLatRad*sinLongiRad;
    double z =((Math.pow(b, 2)/Math.pow(a, 2))*N+0.001*alt)*sinLatRad;

    List<Double> ecef= new ArrayList<>();
    ecef.add(x);
    ecef.add(y);
    ecef.add(z);

    return ecef;


}
public List convertGpsToECEF(双lat、双longi、float-alt){
双a=6378.1;
双b=6356.8;
双N;
双e=1-(数学功率(b,2)/数学功率(a,2));
N=a/(数学sqrt(1.0-(e*Math.pow(Math.sin(Math.toRadians,lat)),2));
double-cosLatRad=Math.cos(Math.toRadians(lat));
双余弦长=数学余弦(数学余弦长);
double sinLatRad=Math.sin(Math.toRadians(lat));
double sinLongiRad=Math.sin(Math.toRadians(longi));
双x=(N+0.001*alt)*余弦*余弦;
双y=(N+0.001*alt)*共轴*正弦;
双z=((数学功率(b,2)/数学功率(a,2))*N+0.001*alt)*sinLatRad;
List ecef=new ArrayList();
ecef.添加(x);
ecef.添加(y);
ecef.添加(z);
返回ecef;
}

LAT=40 LON=-110 echo $LON $LAT | cs2cs +proj=latlong +datum=WGS84 +to +proj=geocent +datum=WGS84

public List<Double> convertGpsToECEF(double lat, double longi, float alt) {

    double a=6378.1;
    double b=6356.8;
    double N;
    double e= 1-(Math.pow(b, 2)/Math.pow(a, 2));
    N= a/(Math.sqrt(1.0-(e*Math.pow(Math.sin(Math.toRadians(lat)), 2))));
    double cosLatRad=Math.cos(Math.toRadians(lat));
    double cosLongiRad=Math.cos(Math.toRadians(longi));
    double sinLatRad=Math.sin(Math.toRadians(lat));
    double sinLongiRad=Math.sin(Math.toRadians(longi));
    double x =(N+0.001*alt)*cosLatRad*cosLongiRad;
    double y =(N+0.001*alt)*cosLatRad*sinLongiRad;
    double z =((Math.pow(b, 2)/Math.pow(a, 2))*N+0.001*alt)*sinLatRad;

    List<Double> ecef= new ArrayList<>();
    ecef.add(x);
    ecef.add(y);
    ecef.add(z);

    return ecef;


}
# Converting lat/long to cartesian
import numpy as np

def get_cartesian(lat=None,lon=None):
    lat, lon = np.deg2rad(lat), np.deg2rad(lon)
    R = 6371 # radius of the earth
    x = R * np.cos(lat) * np.cos(lon)
    y = R * np.cos(lat) * np.sin(lon)
    z = R *np.sin(lat)
    return x,y,z