目录

如何自定义公式计算两点位置坐标的距离

问题现象

华为地图在中国大陆使用GCJ-02坐标系,但有些服务使用的是WGS-84坐标系,可以通过坐标系切换到WGS-84坐标系来精确计算两个坐标之间的距离。GCJ-02实际上是WGS-84经过加密后的坐标,所以直接用WGS-84的计算方法可能不适用。Map Kit的距离计算只有一个接口,无法自定义计算公式。

背景知识

  1. WGS-84坐标系是全球通用的坐标系,用于GPS定位,而GCJ-02坐标系是中国的坐标系,用于国内的电子地图。
  2. Haversine公式专指数学领域用于描述球面几何计算的半正矢函数。该术语源于平面三角学中的正矢函数变体,主要应用于地理信息系统(GIS)、导航算法等领域,通过半正矢公式计算球体表面两点间的大圆距离。

解决方案

  1. 确定坐标系:

    确定两个点的坐标系。假设点A在GCJ-02,点B在WGS-84。

  2. 计算两个地理坐标之间的距离通常使用Haversine公式,这个公式适用于地球表面的大圆距离计算。但是这个公式是基于WGS-84坐标系的,GCJ-02是通过一定的偏移算法从WGS-84转换而来的,这个偏移不是简单的线性变换,而是更复杂的算法。所以,如果有一个GCJ-02的坐标,需要先把它转换回WGS-84,才能用Haversine公式计算距离。
    import { map, mapCommon } from '@kit.MapKit';
    
    
    let locations: Array<mapCommon.CoordinateLatLng> = [
      {
        // 输入香港坐标和WGS84坐标系,若当前地图站点使用GCJ02坐标系,返回GCJ02坐标系和转换后的香港坐标(输入的坐标转换为GCJ02坐标系)
        coordinateType: mapCommon.CoordinateType.WGS84,
        location: { latitude: 22.280556, longitude: 114.984000 }
      }
    ];
    
    
    // 包含await的外层方法需要添加async关键字
    async function rectifyCoordinate(context: Context | undefined): Promise<mapCommon.CoordinateLatLng[]> {
      let arr: Array<mapCommon.CoordinateLatLng> = await map.rectifyCoordinate(context, locations);
      return arr;
    }
    
    
    /*
    * 使用 Haversine 公式计算两个经纬度点之间的距离。
    * @param lon1 - 第一个点的经度
    * @param lat1 - 第一个点的纬度
    * @param lon2 - 第二个点的经度
    * @param lat2 - 第二个点的纬度
    * @returns 两点之间的距离(公里)
    */
    function haversine(lon1: number, lat1: number, lon2: number, lat2: number): number {
      const R = 6371; // 地球半径,单位为公里
      const radians = (degrees: number) => degrees * Math.PI / 180.0; // 将角度转换为弧度的函数
    
    
      const φ1 = radians(lat1); // 将第一个点的纬度转换为弧度
      const φ2 = radians(lat2); // 将第二个点的纬度转换为弧度
      const λ1 = radians(lon1); // 将第一个点的经度转换为弧度
      const λ2 = radians(lon2); // 将第二个点的经度转换为弧度
    
    
      const Δφ = φ2 - φ1; // 计算两个纬度的差值
      const Δλ = λ2 - λ1; // 计算两个经度的差值
    
    
      const a = Math.sin(Δφ / 2)**2 + Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2)**2; // 计算Haversine公式中的a值
      const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); // 计算Haversine公式中的c值(中心角)
      const distance = R * c; // 计算两点之间的距离
    
    
      return distance; // 返回计算的距离
    }
    
    
    @Entry
    @Component
    struct haversinePage {
      build() {
        Column() {
          Button('Calculate Distance')
            .onClick(() => {
              haversine(114.984000, 22.280556, 115.0, 22.3);
              rectifyCoordinate(this.getUIContext().getHostContext());
            });
        };
      }
    }