Cesium介绍与场景应用

6,074 阅读7分钟

本文主要是对cesium进行粗略的介绍和展示,并收集整理一下网上已有的学习资源,供大家参考。

介绍和应用

  1. Cesium是一款开源的基于JavaScript的3D地图框架。Cesium能够跨平台、跨浏览器支持绝大多数的浏览器和移动端浏览器;使用WebGL进行3D图形展示;基于Apache2.0 许可的开源,所以它可以免费的用于商业和非商业用途。
  2. Cesium支持以2D,2.5D,3D 形式进行地理(地图)数据展示,如各种几何图形、高亮区域、三维模型和动态数据的可视化展示,
  3. Cesium 可应用于三维数字地球, 数据可视化, 创建虚拟场景等功能

环境搭建及demo

  1. 通过script标签来引入Cesium
下载Cesium库并放进项目目录中引入,  下载链接
目录结构:

 Cesium应用程序代码在 Build 文件夹下,可将Build/Cesium文件夹放进项目目录中引入,或引入第三方cdn

<script src="https://cesium.com/downloads/cesiumjs/releases/1.62/Build/Cesium/Cesium.js"></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.62/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
   2.  npm安装

Cesium支持通过npm安装,配合webpack打包和使用import来引入模块。教程

上述的配置较复杂,也可以结合 create-react-app 脚手架快速搭建Cesium项目 教程

   3. 示例(下载源码包引入)
(1)引入Cesium模块

<script src="../Build/Cesium/Cesium.js"></script>
(2)导入Cesium Viewer widget的样式

@import url(../Build/Cesium/Widgets/widgets.css);
(3)编写cesium view挂载的div

<div id="cesiumContainer"></div>
(4)创建cesium viewer,cesiumContainer为第3步创建的div的id

var viewer = new Cesium.Viewer('cesiumContainer');

   4. 通过Cesium ion可以把数据添加到用户的CesiumJS应用中,而且使用贴图和Cesium世界地形都需要ion的支持,所以在使用Cesium开发前需要申请access token。

(1)打开 cesium.com/ion/ 注册一个新的账户。

(2)登录后进入 Access Tokens page页面 ,复制 token,在页面中引入 

Cesium.Ion.defaultAccessToken = '<YOUR ACCESS TOKEN HERE>';

配置自带组件

Cesium Viewer自带的组件 


  1. Geocoder : 一种地理位置搜索工具,用于显示相机访问的地理位置。默认使用微软的Bing地图。
  2. HomeButton : 首页位置,点击之后将视图跳转到默认视角。
  3. SceneModePicker : 切换2D、3D 和 Columbus View (CV) 模式。
  4. BaseLayerPicker : 选择三维数字地球的底图(imagery and terrain)。
  5. NavigationHelpButton : 帮助提示,如何操作数字地球。
  6. Animation :控制视窗动画的播放速度。
  7. CreditsDisplay : 展示商标版权和数据源。
  8. Timeline : 展示当前时间和允许用户在进度条上拖动到任何一个指定的时间。
  9. FullscreenButton : 视察全屏按钮。
(1)可通过配置参数在初始化Viewer时添加或移除相关组件

//demo: 保留常用组件
var viewer = new Cesium.Viewer('cesiumContainer', {
    animation: false,  //动画控制不显示     
    timeline: false,    //时间线不显示
    fullscreenButton: false, //全屏按钮不显示
    baseLayerPicker: false // 底图选择不显示
});
viewer._cesiumWidget._creditContainer.style.display = "none"; //不显示logo


(2)设置语言。cesium没有修改语言功能,所以需要通过组件的相关api接口,逐个修改。实在没有api可通过修改DOM结点和样式的方式修改

viewer.sceneModePicker.viewModel.tooltip3D = "三维";
viewer.sceneModePicker.viewModel.tooltip2D = "二维";
viewer.sceneModePicker.viewModel.tooltipColumbusView = "哥伦布视图";

viewer.homeButton.viewModel.tooltip = "初始位置";

viewer.geocoder.container.getElementsByClassName('cesium-geocoder-input')[0].setAttribute("placeholder","搜索");

