gmt-china / GMT_docs

GMT 中文手册
https://docs.gmt-china.org
114 stars 76 forks source link

修正“Flat Earth Distance”和“Geodesic distance”的中文翻译 #769

Closed seisman closed 3 years ago

seisman commented 3 years ago

-je 是椭球面上两点的距离,大地测量里一般称为大地线长(看上去就是现在文档里说的测地距离),单位从来都是 m/km 等长度单位,没见过用度的。计算公式比较多,但精度和效率不同,比较常用的就是 Vincenty 公式,也是 GMT 默认的计算大地线长的公式,精度非常高,在几千公里的尺度上,精度仍然十分可靠,可以达到分米。

-jg 球近似,也就是球面上两点的距离,看上去等同于文档里说的大圆距离,但是和大地测量里的球面距离是不一样的,大地测量里的球的定义一般是唯一的,单位也是 m/km。据我了解,在 1 度(大概 111 km)的尺度上,误差已经大于 500m。

-jf 平面近似,平面上两点的距离。通常情况下,在很小的区域内,可以把椭球/球可以近似为平面,然后进行计算。对于一般的工程应用来说,10km 尺度以内,可以使用平面近似,大于 10km,就不能用平面近似。

所以三种计算距离的方式的准确名称是:大地线长距离,大圆路径距离和平面距离?

_Originally posted by @seisman in https://github.com/gmt-china/GMT_docs/issues/766#issuecomment-959295701_

根据 @ZMAlt 的反馈,中文手册中目前对 flat earth distance 和 geodesic distance 的翻译并不准确。

