手把手带你开发Cesium三维场景【3D智慧城市警情预警】
📢 C语言专栏:想学C语言的,冲
📢?VUE专栏:想学VUE的,冲这里
📢?CSS专栏:想学CSS的,冲这里
📢 Krpano专栏:想学VUE的,冲这里
🔔 上述专栏,都在不定期持续更新中!!!!!!!!!!!!!
??
效果演示
警情模拟示例
? 一、?前言
本文主要用于构建Cesium三维地图场景,主要实现了以下功能:
1、初始化三维地图控件
????????使用Cesium.Viewer和Cesium.Scene等对象初始化三维地图,设置地图纹理、视角位置、阴影参数等配置信息,进行三维场景的初始化。
2、封装场景操作类
????????封装D3类对场景进行管理,实现场景配置、数据加载、事件绑定等功能,以更好地控制三维场景。
3、CSS3渲染标注
????????使用CSS3渲染在三维场景中添加Html标注信息。
4、实现视角导航动画
????????实现不同场景状态下的视角平滑导航动画,使用flyTo方法实现过渡动画效果。
5、构建交互界面
????????使用dat.GUI构建交互界面,可以控制场景效果参数、添加各种内容。
6、警情场景模拟
????????实现警情监控、预报、分析、调度四个场景状态的模拟。
7、封装视觉效果方法
????????封装添加模型、粒子、标注、墙体等常用场景效果的方法。
二、关键技术要点
1. 初始化三维场景
/**
* 初始化
*/
D3.prototype.init = function (opt = {}) {
if (configs.mapDom && configs.mapUrl) {
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJlYTQ2ZjdjNS1jM2E0LTQ1M2EtOWM0My1mODMzNzY3YjYzY2YiLCJpZCI6MjkzMjcsInNjb3BlcyI6WyJhc3IiLCJnYyJdLCJpYXQiOjE1OTE5NDIzNjB9.RzKlVTVDTQ9r7cqCo-PDydgUh8Frgw0Erul_BVxiS9c';
// 添加镜像服务
// mapbox.satellite 卫星图像
// mapbox.streets 街道图像
this._viewer = new Cesium.Viewer(configs.mapDom, configs.mapOptions);
this._util = new Cesium.Utils(this._viewer)
//BingMapsImageryProvider Bing地图影像,可以指定mapStyle,详见BingMapsStyle类
// 其中可以指定mapStyle,选择多种风格,目前Cesium中支持AERIAL、AERIAL_WITH_LABELS、ROAD、ORDNANCE_SURVEY、COLLINS_BART五种。
this._viewer.imageryLayers.addImageryProvider(new Cesium.BingMapsImageryProvider({
url: 'https://dev.virtualearth.net',
mapStyle: Cesium.BingMapsStyle.AERIAL,
key: URL_CONFIG.BING_MAP_KEY
}))
this._scene = this._viewer.scene
this._scene.skyBox = this._util.setOneGroundSkyBox()
// this._util.setSnowEffect()
this.config(opt) //默认开始配置
this.loadScene() //加载场景
// this.addThreeObject() //加载three obj
} else {
alert("请配置地图参数")
}
}
使用Cesium中常用的Viewer、Scene等对象初始化三维视图,主要进行以下配置:
- 设置地图纹理为Bing地图
- 配置场景的光照、阴影参数
- 关闭默认的天空背景、大气效果
- 开启各种画质优化效果
相关API:
- Cesium.Viewer:三维场景的主要容器
new Cesium.Viewer(container,?options)
????????用于构建应用程序的基本小部件。它将所有标准 Cesium 组件组合到一个可重用的包中。小部件总是可以通过使用mixins来扩展,它可以添加对各种应用程序有用的功能。?
Name | Type | Description |
---|---|---|
container | Element?|?string | 包含小部件的DOM元素或ID。 |
options | Viewer.ConstructorOptions | 描述初始化选项的对象 |
? Throws:
- DeveloperError:文档中不存在id为“container”的元素。?
- DeveloperError:选项。当不使用BaseLayerPicker小部件时,selectedImageryProviderViewModel不可用,请指定选项。baseLayer代替。
- DeveloperError:选项。当不使用BaseLayerPicker小部件时,selectedTerrainProviderViewModel不可用,请指定选项。terrainProvider代替。
? 示例:
//使用几个自定义选项和mixins初始化查看器小部件。
try {
const viewer = new Cesium.Viewer("cesiumContainer", {
// 从Columbus Viewer开始
sceneMode: Cesium.SceneMode.COLUMBUS_VIEW,
// 使用Cesium World地形
terrain: Cesium.Terrain.fromWorldTerrain(),
// 隐藏底层选择器
baseLayerPicker: false,
// 使用 OpenStreetMaps
baseLayer: new Cesium.ImageryLayer(new Cesium.OpenStreetMapImageryProvider({
url: "https://tile.openstreetmap.org/"
})),
skyBox: new Cesium.SkyBox({
sources: {
positiveX: "stars/TychoSkymapII.t3_08192x04096_80_px.jpg",
negativeX: "stars/TychoSkymapII.t3_08192x04096_80_mx.jpg",
positiveY: "stars/TychoSkymapII.t3_08192x04096_80_py.jpg",
negativeY: "stars/TychoSkymapII.t3_08192x04096_80_my.jpg",
positiveZ: "stars/TychoSkymapII.t3_08192x04096_80_pz.jpg",
negativeZ: "stars/TychoSkymapII.t3_08192x04096_80_mz.jpg"
}
}),
// 显示 Columbus View map 与 Web Mercator projection
mapProjection: new Cesium.WebMercatorProjection()
});
} catch (error) {
console.log(error);
}
// 添加基本的拖放功能
viewer.extend(Cesium.viewerDragDropMixin);
// 如果在处理删除的文件时遇到错误,则显示弹出警报
viewer.dropError.addEventListener(function(dropHandler, name, error) {
console.log(error);
window.alert(error);
});
- Scene:场景的主要渲染对象
new Cesium.Scene(options)
????????所有的3 d图形对象的容器和国家Cesium虚拟场景。一般来说都不是直接创建的;它是由CesiumWidget隐式创建。?
options对象:
Name | Type | Default | Description |
---|---|---|---|
canvas | HTMLCanvasElement | 用于创建场景的HTML cancas元素。 | |
contextOptions | ContextOptions | 环境和WebGL创建属性 | |
creditContainer | Element | 用于显示服务描述信息的HTML元素。 | |
creditViewport | Element | 要在其中显示信用弹出窗口的HTML元素。如果未指定,则视口将作为画布的兄弟添加。 | |
mapProjection | MapProjection | 在二维和Columbus 视图模式下使用的地图投影。 | |
orderIndependentTranslucency | boolean | true | 如果此项设置为true,并且使用设备支持,将使用与顺序无关的半透明。 |
scene3DOnly | boolean | false | 如果此项设置为true,将优化三维模式的内存使用和性能,但禁止使用二维或Columbus视图功能。 |
shadows | boolean | false | 确定阴影是否由太阳投射形成。 |
mapMode2D | MapMode2D | 确定二维地图是可旋转的或是可以在在水平方向上无限滚动。 | |
requestRenderMode | boolean | false | |
maximumRenderTimeChange | number | 0.0 | |
depthPlaneEllipsoidOffset | number | 0.0 | |
msaaSamples | number | 1 |
? Throws:?
-
D?eveloperError?: options and options.canvas are required.
? 示例:
// 创建场景没有各向异性纹理过滤
const scene = new Cesium.Scene({
canvas : canvas,
contextOptions : {
allowTextureFilterAnisotropic : false
}
});
- Cesium.BingMapsImageryProvider:Bing地图服务提供者
new Cesium.BingMapsImageryProvider(options)
要构造一个BingMapsImageryProvider,调用BingMapsImageryProvider. fromurl。不要直接调用构造函数。
????????使用必应地图图像REST API提供平铺图像。?
Name | Type | Description |
---|---|---|
options | BingMapsImageryProvider.ConstructorOptions | 描述初始化选项的对象 |
? 示例:
const bing = await Cesium.BingMapsImageryProvider.fromUrl(
"https://dev.virtualearth.net", {
key: "get-yours-at-https://www.bingmapsportal.com/",
mapStyle: Cesium.BingMapsStyle.AERIAL
});
2. 场景操作类
/**
* 场景配置
*
* @param opt
*/
D3.prototype.config = function (opt) {
if (this._scene) {
//设置第二重烘焙纹理的效果(明暗程度)
this._scene.shadowMap.darkness = 1.275;
//设置环境光
this._scene.lightSource.ambientLightColor = opt.ambientLightColor || new Cesium.Color(0.7, 0.7, 0.7, 1);
//深度检测
this._scene.globe.depthTestAgainstTerrain = true;
//地面调节
//this._scene.globe.baseColor = Cesium.Color.BLACK;
this._scene.globe.globeAlpha = 0.5;
this._scene.undergroundMode = true;
this._scene.terrainProvider.isCreateSkirt = false;
//调节场景环境
this._scene.sun.show = false;
this._scene.moon.show = false;
// this._scene.skyBox.show = false;
this._scene.skyAtmosphere.show = false;
this._scene.fxaa = true;
//开启颜色校正
this._scene.colorCorrection.show = opt.colorCorrection || false;
this._scene.colorCorrection.saturation = opt.saturation || 3.1;
this._scene.colorCorrection.brightness = opt.brightness || 1.8;
this._scene.colorCorrection.contrast = opt.contrast || 1.2;
this._scene.colorCorrection.hue = opt.hue || 0;
//开启泛光和HDR
this._scene.bloomEffect.show = opt.bloomEffect || false;
this._scene.hdrEnabled = opt.hdrEnabled || true;
this._scene.bloomEffect.threshold = 1;
this._scene.bloomEffect.bloomIntensity = 2;
//最大距离
this._scene.screenSpaceCameraController.maximumZoomDistance = 5000.0
}
}
封装D3类对场景进行管理,其中主要功能有:
- init:场景初始化,包含场景配置、数据加载等
- config:场景参数配置,如环境光、阴影等
- loadScene:加载场景数据,如3Dtiles、模型
- bindHandle:绑定交互事件
- closeScene:关闭场景,释放资源
使用面向对象的方式对复杂场景进行模块化管理。
3. 事件处理
/**
* 事件处理
*/
D3.prototype.bindHandle = function () {
// ScreenSpaceEventHandler提供ScreenSpaceEventType一种监听用户输入并对用户输入进行分类的方法
// 这段代码是在Cesium中使用ScreenSpaceEventHandler来处理canvas的点击事件。
// 具体来说:
// _handler 是ScreenSpaceEventHandler的一个实例,用来处理canvas上的屏幕空间事件。
// 它通过Cesium.ScreenSpaceEventHandler构造函数传入viewer的scene的canvas来创建。
// 设置了一个左击事件的回调函数,在回调函数中可以获取到点击事件的一些信息,如点击位置的movement对象。
// 接着使用scene的pick方法根据点击位置拾取到对象。
// 如果拾取到的对象id名称为“警情分析”,则调用analysis()方法进行后续处理。
// 所以这段代码的作用是:在Cesium场景canvas上,当点击“警情分析”对象时,调用analysis()方法进行响应。
// ScreenSpaceEventHandler还可以处理其他事件类型,如右击、移动、长按等。事件类型包括:
// LEFT_CLICK
// RIGHT_CLICK
// MIDDLE_CLICK
// WHEEL
// PINCH_START
// PINCH_END
// PINCH_MOVE
// MOUSE_MOVE 等。
this._handler = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas)
this._handler.setInputAction((movement) => {
// var cartesian = this._util.getCatesian3FromPX(movement.position)
// console.log(this._util.transformCartesianToWGS84(cartesian))
var obj = this._scene.pick(movement.position);
if (obj && obj.id && obj.id.name && "警情分析" == obj.id.name) this.analysis()
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// this._viewer.scene.camera.moveEnd.addEventListener((move) => {
// console.log(this._util.getCameraPosition())
// });
// this._util.getHandelPosition((position,handel)=>{
// console.log(position)
// })
// this._util.setScanCircleEffect({
// position: new Cesium.Cartesian3.fromDegrees(106.50642721790797, 29.658575326606123, 5.0)
// })
// this._util.drawLine((value) => {
// console.log(value)
// })
}
主要使用两种事件处理方式:
-
ScreenSpaceEventHandler:处理鼠标交互事件
new Cesium.ScreenSpaceEventHandler(element)
????????处理用户输入事件。可以添加自定义函数,以便在用户输入时执行。?
Name | Type | Default | Description |
---|---|---|---|
element | HTMLCanvasElement | document | 要向其中添加事件的元素。 |
// 处理左击事件
this._handler.setInputAction((movement) => {
// 事件处理逻辑
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
-
相机移动回调函数:处理飞行结束事件
Related API:
- Cesium.ScreenSpaceEventHandler
- Camera.moveEnd
?
4. 视角控制
D3.prototype.loadCameraPath = function (callback) {
this._util.setView({
position: { x: -2180840.640119748, y: 4381647.215317032, z: 4091216.503229185 },
orientation: {
heading: Cesium.Math.toRadians(356.76499726379865),
pitch: Cesium.Math.toRadians(-22.735599006353922),
roll: Cesium.Math.toRadians(0.00133659048757427)
}
});
setTimeout(() => {
this._util.flyTo({
position: { x: -2178897.313757382, y: 4381397.305312672, z: 4091462.297319925 },
orientation: {
heading: Cesium.Math.toRadians(46.527000640600505),
pitch: Cesium.Math.toRadians(-5.17091508581087),
roll: Cesium.Math.toRadians(1.90833280887811)
},
duration: 5,
callback: () => {
this._util.flyTo({
position: { x: -2178132.972253719, y: 4380734.091723098, z: 4093209.132147421 },
orientation: {
heading: Cesium.Math.toRadians(105.62030224024655),
pitch: Cesium.Math.toRadians(-21.59096416111003),
roll: Cesium.Math.toRadians(359.9987311314987)
},
duration: 5,
callback: () => {
this._util.flyTo({
position: { x: -2179780.958069727, y: 4379145.05670711, z: 4093251.679035389 },
orientation: {
heading: Cesium.Math.toRadians(202.12146484437022),
pitch: Cesium.Math.toRadians(-4.367558356924628),
roll: Cesium.Math.toRadians(0.0006130606451948047)
},
duration: 5,
callback: () => {
this._util.flyTo({
position: { x: -2182832.9113919945, y: 4380248.782123272, z: 4093233.182007854 },
orientation: {
heading: Cesium.Math.toRadians(282.56605551019436),
pitch: Cesium.Math.toRadians(-38.5875540173017),
roll: Cesium.Math.toRadians(359.99999999993923)
},
duration: 5,
callback: callback
})
}
})
}
})
}
})
}, 2000)
}
主要通过flyTo方法实现视角的平滑飞行过渡动画。
// fly to 函数
_util.flyTo({
destination : {
x : 1.0,
y : 2.0,
z : 3.0
},
duration : 5
});
设置destination目标位置和orientation朝向,以及duration动画时间实现视角导航动画。
5. CSS3渲染
使用Cesium.Css3Renderer实现CSS3渲染:
// 创建CSS3渲染器
var cssRenderer = new Cesium.Css3Renderer();
// 添加标签层
cssRenderer.addLayer({
position : [1.0, 2.0, 3.0],
element : document.getElementById('label')
});
将Html标签元素渲染到指定三维位置。
相关API:
- Cesium.Css3Renderer
6. 状态管理
使用状态码管理不同的场景状态,在状态切换时校验当前状态。
// 状态码
this._STATECODE = {
zero : 0,
one : 1,
//...
};
// 当前状态
this._state = this._STATECODE.zero;
// 状态检查
if (this._STATECODE.zero !== this._state) {
// 错误提示
return ;
}
?
这样可以确保场景按顺序演示。
三、场景实现要点
1. 警情监控
/**
* 警情监控
*/
D3.prototype.monitoring = function (callback) {
if (this._STATECODE.zero !== this._state & this._STATECODE.all !== this._state) {
this._layers.msg('请先初始化场景 ', {
time: 2500,
});
return false
}
var start = () => {
this.postProcess.push(this._util.setRadarScanEffect({
position: Cesium.Cartesian3.fromDegrees(116.45141573633816, 39.91324637901737, 10.0),
color: Cesium.Color.RED,
radius: 500
}))
this._util.flyTo({
position: { x: -2178693.2564594974, y: 4380220.704344869, z: 4093694.8169494905 },
orientation: {
heading: Cesium.Math.toRadians(154.12738034665816),
pitch: Cesium.Math.toRadians(-36.860896281659365),
roll: Cesium.Math.toRadians(5.0125541779865026)
},
duration: 5,
callback: () => {
this._scene.camera.flyCircle(Cesium.Cartesian3.fromDegrees(116.45141573633816, 39.91324637901737, 100.0));
if (typeof callback === 'function') {
setTimeout(() => {
callback()
}, 3000)
} else {
// update state
this._state = this._STATECODE.one
}
}
})
}
if (this.postProcess.length > 0) {
this.closeScene(() => {
start()
})
} else {
start()
}
}
主要实现:
- 添加雷达扫描效果
- 相机环绕目标点
使用?Cesium.PostProcessStage?
添加雷达扫描后期效果:
// 添加雷达扫描特效
scene.postProcessStages.add(Cesium.PostProcessStageLibrary.createRadarScanStage());
并设置相机环绕点飞行实现监控效果:
// 相机环绕点飞行
camera.flyCircle(center);
?
2. 警情预报
/**
*
* 警情预报
*/
D3.prototype.startSceneOne = function (callback) {
if (this._STATECODE.one !== this._state & this._STATECODE.all !== this._state) {
this._layers.msg('请先预览完警情监控 ', {
time: 3000,
});
return false
}
this._viewer.scene.camera.stopFlyCircle();
this._util.flyTo({
position: { x: -2178463.9456453873, y: 4381002.914153181, z: 4093890.133365481 },
orientation: {
heading: Cesium.Math.toRadians(128.64858283790525),
pitch: Cesium.Math.toRadians(-44.65849475098552),
roll: Cesium.Math.toRadians(0.0023842018258495466)
},
duration: 5,
callback: () => {
this._util.flyTo({
position: { x: -2179037.6221276326, y: 4380549.292276369, z: 4092247.909965294 },
orientation: {
heading: Cesium.Math.toRadians(38.73496800382902),
pitch: Cesium.Math.toRadians(-21.116761624408735),
roll: Cesium.Math.toRadians(0.00018448854527482853)
},
duration: 5,
callback: () => {
this._util.flyTo({
position: { x: -2179048.567425212, y: 4380181.227054535, z: 4092287.128962158 },
orientation: {
heading: Cesium.Math.toRadians(57.01126750844415),
pitch: Cesium.Math.toRadians(-4.698058614089507),
roll: Cesium.Math.toRadians(0.00009319620311191225)
},
duration: 5,
callback: () => {
if (typeof callback === 'function') {
setTimeout(() => {
callback()
}, 3000)
} else {
// update state
this._state = this._STATECODE.tow
}
}
})
}
})
}
})
//异常提示
new Promise((resolve, reject) => {
this.addDynamicEntity({
position: Cesium.Cartesian3.fromDegrees(116.450217639056, 39.912527799624065, 130.0),
model: { lng: 116.450217639056, lat: 39.912527799624065, alt: 130.0 },
m_color: Cesium.Color.RED.withAlpha(0.5),
label: true,
billboard: true,
text: ' 商务办公楼 ',
l_font: '14px sans-serif',
l_fillColor: Cesium.Color.WHITE,
l_backgroundColor: Cesium.Color.RED,
l_pixelOffset: new Cesium.Cartesian2(0, -5),
l_showBackground: false
})
var cricleEntity = this._util.createDynamicCricle({
center: { lng: 116.450217639056, lat: 39.912527799624065, alt: 130.0 },
material: new Cesium.CircleWaveMaterialProperty({
color: Cesium.Color.RED,
count: 3,
gradient: 0.9
}),
height: 100,
radius: 50,
rotateAmount: 0.01
})
this._viewer.entities.add(cricleEntity)
})
// 模拟效果
new Promise((resolve, reject) => {
//添加火焰粒子
this.primitives.push(this._util.setFlameParticle({
position: Cesium.Cartesian3.fromDegrees(116.4499827986952, 39.91231248171688, 0),
tx: 0, ty: 0, tz: 50
}))
this.primitives.push(this._util.setFlameParticle({
position: Cesium.Cartesian3.fromDegrees(116.45045144518653, 39.91234434075017, 0),
tx: 0, ty: 0, tz: 50
}))
// position:表示模型在场景中的位置,使用经度、纬度和高度来定义。在这个示例中,使用 Cesium.Cartesian3.fromDegrees 方法将经度和纬度转换为笛卡尔坐标系。
// m_url:表示模型的 URI,即模型数据的地址。在这个示例中,使用了相对路径 'examples/SampleData/gltf/man/walk.gltf'。
// m_scale:表示模型在三个轴上的缩放比例。在这个示例中,模型将按照原始比例的 3 倍进行缩放。
// m_minimumPixelSize:以像素为单位,表示模型渲染时的最小尺寸。在这个示例中,指定最小尺寸为 1 个像素。
//添加人群
this._viewer.entities.add(this._util.createModel({
position: Cesium.Cartesian3.fromDegrees(116.45007132823285, 39.91223440231512, 5.0),
m_url: 'examples/SampleData/gltf/man/walk.gltf',
m_scale: 3,
m_minimumPixelSize: 1,
}))
this._viewer.entities.add(this._util.createModel({
position: Cesium.Cartesian3.fromDegrees(116.45026244256015, 39.91226094401238, 5.0),
m_url: 'examples/SampleData/gltf/man/walk.gltf',
m_scale: 3,
m_minimumPixelSize: 1,
}))
this._viewer.entities.add(this._util.createModel({
position: Cesium.Cartesian3.fromDegrees(116.45059442902425, 39.912284437562185, 5.0),
m_url: 'examples/SampleData/gltf/man/walk.gltf',
m_scale: 3,
m_minimumPixelSize: 1,
}))
})
}
主要实现:
- 添加火焰、人群3D模型
- 显示建筑物异常情况
使用?Entity?
系统添加模型:
// 添加3D人群
viewer.entities.add({
position : ...,
model : {
uri : '...',
scale : ...
}
});
并通过添加模型颜色、动画圈等方式显示异常情况。
3. 警情分析
/**
* 警情分析
*/
D3.prototype.analysis = function (callback) {
if (this._STATECODE.tow !== this._state & this._STATECODE.all !== this._state) {
this._layers.msg('请先预览完警情预报', {
time: 3000,
});
return false
}
this._viewer.scene.camera.stopFlyCircle();
// 下面这段代码是在Cesium中使用flyTo方法进行视角飞行,并在飞行完成后添加一些视觉效果。
// 具体来看:
// _util.flyTo 是Cesium中的视角飞行方法。
// position: 设定飞行完成后视角的笛卡尔空间坐标。
// orientation: 设定飞行完成后视角的方向,包括航向角、俯仰角、滚转角。
// duration: 整个飞行动画的持续时间,单位是秒。
// callback: 飞行完成后的回调函数。
// 在回调函数中添加了CSS3标签、相机环绕飞行的动画效果。
// 还添加了警示线材质的Entity。
// 如果传入了callback函数则在动画结束后执行。
// flyTo除了上述参数,还可以设置:
// maximumHeight: 飞行高度限制。
// pitchAdjustHeight: 调整相机飞行高度的距离。
// flyOverLongitude 和 flyOverLatitude: 飞行路线的经纬度。
// 总之,这段代码实现了一个视角飞行的动画效果,并在飞行后的回调里增添了视觉效果,实现了一个较为复杂的动画场景。
this._util.flyTo({
position: { x: -2178835.9901788016, y: 4380941.406850311, z: 4092044.408504874 },
orientation: {
heading: Cesium.Math.toRadians(45.453049548959),
pitch: Cesium.Math.toRadians(-15.610707989693905),
roll: Cesium.Math.toRadians(359.99999999987216)
},
duration: 5,
callback: () => {
// css3 实现标牌
let css3Elements = [];
this._css3Renderer = new Cesium.Css3Renderer(css3Elements, true) //第三个参数为当标签在地球背面时候会隐藏
this._css3Renderer.addEntityLayer({
id: 'labelTip',
position: [116.450217639056, 39.912527799624065, 130.0],//高度为 boxHeightMax
element: `<div class='ysc-dynamic-layer ys-css3-box' id='labelTip'>
<div class='line'></div>
<div class='main' style="font-size:25px">
<div class="" style="color:#ff9800">警情分析</div>
<div class="">该楼七层发生火灾</div>
<div class="">指派救生队伍支援!</div>
</div>
</div>`,
offset: [10, -250],
boxShow: false,
circleShow: false,
})
this._viewer.scene.camera.speedRatio = 0.1
this._viewer.scene.camera.flyCircle(Cesium.Cartesian3.fromDegrees(116.450217639056, 39.912527799624065, 100.0));
// 警示线特效
var warn = [
116.45121972426787, 39.912280505197565, 30.0,
116.449751129691, 39.912270436562736, 30.0,
116.44971753510406, 39.91321324258255, 30.0,
116.45131361499521, 39.91317812427803, 30.0,
116.45127073097758, 39.91221994119961, 30.0,
]
this._viewer.entities.add({
wall: {
positions: Cesium.Cartesian3.fromDegreesArrayHeights(warn),
material: new Cesium.WarnLinkMaterialProperty({ freely: 'cross', color: Cesium.Color.YELLOW, duration: 1000, count: 1.0, direction: '-' }),
}
});
if (typeof callback === 'function') {
setTimeout(() => {
callback()
}, 3000)
} else {
// update state
this._state = this._STATECODE.three
}
}
})
}
主要实现:
- 添加HTML标注
- 相机环绕目标点
使用CSS3渲染添加HTML标注:
// 添加标注
cssRenderer.addLayer({
position : [116.xx, 39.xx, 130.0],
element : document.getElementById('label')
});
?
并设置相机环绕飞行完成对目标区域的分析。
4. 警情调度
/**
* 警情调度
*/
D3.prototype.scheduling = function () {
if (this._STATECODE.three !== this._state & this._STATECODE.all !== this._state) {
this._layers.msg('请先预览完警情分析 ', {
time: 3000,
});
return false
}
// 救护车
var paths = [{ lon: 116.44753798513237, lat: 39.91329913144483, alt: 5.0, time: 0 },
{ lon: 116.44754831320495, lat: 39.91205867447874, alt: 5.0, time: 120 },
{ lon: 116.44919669983119, lat: 39.91207453317339, alt: 5.0, time: 240 },
{ lon: 116.45021742143986, lat: 39.91208239585685, alt: 5.0, time: 360 },
{ lon: 116.45021742143986, lat: 39.91208239585685, alt: 5.0, time: 480 }]
// 消防车
var paths2 = [{ lon: 116.4552207886404, lat: 39.91205626109142, alt: 5.0, time: 0 },
{ lon: 116.4531359117942, lat: 39.9120348488425, alt: 5.0, time: 120 },
{ lon: 116.45169757241298, lat: 39.91202452492026, alt: 5.0, time: 240 },
{ lon: 116.45021328751454, lat: 39.91201148288871, alt: 5.0, time: 360 },
{ lon: 116.45021328751454, lat: 39.91201148288871, alt: 5.0, time: 480 }]
// 添加引导线
this._util.addMaterialLine({
positions: this._util.transformWGS84ArrayToCartesianArray(paths),
width: 50,
material: new Cesium.PolylineCityLinkMaterialProperty({
color: Cesium.Color.RED,
duration: 20000
}),
clampToGround: true
})
this._util.addMaterialLine({
positions: this._util.transformWGS84ArrayToCartesianArray(paths2),
width: 50,
material: new Cesium.PolylineCityLinkMaterialProperty({
color: Cesium.Color.RED,
duration: 20000
}),
clampToGround: true
})
var addMan = () => {
this._viewer.clock.multiplier = 1.0
this._viewer.entities.add(this._util.createModel({
position: Cesium.Cartesian3.fromDegrees(116.4500554199689, 39.91221044177715, 5.0),
m_url: 'examples/data/model/xiaofangyuan-run.gltf',
m_scale: 7,
m_minimumPixelSize: 1,
}))
this._viewer.entities.add(this._util.createModel({
position: Cesium.Cartesian3.fromDegrees(116.45035101783887, 39.912153073679924, 5.0),
m_url: 'examples/data/model/xiaofangyuan-run.gltf',
m_scale: 7,
m_minimumPixelSize: 1,
}))
}
// 添加车辆
new Promise(() => {
this._util.setPathRoaming({
paths: paths,
model: true,
m_url: 'examples/data/model/qiche.gltf',
m_scale: 0.1,
m_minimumPixelSize: 1,
label: true,
l_text: '救护车',
l_pixelOffset: new Cesium.Cartesian2(52, -48),
l_fillColor: Cesium.Color.WHITE,
l_outlineWidth: 3,
billboard: true,
b_img: 'examples/images/Textures/bp2.png',
b_width: 55,
b_height: 80,
b_scale: 2,
b_pixelOffset: new Cesium.Cartesian2(30, 0)
})
this._util.setPathRoaming({
paths: paths2,
model: true,
m_url: 'examples/data/model/qiche.gltf',
m_scale: 0.1,
m_minimumPixelSize: 1,
label: true,
l_text: '消防车',
l_pixelOffset: new Cesium.Cartesian2(52, -48),
l_fillColor: Cesium.Color.WHITE,
l_outlineWidth: 3,
billboard: true,
b_img: 'examples/images/Textures/bp.png',
b_width: 55,
b_height: 80,
b_scale: 2,
b_pixelOffset: new Cesium.Cartesian2(30, 0)
})
})
//街道漫游
this._viewer.scene.camera.stopFlyCircle();
// 远景
this._util.flyTo({
position: { x: -2178725.2326817405, y: 4380717.691272014, z: 4092429.139375593 },
orientation: {
heading: Cesium.Math.toRadians(74.6359315563435),
pitch: Cesium.Math.toRadians(-31.233145079364085),
roll: Cesium.Math.toRadians(0.00021380944582563688)
},
duration: 5,
callback: () => {
//街道
this._util.flyTo({
position: { x: -2178718.4499226217, y: 4380320.631065833, z: 4092296.741367402 },
orientation: {
heading: Cesium.Math.toRadians(83.59293245172353),
pitch: Cesium.Math.toRadians(-2.0635543646730805),
roll: Cesium.Math.toRadians(359.9999999999991)
},
duration: 5,
callback: () => {
//漫游 1
this._util.flyTo({
position: { x: -2178907.5523918574, y: 4380227.944369431, z: 4092295.2689017 },
orientation: {
heading: Cesium.Math.toRadians(83.59451489628981),
pitch: Cesium.Math.toRadians(-2.0635543646734114),
roll: Cesium.Math.toRadians(359.99999999999926)
},
duration: 15,
callback: () => {
//漫游 2
this._util.flyTo({
position: { x: -2179038.3685479737, y: 4380186.554328359, z: 4092297.2180936695 },
orientation: {
heading: Cesium.Math.toRadians(56.38807730423329),
pitch: Cesium.Math.toRadians(-11.712623638749156),
roll: Cesium.Math.toRadians(359.9999999999992)
},
duration: 10,
callback: () => {
addMan() // 添加消防员
//漫游 3
this._util.flyTo({
position: { x: -2178996.2169643864, y: 4380316.564571191, z: 4092306.3786329245 },
orientation: {
heading: Cesium.Math.toRadians(64.96210850602627),
pitch: Cesium.Math.toRadians(-21.931507732669104),
roll: Cesium.Math.toRadians(359.9998957985643)
},
duration: 8,
callback: () => {
// 弹出结果信息
this._layers.open({
type: 1
, title: false
, closeBtn: 1
, shade: false
, shadeClose: true
, anim: 2
, area: ['500px', '300px']
, offset: 'auto'
, content: `<div style="color:white"><h2 style="text-align:center;padding:10px">警情报告</h2>
<div style="font-size:15px;padding:20px">
<p style="padding-bottom:20px">xxx大楼七层于29日下午发生火灾,报告如下:</p>
<p>原因: 七层火锅商铺电器泄露引起火灾;</p>
<p>损失: 七层共7家商铺受影响,其中两家紧靠起火地较严重;</p>
<p>出警: 接警后10分钟救护车与消防车到达现场,10分钟灭火救险;</p>
<p>伤亡: 无重大伤亡,5人轻伤.</p>
</div></div>`
, btn: ['确认']
, btn1: function () {
layer.closeAll();
}
});
}
})
}
})
}
})
}
})
}
})
}
主要实现:
- 添加车辆模型
- 实现车辆运动、街道漫游动画
使用?Entity?
系统添加车辆模型,配合贝塞尔曲线实现运动动画:
// 添加车辆实体
var car = viewer.entities.add({
// 贝塞尔曲线位置
position : Cesium.CallbackProperty(...),
model : {...}
})
通过飞行设置视角完成街道漫游动画效果。
? 源码
?请点击上方绑定的资源下载
? 结语
- Cesium是一个功能强大的三维地图引擎,使用它可以快速实现各种三维可视化应用。
- 使用面向对象方式进行代码封装,可以很好地模块化复杂的三维场景。
- 利用Cesium提供的各种对象和效果实现丰富的场景和动画。
- 状态管理可以确保场景动画的顺序展现。
- Cesium中提供了许多辅助类和工具,可以大幅简化三维开发。
我们改日再会
??
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!