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

#### 问题现象

华为地图在中国大陆使用GCJ-02坐标系，但有些服务使用的是WGS-84坐标系，可以通过坐标系切换到WGS-84坐标系来精确计算两个坐标之间的距离。GCJ-02实际上是WGS-84经过加密后的坐标，所以直接用WGS-84的计算方法可能不适用。[Map Kit](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/map-kit-guide)的距离计算只有一个接口，无法自定义计算公式。

#### 背景知识

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());
            });
        };
      }
    }
    
    上述示例给出的距离计算方法的关键应用场景示例可参考[根据实时定位获取经纬度计算距离](https://developer.huawei.com/consumer/cn/doc/architecture-guides/near_people-0000002237251858)。