1. 矢量数据:
1.1. GeoJSON
定义:
一个基于JSON的地理数据格式,Cesium支持GeoJSON的直接加载。
例子:
加载一个简易故宫建筑的GeoJSON数据。
代码:
/**
* 添加故宫geojson数据
*/
AddGuGong() {
var viewer = this.viewer;
Cesium.GeoJsonDataSource.load("../static/geojson/故宫.geojson").then(
function(data) {
viewer.dataSources.add(data);
const entities = data.entities.values;
for (let i = 0; i < entities.length; i++) {
let entity = entities[i];
var height = entity.properties.height._value;
entity.polygon.heightReference =
Cesium.HeightReference.CLAMP_TO_GROUND;
entity.polygon.outline = false;
// 将高度拉伸至高度属性值
entity.polygon.extrudedHeight = height != null ? height : 5;
}
}
);
},
获取并修改样式(下面的KML和CZML也一样):
从viewer.dataSources.add(data);
可以看出,数据被添加到viewer.dataSources
里面了,那如何获取就显而易见了。
在viewer.dataSources.add(data);
添加数据之前,为data加个name属性data.name="故宫geojson"
,然后遍历获取并修改属性
// 获取已加载的数据源
var dataSources = viewer.dataSources;
// 遍历所有数据源
for (var i = 0; i < dataSources.length; i++) {
var dataSource = dataSources.get(i);
// 检查是否是你加载的故宫数据源
if (dataSource.name === "故宫geojson") { // 注意替换成实际的数据源名称
var entities = dataSource.entities.values;
// 遍历故宫数据源中的实体
for (var j = 0; j < entities.length; j++) {
var entity = entities[j];
// 进行属性修改,例如修改颜色
entity.polygon.material = Cesium.Color.RED;
}
}
}
1.2. KML/KMZ
定义:
KML (keyhole markup language)是以XML语言为基础开发的一种文件格式,用来描述和存储地理信息数据(点、线、面、图片等),是纯粹的xml文本格式, KMZ是Google Earth默认的输出文件格式,是一个经过ZIP格式压缩过的KML文件。
例子:
添加山东省边界kml数据。
代码:
/**
* 添加山东省边界kml数据
*/
AddKml() {
var viewer = this.viewer;
viewer.dataSources
.add(Cesium.KmlDataSource.load("../static/山东省边界.kml"))
.then(function(dataSource) {});
},
1.3. CZML (Cesium Language)
定义:CZML是Cesium的JSON格式,用于描述时间动态的图形场景。
例子:添加卫星轨迹czml数据。
代码:
/**
* 添加卫星轨迹czml数据
*/
AddCzml() {
var viewer = this.viewer;
viewer.dataSources
.add(Cesium.CzmlDataSource.load("../static/卫星轨迹.czml"))
.then(function(dataSource) {});
},
2. 影像服务:
2.1. WMS (Web Map Service)
定义:
Cesium可以直接加载和显示WMS服务提供的图层。
例子:
加载三国州郡地图WMS服务。
代码:
/**
* 向当前视图添加geoserver发布的WMS服务(多个图层)
*/
AddGeoserverService: function() {
let viewer = this.viewer;
let _this = this;
const layerConfigs = [
{
layers: "sanmap:州界面"
},
{
layers: "sanmap:河流湖泊面"
},
{
layers: "sanmap:河流线"
},
{
layers: "sanmap:郡治点"
}
];
layerConfigs.forEach(config => {
const wmsImageryProvider = new Cesium.WebMapServiceImageryProvider({
url: "http://******/geoserver/sanmap/wms",
layers: config.layers,
parameters: {
transparent: true,
format: "image/png",
srs: "EPSG:4326"
}
});
viewer.imageryLayers.addImageryProvider(wmsImageryProvider);
});
},
获取并修改样式(下面的WMTS和XYZ也差不多,但获取方式略有差别,反正都在viewer.imageryLayers里查找就是了)
从viewer.imageryLayers.addImageryProvider(wmsImageryProvider);
这一句不难看出,影像图层是保存到viewer.imageryLayers
了,同样的获取方式
// 获取已加载的影像图层列表
var imageryLayers = viewer.imageryLayers;
// 遍历影像图层列表
for (var i = 0; i < imageryLayers.length; i++) {
var layer = imageryLayers.get(i);
// 检查是否是你加载的图层
if (layer.imageryProvider.layers === "sanmap:州界面") {
layer.alpha = 0.3;
}
}
2.2. WMTS (Web Map Tile Service)
定义:
Cesium可以直接加载和显示WMTS服务提供的预渲染瓦片图层。
例子:
加载天地图WMTS地图服务。
代码:
/**
* 加载天地图wmts服务
*/
AddWmts(){
let _this = this;
let viewer = _this.viewer;
//天地图token
let token = window.tiandituToken;
//加载在线天地图
let obj=({
url: "http://t0.tianditu.com/cia_w/wmts?tk=" + token,
label: "天地图影像",
loadType: "WebMapTileServiceImageryProvider",
layer: "cia",
style: "default",
tileMatrixSetID: "w",
format: "tiles",
maximumLevel: 18
});
var wmtsImageryProvider = new Cesium.WebMapTileServiceImageryProvider(obj);
viewer.imageryLayers.addImageryProvider(wmtsImageryProvider);
},
2.3.TMS /XYZ(Tile Map Service)
定义:
用于加载地图瓦片,Cesium支持这种服务,尤其是加载卫星影像和其他地图底图。
例子:
加载一个OpenStreetMap的XYZ格式瓦片图层作为地球的底图。
代码:
/**
* 加载XYZ瓦片服务
*/
AddXyz(){
let _this=this
let viewer=_this.viewer
var osmProvider = new Cesium.UrlTemplateImageryProvider({
url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'
});
viewer.imageryLayers.addImageryProvider(osmProvider);
},
2.4.TMS、XYZ与WMTS的不同:
(1)TMS (Tile Map Service):
它是由OSGeo组织提出的开放标准。
定义了如何访问和组织地图瓦片。
在TMS中,瓦片的y坐标是从下至上递增的,这意味着当你向北移动时,y值会增加。
(2)XYZ:
这不是一个正式的标准或规范,但它已经成为了事实上的标准,被许多现代Web地图服务采用,如Google Maps、OpenStreetMap等。
与TMS相反,瓦片的y坐标是从上至下递增的。
在实际应用中,XYZ通常被认为是更直观和简单的,因为它更符合Web浏览器的坐标系统(其中y坐标从上至下递增)。
(3)WMTS (Web Map Tile Service):
它是由Open Geospatial Consortium (OGC) 提出的标准。
是一个比TMS更复杂、更完整的服务规范,它包括了不仅仅是如何访问瓦片,还有如何描述服务、如何列出可用的瓦片集等。
WMTS支持多种“瓦片矩阵集”,这些矩阵集中的一种就是TMS格式。因此,可以说TMS是WMTS的一个子集或一个选项。
(4)关系总结:
TMS 和 XYZ 主要的区别在于瓦片的y坐标如何增加:在TMS中从下至上,而在XYZ中从上至下。
WMTS 是一个比TMS更广泛、更完整的标准。WMTS支持多种瓦片编址方案,其中TMS是其中之一。XYZ格式并不是WMTS的正式部分,但由于它的普遍性,很多WMTS实现也支持XYZ格式作为非正式的扩展。
从实际应用的角度看,XYZ格式已经被广大Web开发者接受并广泛使用,尽管它并没有像TMS和WMTS那样的正式规范背书。
2.5.WMTS与WMS的关系:
数据提供方式:
WMS (Web Map Service): WMS按请求提供地图图像。当用户或客户端发送一个包含地理范围、图像大小等参数的请求时,WMS会生成一个对应的地图图像并返回。这意味着每次你浏览或缩放地图时,WMS都需要动态渲染一个新的图像。
WMTS: 与WMS不同,WMTS提供预渲染的地图瓦片。这些瓦片是按照特定的规模和范围提前渲染的,当用户请求时,只需要选择和提供相应的瓦片,而不需要每次都进行渲染。
性能:
由于WMTS使用预渲染的瓦片,其性能通常优于WMS,尤其是在高并发的情况下。预渲染的瓦片可以在CDN或缓存中存储,从而进一步提高数据的提取速度。
灵活性:
WMS由于是按需渲染的,因此可以提供更高的灵活性,如动态样式、过滤特定的数据等。然而,这种灵活性通常以性能为代价。
WMTS由于是预渲染的,灵活性较低,但是在需要快速提供地图内容的情境中,其性能表现优越。
应用场景:
WMS: 当你需要根据用户的需求动态生成地图内容,或者需要特定的样式和数据过滤时,WMS可能是更好的选择。
WMTS: 当你需要为大量用户快速提供地图内容,尤其是常用的地图层时,WMTS是更好的选择。
总的来说,WMTS是WMS的一个补充。在选择使用哪种服务时,应根据应用的需求、预期的用户量以及性能需求来进行决策。
3. 地形服务:
3.1.CesiumTerrainProvider
描述:
这是Cesium为了处理高精度的全球地形数据而创建的API。地形数据切片使用quantized-mesh v1.0格式,它允许高效的流式传输和渲染。
特点:
除了地形高度外,这种地形还支持实时的太阳光照效果和真实的水体渲染效果。
如何调用:
使用Cesium中的CesiumTerrainProvider API可以很容易地调用并加载这种地形数据。
代码:
// 加载地形数据
//viewer.terrainProvider = Cesium.createWorldTerrain();
// viewer.terrainProvider = Cesium.createWorldTerrain({
// requestVertexNormals: true,
// requestWaterMask: true
// });
// 或
const terrainProvider = new Cesium.CesiumTerrainProvider({
url: Cesium.IonResource.fromAssetId(1), //这使用了Cesium Ion的默认全球地形
requestWaterMask: true, //请求水体效果所需要的海岸线数据
requestVertexNormals: true //请求地形照明数据
});
viewer.terrainProvider = terrainProvider;
//地形夸张
viewer.scene.globe.terrainExaggeration = 1.3;
4. 三维数据:
4.1. glTF (GL Transmission Format)/glb
定义:
是3D模型的一种格式,Cesium使用这种格式来优化3D模型的加载和渲染。
不同:
glTF: 这是 glTF 的标准格式,使用JSON格式表示3D内容,并且通常以 .gltf 为扩展名。与此相关的资源(如纹理和二进制网格数据)通常存储在与主 gltf 文件分开的文件中。
glb: 这是 glTF 的二进制格式,通常以 .glb 为扩展名。所有相关的资源(如纹理、着色器、网格等)都嵌入到单一的二进制文件中,使其更容易传输。
例子:
添加飞机glb模型(键盘控制移动)
代码:
/**
* 添加glb模型(键盘控制移动)
* @param {Number} x 经度
* @param {Number} y 纬度
* @param {Number} z 高度
*/
AddCesiumglb(x, y, z) {
var viewer = this.viewer;
let url = "../static/Cesium_Air.glb";
// 模型姿态变化
let headingPitchRoll = new Cesium.HeadingPitchRoll();
// 模型初始位置
let position2 = new Cesium.Cartesian3.fromDegrees(x, y, z);
// 局部变换坐标系
let fixedFrameTransform = Cesium.Transforms.localFrameToFixedFrameGenerator(
"north",
"west"
);
// 每次操作姿态变化为5°
let deltaRadians = Cesium.Math.toRadians(5.0);
// 速度
let speed = 10;
// 速度向量
let speedVector = new Cesium.Cartesian3();
// 添加实体
// 使用primitive方式加载模型
const modelEntity = viewer.scene.primitives.add(
Cesium.Model.fromGltf({
url: url,
scale: 20.0,
modelMatrix: Cesium.Transforms.headingPitchRollToFixedFrame(
position2,
headingPitchRoll,
Cesium.Ellipsoid.WGS84,
fixedFrameTransform
),
minimumPixelSize: 12,
maximumScale: 200
})
);
// 添加键盘监听事件
document.addEventListener("keydown", function(e) {
switch (e.keyCode) {
// 抬头
case 38:
headingPitchRoll.pitch += deltaRadians;
// 判断是否超过2π范围
if (headingPitchRoll.pitch > Cesium.Math.TWO_PI) {
headingPitchRoll.pitch -= Cesium.Math.TWO_PI;
}
console.log("抬头:pitch+");
break;
// 低头
case 40:
headingPitchRoll.pitch -= deltaRadians;
if (headingPitchRoll.pitch < -Cesium.Math.TWO_PI) {
headingPitchRoll.pitch += Cesium.Math.TWO_PI;
}
console.log("低头:pitch-");
break;
// 左转
case 37:
headingPitchRoll.heading -= deltaRadians;
// 判断是否超过2π范围
if (headingPitchRoll.heading < -Cesium.Math.TWO_PI) {
headingPitchRoll.heading += Cesium.Math.TWO_PI;
}
console.log("左转:heading+");
break;
// 右转
case 39:
headingPitchRoll.heading += deltaRadians;
// 判断是否超过2π范围
if (headingPitchRoll.heading > Cesium.Math.TWO_PI) {
headingPitchRoll.heading -= Cesium.Math.TWO_PI;
}
console.log("右转:heading-");
break;
// 顺时针
case 96:
headingPitchRoll.roll += deltaRadians;
// 判断是否超过2π范围
if (headingPitchRoll.roll > Cesium.Math.TWO_PI) {
headingPitchRoll.roll -= Cesium.Math.TWO_PI;
}
console.log("顺时针翻滚:roll+");
break;
// 逆时针
case 110:
headingPitchRoll.roll -= deltaRadians;
// 判断是否超过2π范围
if (headingPitchRoll.roll < -Cesium.Math.TWO_PI) {
headingPitchRoll.roll += Cesium.Math.TWO_PI;
}
console.log("逆时针翻滚:roll-");
break;
// 加速
case 187:
speed += 10;
speed = Math.min(speed, 10000);
console.log("加速:" + speed);
break;
// 减速
case 189:
speed -= 10;
speed = Math.max(speed, 100);
console.log("减速:" + speed);
break;
default:
break;
}
});
// 渲染更新前阶段添加监听
viewer.scene.preUpdate.addEventListener(() => {
if (window.fly) {
speedVector = Cesium.Cartesian3.multiplyByScalar(
Cesium.Cartesian3.UNIT_X,
speed / 10,
speedVector
);
position2 = Cesium.Matrix4.multiplyByPoint(
modelEntity.modelMatrix,
speedVector,
position2
);
// 更新模型姿态与位置
Cesium.Transforms.headingPitchRollToFixedFrame(
position2,
headingPitchRoll,
Cesium.Ellipsoid.WGS84,
fixedFrameTransform,
modelEntity.modelMatrix
);
// 俯视跟随
viewer.camera.lookAt(position2, new Cesium.Cartesian3(0, 0, 2000));
// 第一视角跟随
//viewer.camera.lookAt(position2, new Cesium.HeadingPitchRange(headingPitchRoll.heading, headingPitchRoll.pitch, 2000))
}
});
},
获取并修改样式(下面的3D Tiles也差不多,不过是Cesium.Cesium3DTileset)
从const modelEntity = viewer.scene.primitives.add
不难看出,模型保存在这里viewer.scene.primitives
。给模型赋上名称modelEntity.name="飞机模型"
,然后获取
// 获取已加载的3D模型列表
var primitives = viewer.scene.primitives;
for (var i = 0; i < primitives.length; i++) {
var primitive = primitives.get(i);
// 判断是否为3D模型(glTF)
if (primitive instanceof Cesium.Model&&primitive.name=="飞机模型") {
console.log(primitive)
primitive.color = new Cesium.Color(1.0, 0.0, 0.0, 1.0);
}
}
4.2.3D Tiles
定义:
这是Cesium推出的一个规范,用于流式传输和加载大型3D数据集。
例子:
加载大雁塔3D建筑模型。
代码:
/**
* 添加大雁塔模型
*/
Add3DTileset() {
let _this = this;
let viewer = _this.viewer;
let tileSetModel = new Cesium.Cesium3DTileset({
url: "./static/3DT/dayanta/tileset.json"
});
// 加载3D瓦片集模型
tileSetModel.readyPromise
.then(tileset => {
// 将3D瓦片集的边界球中心转换为地理坐标
let cartographicCenter = Cesium.Cartographic.fromCartesian(tileset.boundingSphere.center);
// 使用sampleTerrainMostDetailed函数获取边界球中心的地形高度
Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, [cartographicCenter]).then(function(samples) {
// 更新地形高度
cartographicCenter.height = samples[0].height;
// 根据地形高度更新模型位置
let surfaceCenter = Cesium.Cartesian3.fromRadians(cartographicCenter.longitude, cartographicCenter.latitude, cartographicCenter.height);
let translation = Cesium.Cartesian3.subtract(surfaceCenter, tileset.boundingSphere.center, new Cesium.Cartesian3());
tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
// 将模型添加到场景中
viewer.scene.primitives.add(tileset);
// 调整视角至模型位置
viewer.zoomTo(
tileset,
new Cesium.HeadingPitchRange(
0.5,
-0.2,
tileset.boundingSphere.radius * 1.0
)
);
});
})
.catch(function(error) {
console.log(error);
});
},