Cesium区域坡度

采用Canvas绘制贴地矩形的材质

核心

通过等分矩形区域获取格网点坡度,将数据映射到Canvas上。

注意点

调试的时候一直出现条纹状材质,原因是起初通过turf.squareGrids确定格网点,出现canvas与原始数据对应不上的问题。由于canvas坐标系统以左上角为原点,自左向右,自上向下,因此需要确保原始数据的顺序也以此为准。

源码

1.绘制区域

假设动态绘制出矩形区域,通过turf.square生成正方形区域(方便调试)

2.采集数据

// 测试区域 const extent = turf.square([119.95, 29.95, 120, 30])
// 通过按需引入cesium的方法,如import {Rectangle} from "cesium" 可自行添加
addSlopeCanvas(extent: turf.BBox) {
    // 获取包围盒坐标,res [119.95, 29.95, 120, 30]
    const polygonPos = turf.getCoord(extent);
    // 存储在全局
    this.polygonPos = polygonPos;
    const rectangle = Rectangle.fromDegrees(...polygonPos);
    const width = 50; // 横向点数
    const height = 50; // 纵向点数
    const positions = [];
    // 格网度数,为了等分矩形
    const dx = (polygonPos[2] - polygonPos[0]) / width;
    const dy = (polygonPos[1] - polygonPos[1]) / height;
    // 格网距离,为了计算坡度
    const ddx =
      Cartesian3.distance(
        Cartesian3.fromDegrees(polygonPos[0], polygonPos[1]),
        Cartesian3.fromDegrees(polygonPos[2], polygonPos[1])
      ) / width;
    const ddy =
      Cartesian3.distance(
        Cartesian3.fromDegrees(polygonPos[0], polygonPos[1]),
        Cartesian3.fromDegrees(polygonPos[0], polygonPos[3])
      ) / height;

    for (let y = 0; y < height; y++) {
      for (let x = 0; x < width; x++) {
        // 插值 这里开始规划数据顺序,以矩形区域左上角为第一点,自左向右,自上到下
        const longitude = CesiumMath.toDegrees(
          CesiumMath.lerp(rectangle.west, rectangle.east, x / (width - 1))
        );
        const latitude = CesiumMath.toDegrees(
          CesiumMath.lerp(rectangle.north, rectangle.south, y / (height - 1))
        );

        // 八连通点
        positions.push(Cartographic.fromDegrees(longitude - dx / 2, latitude)); // w
        positions.push(
          Cartographic.fromDegrees(longitude - dx / 2, latitude - dy / 2)
        ); // ws
        positions.push(Cartographic.fromDegrees(longitude, latitude + dy / 2)); // n
        positions.push(
          Cartographic.fromDegrees(longitude - dx / 2, latitude + dy / 2)
        ); // wn
        positions.push(Cartographic.fromDegrees(longitude + dx / 2, latitude)); // e
        positions.push(
          Cartographic.fromDegrees(longitude + dx / 2, latitude + dy / 2)
        ); // en
        positions.push(Cartographic.fromDegrees(longitude, latitude - dy / 2)); // s
        positions.push(
          Cartographic.fromDegrees(longitude + dx / 2, latitude - dy / 2)
        ); // es

        // 顶点
        positions.push(Cartographic.fromDegrees(longitude, latitude)); // mid
      }
    }
    // console.log(positions);

    const slopes: number[] = [];
    sampleTerrainMostDetailed(this.viewer.terrainProvider, positions).then(
      (updatedPositions) => {
        for (let i = 0; i < updatedPositions.length; i += 9) {
          // 备用中心点
          // let center = updatedPositions[i + 8];

          // Horn算法,常用的坡度算法
          // fx = (ws - wn + 2(s - n) + es - en)/(8*GridSize)
          // fy = (en - wn + 2(e - w) + es - ws)/(8*GridSize)
          // slope = arctan(sqrt(fx^2 + fy^2)) * 180 / PI
          const westHeight = updatedPositions[i + 0].height;
          const westSouthHeight = updatedPositions[i + 1].height;
          const northHeight = updatedPositions[i + 2].height;
          const westNorthHeight = updatedPositions[i + 3].height;
          const eastHeight = updatedPositions[i + 4].height;
          const eastNorthHeight = updatedPositions[i + 5].height;
          const southHeight = updatedPositions[i + 6].height;
          const eastSouthHeight = updatedPositions[i + 7].height;

          const fx =
            (westSouthHeight +
              2 * southHeight +
              eastSouthHeight -
              (westNorthHeight + 2 * northHeight + eastNorthHeight)) /
            (8 * ddx);
          const fy =
            (eastNorthHeight +
              2 * eastHeight +
              eastSouthHeight -
              (westNorthHeight + 2 * westHeight + westSouthHeight)) /
            (8 * ddy);
          const slope = Math.atan(Math.sqrt(fx ** 2 + fy ** 2));

          slopes.push(slope);
        }
        this.slopes = slopes;

        this.createMaterial();
      }
    );
  }

