【三维GIS可视化】基于Vue+Cesium+Supermap实现智慧城市(三)

10,039 阅读5分钟
                                    FBI  WARNING!
                                    五一假期已结束
               不知道xdm都去哪里玩了?给点游玩的建议,我十一假期参考一下啊哈哈……

复习一下,上一篇我们首先讲了地图上的几大要素,包括点线面,然后了解了二维地图、三维地图中所使用的几大坐标系及其转换方式,最后大致讲了Cesium中的Viewer实体和Camera实体,对应着窗口和摄像机。接下来我们就进行实操,了解如何将点线面要素添加到我们的地球上。如果文章中有错误的话欢迎评论区指出,定当虚心请教并及时修改!

Entity实体


在Cesium中,有几种添加实体的方式,例如利用Entity添加,以及Primitive添加。后者更接近渲染引擎底层所以今天先不介绍。Cesium中利用Entity可以添加许多形状:点、线、面、管道、圆柱体等等,在Cesium官网的Sandcastle中都有对应的例子,有需要的可以自行查看。

Billboard

在Cesium中,点的是通过Billboard的方式呈现的,顾名思义就是广告牌。Billboard会在指定坐标位置生成一个面朝屏幕的指定图片。话不多说,我们通过代码来了解一下:

viewer.entities.add({
    position: Cesium.Cartesian3.fromDegrees(121.54035, 38.92146,100),
    billboard: {
      image: require("@/views/images/blueCamera.png"), // default: undefined
      show: true, // default
      pixelOffset: new Cesium.Cartesian2(0, -50), // default: (0, 0)
      eyeOffset: new Cesium.Cartesian3(0.0, 0.0, 0.0), // default
      horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // default
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // default: CENTER
      scale: 2.0, // default: 1.0
      color: Cesium.Color.LIME, // default: WHITE
      rotation: Cesium.Math.PI_OVER_FOUR, // default: 0.0
      alignedAxis: Cesium.Cartesian3.ZERO, // default
      width: 100, // default: undefined
      height: 25, // default: undefined
    },
});

可以看到在这里我们用了Viewerentities下的一个方法add,entity通过这个方法添加到viewer内。

我在坐标转换的时候给了它一点高程值,以便显示的更完整。效果如下

1.gif

线Polyline

Billboard一样,线也是通过viewer.add()方法进行添加的。接下来先放代码:

viewer.entities.add({
        // name:entity.name,
    polyline: {
      positions: Cesium.Cartesian3.fromDegreesArray([121.534575,38.926131, 121.537579,38.92543,121.541784,38.924578,121.543973,38.924144,121.545947,38.923944]),
      width: 2,
      material: Cesium.Color.DARKORANGE.withAlpha(0.7),
      // clampToGround: true,
      // show: true,
    },
});

positions需要一个笛卡尔做表集用来绘制线,width是线宽,material是线的材质(它就是我们生成动效线的关键),clamToGround是选择线是否贴地渲染,在有地形的底图上贴地模式会贴着地形起伏进行绘制,而绝对高度则会穿过地形,最后的show就是是否显示了。

基本效果(为了显示效果好,换了一个深色底图)

2.gif

这时候你可能就说了,这个线也太丑了吧,我看人家的线都是那种发光的(你说的是奥特曼吗?这个世界上真的有奥特曼吗?)。别急,接下来我提供一种实现发光的思路,当然思路不仅于此,感兴趣的小伙伴可以多上网搜搜。上代码!

// 在上边添加过的线基础上我们再添加一条动效线
viewer.entities.add({
        // name:entity.name,
    polyline: {
      positions: Cesium.Cartesian3.fromDegreesArray([
        121.534575,
        38.926131,
        121.537579,
        38.92543,
        121.541784,
        38.924578,
        121.543973,
        38.924144,
        121.545947,
        38.923944,
      ]),
      width: 4, // 线的宽度,像素为单位
      material: new Cesium.PolylineTrailMaterialProperty({
        // 尾迹线材质
        color: Cesium.Color.GOLD,
        trailLength: 0.4,
        period: 3.0,
      }),
    },
});

效果如下

3.gif

一条线看着效果感觉还好,但是如果是下边这种路网效果其实是不错的。

4.gif

相信聪明的小伙伴已经发现了,诶你添加点,线用的都是add方法而且传递的参数结构基本上都是一个position和一个对应的实体配参。不错,其实我们可以基于这样的结构自己封装一个Entity对象,后续二次进行实体的绘制类和编辑类,这里就不进行说明了。

Polygon

上边那个图其实已经向我们展示了面元素,你肯定会认为我说的是那个绿色的区域,格局小了!其实那些楼房本质上也是一个个面,只不过我们通过拉伸将他拉伸出了一定高度形成了所谓的面。它的添加方式和点、线一样,我就不多赘述了,直接上代码。

viewer.entities.add({
    polygon: {
      hierarchy: Cesium.Cartesian3.fromDegreesArray([
        121.539208,
        38.924962,
        121.539176,
        38.924737,
        121.540195,
        38.924486,
        121.540281,
        38.924737,
      ]),
      extrudedHeight: 50,
      material: Cesium.Color.WHITE,
      // closeTop: false,
      // closeBottom: false,
    },
});

