我们在之前的 Cesium 入门 章节当中介绍了 Cesium
的基本使用方式,我们知道了如何使用 Cesium
去实例化一个干净的地球实例,本章当中我们就更进一步,来看看如何使用 Cesium
来加载各种数据
我们会从基础的影像数据、地形图数据,到矢量数据、空间可视化实体数据,以及三维方面的模型数据和瓦片数据来分类进行介绍,下面我们就先从最为基础的影像数据加载开始看起
加载影像数据
我们都知道,无论是二维地图还是三维地图,如果缺少了底图影像或电子地图,都是不完整的,Cesium
为我们提供了 ImageryLayerCollection
、ImageryLayer
以及相关的 ImageryProvider
类来加载不同的影像图层,虽然 Cesium
把此类图层叫做 Imagery*
,但并不是特指卫星影像数据,还包括一些互联网地图、TMS
、WMS
、WMTS
、单个图片等
ImageryLayer 类
Cesium.ImageryLayer
类用于表示 Cesium
中的影像图层,它就相当于皮毛、衣服,将数据源包裹在内,它需要数据源(imageryProvider
)为其提供内在丰富的地理空间信息和属性信息,同时通过该类还能设置影像图层相关属性,比如透明度、亮度、对比度、色调等
ImageryProvider 类
我们可以将 ImageryProvider
看作是影像图层的数据源(包裹在 ImageryLayer
类内部),我们想使用哪种影像图层数据或服务就用对应的 ImageryProvider
子类去加载就行,目前 Cesium
提供了以下 14
种 ImageryProvider
,如下图所示
每个类别的含义简介如下,我们会在后面分条目来详细进行介绍
ArcGisMapServerImageryProvider
-ArcGIS Online
和Server
的相关服务BingMapsImageryProvider
-Bing
地图影像,可以指定mapStyle
,详见 BingMapsStyle 类GoogleEarthEnterpriseImageryProvider
- 企业级服务GridImageryProvider
- 展示内部渲染网格划分情况,了解每个瓦片的精细度,便于调试地形和图像渲染问题IonImageryProvider
-Cesium Icon
的在线服务,默认全局基础图像图层MapboxImageryProvider
-Mapbox
影像服务,根据mapId
指定地图风格MapboxStyleImageryProvider
-Mapbox
影像服务,根据styleId
指定地图风格OpenStreetMapImageryProvider
-OSM
影像服务,根据不同的url
选择不同的风格SingleTileImageryProvider
- 单张图片的影像服务,适合离线数据或对影像数据要求并不高的场景下TileCoordinatesImageryProvider
- 渲染每一个瓦片的范围,方便调试TileMapServiceImageryProvider
- 根据MapTiler
规范,可以下载瓦片,发布服务,类似ArcGIS
影像服务的过程UrlTemplateImageryProvider
- 指定url
的format
模版,方便用户实现自己的Provider
,比如国内的高德,腾讯等影像服务,url
都是一个固定的规范,都可以通过该Provider
轻松实现,而OSM
也是通过该类实现的WebMapServiceImageryProvider
- 符合WMS
规范的影像服务都可以通过该类封装,指定具体参数实现WebMapTileServiceImageryProvider
- 服务WMTS 1.0.0
规范的影像服务都可以通过该类实现,比如国内的天地图
ImageryLayerCollection 类
Cesium.ImageryLayerCollection
类是 ImageryLayer
类对象的容器,它可以装载、放置多个 ImageryLayer
或 ImageryProvider
类对象,而且它内部放置的 ImageryLayer
或 ImageryProvider
类对象是有序的
Cesium.Viewer
类对象中包含的 imageryLayers
属性就是 ImageryLayerCollection
类的实例,它包含了当前 Cesium
应用程序所有的 ImageryLayer
类对象,即所有影像图层,所以 Cesium
中的影像图层可以添加多个
影像亮度调整
这里我们多看一点,就是当我们加载影像后是可以拿到影像实例 imagery
的,此时我们可以通过 brightness
属性来调节影像亮度,取值范围是 0 ~ 1
,默认为 1
1 | imagery.brightness = 0.9 |
加载不同类型的影像图层
下面我们就来看看如何使用 Cesium
来加载不同类型的影像图层,根据上面提供的 Provider
可知,目前 Cesium
(1.75
版本)支持 14
种类型的影像图层
ArcGisMapServerImageryProvider
主要用于加载 ArcGIS
影像,支持 ArcGIS Online
和 Server
的相关服务,开篇第一个我们稍微介绍的详细一些,首先新建了一个加载影像图层的数据源 arcgisProvider
1 | var arcgisProvider = new Cesium.ArcGisMapServerImageryProvider({ |
但是将数据源添加至 ImageryLayer
类容器进行渲染的话则是有两种方法,第一种是在初始化 viewer
实例时的 options
配置中,我们可以直接在 options
对象的 imageryProvider
属性中放置数据源即可
1 | new Cesium.Viewer('cesiumContainer', { |
另一种方式则是使用 viewer
实例中 imageryLayers
属性的 addImageryProvider
方法来添加即可
1 | var imagery = viewer.imageryLayers.addImageryProvider(arcgisProvider) |
完整代码如下
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
最终的影像效果预览如下
BingMapsImageryProvider
Bing
地图影像,可以指定 mapStyle
,详见 BingMapsStyle 类
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
影像预览如下
GoogleEarthEnterpriseImageryProvider
使用谷歌 Earth
企业 REST API
提供瓦片图像,可与 Google Earth Enterprise
的 3D Earth API
一起使用
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
因加载谷歌 Earth
的瓦片影像需要翻墙,这里就不展示影像预览了
GridImageryProvider
展示内部渲染网格划分情况,了解每个瓦片的精细度,便于调试地形和图像渲染问题,一般用于开发调试,这里我们就使用 ArcGIS
影像为例
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
影像预览如下
IonImageryProvider
Cesium Icon
的在线服务,默认全局基础图像图层(当前为 Bing Maps
)
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
影像预览如下
MapboxImageryProvider
Mapbox
影像服务,根据 mapId
指定地图风格
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
影像预览如下
MapboxStyleImageryProvider
Mapbox
影像服务,根据 styleId
指定地图风格
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
影像预览如下
OpenStreetMapImageryProvider
OSM
影像服务,根据不同的 url
选择不同的风格
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
影像预览如下
SingleTileImageryProvider
单张图片的影像服务,适合离线数据或对影像数据要求并不高的场景下
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
影像预览如下
TileCoordinatesImageryProvider
展示内部渲染网格瓦片划分情况,包括网格瓦片等级、x
、y
序号,便于调试地形和图像渲染问题,当然也可以和 GridImageryProvider
一起叠加使用
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
影像预览如下
TileMapServiceImageryProvider
访问瓦片图的 Rest
接口,瓦片图被转换为 MapTiler
或 GDAL2Tiles
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
因通常使用较少,这里暂时就不展示影像预览了
UrlTemplateImageryProvider
指定 url
的 format
模版,方便用户实现自己的 Provider
,比如国内的高德,腾讯等影像服务,url
都是一个固定的规范,都可以通过该 Provider
轻松实现,而 OSM
也是通过该类实现的
以下是使用 xyz
方式加载上面加载过的 OSM
影像服务
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
影像预览如下
这里需要注意参数 subdomains
,它表示子域,subdomains
参数数组中的四个值可以替换 url
中的 {s}
,也就是改变不同的请求 URL
,从而提高加载数据的速度
另外也可以加载高德影像,代码如下
1 | viewer.imageryLayers.remove(viewer.imageryLayers.get(0)) |
影像预览如下
WebMapServiceImageryProvider
符合 WMS
规范的影像服务都可以通过该类封装,指定具体参数实现
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
影像预览如下
WebMapTileServiceImageryProvider
服务 WMTS 1.0.0
规范的影像服务都可以通过该类实现,比如国内的天地图,其中 url
字段中的 tk
为天地图服务 token
,去天地图官网注册申请一个即可,下面是加载天地图的影像
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
影像预览如下
另外,我们可以发现在加载后的地图上是没有标注的,如果我们需要额外加载标柱,可以像下面这样操作
1 | var label = viewer.imageryLayers.addImageryProvider( |
如下是天地图标注预览
加载地形数据
我们在上面介绍了如何使用 Cesium
内置接口来操作影像数据,但是在一些应用场景中我们需要操作地形数据,例如模拟逼真的三维场景、与高程相关的一些空间分析和计算等
为此 Cesium
提供了 TerrainProvider
基类,该 Provider
负责每一个 Tile
对应的地形数据的构建,定义了一套地形 Provider
所需要实现的接口和规范,但本身并不会参与其中的操作,基于此类,Cesium
为我们封装了五个现成的继承类操作地形数据,如下图所示
不过不像我们之前介绍的影像图层有专门的 ImageryLayer
来进行处理,Cesium
中的地形类是直接通过不同的 terrainProvider
来进行控制的,然后把某一个实例化的 terrainProvider
赋值给 Viewer.terrainProvider
来控制地形数据的显隐,所以 Cesium
中的地形图层只能有一个
加载不同的地形数据
Cesium
支持渐进流式加载和渲染全球高精度地形,并且包含海、湖、河等水面效果,相对 2D
地图,山峰、山谷等其他地形特征的更适宜在这种 3D
地球中展示
Cesium
支持两种类型的地形,STK World Terrain
和 Small Terrain
,不过针对于这两种类型的地形,我们在这里不做过多的介绍,可以参考 这篇文章 来了解更多
地形数据集是巨大的,通常都是 GB
或者 TB
级别,在普通 3D
引擎中,使用底层图形 API
去高效实现地形数据的可视化需要做很多事情,幸好 Cesium
已经帮助我们完成了这个体力活,我们只需要写几行代码就可以实现对应的功能,而这些都是 terrainProvider
的功劳,下面我们就来主要看看 Cesium
中常用的三个 terrainProvider
EllipsoidTerrainProvider
EllipsoidTerrainProvider
是 Globe
默认采用的地形 Provider
,该 Provider
不支持水面,没有法向量,所以即使开启光照,对 Tile
也是无效的,但是它提供了一个全球范围内高度为 0
的地形,不需要额外的地形文件,就可以实时的自己来构建这个高度为 0
的 Mesh
,对那些没有网络环境,或网络不理想,或不需要地形的应用,EllipsoidTerrainProvider
提供了最简单的,无需额外负担的地形数据来构网
另外 EllipsoidTerrainProvider
具有其它 terrainProvider
不具备的属性 tileScheme
,该属性是 Provider
内部地球网格的剖分方式,通常是 WGS84
坐标,也可以选择墨卡托坐标系,Cesium
中目前支持 WGS1984
和墨卡托投影两种
Terrain
和 Imagery
分别采用自己的 TileScheme
,比如目前 Terrain
默认采用 WGS1984
的坐标系,这和经纬高的真实数据更接近,而目前 Imagery
影像服务基本都是墨卡托投影
鉴于此,为了使数据的加载性能更好,可以让地形的 TileScheme
和影像的保持一致,都设置成墨卡托投影
1 | var ellipsoidProvider = new Cesium.EllipsoidTerrainProvider() |
ArcGISTiledElevationTerrainProvider
ArcGIS
的地形,这个可以说是一个真实的(凹凸的)高度图,原理和 EllipsoidTerrainProvider
如出一辙,因此同样的不支持法线,水面,但可以选择 TileScheme
,与 EllipsoidTerrainProvider
不一样之处在于每一个切片会根据 ArcGIS
规范请求一张图片,该图片中的像素对应的值就是该像素对应的高度,真的是名副其实的高度图
1 | var terrainProvider = new Cesium.ArcGISTiledElevationTerrainProvider({ |
CesiumTerrainProvider
Cesium
标准地形,在该 Provider
中支持两种地形格式,一种是高度图(目前 Cesium
已经废弃 ),另一种则是 TIN
网格的 STK
地形
Cesium
厉害的之处就在于目前采用 STK
的地形服务,并通过 QuantizedMeshTerrainData
封装了 STK
地形数据格式,它的优点是支持水面和法线,同时数据量比较小
1 | var terrainProvider = new Cesium.CesiumTerrainProvider({ |
加载矢量数据
我们在之前的章节当中介绍了 Cesium
如何加载影像数据和地形数据,本小结当中我们来看一下 Cesium
是如何加载矢量数据的,不过在此之前,我们得先来了解一下什么是矢量数据
矢量数据
矢量数据(Vector Data
)是用 x
、y
、z
坐标表示地图图形或地理实体位置的数据,一般是通过记录坐标的方式来尽可能将地理实体的空间位置表现的准确无误,常见的矢量数据有点、线、面等格式
我们使用矢量数据的原因就是因为矢量数据具有数据结构紧凑、冗余度低、有利于网络和检索分析、图形显示质量好、精度高等优点,目前最常见的矢量数据格式就是 Shapefile
(简称 SHP
),它是由 Esri
公司开发的一种空间数据开放格式,同时 Shapefile
也成为了 GIS
行业的标准,几乎所有的商业和开源 GIS
软件都支持 Shapefile
,通常情况下一个 Shapefile
通常指带有 .shp
、.shx
、.dbf
和其他扩展名且前缀名称一致的文件(.prj
、.sbn
等)集合
一个 Shapefile
必须包含的文件有下面这些
- 主文件(
*.shp
) - 存储地理要素的几何信息 - 索引文件(
*.shx
) - 存储要素几何图形的索引信息 dBase
表文件(*.dbf
) - 存储地理要素的属性信息(非几何信息)
除此之外还有可选的文件有下面这些
- 空间参考文件(
.prj
) - 存储空间参考信息,即地理坐标系统信息和投影坐标系统信息,使用well-known
文本格式(WKT
)进行描述 - 几何体的空间索引文件(
.sbn
和.sbx
)、只读的Shapefiles
的几何体的空间索引文件(.fbn
和.fbx
)等等
只可惜 Cesium
却不能直接加载 .shp
文件,如果想加载 .shp
文件可以参考 CesiumVectorTile 这个库,Cesium
直接支持的矢量数据格式包括 GeoJSON
、TopoJSON
、KML
以及具有时间特性的 CZML
,并以 DataSouce
后缀去命名相关的类
GeoJSON
GeoJSON
是用于描述地理空间信息的数据格式,它不是一种新的格式,其语法规范是符合 JSON
格式的,只不过对其名称进行了规范,专门用于表示地理信息,GeoJSON
的最外层是一个单独的对象(object
),这个对象可表示
- ① 几何体(
Geometry
) - ② 特征(
Feature
) - ③ 特征集合(
FeatureCollection
)
最外层的 GeoJSON
里可能包含有很多子对象,每一个 GeoJSON
对象都有一个 type
属性,表示对象的类型,其 type
的值可以是 Point
、MultiPoint
、LineString
、MultiLineString
、Polygon
、MultiPolygon
、GeometryCollection
、Feature
、FeatureCollection
,下面是一个 GeoJSON
特征集合示例
1 | { |
TopoJSON
TopoJSON
是 GeoJSON
按拓扑学编码后的扩展形式,是由 D3
的作者 Mike Bostock
制定的,相比 GeoJSON
直接使用 Polygon
、Point
之类的几何体来表示图形的方法,TopoJSON
中的每一个几何体都是通过将共享边(被称为 arcs
)整合后组成的,对比简易图如下
TopoJSON
使用坐标(点)、弧(线、多边形)来表示地理图形,它由 transform
、objects
和 arcs
三部分组成,其中
transform
描述了变换参数objects
描述地理实体包含空间及属性信息arcs
描述了有向弧的空间关系,弧由一系列起点及相对于起点的有向偏移坐标表示,基于这种弧的存储方式可以表达出拓扑关系
由于弧只记录一次及地理坐标使用整数,不使用浮点数,相对于 GeoJSON
,TopoJSON
消除了冗余,文件大小缩小了 80%
左右,不过概念总是那么的抽象,为了表达得更形象些,我们来看下面这个示例
下面的 TopoJSON
在地图上加载后就和上图所呈现效果是一样的,也就是一个长方形和一条直线
1 | { |
下面是一些在线工具推荐
另外,官方提供的示例代码如下
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
效果是下面这样的
KML
KML
(keyhole markup language
)是一种基于 XML
语法格式的文件,用来描述和存储地理信息数据(点、线、面、多边形、多面体以及模型等),通常应用于 Google
地球相关软件中(Google Earth
,Google Map
等),它跟 XML
文件最大的不同就是 KML
描述的是地理信息数据,同时 KML
已正式被 OGC
采用,成为 OGC
众多规范中的一个,KML
文件有两个文件扩展名,分别为 .KML
和 .KMZ
(一个或几个 KML
文件的压缩集,采用 zip
格式压缩)
Cesium
从 1.7
版开始就支持 KML
,不过目前对 KML
的支持还不完整,但是支持大量的标准以及 Google
的 gx
扩展名称空间,有关支持哪些内容和不支持哪些内容的详细列表,请参见 KML Support
这里我们直接来看示例,代码如下
1 | var viewer = new Cesium.Viewer('cesiumContainer') |
效果是下面这样的
CZML
关于 CZML 我们在之前的章节当中已经梳理过了,我们在这里也就只简单的提及一二,CZML
是一种 JSON
格式的字符串,用于描述与时间有关的动画场景,CZML
包含点、线、地标、模型和其他的一些图形元素,并指明了这些元素如何随时间而变化
Cesium
拥有一套富客户端 API
,通过 CZML
采用数据驱动的方式,不用写代码我就可以使用通用的 Cesium viewer
构建出丰富的场景,某种程度上说,Cesium
和 CZML
的关系就像 Google Earth
和 KML
的关系,两者都是用于描述其各自客户端中的场景的数据格式,并且旨在由各种各样的应用程序生成,甚至可能是手工编写的
下面是一个典型的 CZML
数据结构
1 | [ |
如上 CZML
片段描述了两个数据包,每个数据包都有一个 id
标识它描述的对象的属性,id
不一定要求是 GUID
,但它们确实需要唯一地标识 CZML
源中的单个对象,如果 id
未指定,Cesium
将自动生成一个唯一的,但是这会阻止以后的数据包引用该对象,例如向该对象添加更多数据
除 id
属性之外,还包含更多的属性用于定义要绘制对象的属性,在上面的示例中,我们在 WGS 84(-75.5, 40.0, 0.0)
位置中指定了一个 id
为 GroundControlStation
的对象,并在其位置绘制了一个蓝色的点
另外,CZML
比较特殊的是跟时间序列相关的属性
1 | { |
定义了一个 CZML
后,就可以把它载入到场景中,就能获得该对象的动态效果,示例代码如下
1 | var viewer = new Cesium.Viewer('cesiumContainer', { |
下面是加载 Cesium
官网提供的 Vehicle.czml
数据示例的效果,我们可以看到一辆小车正在缓缓移动,可通过动画控制器对小车进行快进、暂停、倒放、回放等等操作