Skip to content

地理数据分为栅格和矢量,栅格通常就是我们用的影像,Cesium的地形图层和影像图层都可以归类到栅格图层里面。cesium将矢量数据扩展到三维空间数据,主要分为三类:1.几何形体,包括点、线、面、体;2.三维模型;3.标签,包括文字标签和图标。cesium中矢量数据因为三维空间特性,所以点是三维点,面可以是水平面、垂直面或者倾斜面。

一、几何形体

我们下面可以看到API有两类,Grachics和Geometry,其中Grachics是Entity API,而Geometry是Primitive API。两种API可以简单理解为一种高度封装的简便方式,一种比较原生但是扩展性强的方式。后边我会详细学习这两种API的使用。

Cesium中通过PointGraphics类可以构建点要素,修改点的颜色,外轮廓等等属性。

  1. 线要素

线要素分为折现以及轮廓线。折线可以设置线形,颜色,宽度,拐角等等属性。PolylineGeometry可以设定折现的样式,宽度等属性,而SimplePolylineGeometry则是折线要素的轮廓线,没有宽度属性。

名称Primitive APIEntity API
折线要素PolylineGeometryPolylineGraphics
轮廓线SimplePolylineGeometry

轮廓线是各种几何体要素外围轮廓线,主要有立方体、圆、廊、圆柱/圆锥、椭圆/挤出椭圆、椭球、矩形、多边形等等轮廓线。轮廓线只有Primitive API。

具体可以查看API文档:OutlineGeometry-Cesium Documentation

  1. 面要素

面要素主要是上边轮廓线所包围的几何面图形。逻辑上是先有几何面后有轮廓线,但是为了点线面的顺序,将轮廓线归到了线要素里面描述。下面体要素也是如此。

cesium中的面主要有圆、廊、椭圆、矩形、多边形、面。

名称Primitive APIEntity API
CircleGeometry
CorridorGeometryCorridorGraphics
椭圆EllipseGeometryPolygonGraphics
矩形RectangleGeometryRectangleGraphics
多边形PolygonGeometryPolygonGraphics
PlanGeometryPlanGraphics
  1. 体要素

Cesium中定义的几何体要素也很多,如下:

名称Primitive APIEntity API
立方体BoxGeometryBoxGraphics
圆柱/圆锥CylinderGeometryCylinderGraphics
椭圆EllipsoidGeometryEllipsoidGraphics
PolylineVolumeGeometryPolylineVolumeGraphics
SphereGeometry-
WallGeometryWallGraphics

二、数据格式

二维中,矢量数据格式很多,常见的又shp、geojson、dwg、kmz/kml等等。shp文件结构比较复杂,网络传输压力大,所以Cesium主要采用geoJSON和KML两种比较适合传输的数据格式存储几何形体。此外Cesium基于JSON的基础定义了CZML(后边也要深入学习),专门用于大数据流传输。

GeoJSON

GeoJSON是一种表示地理数据的数据格式。GeoJSON对象可以表示几何,特征或者特征集合,支持点、线、面、多面、多线、多面和几何几何。

下面是GeoJSON的结构:

json
 {
       "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数据。

json
const viewer = new Cesium.Viewer('cesiumContainer');
viewer.dataSources.add(
  Cesium.GeoJsonDataSource.load(
    "data.geojson"
  )
);
js
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中的多个元素设置不同的渲染方式,如下:

json
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等等。

img

KML

KeyHole标记语言(Keyhole markup language,KML)最初是谷歌旗下keyhole公司开发的,是一种基于XML语法与格式的,用于描述和保存地理信息(点、线、图像、多边形和模型等)的编码规范。目前KML已经被开放地理空间信息联盟(OGC)接管,成为了开放的地理信息编码标准。Cesium中针对KML规范的调用提供了KmlDataSource API接口。

名称描述
dsss定义视角
canvas绘制待展示信息
ellipsoid地球椭球参数,默认WGS-84椭球

示例:

js
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 // 动画反转
    })
});

img

glTF与glb

下图是glTF2.0文件的数据结构。与glTF1.0相比,2.0中删除了着色器源代码的配置,使数据与着色器分离,着色器程序由具体的运行环境来配置。glTF1.0最上层的是JSON文本对象,描述该模型的节点层级、相机、动画等相关逻辑结构,bin则对应这些对象的具体数据信息,目前纹理图片仅支持.jpg和.png照片格式。

glTF 2.0

在glTF2.0中定义描述的三维场景有以下概念:场景(scene)、节点(node)、格网(mesh)、访问器(accessor)、缓冲区块(bufferView)、缓冲区(buffer)、材质(material)、纹理(texture)、图片(image)、取样器(sampler)、蒙皮(skin)、动画(animation)和相机(camera)。以上内容存储在JSON对象中,用于定义三维模型的建模要素。

image-20240310191903976

Cesium支持glTF作为标准数据格式,而且Cesium自己定义的3D Tiles也是在glTF的基础上赋予三维模型细节层次(LOD)

属性,提高了大数据加载流畅度。再Cesium中调用glTF非常方便,通过ModelGraphics API便可调用glTF数据。而且Cesium为开发者提供了缩放尺寸、颜色、显示隐藏等丰富参数设置。

加载示例:

js
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
labelLabelGraphics
billboardBillboardGraphics