看效果:

5.gif

这只是生成建筑的一种方式,同样,这也是面众多用途中的一种,我只负责抛砖,大家才是玉。

点击获取面、广告牌

在项目中我们不可能只是将这些点线面呈现在眼前,我们的要素上一定承载着对应的数据或属性,我们需要通过点击对应要素获取到数据、属性或自定义的操作。

我们先通过ScreenSpaceEventHandler注册一个全局handler,然后利用setInputAction注册LEFT_CLICK鼠标左键点击事件,在它的回调中我们可以获取到鼠标的点击对象。然后通过viewer.scene.pick方法(场景拾取,返回在场景中该窗口位置对应的第一个图元对象,如果该位置没有任何物体则返回undefined),传入坐标,获取到点击位置的实体。


handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction((e) => {
    var pick = viewer.scene.pick(e.position);
    console.log(e , pick);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

6.gif

我们来看看打印出了什么

image.png

e为我们鼠标在屏幕上的屏幕二维坐标组,pick则是返回的图元对象,其中的id则是我们拾取到的实体。

完整代码

<template>
  <div class="container">
    <div id="cesiumContainer"></div>
  </div>
</template>

<script>
var viewer, camera, handler;
export default {
  data() {
    return {};
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      viewer = new Cesium.Viewer("cesiumContainer", {});
      var layer = viewer.imageryLayers.addImageryProvider(
        new Cesium.UrlTemplateImageryProvider({
          url:
            "https://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}",
        })
      );
      //   初始化场景位置
      viewer.scene.camera.flyTo({
        // 初始化相机经纬度
        destination: new Cesium.Cartesian3.fromDegrees(
          121.54035,
          38.92146,
          2000
        ),
        orientation: {
          heading: Cesium.Math.toRadians(0.0),
          pitch: Cesium.Math.toRadians(-25.0), //从上往下看为-90
          roll: 0,
        },
      });

      handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
      handler.setInputAction((e) => {
        var pick = viewer.scene.pick(e.position);
        console.log(e, pick);
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

      this.addBillboard();
      this.addPolyline();
      this.addPolygon();
    },
    addBillboard() {
      viewer.entities.add({
        position: Cesium.Cartesian3.fromDegrees(121.54035, 38.92146, 50),
        billboard: {
          image: require("./images/blueCamera.png"), // default: undefined
          // show: true, // default
          // pixelOffset: new Cesium.Cartesian2(0, -50), // default: (0, 0)
          // eyeOffset: new Cesium.Cartesian3(0.0, 0.0, 0.0), // default
          // horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // default
          // verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // default: CENTER
          // scale: 2.0, // default: 1.0
          // color: Cesium.Color.LIME, // default: WHITE
          // rotation: Cesium.Math.PI_OVER_FOUR, // default: 0.0
          // alignedAxis: Cesium.Cartesian3.ZERO, // default
          // width: 100, // default: undefined
          // height: 25, // default: undefined
        },
      });
    },
    addPolyline() {
      viewer.entities.add({
        polyline: {
          positions: Cesium.Cartesian3.fromDegreesArray([
            121.534575,
            38.926131,
            121.537579,
            38.92543,
            121.541784,
            38.924578,
            121.543973,
            38.924144,
            121.545947,
            38.923944,
          ]),
          width: 4,
          material: Cesium.Color.DARKORANGE.withAlpha(0.3),
          // clampToGround: true,
          // show: true,
        },
      });
      viewer.entities.add({
        // name:entity.name,
        polyline: {
          positions: Cesium.Cartesian3.fromDegreesArray([
            121.534575,
            38.926131,
            121.537579,
            38.92543,
            121.541784,
            38.924578,
            121.543973,
            38.924144,
            121.545947,
            38.923944,
          ]),
          width: 4, // 线的宽度,像素为单位
          material: new Cesium.PolylineTrailMaterialProperty({
            // 尾迹线材质
            color: Cesium.Color.GOLD,
            trailLength: 0.4,
            period: 3.0,
          }),
          // clampToGround: true,
          // show: true,
        },
      });
    },
    addPolygon() {
      viewer.entities.add({
        polygon: {
          hierarchy: Cesium.Cartesian3.fromDegreesArray([
            121.539208,
            38.924962,
            121.539176,
            38.924737,
            121.540195,
            38.924486,
            121.540281,
            38.924737,
          ]),
          extrudedHeight: 50,
          material: Cesium.Color.WHITESMOKE,
          // closeTop: false,
          // closeBottom: false,
        },
      });
    },
  },
};
</script>

<style lang="scss" scoped>
</style>

最后

最基本的Cesium相关操作通过这几篇文章就大概介绍完了,我的砖也抛出来了,接下来就需要大家自己进行玉的雕琢了。后续我还会整理关于点、面的点击以及简易的封装几个常用功能的类。大家可以多多交流共同进步,毕竟我也是一个Cesium的初学者^-^。

附录

【三维GIS可视化】基于Vue+Cesium+Supermap实现智慧城市(一)

【三维GIS可视化】基于Vue+Cesium+Supermap实现智慧城市(二)

【三维GIS可视化】基于Vue+Cesium+Supermap实现智慧城市(四)