Cesium工具应用
文章目录
- 0.引言
- 1.场景截图
- 2.卷帘对比
- 3.反选遮罩
- 4.鹰眼视图
- 5.指南针与比例尺
- 6.坐标测量
- 7.距离测量
- 8.面积测量
- 9.热力图
- 10.视频投影
- 11.日照分析
- 12.淹没分析
- 13.通视分析
- 14.可视域分析
- 15.缓冲区分析
- 16.地形开挖
- 17.要素聚合
- 18.开启地下模式
- 19.开启等高线
- 20.坡度坡向
- 21.填挖方量计算
- 22.动态缓冲区分析
- 23.加载室内场景
- 24.剖面分析
0.引言
现有的gis开发方向较流行的是webgis开发,其中Cesium是一款开源的WebGIS库,主要用于实时地球和空间数据的可视化和分析。它提供了丰富的地图显示和数据可视化功能,并能实现三维可视化开发。本文将使用Cesium完成一些工具应用级别的功能开发,并介绍如何与常见的第三方库(如Echarts、Turf.js、CesiumHeatmap.js等)进行集成来完成一些需求的开发。
1.场景截图
场景截图是指将当前Cesium容器canvas中的场景打印成图片并下载到本地,主要思路为:首先创建DOM元素标签,然后通过canvas.toDataURL方法获取图片的链接,最后使用标签将图片保存到本地。
(1)实现代码
7_01_场景截图.html
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>工具应用篇_场景截图</title> <script src="./Build/Cesium/Cesium.js"></script> <link rel="stylesheet" href="./Build/Cesium//Widgets/widgets.css"> <style> html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } .tool { top: 20px; left: 40px; position: absolute; } </style>
</head> <body> <div id="cesiumContainer"> </div> <div class="tool"> <button onclick="printScreenScene()">打印场景</button> </div> <script> Cesium.Ion.defaultAccessToken = '你的token'; var viewer = new Cesium.Viewer("cesiumContainer", { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 }); var tileset = viewer.scene.primitives.add( new Cesium.Cesium3DTileset({ url: './倾斜摄影/大雁塔3DTiles/tileset.json' }) ); viewer.zoomTo(tileset); //打印图件 function savePng(data, pngName) { var saveLink = document.createElement('a');//创建下载链接标签<a> saveLink.href = data; //设置下载链接 saveLink.download = pngName; //设置下载图片名称 document.body.appendChild(saveLink); //将 <a>标签 添加到 <body> 中 saveLink.click(); //点击<a>标签 }; function printScreenScene() { var image = new Image();//创建img对象 viewer.render();//重新渲染界面 image = viewer.scene.canvas.toDataURL("image/png");//获取下载链接 savePng(image, '当前场景');//调用打印图件函数 } </script>
</body> </html>
(2)结果显示
2.卷帘对比
Cesium卷帘对比功能是指同时加载两个不同的影像底图,并将上层影像卷起来,使其只在左侧或者右侧显示,而下层影像在另一侧显示。通常在对比不同时间段影像或者不同影像底图时会用到该功能。本节将使用Cesium提供的splitDirection、imagerySplitPosition属性来实现影像图与矢量图、注记图的卷帘对比。
实现卷帘对比的整体思路如下:首先加载Bing地图、天地图矢量图层、天地图注记图层3个底图数据;然后给天地图矢量图层及天地图注记图层设置图层分区显示,均设置在右侧显示;接着使用图像分割器在屏幕中的位置进行分区,默认从屏幕中间进行分区;最后根据添加的卷帘工具位置来实时调整图像分割器的位置以实现卷帘效果。下面介绍整个卷帘对比的实现。
(1)实现代码
7_02_卷帘对比.html
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>工具应用篇_卷帘对比</title> <script type="text/javascript" src="./Build/Cesium/Cesium.js"></script> <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css"> </head> <body> <style> html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } #slider { position: absolute; left: 50%; top: 0px; background-color: #d3d3d3; width: 5px; height: 100%; z-index: 9999; } #slider:hover { cursor: ew-resize; } </style> <div id="cesiumContainer"> <div id="slider"></div> </div> <script> Cesium.Ion.defaultAccessToken = '你的token'; var viewer = new Cesium.Viewer("cesiumContainer", { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 }); /* var tileset = viewer.scene.primitives.add( new Cesium.Cesium3DTileset({ url: './倾斜摄影/大雁塔3DTiles/tileset.json',//文件的路径 }) ); //定位过去 viewer.zoomTo(tileset); //卷帘Cesium3DTileset 1.92版本发布 tileset.splitDirection = Cesium.SplitDirection.LEFT; */ var rightImageryVec = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ //天地图矢量图层 url:"http://t{s}.tianditu.com/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=你的tk", subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], //服务负载子域 format: "image/jpeg", tileMatrixSetID: "GoogleMapsCompatible",//使用谷歌的瓦片切片方式 }) ); var rightImageryCva = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ //天地图矢量注记 url:"http://t{s}.tianditu.com/cva_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=cva&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default.jpg&tk=你的tk", subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], format: "image/jpeg", tileMatrixSetID: "GoogleMapsCompatible", }) ); //设置在图像拆分前右侧显示该影像,在右侧显示 rightImageryVec.splitDirection = Cesium.ImagerySplitDirection.RIGHT; rightImageryCva.splitDirection = Cesium.ImagerySplitDirection.RIGHT; //获取或设置图像拆分器在视口中的初始位置。有效值在0.0到1.0之间。 viewer.scene.imagerySplitPosition = 0.5; //卷帘DOM var slider = document.getElementById("slider"); //卷帘激活状态 true为开启 false为关闭 var moveActive = false; //移动卷帘 function move(movement) { if (!moveActive) { return; } //拿到鼠标在卷帘工具中移动结束的屏幕坐标 var relativeOffset = movement.endPosition.x; //计算 图像拆分器在视口中新的位置 var splitPosition = (slider.offsetLeft + relativeOffset) / slider.parentElement.offsetWidth; //卷帘移动,更新卷帘的位置 slider.style.left = `${100.0 * splitPosition}%`; //更新设置 图像拆分器在视口中新的位置 viewer.scene.imagerySplitPosition = splitPosition; } //为卷帘工具实例化ScreenSpaceEventHandler对象 var handler = new Cesium.ScreenSpaceEventHandler(slider); //左键按下开启卷帘 handler.setInputAction(function () { moveActive = true; }, Cesium.ScreenSpaceEventType.LEFT_DOWN); //左键弹起关闭卷帘 handler.setInputAction(function () { moveActive = false; }, Cesium.ScreenSpaceEventType.LEFT_UP); //鼠标移动更新图像拆分器的位置以及卷帘的位置 handler.setInputAction(move, Cesium.ScreenSpaceEventType.MOUSE_MOVE); </script>
</body> </html>
(2)结果显示
3.反选遮罩
反选遮罩通常在需要特别突出某个目标区域时使用,通过将目标区域以外的地图掩盖以达到突出目标区域的效果,基本原理是先绘制一个多边形区域,然后将需要突出的目标区域挖空,并对其余部分设置一定的透明度进行掩盖。下面介绍如何使用Cesium中的polygon绘制带洞的多边形来突出目标区域以实现反选遮罩效果。
(1)实现代码
7_03_反选遮罩层.html
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>工具应用篇_反选遮罩层</title> <script src="./Build/Cesium/Cesium.js"></script> <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css"> <style> html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } </style> </head> <body> <div id="cesiumContainer"> </div> <script> Cesium.Ion.defaultAccessToken = '你的token'; var viewer = new Cesium.Viewer("cesiumContainer", { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 terrainProvider: Cesium.createWorldTerrain() }); /* // 是否支持图像渲染像素化处理 if (Cesium.FeatureDetection.supportsImageRenderingPixelated()) { viewer.resolutionScale = window.devicePixelRatio } // 开启抗锯齿 viewer.scene.postProcessStages.fxaa.enabled = true */ //大区域坐标,够用即可,不必太大,要形成闭环 var pointArr1 = [114.3944, 30.5237, 114.3943, 30.5192, 114.4029, 30.5192, 114.4029, 30.5237, 114.3944, 30.5237]; var positions = Cesium.Cartesian3.fromDegreesArray(pointArr1); //洞的坐标,要形成闭环 var pointArr2 = [114.3972, 30.5224, 114.3972, 30.5218, 114.3988, 30.5218, 114.3988, 30.5224, 114.3972, 30.5224]; var hole = Cesium.Cartesian3.fromDegreesArray(pointArr2); //绘制遮罩函数 function drawMask(positions, hole) { // 带洞区域 var mask = viewer.entities.add({ polygon: { // 获取指定属性(positions,holes(图形内需要挖空的区域)) hierarchy: { positions: positions, holes: [{ positions: hole }], }, // 填充的颜色,withAlpha透明度 material: Cesium.Color.BLACK.withAlpha(0.7), // 是否被提供的材质填充 fill: true, }, }); var hightlightLine = viewer.entities.add({ polyline: { positions: hole, width: 3, material: Cesium.Color.AQUA.withAlpha(1), clampToGround: true, }, }); } //绘制反选遮罩层 drawMask(positions, hole); //设置相机视角 viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(114.3981, 30.5221, 300) }); </script> </body> </html>
(2)结果显示
4.鹰眼视图
鹰眼视图是GIS中的一个基本功能,其数据范围与主数据视图的数据范围保持一致,可以用来展示同一范围内的不同数据。例如,可以在Cesium中添加一个鹰眼视图,设置底图为矢量图,当操作主视图时,鹰眼视图会跟随主视图的视角变化,和主视图中的影像底图进行对比。
在Cesium中制作鹰眼视图有多种方法,可以选择和其他的二维WebGIS框架Leaflet、OpenLayers等集成制作,也可以通过创建多个Viewer来实现。本节将使用Cesium创建另一个Viewer来实现鹰眼视图功能,实现原理为当主视图相机视角发生变化时,实时同步鹰眼视图的相机视角,使其与主视图保持一致。
(1)实现代码
7_04_鹰眼视图.html
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>工具应用篇_鹰眼视图</title> <script src="./Build/Cesium/Cesium.js"></script> <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css"> <style> html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } #eagleEye { position: absolute; width: 25%; height: 30%; bottom: 0; right: 0; z-index: 999; } </style> </head> <body> <div id="cesiumContainer"></div> <!-- 鹰眼 --> <div id="eagleEye"></div> <script> Cesium.Ion.defaultAccessToken = '你的token'; var viewer = new Cesium.Viewer("cesiumContainer", { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 terrainProvider: Cesium.createWorldTerrain() }); var viewerEye = new Cesium.Viewer("eagleEye", { geocoder: false, //是否显示地名查找工具 homeButton: false, //是否显示首页位置工具 sceneModePicker: false, //是否显示视角模式切换工具 baseLayerPicker: false, //是否显示默认图层选择工具 navigationHelpButton: false, //是否显示导航帮助工具 animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 terrainProvider: Cesium.createWorldTerrain(), //加载天地图矢量图 imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ url:"http://t{s}.tianditu.com/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=你的tk", subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], //服务负载子域 layer: "tdtImgLayer", style: "default", format: "image/jpeg", tileMatrixSetID: "GoogleMapsCompatible",//使用谷歌的瓦片切片方式 show: true }) }); viewerEye.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({ //天地矢量注记 url:"http://t{s}.tianditu.com/cva_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=cva&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default.jpg&tk=你的tk", subdomains: ['0','1','2','3','4','5','6','7'], layer: "tdtCiaLayer", style: "default", format: "image/jpeg", tileMatrixSetID: "GoogleMapsCompatible", show: true })); viewerEye._cesiumWidget._creditContainer.style.display = 'none';//去除cesium版权信息 //禁用鹰眼视图相机操作 // 旋转 viewerEye.scene.screenSpaceCameraController.enableRotate = false; // 平移 viewerEye.scene.screenSpaceCameraController.enableTranslate = false; // 放大 viewerEye.scene.screenSpaceCameraController.enableZoom = false; // 倾斜 viewerEye.scene.screenSpaceCameraController.enableTilt = false; // 看向 viewerEye.scene.screenSpaceCameraController.enableLook = false; //控制鹰眼视图相机视角 function reViewer() { viewerEye.camera.flyTo({ destination: viewer.camera.position, orientation: { heading: viewer.camera.heading, pitch: viewer.camera.pitch, roll: viewer.camera.roll }, duration: 0.0 }); } //设置主视图引起监听事件触发的相机变化幅度,越小越灵敏 viewer.camera.percentageChanged = 0.01; //当主视图相机变化时,鹰眼视图跟着变化 viewer.camera.changed.addEventListener(reViewer); </script> </body> </html>
(2)结果显示
5.指南针与比例尺
Cesium本身并没有提供指南针、比例尺及罗盘等控件,因此不能像开启其他Cesium默认控件一样直接使用指南针与比例尺。本节介绍GitHub上的一个名为solocao的工程师维护的插件,该插件的使用方式非常简单,只需引入viewerCesiumNavigationMixin.min.js文件,然后使用几行代码即可直接在场景中添加指南针、比例尺、罗盘及缩放按钮等控件。
(1)实现代码
7_05_指南针与比例尺.html
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>工具应用篇_指南针与比例尺</title> <script src="./Build/Cesium/Cesium.js"></script> <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css"> <!-- 指南针、比例尺等 --> <script src="./Build/js/viewerCesiumNavigationMixin.min.js"></script> <style> html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } /*比例尺定位*/ .distance-legend { position: absolute; left: 0px; bottom: 30px; z-index: 10; } </style> </head> <body> <div id="cesiumContainer"> </div> <script> Cesium.Ion.defaultAccessToken = '你的token'; var viewer = new Cesium.Viewer("cesiumContainer", { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 }); /* var options = {}; // 用于在使用重置导航重置地图视图时设置默认视图控制。接受的值是Cesium.Cartographic 和Cesium.Rectangle. options.defaultResetView = Cesium.Cartographic.fromDegrees(110, 30, 2000000); // 用于启用或禁用罗盘。true是启用罗盘,false是禁用罗盘。默认值为true。如果将选项设置为false,则罗盘将不会添加到地图中。 options.enableCompass = true; // 用于启用或禁用缩放控件。true是启用,false是禁用。默认值为true。如果将选项设置为false,则缩放控件 将不会添加到地图中。 options.enableZoomControls = true; // 用于启用或禁用距离图例。true是启用,false是禁用。默认值为true。如果将选项设置为false,距离图例将不会添加到地图中。 options.enableDistanceLegend = true; // 用于启用或禁用指南针外环。true是启用,false是禁用。默认值为true。如果将选项设置为false,则该环将可见但无效。 options.enableCompassOuterRing = true; */ //添加指南针、罗盘、比例尺等 viewer.extend(Cesium.viewerCesiumNavigationMixin, { // 用于在使用重置导航重置地图视图时设置默认视图控制。接受的值是Cesium.Cartographic 和Cesium.Rectangle. defaultResetView: Cesium.Cartographic.fromDegrees(110, 30, 2000000), // 用于启用或禁用罗盘。true是启用罗盘,false是禁用罗盘。默认值为true。如果将选项设置为false,则罗盘将不会添加到地图中。 enableCompass : true, // 用于启用或禁用缩放控件。true是启用,false是禁用。默认值为true。如果将选项设置为false,则缩放控件 将不会添加到地图中。 enableZoomControls : true, // 用于启用或禁用距离图例。true是启用,false是禁用。默认值为true。如果将选项设置为false,距离图例将不会添加到地图中。 enableDistanceLegend : true, // 用于启用或禁用指南针外环。true是启用,false是禁用。默认值为true。如果将选项设置为false,则该环将可见但无效。 enableCompassOuterRing : true, }); </script> </body> </html>
(2)结果显示
6.坐标测量
坐标测量是指在三维场景中,获取单击点位置的相关经纬度、高度信息并标注出来。测量功能是GIS系统必备的基本功能,下面介绍在三维场景中,如何对加载的三维模型、地形等实现坐标测量。
(1)实现代码
7_06_坐标测量.html
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>工具应用篇_坐标测量</title> <script src="./Build/Cesium/Cesium.js"></script> <link rel="stylesheet" href="./Build/Cesium/Widgets/widgets.css"> <style> html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } </style> </head> <body> <div id="cesiumContainer"> </div> <script> Cesium.Ion.defaultAccessToken = '你的token'; var viewer = new Cesium.Viewer("cesiumContainer", { animation: false, //是否显示动画工具 timeline: false, //是否显示时间轴工具 fullscreenButton: false, //是否显示全屏按钮工具 terrainProvider: Cesium.createWorldTerrain() }); //viewer.scene.globe.depthTestAgainstTerrain = false;//开启深度检测后 会有高程遮挡效果 var tileset = viewer.scene.primitives.add( new Cesium.Cesium3DTileset({ url: './倾斜摄影/大雁塔3DTiles/tileset.json' }) ); viewer.zoomTo(tileset); //实例化屏幕空间事件ScreenSpaceEventHandler对象 var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas); //实例化标签集合并添加至场景中 var annotations = viewer.scene.primitives.add( new Cesium.LabelCollection() ); //添加点 function createPoint(worldPosition) { var point = viewer.entities.add({ position: worldPosition, point: { color: Cesium.Color.CRIMSON, pixelSize: 9, outlineColor: Cesium.Color.ALICEBLUE, outlineWidth: 2, disableDepthTestDistance: 1000 //当距离在1000以下不被高程遮挡 } }); return point; } //添加点和标注框 function annotate(cartesian, lng, lat, height) { //创建点 createPoint(cartesian); //添加标注框 annotations.add({ position: cartesian, text: 'Lon: ' + lng.toFixed(5) + '\u00B0' + '\nLat: ' + lat.toFixed(5) + '\u00B0' + "\nheight: " + height.toFixed(2) + "m", showBackground: true, font: '22px monospace', horizontalOrigin: Cesium.HorizontalOrigin.LEFT, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, disableDepthTestDistance: Number.POSITIVE_INFINITY }); } //鼠标左键点击事件 handler.setInputAction(function (evt) { var pickedObject = viewer.scene.pick(evt.position);//判断是否拾取到模型 console.log('pickedObject',pickedObject); //如果拾取到模型 if (viewer.scene.pickPositionSupported && Cesium.defined(pickedObject)) { var cartesian = viewer.scene.pickPosition(evt.position); if (Cesium.defined(cartesian)) { var cartographic = Cesium.Cartographic.fromCartesian(cartesian); //根据笛卡尔坐标获取到弧度 var lng = Cesium.Math.toDegrees(cartographic.longitude); //根据弧度获取到经度 var lat = Cesium.Math.toDegrees(cartographic.latitude); //根据弧度获取到纬度 var height = cartographic.height;//模型高度 annotate(cartesian, lng, lat, height); } } /* //如果未拾取到模型,拾取到地形 else { //在世界坐标系中从屏幕坐标向场景中创建射线 var ray = viewer.camera.getPickRay(evt.position); //找到射线与渲染的地球表面之间的交点 值为Cartesian3类型 var cartesian = viewer.scene.globe.pick(ray, viewer.scene); if (Cesium.defined(cartesian)) { //根据交点得到经纬度、高度信息并添加点和标签 var cartographic = Cesium.Cartographic.fromCartesian(cartesian); var lng = Cesium.Math.toDegrees(cartographic.longitude); //根据弧度获取到经度 var lat = Cesium.Math.toDegrees(cartographic.latitude); //根据弧度获取到纬度 var height = cartographic.height;//高度 annotate(cartesian, lng, lat, height); } } */ }, Cesium.ScreenSpaceEventType.LEFT_CLICK); //鼠标右键点击,删除点和标注框 handler.setInputAction(function () { //清除点 viewer.entities.removeAll() //清除标注框 annotations.removeAll(); }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); </script> </body> </html>
(2)结果显示
7.距离测量
距离测量是指空间距离测量,即考虑点与点之间的位置坐标及高度差来计算两点之间的距离,不仅可以计算平面距离,还可以计算两个高度差较大的点(如屋顶与地面)之间的距离。下面将介绍如何实现空间距离测量。
(1)实现代码
7_07_空间距离测量.html
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv=