百度地图 - 基础学习(8): 折线构成闭合图形面积计算


前面  GeoUtils 类可以很好的计算密闭多边形、矩形框出的区域面积,但没有解决折线自相交框出的区域面积计算。虽然折线自相交形成的区域框,绝大多数都可以用多边形区域框代替,但有时不免要用折线去形成一些特殊的区域框,而恰恰这些区域框又需要计算面积,这就形成了一个特殊需求。然而百度原生API以及各个开源库又都没有提供这种计算方法,于是就只能开发人员自己去解决了。

在度娘了几篇文章后,最终找到了一个计算方法,经实测效果不错,结果也比较精准。

// 计算图形面积
// path:[{lat:,lng:}],[{lat:,lng:}],[{lat:,lng:}]  路劲坐标点数组
computeSignedArea(path) {
  let radius = 6370996.81; // 地球平均半径
  let len = path.length;
  if (len < 3) return 0;
  let total = 0;
  let prev = path[len - 1];
  let prevTanLat = Math.tan((Math.PI / 2 - (prev.lat / 180) * Math.PI) / 2);
  let prevLng = (prev.lng / 180) * Math.PI;
  for (let i = 0; i < len; i++) {
    let tanLat = Math.tan(
      (Math.PI / 2 - (path[i].lat / 180) * Math.PI) / 2
    );
    let lng = (path[i].lng / 180) * Math.PI;
    total += this.polarTriangleArea(tanLat, lng, prevTanLat, prevLng);
    prevTanLat = tanLat;
    prevLng = lng;
  }
  return Math.abs(total * (radius * radius));
},


// 计算图形面积
polarTriangleArea(tan1, lng1, tan2, lng2) {
  let deltaLng = lng1 - lng2;
  let t = tan1 * tan2;
  return 2 * Math.atan2(t * Math.sin(deltaLng), 1 + t * Math.cos(deltaLng));
}

方法使用也比较简单,直接将自相交折线 各个点的坐标组成一个数组,传入 computeSignedArea(path) 即可。

由于方法返回的面积是以平方米作为单位的,所以需要处理下(毕竟地图区域那么大,以平方米计算,数字显得很大,但区域却不见得有多大,故用平方千米作为单位,以此来和我大中国960万平方千米比较,显得你这个区域有多大点)

geoUtilsValue = this.computeSignedArea(overlayList) / 1000000 + "平方千米";

以 沈阳故宫博物院为例,资料显示是六万多平方米(即0.06+平方千米),实际折线框图计算面积:0.0614平方千米,精确度还可以。

计算面积调用方法:

// 计算面积
getSignedArea() {
  if (
    this.circleObj ||
    this.polygonObj ||
    this.rectangleObj ||
    this.polylineObj
  ) {
    if (this.circleObj) {
      // let geoUtilsValue =
      //   this.getPolygonArea(this.circleObj.pointList) / 1000000 +
      //   "平方千米"; // 多边形、矩形计算面积(除以1000000,将平方米换算成平方千米)
      // alert(geoUtilsValue);
    }
    if (this.polygonObj || this.rectangleObj) {  // 多边形、矩形 密闭多边形
      let overlayList = this.polygonObj
        ? this.polygonObj.pointList
        : this.rectangleObj.pointList;
      let geoUtilsValue =
        BMapLib.GeoUtils.getPolygonArea(overlayList) / 1000000 + "平方千米"; // 多边形、矩形计算面积(除以1000000,将平方米换算成平方千米)
      alert(geoUtilsValue);
    }

    // 判定折线对象是否存在
    if (this.polylineObj) {  // 折线自相交多边形
      let pointList = this.polylineObj.pointList,
        pointListLeng = pointList.length;
      let firstPoint = pointList[0];
      let lastPoint = pointList[pointListLeng - 1];
      // 判定折线首尾点距离,首尾点距离不超过10米视为构成密闭图像区域,则可计算面积
      if (
        pointListLeng > 3 &&
        BMapLib.GeoUtils.getDistance(
          // 计算两点之间的距离,两点坐标必须为经纬度
          new BMap.Point(firstPoint.lng, firstPoint.lat),
          new BMap.Point(lastPoint.lng, lastPoint.lat)
        ) < 10
      ) {
        let geoUtilsValue =
          this.computeSignedArea(this.polylineObj.pointList) / 1000000 +
          "平方千米"; // 多边形、矩形计算面积(除以1000000,将平方米换算成平方千米)
        alert(geoUtilsValue);
      } else {
        alert(
          pointListLeng > 3
            ? "折线首尾坐标点相距太远,无法形成密闭图形区域"
            : "坐标点过少,无法构成密闭图形区域"
        );
      }
    }
    this.clearOverlayObjAndLayer();
  } else {
    if (
      !(
        this.circleObj ||
        this.polygonObj ||
        this.rectangleObj ||
        this.polylineObj
      )
    ) {
      alert("请先绘制密闭图形或自相交折线图形!");
    }
  }
},

参考博文链接:https://blog.csdn.net/qq_38615014/article/details/89207005