地理数据分为栅格和矢量,栅格通常就是我们用的影像,Cesium的地形图层和影像图层都可以归类到栅格图层里面。cesium将矢量数据扩展到三维空间数据,主要分为三类:1.几何形体,包括点、线、面、体;2.三维模型;3.标签,包括文字标签和图标。cesium中矢量数据因为三维空间特性,所以点是三维点,面可以是水平面、垂直面或者倾斜面。
一、几何形体
我们下面可以看到API有两类,Grachics和Geometry,其中Grachics是Entity API,而Geometry是Primitive API。两种API可以简单理解为一种高度封装的简便方式,一种比较原生但是扩展性强的方式。后边我会详细学习这两种API的使用。
- 点
Cesium中通过PointGraphics类可以构建点要素,修改点的颜色,外轮廓等等属性。
- 线要素
线要素分为折现以及轮廓线。折线可以设置线形,颜色,宽度,拐角等等属性。PolylineGeometry可以设定折现的样式,宽度等属性,而SimplePolylineGeometry则是折线要素的轮廓线,没有宽度属性。
名称 | Primitive API | Entity API |
---|---|---|
折线要素 | PolylineGeometry | PolylineGraphics |
轮廓线 | SimplePolylineGeometry |
轮廓线是各种几何体要素外围轮廓线,主要有立方体、圆、廊、圆柱/圆锥、椭圆/挤出椭圆、椭球、矩形、多边形等等轮廓线。轮廓线只有Primitive API。
具体可以查看API文档:OutlineGeometry-Cesium Documentation
- 面要素
面要素主要是上边轮廓线所包围的几何面图形。逻辑上是先有几何面后有轮廓线,但是为了点线面的顺序,将轮廓线归到了线要素里面描述。下面体要素也是如此。
cesium中的面主要有圆、廊、椭圆、矩形、多边形、面。
名称 | Primitive API | Entity API |
---|---|---|
圆 | CircleGeometry | 无 |
廊 | CorridorGeometry | CorridorGraphics |
椭圆 | EllipseGeometry | PolygonGraphics |
矩形 | RectangleGeometry | RectangleGraphics |
多边形 | PolygonGeometry | PolygonGraphics |
面 | PlanGeometry | PlanGraphics |
- 体要素
Cesium中定义的几何体要素也很多,如下:
名称 | Primitive API | Entity API |
---|---|---|
立方体 | BoxGeometry | BoxGraphics |
圆柱/圆锥 | CylinderGeometry | CylinderGraphics |
椭圆 | EllipsoidGeometry | EllipsoidGraphics |
管 | PolylineVolumeGeometry | PolylineVolumeGraphics |
球 | SphereGeometry | - |
墙 | WallGeometry | WallGraphics |
二、数据格式
二维中,矢量数据格式很多,常见的又shp、geojson、dwg、kmz/kml等等。shp文件结构比较复杂,网络传输压力大,所以Cesium主要采用geoJSON和KML两种比较适合传输的数据格式存储几何形体。此外Cesium基于JSON的基础定义了CZML(后边也要深入学习),专门用于大数据流传输。
GeoJSON
GeoJSON是一种表示地理数据的数据格式。GeoJSON对象可以表示几何,特征或者特征集合,支持点、线、面、多面、多线、多面和几何几何。
下面是GeoJSON的结构:
{
"type": "FeatureCollection",
"features": [{//点
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [102.0, 0.5]
},
"properties": {
"prop0": "value0"
}
}, {//线
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[102.0, 0.0],
[103.0, 1.0],
[104.0, 0.0],
[105.0, 1.0]
]
},
"properties": {
"prop0": "value0",
"prop1": 0.0
}
}, {//面
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[100.0, 0.0],
[101.0, 0.0],
[101.0, 1.0],
[100.0, 1.0],
[100.0, 0.0]
]
]
},
"properties": {
"prop0": "value0",
"prop1": {
"this": "that"
}
}
}]
}
cesium设置了GeoJsonDataSource API来加载GeoJson数据。
const viewer = new Cesium.Viewer('cesiumContainer');
viewer.dataSources.add(
Cesium.GeoJsonDataSource.load(
"data.geojson"
)
);
const viewer = new Cesium.Viewer('cesiumContainer');
viewer.dataSources.add(Cesium.GeoJsonDataSource.load('data.geojson', {
stroke: Cesium.Color.HOTPINK,
fill: Cesium.Color.PINK,
strokeWidth: 3,
clamToGround: true
}));
其中load就是加载数据,而三维相关属性则通过参数配置,例如颜色,是否贴地等等。
但是如果我们想要为geoJSON中的多个元素设置不同的渲染方式,如下:
const viewer = new Cesium.Viewer('cesiumContainer');
const promise = Cesium.GeoJsonDataSource.load("data.geojson");
promise.then(function (dataSource) { // 类似于添加3D对象中的动画
viewer.dataSources.add(dataSource); // 先添加对象
//获取所有对象
const entities = dataSource.entities.values;
const colorHash = {};
for (let i = 0; i < entities.length; i++) { // 逐一遍历循环
const entity = entities[i];
const name = entity.name; // 取出name属性
let color = colorHash[name]; // 如果name属性相同,赋予同一个颜色
if (!color) {
color = Cesium.Color.fromRandom({
alpha: 1.0,
});
colorHash[name] = color;
}
entity.polygon.material = color; //设置polygon对象的填充颜色
entity.polygon.outline = false; // 边线是否显示
entity.polygon.extrudedHeight = entity.properties.Population / 50.0; // 根据Population属性设置polygon高
}
})
.catch(function (error) {
//Display any errrors encountered while loading.
window.alert(error);
});
此种方式先load数据,而后逐一设置加载数据的Entity。GeoJSON中属性可以通过entity.properties.Population读取,Population为属性key。
如果我们是一份shp数据,可以先转换为geoJSON再次使用,工具很多QGIS,ArcGIS等等。
KML
KeyHole标记语言(Keyhole markup language,KML)最初是谷歌旗下keyhole公司开发的,是一种基于XML语法与格式的,用于描述和保存地理信息(点、线、图像、多边形和模型等)的编码规范。目前KML已经被开放地理空间信息联盟(OGC)接管,成为了开放的地理信息编码标准。Cesium中针对KML规范的调用提供了KmlDataSource API接口。
名称 | 描述 |
---|---|
dsss | 定义视角 |
canvas | 绘制待展示信息 |
ellipsoid | 地球椭球参数,默认WGS-84椭球 |
示例:
const viewer = new Cesium.Viewer("cesiumContainer");
const options = {
camera: viewer.scene.camera,
canvas: viewer.scene.canvas,
screenOverlayContainer: viewer.container,
};
viewer.dataSources.add(
Cesium.KmlDataSource.load(
"data.kml",
options
)
);
CZML
CZML 是 Cesium 中很重要的一个概念,也是一个亮点,CZML 使得 cesium 很酷很炫地展示动态数据成为可能。CZML 是一种 JSON 格式的字符串,用于描述与时间有关的动画场景,CZML 包含点、线、地标、模型、和其他的一些图形元素,并指明了这些元素如何随时间而变化。某种程度上说, Cesium 和 CZML 的关系就像 Google Earth 和 KML。
CZML 的一个典型结构如下
[
// packet one
{
"id": "GroundControlStation"
"position": { "cartographicDegrees": [-75.5, 40.0, 0.0] },
"point": {
"color": { "rgba": [0, 0, 255, 255] },
}
},
// packet two
{
"id": "PredatorUAV",
// ...
}
]
CZML 可以记录对象与时间的关系,其时间序列相关属性如下:
{
// ...
"someInterpolatableProperty": {
"cartesian": [
"2012-04-30T12:00Z", 1.0, 2.0, 3.0, //表示当时间为2012-04-30T12:00Z,坐标为(1,2,3)
"2012-04-30T12:01Z", 4.0, 5.0, 6.0, //表示当时间为2012-04-30T12:01Z,坐标为(4,5,6)
"2012-04-30T12:02Z", 7.0, 8.0, 9.0 //表示当时间为2012-04-30T12:02Z,坐标为(7,8,9)
]
}
}
{
// ...
"someInterpolatableProperty": {
"epoch": "2012-04-30T12:00Z", //表示时间起点为2012-04-30T12:00:00
"cartesian": [
0.0, 1.0, 2.0, 3.0, //从起点开始,第0秒时坐标为(1,2,3)
60.0, 4.0, 5.0, 6.0, //从起点开始,第60秒时坐标为(4,5,6)
120.0, 7.0, 8.0, 9.0 //从起点开始,第120秒时坐标为(7,8,9)
]
}
}
{
// ...
"someInterpolatableProperty": {
"epoch": "2012-04-30T12:00Z",
"cartesian": [
0.0, 1.0, 2.0, 3.0,
60.0, 4.0, 5.0, 6.0,
120.0, 7.0, 8.0, 9.0
],
"interpolationAlgorithm": "LAGRANGE", //插值算法为LAGRANGE,还有HERMITE,GEODESIC
"interpolationDegree": 5 //1为线性插值,2为平方插值
},
}
具体的可以查阅相关资料。将 CZML 数据载入场景的方式与前两者一致,加载完后处理方式也基本一致,如下:
dataSource = new Cesium.CzmlDataSource();
var czml = 'data/Vehicle.czml';
dataSource.load(czml);
viewer.dataSources.add(dataSource);
三、三维模型
三维模型的数据格式是很多的,经常见到的就有DAE、OBJ、STL、3DS MAX、CLM、IFC等等。这些数据格式结构复杂,不适用与网络传输,因此Khronos公司的GL传输格式(GL transmission format,glTF)数据格式成为了Cesium首选的三维数据渲染数据标准。glTF的特点就是传输和解析高效。
加载 3D 对象
通过 Cesium 可以很清楚的将一个三维模型加载到地球中。有两种方式可以实现此功能。
entity
var entity = viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706),
model : { uri : '../Apps/SampleData/models/CesiumGround/Cesium_Ground.gltf' }
});
viewer.trackedEntity = entity; // 镜头追踪,将镜头固定在对象上
清晰明了,不做过多介绍。
primitives
// 这种方式会以最大最小值为缩放边界,采用entity的方式会完全根据地图进行缩放
var scene = viewer.scene;
var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(-123.0745725, 44.0503706));
var model = scene.primitives.add(Cesium.Model.fromGltf({
url: 'data/Cesium_Ground.gltf',
//以下这些信息也均可在entity中设置
color : Cesium.Color.fromAlpha(Cesium.Color.RED, parseFloat(0.5)),//模型颜色,透明度
silhouetteColor : Cesium.Color.fromAlpha(Cesium.Color.GREEN, parseFloat(0.5)),//轮廓线
colorBlendMode : Cesium.ColorBlendMode.MIX,//模型样式['Highlight', 'Replace', 'Mix']
modelMatrix: modelMatrix,
minimumPixelSize : 256, // 最小的缩放尺寸,256个像素,就是一个瓦片的尺寸。
maxiumScale: 2 // 最大的缩放倍数
}));
其中 modelMatrix 定义了对象的位置,第一种添加方式模型会自动按照 gltf 设置好的动画进行播放,第二种方式则需要添加下述代码设置动画。
//添加动画
Cesium.when(model.readyPromise).then(function (model) {
model.activeAnimations.addAll({
loop: Cesium.ModelAnimationLoop.REPEAT,//控制重复
speedup: 0.5, // 速度,相对于clock
reverse: true // 动画反转
})
});
glTF与glb
下图是glTF2.0文件的数据结构。与glTF1.0相比,2.0中删除了着色器源代码的配置,使数据与着色器分离,着色器程序由具体的运行环境来配置。glTF1.0最上层的是JSON文本对象,描述该模型的节点层级、相机、动画等相关逻辑结构,bin则对应这些对象的具体数据信息,目前纹理图片仅支持.jpg和.png照片格式。
在glTF2.0中定义描述的三维场景有以下概念:场景(scene)、节点(node)、格网(mesh)、访问器(accessor)、缓冲区块(bufferView)、缓冲区(buffer)、材质(material)、纹理(texture)、图片(image)、取样器(sampler)、蒙皮(skin)、动画(animation)和相机(camera)。以上内容存储在JSON对象中,用于定义三维模型的建模要素。
Cesium支持glTF作为标准数据格式,而且Cesium自己定义的3D Tiles也是在glTF的基础上赋予三维模型细节层次(LOD)
属性,提高了大数据加载流畅度。再Cesium中调用glTF非常方便,通过ModelGraphics API便可调用glTF数据。而且Cesium为开发者提供了缩放尺寸、颜色、显示隐藏等丰富参数设置。
加载示例:
var entity = viewer.entities.add({
name: "plane",
Position: Cesiun.Cartesian3.fromDegrees(102.3187, 24.4923, 0), //模型位置
model: {
uri: "Cesium_Air.gltf",
//glTE 模型
scale: 2,
//模型本身大小
minimumPixelSize: 128,
//最小的模型像素
maximumScale: 20000,
//最大的模型像素
runAnimations: true,
//是否显示动画
clampAnimations: true,
//是否保持最后一针的动画
color: Cesium.Color.RED,
//模型加颜色
colorBlendMode: Cesiun.ColorBlendMode['MIX'], //用于设置模型和颜色的关系
colorBlendAmount: 0.5, //这个属性必须是MIX混合属性才能生效,见colorBlendMode
show: true, //是否显示或隐藏
}
});
viewer.trackedEntity = entity;//设置摄像头定位到模型处
3D Tile
3D 瓦片可以显示建筑物、地标乃至森林广告牌等等以及其对应的属性信息。每个 3D 瓦片就是一个 3D 对象,具体的数据范围等等信息在 tileset.json 中定义。
加载
var tileSet = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
// 同样url只定义编号前面的部分,具体的编号(数字或者非数字都有可能)在此URL下的tileset.json文件中定义,包括此3d瓦片图层的范围等等。
url: 'https://beta.cesium.com/api/assets/1461?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJiMTBjN2E3Mi03ZGZkLTRhYmItOWEzNC1iOTdjODEzMzM5MzgiLCJpZCI6NDQsImlhdCI6MTQ4NjQ4NDM0M30.B3C7Noey3ZPXcf7_FXBEYwirct23fsUecRnS12FltN8&v=1.0'
}));
tileSet.readyPromise.then(function (tileset) {
viewer.camera.viewBoundingSphere(tileset.boundingSphere, new Cesium.HeadingPitchRange(0, -0.5, 0));
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
});
tileset.json 文件
不同分辨率显示不同 3D 瓦片,全靠此文件定义。
{
"asset": {
"version": "1.0"
},
"geometricError": 500,
"root": {
"transform": [
96.86356343768793,
24.848542777253734,
0,
0,
-15.986465724980844,
62.317780594908875,
76.5566922962899,
0,
19.02322243409411,
-74.15554020821229,
64.3356267137516,
0,
1215107.7612304366,
-4736682.902037748,
4081926.095098698,
],
"boundingVolume": {
"box": [
0,
0,
0,
7.0955,
0,
0,
0,
3.1405,
0,
0,
0,
5.0375
]
},
"geometricError": 100,
"refine": "REPLACE",
"content": {
"url": "dragon_low.b3dm"
},
"children": [
{
"boundingVolume": {
"box": [
0,
0,
0,
7.0955,
0,
0,
0,
3.1405,
0,
0,
0,
5.0375
]
},
"geometricError": 10,
"content": {
"url": "dragon_medium.b3dm"
},
"children": [
{
"boundingVolume": {
"box": [
0,
0,
0,
7.0955,
0,
0,
0,
3.1405,
0,
0,
0,
5.0375
]
},
"geometricError": 0,
"content": {
"url": "dragon_high.b3dm"
}
}
]
}
]
}
}
其中 boundingVolume.region 属性是包含六个元素的数组对象,用于定义边界地理区域,格式是 [west, south, east, north, minimum height, maximum height]。经度和维度以弧度为单位,高度以米为单位(高于或低于 WGS84 椭球体)除了 region,也有其他边界体可以用,比如 box 和 sphere。其余各个字段包含信息可以查阅官方手册。
支持的格式
b3dm: Batched 3D Model 用于展示城市建筑等大规模的 3D 对象
l3dm: Instanced 3D Model 用于展示模型等。
pnts: Point Cloud 用于展示大量的 3D 点。
vctr: Vector Data 用于展示矢量元素,代替 KML(那么 CZML 呢?动画?)
cmpt: Composite 用于合并异构 3D 瓦片,如将城市建筑的 b3dm 和树的 i3dm 合在一起展示。
Style
可以根据对象的属性信息进行不同的可视化处理,包括颜色、显示与否等等。
var styleJson = {
color : {
conditions : [
["${height} > 70.0", "rgb(0, 0, 255)"],
["${height} > 50.0", "rgb(0, 255, 0)"],
["${height} > 30.0", "rgb(0, 255, 255)"],
["${height} > 10.0", "color('purple', 1)"],
["${height} > 1.0", "color('gray', 0.5)"],
["true", "color('blue')"] // conditions
]
},
show : '${height} > 0',
meta : {
description : '"Building id ${id} has height ${height}."'
}
};
tileSet.style = new Cesium.Cesium3DTileStyle(styleJson);
注意 conditions 中条件必须闭合,不能出现分类不完整,所以一般最后会加一个 true 项,相当于 default。
四、标签
标签是一种特殊的空间数据,相当于二维地图的图标,主要用作标准信息,标明三维模型或其它地理空间数据的名称等属性。
名称 | Entity API |
---|---|
label | LabelGraphics |
billboard | BillboardGraphics |