@ZMAlt 的建议是三种距离方式翻译为“平面距离”,“大圆路径距离”和“大地线长度”。根据 ArcGIS 的一篇博文(https://pro.arcgis.com/zh-cn/pro-app/latest/tool-reference/spatial-analyst/geodesic-versus-planar-distance.htm ),似乎测地线距离也是很常用的翻译。

我个人更倾向于将三者翻译为“平面距离”,“大圆路径距离”,和“测地线距离”。@ZMAlt 你的意见如何?

wangliang1989 commented 3 years ago

平面距离=墨卡托投影里的纸面距离 测地线距离=球体地球的球面距离 大圆路径距离是什么?

wangliang1989 commented 3 years ago

平面距离=墨卡托投影里的纸面距离 测地线距离=球体地球的球面距离 大圆路径距离是什么?

我知道大圆路径是什么,只是说如果测地线距离=球体地球的球面距离,测地线距离!=大圆路径距离,那大圆路径距离是什么?

wangliang1989 commented 3 years ago

平面距离=墨卡托投影里的纸面距离 测地线距离=球体地球的球面距离 大圆路径距离是什么?

我知道大圆路径是什么,只是说如果测地线距离=球体地球的球面距离,测地线距离!=大圆路径距离,那大圆路径距离是什么?

ZMAlt commented 3 years ago

@ZMAlt 的建议是三种距离方式翻译为“平面距离”,“大圆路径距离”和“大地线长度”。根据 ArcGIS 的一篇博文(https://pro.arcgis.com/zh-cn/pro-app/latest/tool-reference/spatial-analyst/geodesic-versus-planar-distance.htm ),似乎测地线距离也是很常用的翻译。

我个人更倾向于将三者翻译为“平面距离”,“大圆路径距离”,和“测地线距离”。@ZMAlt 你的意见如何?

我搜了下,维基也有同样的描述 https://zh.wikipedia.org/wiki/%E6%B5%8B%E5%9C%B0%E7%BA%BF 我觉得可以

ZMAlt commented 3 years ago

平面距离=墨卡托投影里的纸面距离 测地线距离=球体地球的球面距离 大圆路径距离是什么?

平面距离不一定是墨卡托投影,可以是其他投影,只要投影到平面 测地线/大地线 是椭球上两点的距离 大圆路径 可以认为是球面距离

wangliang1989 commented 3 years ago

平面距离=墨卡托投影里的纸面距离 测地线距离=球体地球的球面距离 大圆路径距离是什么?

平面距离不一定是墨卡托投影,可以有很多投影,只要投影到平面 测地线/大地线 是椭球上两点的距离 大圆路径 可以认为是球面距离

如果大圆距离是球面距离,那gmt的计算结果里,经度相同而纬度不相同的点的距离就该是纬度直接相减,昨天的实验不是

ZMAlt commented 3 years ago

如果大圆距离是球面距离,那gmt的计算结果里,经度相同而纬度不相同的点的距离就该是纬度直接相减,昨天的实验不是

我觉得角度为单位的结果就有问题,不同纬度的角度对应的实际距离也在变化

wangliang1989 commented 3 years ago

如果大圆距离是球面距离,那gmt的计算结果里,经度相同而纬度不相同的点的距离就该是纬度直接相减,昨天的实验不是

我觉得角度为单位的结果就有问题,不同纬度的角度对应的实际距离也在变化

球面不存在这个问题。我意思是,gmt里的大圆距离和测地线距离可能都是在椭球地球里算的,但是默认情况下用的一个简化公式

ZMAlt commented 3 years ago

球面不存在这个问题。我意思是,gmt里的大圆距离和测地线距离可能都是在椭球地球里算的,但是默认情况下用的一个简化公式

我看了下源码: 大圆距离用的确实是球面距离的公式 https://zh.wikipedia.org/wiki/%E5%A4%A7%E5%9C%86%E8%B7%9D%E7%A6%BB 公式的结果为度, 如果单位设置为 m/km 的话,就乘以一个 scale

对于大地线长度, 如果设置单位是 m/km... 的话,默认用的是 vincenty 公式,结果单位是 m 如果设置单位为 度... 的话,用的不是 vincenty 公式(因为 vincenty 公式的结果就是 m/km),而是把椭球坐标转换为球坐标,然后计算(详细计算过程我没看)

所以,我认为,结论如下:

  1. 所有的尺度均可以使用大地线长度,精度最高,小尺度可以用大圆距离和平面距离
  2. 单位最好用 km,度一般是大概估计
seisman commented 3 years ago

The issue was fixed by 0d215103.

ZMAlt commented 3 years ago

gmt计算大圆距离有三种计算方法,但是只有个两种“地球”,球体和椭球体,所以为什么gmt有三种计算方式,我的疑问还是没解决

来自 @wangliang1989 https://github.com/gmt-china/GMT_docs/pull/766#issuecomment-962908611

Flat earth 一定是用了投影的,把地理坐标投影到平面,然后计算。 Sphere earth 我猜是用的球面距离公式,但是球的定义可能有点门道,我还没细看过

来自 @ZMAlt https://github.com/gmt-china/GMT_docs/pull/766#issuecomment-959148084

这里我又看了下 flat earth 的源码,我关于 Flat earth的表述有点问题,我原本以为是分别对地理坐标投影,然后分带计算平面距离。但其实不是,flat earth 用的不是投影到平面计算以 m/km 为单位的距离,而是非常简单的经纬度差值的 hypot 计算,然后乘以一个投影地区整体的 scale。这样看来,精度就更加低了。 也就是说 flat earth 是直接用的地理坐标的经纬度差值和投影地区的 scale 计算的。这种情况下,精度已经非常差了,基本到不了考虑是球还是椭球的地步了。

看了下面源码结合当前的中文文档基本就明白了。

flat earth

源码

GMT_LOCAL double gmtmap_flatearth_dist_degree (struct GMT_CTRL *GMT, double x0, double y0, double x1, double y1) {
    /* Calculates the approximate flat earth distance in degrees.
       If difference in longitudes exceeds 180 we pick the other
       offset (360 - offset)
     */
    double dlon;
    gmt_M_unused(GMT);

    gmt_M_set_delta_lon (x0, x1, dlon);
    return (hypot ( dlon * cosd (0.5 * (y1 + y0)), (y1 - y0)));
}

/*! . */
GMT_LOCAL double gmtmap_flatearth_dist_meter (struct GMT_CTRL *GMT, double x0, double y0, double x1, double y1) {
    /* Calculates the approximate flat earth distance in km.
       If difference in longitudes exceeds 180 we pick the other
       offset (360 - offset)
     */
    return (gmtmap_flatearth_dist_degree (GMT, x0, y0, x1, y1) * GMT->current.proj.DIST_M_PR_DEG);
}

Sphere earth

GMT_LOCAL double gmtmap_haversine (struct GMT_CTRL *GMT, double lon1, double lat1, double lon2, double lat2) {
    /* Haversine formula for great circle distance.  Intermediate function that returns sin^2 (half_angle).
     * This avoids problems with short distances where cos(c) is close to 1 and acos is inaccurate.
     */

    double sx, sy, sin_half_squared;

    if (lat1 == lat2 && lon1 == lon2) return (0.0);

    if (GMT->current.setting.proj_aux_latitude != GMT_LATSWAP_NONE) {   /* Use selected auxiliary latitude */
        lat1 = gmt_lat_swap (GMT, lat1, GMT->current.setting.proj_aux_latitude);
        lat2 = gmt_lat_swap (GMT, lat2, GMT->current.setting.proj_aux_latitude);
    }

    sy = sind (0.5 * (lat2 - lat1));
    sx = sind (0.5 * (lon2 - lon1));    /* If there is a 360 wrap here then the sign of sx is wrong but we only use sx^2 */
    sin_half_squared = sy * sy + cosd (lat2) * cosd (lat1) * sx * sx;

    return (sin_half_squared);
}

double gmtlib_great_circle_dist_degree (struct GMT_CTRL *GMT, double lon1, double lat1, double lon2, double lat2) {
    /* Great circle distance on a sphere in degrees */

    double sin_half_squared = gmtmap_haversine (GMT, lon1, lat1, lon2, lat2);
    return (2.0 * d_asind (d_sqrt (sin_half_squared)));
}

/*! . */
double gmt_great_circle_dist_meter (struct GMT_CTRL *GMT, double lon1, double lat1, double lon2, double lat2) {
    /* Calculates the great circle distance in meter */
    return (gmtlib_great_circle_dist_degree (GMT, lon1, lat1, lon2, lat2) * GMT->current.proj.DIST_M_PR_DEG);
}

Geodesic earth

GMT_LOCAL double gmtmap_geodesic_dist_degree (struct GMT_CTRL *GMT, double lonS, double latS, double lonE, double latE) {
    /* Compute the great circle arc length in degrees on an ellipsoidal
     * Earth.  We do this by converting to geocentric coordinates.
     */
...
GMT_LOCAL double gmtmap_vincenty_dist_meter (struct GMT_CTRL *GMT, double lonS, double latS, double lonE, double latE) {
    /* Translation of NGS FORTRAN code for determination of true distance
    ** and respective forward and back azimuths between two points on the
    ** ellipsoid.  Good for any pair of points that are not antipodal.
    **
    **      INPUT
    **  latS, lonS -- latitude and longitude of first point in radians.
    **  latE, lonE -- latitude and longitude of second point in radians.
    **
    **  OUTPUT
    **  s -- distance between points in meters.
    ** Modified by P.W. from: http://article.gmane.org/gmane.comp.gis.proj-4.devel/3478
    */
...

所以基本结论还是不变,追求精度就用大地线,不追求就用大圆和平面,单位是 km/m 比较靠谱。

wangliang1989 commented 3 years ago

gmt计算大圆距离有三种计算方法,但是只有个两种“地球”,球体和椭球体,所以为什么gmt有三种计算方式,我的疑问还是没解决

来自 @wangliang1989 #766 (comment)

Flat earth 一定是用了投影的,把地理坐标投影到平面,然后计算。 Sphere earth 我猜是用的球面距离公式,但是球的定义可能有点门道,我还没细看过

来自 @ZMAlt #766 (comment)

这里我又看了下 flat earth 的源码,我关于 Flat earth的表述有点问题,我原本以为是分别对地理坐标投影,然后分带计算平面距离。但其实不是,flat earth 用的不是投影到平面计算以 m/km 为单位的距离,而是非常简单的经纬度差值的 hypot 计算,然后乘以一个投影地区整体的 scale。这样看来,精度就更加低了。 也就是说 flat earth 是直接用的地理坐标的经纬度差值和投影地区的 scale 计算的。这种情况下,精度已经非常差了,基本到不了考虑是球还是椭球的地步了。

看了下面源码结合当前的中文文档基本就明白了。

flat earth

源码

GMT_LOCAL double gmtmap_flatearth_dist_degree (struct GMT_CTRL *GMT, double x0, double y0, double x1, double y1) {
  /* Calculates the approximate flat earth distance in degrees.
     If difference in longitudes exceeds 180 we pick the other
     offset (360 - offset)
   */
  double dlon;
  gmt_M_unused(GMT);

  gmt_M_set_delta_lon (x0, x1, dlon);
  return (hypot ( dlon * cosd (0.5 * (y1 + y0)), (y1 - y0)));
}

/*! . */
GMT_LOCAL double gmtmap_flatearth_dist_meter (struct GMT_CTRL *GMT, double x0, double y0, double x1, double y1) {
  /* Calculates the approximate flat earth distance in km.
     If difference in longitudes exceeds 180 we pick the other
     offset (360 - offset)
   */
  return (gmtmap_flatearth_dist_degree (GMT, x0, y0, x1, y1) * GMT->current.proj.DIST_M_PR_DEG);
}

Sphere earth

GMT_LOCAL double gmtmap_haversine (struct GMT_CTRL *GMT, double lon1, double lat1, double lon2, double lat2) {
  /* Haversine formula for great circle distance.  Intermediate function that returns sin^2 (half_angle).
   * This avoids problems with short distances where cos(c) is close to 1 and acos is inaccurate.
   */

  double sx, sy, sin_half_squared;

  if (lat1 == lat2 && lon1 == lon2) return (0.0);

  if (GMT->current.setting.proj_aux_latitude != GMT_LATSWAP_NONE) {   /* Use selected auxiliary latitude */
      lat1 = gmt_lat_swap (GMT, lat1, GMT->current.setting.proj_aux_latitude);
      lat2 = gmt_lat_swap (GMT, lat2, GMT->current.setting.proj_aux_latitude);
  }

  sy = sind (0.5 * (lat2 - lat1));
  sx = sind (0.5 * (lon2 - lon1));    /* If there is a 360 wrap here then the sign of sx is wrong but we only use sx^2 */
  sin_half_squared = sy * sy + cosd (lat2) * cosd (lat1) * sx * sx;

  return (sin_half_squared);
}

double gmtlib_great_circle_dist_degree (struct GMT_CTRL *GMT, double lon1, double lat1, double lon2, double lat2) {
  /* Great circle distance on a sphere in degrees */

  double sin_half_squared = gmtmap_haversine (GMT, lon1, lat1, lon2, lat2);
  return (2.0 * d_asind (d_sqrt (sin_half_squared)));
}

/*! . */
double gmt_great_circle_dist_meter (struct GMT_CTRL *GMT, double lon1, double lat1, double lon2, double lat2) {
  /* Calculates the great circle distance in meter */
  return (gmtlib_great_circle_dist_degree (GMT, lon1, lat1, lon2, lat2) * GMT->current.proj.DIST_M_PR_DEG);
}

Geodesic earth

GMT_LOCAL double gmtmap_geodesic_dist_degree (struct GMT_CTRL *GMT, double lonS, double latS, double lonE, double latE) {
  /* Compute the great circle arc length in degrees on an ellipsoidal
   * Earth.  We do this by converting to geocentric coordinates.
   */
...
GMT_LOCAL double gmtmap_vincenty_dist_meter (struct GMT_CTRL *GMT, double lonS, double latS, double lonE, double latE) {
  /* Translation of NGS FORTRAN code for determination of true distance
  ** and respective forward and back azimuths between two points on the
  ** ellipsoid.  Good for any pair of points that are not antipodal.
  **
  **      INPUT
  **  latS, lonS -- latitude and longitude of first point in radians.
  **  latE, lonE -- latitude and longitude of second point in radians.
  **
  **  OUTPUT
  **  s -- distance between points in meters.
  ** Modified by P.W. from: http://article.gmane.org/gmane.comp.gis.proj-4.devel/3478
  */
...

所以基本结论还是不变,追求精度就用大地线,不追求就用大圆和平面,单位是 km/m 比较靠谱。

这段论述的信息应该加到手册里,我这么认为

ZMAlt commented 3 years ago

这段论述的信息应该加到手册里,我这么认为

用 GMT 算距离人很少,大多数人并不会关心的。学测量的人,需要的话大多数都已经手写了这些公式了,也搞的比较清楚。中文手册现在基本上已经够了,后面我找时间简单修一下。