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

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

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

Entity实体


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

Billboard

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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()方法进行添加的。接下来先放代码:

1
2
3
4
5
6
7
8
9
10
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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 在上边添加过的线基础上我们再添加一条动效线
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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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),传入坐标,获取到点击位置的实体。

1
2
3
4
5
6
7

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则是我们拾取到的实体。

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
<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实现智慧城市(三)
https://moewang0321.github.io/2021/05/05/【三维GIS可视化】基于Vue+Cesium+Supermap实现智慧城市(三)/
作者
Moe Wang
发布于
2021年5月5日
许可协议