Cesium加载三维路线
1. 概述
将路线加载到三维地图中,能直观显示道路的坡度变化,协同DEM和遥感影像,能极大丰富道路的可视化效果
本文此处基于Cesium,加载地形数据,叠加遥感影像,再叠加路网数据,形成三维地图,效果如下:
2. 代码实现
2.1 CDN引入
笔者这里使用 CDN 引入 Cesium,另外后续加载路网数据需要使用Ajax,这里引入jQuery
<!-- Include the CesiumJS JavaScript and CSS files --> <script src=https://cesium.com/downloads/cesiumjs/releases/1.92/Build/Cesium/Cesium.js></script> <link href=https://cesium.com/downloads/cesiumjs/releases/1.92/Build/Cesium/Widgets/widgets.css rel=stylesheet> <script src=http://libs.baidu.com/jquery/2.0.0/jquery.min.js></script>
2.2 加载地形
笔者这里使用Cesium的地形数据
// Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID. var viewer = new Cesium.Viewer('cesiumContainer', { terrainProvider: Cesium.createWorldTerrain() });
2.3 加载遥感影像
笔者这里使用Bing的遥感影像
var bingStyle = [ Cesium.BingMapsStyle.AERIAL_WITH_LABELS, Cesium.BingMapsStyle.COLLINS_BART, Cesium.BingMapsStyle.CANVAS_GRAY, Cesium.BingMapsStyle.CANVAS_LIGHT, Cesium.BingMapsStyle.CANVAS_DARK, Cesium.BingMapsStyle.ORDNANCE_SURVEY, Cesium.BingMapsStyle.ROAD, Cesium.BingMapsStyle.AERIAL, ]; var bingMapProvider = new Cesium.BingMapsImageryProvider({ url: https://dev.virtualearth.net, key: AmXdbd8UeUJtaRSn7yVwyXgQlBBUqliLbHpgn2c76DfuHwAXfRrgS5qwfHU6Rhm8, mapStyle: bingStyle[7], }); viewer.imageryLayers.addImageryProvider(bingMapProvider);
2.4 设置视点
笔者这里将视点即观察点设置为长沙岳麓山附近
// Fly the camera to Changsha at the given longitude, latitude, and height. viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(112.9448, 28.1708, 1200), orientation: { heading: Cesium.Math.toRadians(0.0), pitch: Cesium.Math.toRadians(-15.0), } });
2.5 小结测试
到目前为止,整体代码如下:
<!DOCTYPE html> <html lang=zh-cn> <head> <meta charset=utf-8> <!-- Include the CesiumJS JavaScript and CSS files --> <script src=https://cesium.com/downloads/cesiumjs/releases/1.92/Build/Cesium/Cesium.js></script> <link href=https://cesium.com/downloads/cesiumjs/releases/1.92/Build/Cesium/Widgets/widgets.css rel=stylesheet> <script src=http://libs.baidu.com/jquery/2.0.0/jquery.min.js></script> </head> <body> <div id=cesiumContainer></div> <script> // Your access token can be found at: https://cesium.com/ion/tokens. // Replace `your_access_token` with your Cesium ion access token. // Cesium.Ion.defaultAccessToken = 'your_access_token'; // Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID. var viewer = new Cesium.Viewer('cesiumContainer', { terrainProvider: Cesium.createWorldTerrain() }); var bingStyle = [ Cesium.BingMapsStyle.AERIAL_WITH_LABELS, Cesium.BingMapsStyle.COLLINS_BART, Cesium.BingMapsStyle.CANVAS_GRAY, Cesium.BingMapsStyle.CANVAS_LIGHT, Cesium.BingMapsStyle.CANVAS_DARK, Cesium.BingMapsStyle.ORDNANCE_SURVEY, Cesium.BingMapsStyle.ROAD, Cesium.BingMapsStyle.AERIAL, ]; var bingMapProvider = new Cesium.BingMapsImageryProvider({ url: https://dev.virtualearth.net, key: AmXdbd8UeUJtaRSn7yVwyXgQlBBUqliLbHpgn2c76DfuHwAXfRrgS5qwfHU6Rhm8, mapStyle: bingStyle[7], }); viewer.imageryLayers.addImageryProvider(bingMapProvider); // Fly the camera to Changsha at the given longitude, latitude, and height. viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(112.9448, 28.1708, 1200), orientation: { heading: Cesium.Math.toRadians(0.0), pitch: Cesium.Math.toRadians(-15.0), } }); </script> </div> </body> </html>
我们测试其效果,笔者这里使用的是VS Code的Live Server插件打开:
2.6 路网加载
路网(Ployline
)的加载方式主要有两种:
- 使用
Viewer.entities
- 使用
Cesium.GroundPolylinePrimitive
此处笔者的示例数据如下:
112.91725386767241,28.18088394284931,47.28909519744873 112.91765398304703,28.18080062181755,52.27461015478515 112.94271541045252,28.18907071666184,34.729803589843755 112.94263996370492,28.18929672498712,44.796474171875005 112.94263996370492,28.18929672498712,44.796474171875005 112.94271541045252,28.18907071666184,34.729803589843755 112.94264628370074,28.190083096717974,36.39323925 112.94259227750655,28.18977721403619,24.70917075 112.94259227750655,28.18977721403619,24.70917075 112.94264628370074,28.190083096717974,36.39323925 112.94264628370074,28.190083096717974,36.39323925 112.94255004568583,28.19039785102342,46.969459281249996 112.94255004568583,28.19039785102342,46.969459281249996 112.94264628370074,28.190083096717974,36.39323925 112.94263996370492,28.18929672498712,44.796474171875005 112.942639007202,28.18939392688125,41.37971635546875 112.942639007202,28.18939392688125,41.37971635546875 112.94263996370492,28.18929672498712,44.796474171875005 112.942639007202,28.18939392688125,41.37971635546875 112.94259227750655,28.18977721403619,24.70917075 112.94259227750655,28.18977721403619,24.70917075 112.942639007202,28.18939392688125,41.37971635546875 112.94255707716033,28.19747999678687,78.00138119911344 112.94251096347146,28.197641540468794,62.308529711560176 112.94251096347146,28.197641540468794,62.308529711560176 112.94251086130572,28.19765191789022,62.308529711560176 112.94251086130572,28.19765191789022,62.308529711560176 112.94216077246415,28.19774676732831,88.14892901957208 112.94251096347146,28.197641540468794,62.308529711560176 112.94255707716033,28.19747999678687,78.00138119911344 112.94251086130572,28.19765191789022,62.308529711560176 112.94251096347146,28.197641540468794,62.308529711560176
数据文件的名字为trans_final_map_with_dem.csv
,笔者使用Ajax加载并解析
前者Viewer.entities
的代码如下:
$.ajax({ url: 'trans_final_map_with_dem.csv', dataType: 'text', }).done(successFunction); var groundPolylineGeometryInstances = []; function successFunction(data) { var allRows = data.split(/\r?\n|\r/); for (let i = 0; i < allRows.length - 1; i = i + 2) { var rowCell1 = allRows[i].split(','); var rowCell2 = allRows[i + 1].split(','); viewer.entities.add({ polyline: { positions: Cesium.Cartesian3.fromDegreesArrayHeights([ rowCell1[0], rowCell1[1],rowCell1[2], rowCell2[0], rowCell2[1],rowCell2[2] ]), width: 4.0, material: Cesium.Color.ORANGE, clampToGround: true } }) } }
后者Cesium.GroundPolylinePrimitive
的代码如下:
$.ajax({ url: 'trans_final_map_with_dem.csv', dataType: 'text', }).done(successFunction); var groundPolylineGeometryInstances = []; function successFunction(data) { var allRows = data.split(/\r?\n|\r/); for (let i = 0; i < allRows.length - 1; i = i + 2) { var rowCell1 = allRows[i].split(','); var rowCell2 = allRows[i + 1].split(','); groundPolylineGeometryInstances.push(new Cesium.GeometryInstance({ geometry: new Cesium.GroundPolylineGeometry({ positions: Cesium.Cartesian3.fromDegreesArrayHeights([ rowCell1[0], rowCell1[1], rowCell1[2], rowCell2[0], rowCell2[1], rowCell2[2] ]), width: 4.0, }), attributes: { color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.ORANGE.withAlpha(1.0)) } })); } var groundPolylinePrimitive = new Cesium.GroundPolylinePrimitive({ geometryInstances: groundPolylineGeometryInstances, show: true, appearance: new Cesium.PolylineColorAppearance() }); viewer.scene.groundPrimitives.add(groundPolylinePrimitive) }
注意:
- 笔者这里的数据是每两个点构成一个Polyline,每一行最后是换行符'\n'
- 数据量大时尽可能使用
Cesium.GroundPolylinePrimitive
2.7 最终测试
整体代码如下:
<!DOCTYPE html> <html lang=zh-cn> <head> <meta charset=utf-8> <!-- Include the CesiumJS JavaScript and CSS files --> <script src=https://cesium.com/downloads/cesiumjs/releases/1.92/Build/Cesium/Cesium.js></script> <link href=https://cesium.com/downloads/cesiumjs/releases/1.92/Build/Cesium/Widgets/widgets.css rel=stylesheet> <script src=http://libs.baidu.com/jquery/2.0.0/jquery.min.js></script> </head> <body> <div id=cesiumContainer></div> <script> // Your access token can be found at: https://cesium.com/ion/tokens. // Replace `your_access_token` with your Cesium ion access token. // Cesium.Ion.defaultAccessToken = 'your_access_token'; // Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID. var viewer = new Cesium.Viewer('cesiumContainer', { terrainProvider: Cesium.createWorldTerrain() }); var bingStyle = [ Cesium.BingMapsStyle.AERIAL_WITH_LABELS, Cesium.BingMapsStyle.COLLINS_BART, Cesium.BingMapsStyle.CANVAS_GRAY, Cesium.BingMapsStyle.CANVAS_LIGHT, Cesium.BingMapsStyle.CANVAS_DARK, Cesium.BingMapsStyle.ORDNANCE_SURVEY, Cesium.BingMapsStyle.ROAD, Cesium.BingMapsStyle.AERIAL, ]; var bingMapProvider = new Cesium.BingMapsImageryProvider({ url: https://dev.virtualearth.net, key: AmXdbd8UeUJtaRSn7yVwyXgQlBBUqliLbHpgn2c76DfuHwAXfRrgS5qwfHU6Rhm8, mapStyle: bingStyle[7], }); viewer.imageryLayers.addImageryProvider(bingMapProvider); $.ajax({ url: 'trans_final_map_with_dem.csv', dataType: 'text', }).done(successFunction); // const polylines = new Cesium.PolylineCollection(); var groundPolylineGeometryInstances = []; function successFunction(data) { var allRows = data.split(/\r?\n|\r/); for (let i = 0; i < allRows.length - 1; i = i + 2) { var rowCell1 = allRows[i].split(','); var rowCell2 = allRows[i + 1].split(','); // viewer.entities.add({ // polyline: { // positions: Cesium.Cartesian3.fromDegreesArrayHeights([ // rowCell1[0], rowCell1[1],rowCell1[2], // rowCell2[0], rowCell2[1],rowCell2[2] // ]), // width: 4.0, // material: Cesium.Color.ORANGE, // clampToGround: true // } // }) // } groundPolylineGeometryInstances.push(new Cesium.GeometryInstance({ geometry: new Cesium.GroundPolylineGeometry({ positions: Cesium.Cartesian3.fromDegreesArrayHeights([ rowCell1[0], rowCell1[1], rowCell1[2], rowCell2[0], rowCell2[1], rowCell2[2] ]), width: 4.0, }), attributes: { color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.ORANGE.withAlpha(1.0)) } })); // } } var groundPolylinePrimitive = new Cesium.GroundPolylinePrimitive({ geometryInstances: groundPolylineGeometryInstances, show: true, appearance: new Cesium.PolylineColorAppearance() }); viewer.scene.groundPrimitives.add(groundPolylinePrimitive) } // Fly the camera to Changsha at the given longitude, latitude, and height. viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(112.9448, 28.1708, 1200), orientation: { heading: Cesium.Math.toRadians(0.0), pitch: Cesium.Math.toRadians(-15.0), } }); </script> </div> </body> </html>
最后效果如下:
参考资料
[1]Sandcastle