viewer.navigationHelpButton.viewModel.tooltip = "操作指南";
var clickHelper = viewer.navigationHelpButton.container.getElementsByClassName("cesium-click-navigation-help")[0];
var touchHelper = viewer.navigationHelpButton.container.getElementsByClassName("cesium-touch-navigation-help")[0];
var button = viewer.navigationHelpButton.container.getElementsByClassName("cesium-navigation-button-right")[0];
button.innerHTML = button.innerHTML.replace(">Touch", ">手势");
button = viewer.navigationHelpButton.container.getElementsByClassName("cesium-navigation-button-left")[0];
button.innerHTML = button.innerHTML.replace(">Mouse", ">鼠标");
var click_help_pan = clickHelper.getElementsByClassName("cesium-navigation-help-pan")[0];
click_help_pan.innerHTML = "平移";
var click_help_pan_details = click_help_pan.parentNode.getElementsByClassName("cesium-navigation-help-details")[0];
click_help_pan_details.innerHTML = "按下左键 + 拖动";
var click_help_zoom = clickHelper.getElementsByClassName("cesium-navigation-help-zoom")[0];
click_help_zoom.innerHTML = "旋转";
click_help_zoom.parentNode.getElementsByClassName("cesium-navigation-help-details")[0].innerHTML = "按下右键+拖动";
click_help_zoom.parentNode.getElementsByClassName("cesium-navigation-help-details")[1].innerHTML = "";
var click_help_rotate = clickHelper.getElementsByClassName("cesium-navigation-help-rotate")[0];
click_help_rotate.innerHTML = "缩放";
click_help_rotate.parentNode.getElementsByClassName("cesium-navigation-help-details")[0].innerHTML = "滚动鼠标滚轮";
click_help_rotate.parentNode.getElementsByClassName("cesium-navigation-help-details")[1].innerHTML = "";
//触屏操作
var touch_help_pan = touchHelper.getElementsByClassName("cesium-navigation-help-pan")[0];
touch_help_pan.innerHTML = "平移";
touch_help_pan.parentNode.getElementsByClassName("cesium-navigation-help-details")[0].innerHTML = "单指拖动";
var touch_help_zoom = touchHelper.getElementsByClassName("cesium-navigation-help-zoom")[0];
touch_help_zoom.innerHTML = "缩放";
touch_help_zoom.parentNode.getElementsByClassName("cesium-navigation-help-details")[0].innerHTML = "双指捏合";
var touch_help_tilt = touchHelper.getElementsByClassName("cesium-navigation-help-rotate")[0];
touch_help_tilt.innerHTML = "俯仰";
touch_help_tilt.parentNode.getElementsByClassName("cesium-navigation-help-details")[0].innerHTML = "双指同向拖动";
var touch_help_rotate = touchHelper.getElementsByClassName("cesium-navigation-help-tilt")[0];
touch_help_rotate.innerHTML = "旋转";
touch_help_rotate.parentNode.getElementsByClassName("cesium-navigation-help-details")[0].innerHTML = "双指反向拖动";

使用影像服务

BaseLayerPicker 组件提供了多种底图切换,但通常我们并不需要切换底图,所以可以在Viewer初始化时就配置好影像服务。在多种服务商中MapBox的地图比较清晰而且api也比较简单,能满足需求,如果要使用其他服务商影像请参考这里: 影像服务

