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

基于Cesium,加载地形数据,叠加遥感影像,再叠加路网数据,形成三维地图
浙公网安备 33010602011771号