3. 创建几何体材质

createMaterial() {
    // 见第四点
    const canvas = this.toCanvas();
    // this.polygonPos 全局存储的矩形区域四至点
    const positions = [
      Cartesian3.fromDegrees(this.polygonPos[0], this.polygonPos[1]),
      Cartesian3.fromDegrees(this.polygonPos[0], this.polygonPos[3]),
      Cartesian3.fromDegrees(this.polygonPos[2], this.polygonPos[3]),
      Cartesian3.fromDegrees(this.polygonPos[2], this.polygonPos[1]),
    ];
    // 将canvas生成的图像作为贴地几何体材质
    const polygon = this.viewer.entities.add({
      polygon: {
        hierarchy: new PolygonHierarchy(positions),
        material: new ImageMaterialProperty({
          image: canvas,
        }),
        classificationType: ClassificationType.BOTH,
      },
    });
  }

4.生成图像

// 重点是数据与图像像素一一对应
toCanvas() {
    const w = 50;
    const h = 50;
    const canvas = document.createElement("canvas");
    canvas.height = h;
    canvas.width = w;
    const ctx: any = canvas.getContext("2d");
    const bitmap = new Uint8ClampedArray(w * h * 4); // 各像素点rgba
    // console.log(this.slopes);
    for (let y = 0; y < h; y++) {
      for (let x = 0; x < w; x++) {
        // 左上角为坐标原点
        const slope = this.slopes[y * w + x];
        // hsl颜色有过渡性slope / (Math.PI / 2)转为0-1,也可以直接写slope / (Math.PI / 2)
        const hue = (1 - slope / (Math.PI / 2)) / 2;
        const color = Color.fromHsl(hue, 1, 0.5).withAlpha(
          0.5
        );
        const bitmapIndex = (y * w + x) * 4;
        bitmap[bitmapIndex + 0] = color.red * 255;
        bitmap[bitmapIndex + 1] = color.green * 255;
        bitmap[bitmapIndex + 2] = color.blue * 255;
        bitmap[bitmapIndex + 3] = color.alpha * 255;
      }
    }
    const imageData = new ImageData(bitmap, w, h);
    ctx.putImageData(imageData, 0, 0);
    return canvas;
  }

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Cesium是一种帮助我们进行坡度计算的工具或库。坡度是指地表或物体表面的高程变化在水平方向上的变化率,通常以百分比或角度表示。而在计算坡度时,我们需要知道地表或物体表面的高程数据。 使用Cesium进行坡度计算主要分为以下几个步骤: 1. 首先,我们需要获取地表或物体表面的高程数据。Cesium提供了多种数据源,比如地图服务、遥感数据或三维模型等。通过Cesium的接口,我们可以获取相应的高程数据。 2. 接下来,我们需要选择计算区域或所关注的物体。Cesium提供了灵活的方式来选择或绘制所需要计算区域或物体,比如提供一个矩形框或多边形选取。 3. 在获取了高程数据并选择了计算区域后,我们可以使用Cesium的函数或方法来计算坡度Cesium提供了一些计算坡度的函数,比如计算某一位置的坡度计算某一区域内的平均坡度等。我们可以根据需求选择适合的计算方法。 4. 最后,使用Cesium的可视化功能来展示计算的结果。Cesium可以将计算得到的坡度数据以三维或二维形式可视化展示,比如通过颜色或高程变化来表示不同的坡度值,让我们更直观地观察和理解坡度计算结果。 总而言之,Cesium是一种强大的工具,可以帮助我们方便地进行坡度计算。通过获取高程数据、选择计算区域、使用相应的计算函数并进行可视化展示,我们可以更全面地了解地表或物体表面的坡度情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值