var viewer = new Cesium.Viewer('cesiumContainer',{
    imageryProvider: new Cesium.MapboxImageryProvider({
        mapId:'mapbox.satellite'
    })
}
// mapbox.satellite 卫星图像
// mapbox.streets 街道图像

添加地形和光照

Cesium支持全球高程投影、地形地势、水形数据,包括海洋、湖泊、河流、山峰、峡谷等地形数据。添加地形和光照后更能体现Cesium 三维地图的优势可用于虚拟场景展示。这里可以直接使用Cesium默认提供的世界地形服务(加载地形数据会导致渲染延迟)

var viewer = new Cesium.Viewer('cesiumContainer',{
    imageryProvider: new Cesium.MapboxImageryProvider({
        mapId:'mapbox.satellite'
    }),
    terrainProvider: new Cesium.createWorldTerrain({
        requestWaterMask : true, // 水特效
        requestVertexNormals : true // 照明特效
    })
});
viewer.scene.globe.depthTestAgainstTerrain = true; //让最前面、最上面的objects可见
viewer.scene.globe.enableLighting = true; // 基于太阳位置的光照


定位区域

通过上面步骤已经生成了一个较逼真的3维场景,接下来需要定位到我们想要展示的区域。定位区域使用了viewer.scene中的camera属性,可以通过直接设置它的位置和方向来控制当前可见的域。

(1)坐标类型

  • Cartesian3 : 三维笛卡尔坐标,表示相对于地球中心的位置
  • Cartographic : 由WGS84经度、纬度(弧度)和椭球面高度确定的位置。
两种类型都可以通过fromDegrees 方法用经度、纬度、高度确定位置,详细请看这里

(2)Camera API

更多类型请看这里,也可以立即体验多种API定位的效果 这里

var initialOrientation = new Cesium.HeadingPitchRoll.fromDegrees(7.1077496389876024807, -31.987223091598949054, 0.025883251314954971306);
viewer.scene.camera.setView({
    destination : Cesium.Cartesian3.fromDegrees(114.0595699327, 22.542875036, 10000), // 位置
    orientation : {  // 角度
        heading : initialOrientation.heading,
        pitch : initialOrientation.pitch,
        roll : initialOrientation.roll
    }
});

现在已经实现了定位到我们想要看到的区域了,下面将会补充交互的部份~

空间数据可视化

使用Cesium的Entity API可以绘制空间数据,如点,图标,文字标注,折线,模型,图形和立体图形。创建3D地图的一个重要应用方向就是(空间)数据可视化用于更好进行数据统计和决策。如可以在地图上绘制点表示地铁站点,绘制线表示地铁线用来展示站点和线路分布信息;绘制柱状图表示各地人口数量用来展示人口分布关系等。 下面具体介绍几类实体的绘制的用法。

1. 通过viewer.entities.add(Entity对象手动绘制

// polygon 多边形
{
hierarchy : 多边形位置,由至少三个点的坐标相连形成的多边形
height: 相对于地球表面的高度
extrudedHeight:相对于地球表面凸出的高度,用来生成立体形状
material: 填充进多边形的材料,可以是颜色、图片等
outline: 轮廓可见
outlineColor: 轮廓颜色
}
// poline 线条
{
 positions : 线条位置,由至少两个点坐标相连
 width : 线条宽度
 arcType : 类型 默认为贴合地面
 material : 填充进线条的材料
}
// point 点
绘制点的位置需要在 entity对象中定义
{ 
 pixelSize : 点大小
 color : 颜色,
 outlineColor : 轮廓颜色, outlineWidth : 轮廓宽度
}
// model 3d模型
绘制点的位置需要在 entity对象中定义{
   uri : 模型的资源路径
   scale: 缩放,默认为 1
}
var entities1 = viewer.entities.add({
  name : 'entitites1',
  polygon : {
    hierarchy : Cesium.Cartesian3.fromDegreesArray([
                              -109.080842,45.002073,
                              -105.91517,45.002073,
                              -104.058488,44.996596,
                              -104.053011,43.002989,
                              -104.053011,41.003906,
                              -105.728954,40.998429,
                              -107.919731,41.003906,
                              -109.04798,40.998429,
                              -111.047063,40.998429,
                              -111.047063,42.000709,
                              -111.047063,44.476286,
                              -111.05254,45.002073]),
    height : 0,
    material : Cesium.Color.RED.withAlpha(0.5),
    outline : true,
    outlineColor : Cesium.Color.BLACK
  }
});


此外还有立方体、圆和椭圆、墙、球等,详见API示例

2. 通过资源文件绘制 viewer.dataSources.add(dataSource);。实际的应用多数都是加载资源文件来绘制实体,但资源文件geojson等都依赖于数据转换和资源发布,这属于专业GIS开发了。

var promise = Cesium.GeoJsonDataSource.load('./states.json'); 加载资源文件 geojson    
promise.then(function(dataSource) {        
    viewer.dataSources.add(dataSource); 
    // 可以遍历各个entity进行操作,如填充颜色、设置高度等        
    var entities = dataSource.entities.values;        
    var colorHash = {};        
    for (var i = 0; i < entities.length; i++) {            
        var entity = entities[i]; 
        //Set the polygon material to our random color.            
        entity.polygon.material = Color.fromRandom({ alpha : 1.0 });;            
        //Remove the outlines.            
        entity.polygon.outline = false;            
        //Extrude the polygon based on the state's population. 
        entity.polygon.extrudedHeight = entity.properties.Population / 50.0;        
    }    
}).otherwise(function(error){        //Display any errrors encountered while loading.        
    window.alert(error);    
});


小结:

对于小数据量和简单的实体,适合这种viewr.entities的方式,比如全国省份人口统计用柱状图展示,只需要知道每个省的一个点坐标和人口数即可;还有加入模型实体,只需准备模型文件和设置放置的点坐标即可。 对于大数据量或复杂的实体(如上图)则适合使用viewer.dataSources方式绘制。


参考资料

官方:

Cesium官网

下载

在线编辑示例程序

教程:

Cesium介绍

Cesium教程系列

Cesium中文网教程

Cesium二次封装库

超图

火星