将 GPS 转换为 ENU
Converting GPS to ENU
我想创建 android 应用程序 "Points of interest"。我读过很多不同的教程,但我不明白为什么我需要将 GPS 坐标转换为 ECEF,然后再转换为 ENU。你能解释一下吗?
谢谢!
地理空间坐标系是一个很大的话题,但在 ECEF 和 ENU 等系统之间的主要选择是关于您是要描述地球表面的大区域还是小区域。
当Android提供一个geolocation via the LocationListener API, it typically does this using latitude/longitude/altitude which is ideal for representing any point over the Earth's surface, but is a "polar" or "geodetic" coordinate system that isn't ideal for plotting 2D locations. Standard techniques允许这个坐标系转换成ECEF,这是另一个适合全球的坐标系,但是"cartesian"所以可以使用比原始 latitude/longitude/altitude 坐标简单得多的数学运算进行旋转和缩放。
Earth-Centred 地球固定 (ECEF) 使用以地球中心为原点的坐标系,因此地面上的任何点都将具有通常以百万米为单位的坐标值.这对于描述卫星轨道或跨越多个大陆的位置非常有用,但对于城镇或城市内兴趣点的二维图不是很方便。
如果您想绘制地球表面一小块区域的二维地图,那么 East-North-Up 坐标系可能会方便得多。要使用它,您需要一个参考位置(例如特定城市的中心),可以定义当地 East/North/Up 方向。然后那些提供一组 x/y/z 轴,其中 x 和 y 轴可以直接转换为 2D 屏幕坐标。显然,随着感兴趣区域变大(例如超过 100 公里),地球曲率的影响变得更加明显,ENU 坐标系将变得不那么有用。有关详细信息,请参阅 wikipedia。
从 ECEF 到 ENU 坐标系的移动可以通过一组简单的矩阵加法和乘法来完成,这些加法和乘法可以根据地图中心的 ECEF 位置和 [=27= 中的单位向量计算得出] 方向。
您可以在 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<Double> convertECEFtoENU(List<Double> ecefUser, List<Double> ecefPOI, double lat, double longi){
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));
List<Double> vector = new ArrayList<>();
vector.add(ecefUser.get(0)-ecefPOI.get(0));
vector.add(ecefUser.get(1)-ecefPOI.get(1));
vector.add(ecefUser.get(2)-ecefPOI.get(2));
double e= vector.get(0)*(-sinLongiRad)+vector.get(0)*(cosLongiRad);
double n= vector.get(0)*(-sinLatRad)*(cosLongiRad)+vector.get(1)*(-sinLatRad)*(sinLongiRad)+vector.get(2)*cosLatRad;
double u= vector.get(0)*(cosLatRad)*(cosLongiRad)+vector.get(1)*(cosLatRad)*(sinLongiRad)+vector.get(2)*sinLatRad;
List<Double> enu= new ArrayList<>();
enu.add(e);
enu.add(n);
enu.add(u);
return enu;
}
我想创建 android 应用程序 "Points of interest"。我读过很多不同的教程,但我不明白为什么我需要将 GPS 坐标转换为 ECEF,然后再转换为 ENU。你能解释一下吗?
谢谢!
地理空间坐标系是一个很大的话题,但在 ECEF 和 ENU 等系统之间的主要选择是关于您是要描述地球表面的大区域还是小区域。
当Android提供一个geolocation via the LocationListener API, it typically does this using latitude/longitude/altitude which is ideal for representing any point over the Earth's surface, but is a "polar" or "geodetic" coordinate system that isn't ideal for plotting 2D locations. Standard techniques允许这个坐标系转换成ECEF,这是另一个适合全球的坐标系,但是"cartesian"所以可以使用比原始 latitude/longitude/altitude 坐标简单得多的数学运算进行旋转和缩放。
Earth-Centred 地球固定 (ECEF) 使用以地球中心为原点的坐标系,因此地面上的任何点都将具有通常以百万米为单位的坐标值.这对于描述卫星轨道或跨越多个大陆的位置非常有用,但对于城镇或城市内兴趣点的二维图不是很方便。
如果您想绘制地球表面一小块区域的二维地图,那么 East-North-Up 坐标系可能会方便得多。要使用它,您需要一个参考位置(例如特定城市的中心),可以定义当地 East/North/Up 方向。然后那些提供一组 x/y/z 轴,其中 x 和 y 轴可以直接转换为 2D 屏幕坐标。显然,随着感兴趣区域变大(例如超过 100 公里),地球曲率的影响变得更加明显,ENU 坐标系将变得不那么有用。有关详细信息,请参阅 wikipedia。
从 ECEF 到 ENU 坐标系的移动可以通过一组简单的矩阵加法和乘法来完成,这些加法和乘法可以根据地图中心的 ECEF 位置和 [=27= 中的单位向量计算得出] 方向。
您可以在 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<Double> convertECEFtoENU(List<Double> ecefUser, List<Double> ecefPOI, double lat, double longi){
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));
List<Double> vector = new ArrayList<>();
vector.add(ecefUser.get(0)-ecefPOI.get(0));
vector.add(ecefUser.get(1)-ecefPOI.get(1));
vector.add(ecefUser.get(2)-ecefPOI.get(2));
double e= vector.get(0)*(-sinLongiRad)+vector.get(0)*(cosLongiRad);
double n= vector.get(0)*(-sinLatRad)*(cosLongiRad)+vector.get(1)*(-sinLatRad)*(sinLongiRad)+vector.get(2)*cosLatRad;
double u= vector.get(0)*(cosLatRad)*(cosLongiRad)+vector.get(1)*(cosLatRad)*(sinLongiRad)+vector.get(2)*sinLatRad;
List<Double> enu= new ArrayList<>();
enu.add(e);
enu.add(n);
enu.add(u);
return enu;
}