3分钟,教你搭建一个三维城市建筑可视化系统 ( Cesium 加载 shp 数据 )

2,205 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

三维地图可视化,就是将地理数据转换成三维立体的可视化形态,通过将具有地域特征的数据,或者数据分析结果,形象地表现在三维地图上,使得用户可以更加容易理解数据规律和趋势。

通俗地讲,三维地图可视化可以将地理数据更清晰直白地展现出来。

开发前准备

  • 城市建筑矢量数据 (.shp 文件)
  • 搭建一个vue + cesium 的开发环境
  • .shp 矢量数据转 GeoJson 或者 3dtiles ( 建议使用 3dtiles 来加载 )
  • cesium 基础使用 ( 加载底图以及控件等 )
  • vue 基础 ( 本人做的所有实例都是基于 vue 来开发的 )

具体环境配置以及数据转换操作和代码实现

环境搭建 ( vue + cesium )

npm install cesium --save

webpack 配置

// resolve
resolve: {
     alias: {
         cesium: path.resolve(__dirname, '../node_modules/cesium/Source')
     }
 },

 // plugins
 plugins: [
          new HtmlWebpackPlugin({
              template: 'src/index.html'
            }),
            // Copy Cesium Assets, Widgets, and Workers to a static directory
            new CopyWebpackPlugin([ { from: path.join('node_modules/cesium/Source', '../Build/Cesium/Workers'), to: 'Workers' } ]),
          new CopyWebpackPlugin([ { from: path.join('node_modules/cesium/Source', 'Assets'), to: 'Assets' } ]),
          new CopyWebpackPlugin([ { from: path.join('node_modules/cesium/Source', 'Widgets'), to: 'Widgets' } ]),
          new webpack.DefinePlugin({
           // Define relative base path in cesium for loading assets
           CESIUM_BASE_URL: JSON.stringify('')
      })
    ],

组件内引入

import Cesium from 'cesium/Cesium'
import 'cesium/Widgets/widgets.css'

至此,基本环境已经搭建完成, 下一步 把准备好的 shp 数据转换成 3dtiles

数据转换

ceisum 加载 shp 格式的建筑。有两种思路,目前推荐第二种。

  • 方法一:将 shp 格式转换为 geojson 格式,然后采用 cesium 提供的接口加载到 ceisum 中。

  • 严重缺陷:在面对大场景问题,即数据量较大时,非常容易卡死、崩溃

  • 方法二:将 shp 转换为 3dtiles,然后加载到 ceiusm 中。

3dtiles 是 ceisum 解决大场景问题专门提供的一种数据格式。

    打开下载好的 shp 数据 和转换工具

按照图上所示,根据自己的需求来选择即可,这里除了做一些基础设置外还可以设置贴图和地形高程,在这里不做过多阐述,可自行研究

最终选择输出目录,点击确认,即可获得自己想要的 3dtiles 数据

数据和开发环境都有了,那就直接上代码吧:

  1. 首先到官方获取 token https://cesium.com/ion/signin/tokens

  2. 组件中设置 token

Cesium.Ion.defaultAccessToken = "你自己的 token"
  1. 初始化地图,加载高德影像地图 ( 这里可以加载多种地图,比如 mapbox Google 地图 天地图 等,本实列加载的是高德 )
var viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider: Cesium.createWorldTerrain({
// required for water effects
requestWaterMask: true,
// required for terrain lighting
requestVertexNormals: true,
}),
animation: true, //是否显示动画控件
animation: false, //是否显示动画控件
scene3DOnly: true,
baseLayerPicker: false, //是否显示图层选择控件
geocoder: true, //是否显示地名查找控件
timeline: true, //是否显示时间线控件
sceneModePicker: true, //是否显示投影方式控件
navigationHelpButton: false, //是否显示帮助信息控件
infoBox: true, //是否显示点击要素之后显示的信息

 // 加载高德影像地图
imageryProvider: new Cesium.UrlTemplateImageryProvider({
url:
"https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}",
}),
});
  1. 加载转换好的 3dtiles 数据

3dtiles 数据最好是本地启个服务去加载,最简单的方式就是 vscode live server

var palaceTileset = new Cesium.Cesium3DTileset({
url: "http://127.0.0.1:5501/tileset.json",
});
viewer.scene.primitives.add(palaceTileset);

    palaceTileset.readyPromise
      .then(function (tileset) {
        viewer.scene.primitives.add(tileset);
        viewer.zoomTo(
          tileset,
          new Cesium.HeadingPitchRange(
            0.5,
            -0.2,
            tileset.boundingSphere.radius * 1.0
          )
        );
      })
      .otherwise(function (error) {
        console.log(error);
      });
  1. 这个时候建筑加载出来的还是白色, 为了效果可以加点色 (根据建筑物高度设置不同的颜色,也可以根据经纬度来设置)
palaceTileset.style = new Cesium.Cesium3DTileStyle({
color: {
conditions: [
["${Floor} >= 300", "rgba(45, 0, 75, 0.5)"],
["${Floor} >= 200", "rgba(102, 71, 151,0.5)"],
["${Floor} >= 100", "rgba(45, 0, 75, 0.5)"],
["${Floor} >= 50", "rgba(102, 71, 151,0.5)"],
["${Floor} >= 25", "rgba(252, 230, 200,0.5)"],
["${Floor} >= 10", "rgba(248, 176, 87,0.5)"],
["${Floor} >= 5", "rgba(198, 106, 11,0.5)"],
["true", "rgb(127, 59, 8)"],
],
},
});
  1. 最后来给地图加个点吧
let entity = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(118.78, 32.07, 20.61),
point: {
color: Cesium.Color.RED, //点位颜色
pixelSize: 10, //像素点大小
},
label: {
// text : '测试名称',
font: "14pt Source Han Sans CN", //字体样式
fillColor: Cesium.Color.BLACK, //字体颜色
backgroundColor: Cesium.Color.AQUA, //背景颜色
showBackground: true, //是否显示背景颜色
style: Cesium.LabelStyle.FILL, //label 样式
outlineWidth: 2,
verticalOrigin: Cesium.VerticalOrigin.CENTER, //垂直位置
horizontalOrigin: Cesium.HorizontalOrigin.LEFT, //水平位置
pixelOffset: new Cesium.Cartesian2(10, 0), //偏移
},
});

写在最后

公众号前端开发爱好者 专注分享 web 前端相关技术文章视频教程资源、热点资讯等,如果喜欢我的分享,给 🐟🐟 点一个 👍 或者关注 ➕ 都是对我最大的支持。