【Cesium开发实战】火灾疏散功能的实现,可设置火源点、疏散路径、疏散人数
Cesium有很多很强大的功能,可以在地球上实现很多炫酷的3D效果。今天给大家分享一个可自定义的火灾疏散人群的功能。
1.话不多说,先展示
火灾疏散模拟
2.设计思路
根据项目需求要求,可设置火源点、绘制逃生路线、可设置逃生人数。所以点击火灾点绘制后,在地图点击可看到火光的粒子效果。点击疏散路径绘制后,在地图上点击可以绘制路径,双击结束绘制,一个火灾点会有多条疏散路径,可再次同样步骤操作绘制路径,点击保存可编辑名称和设定每条路径疏散的人数数量形成列表数据,点击开始疏散,通过czml数据格式实现疏散动画效果。
3.具体代码
<template><div class="page"><el-button @click="drawStartPosition">火灾点绘制</el-button><el-button @click="drawLineRoad">疏散路径绘制</el-button><el-button @click="save">保存</el-button><div style="margin-top: 10px"><el-table :data="dataList" border @row-click="rowClick"><el-table-column prop="name" label="名称" align="center" /><el-table-column label="操作" align="center"><template #default="scope"><el-button type="primary" style="width: 50px;"@click="startShus(scope.row, scope.$index)">开始疏散</el-button><el-button link type="primary" size="small" @click="delEntity(scope.row, scope.$index)"><el-icon:size="16"><ele-Delete /> </el-icon></el-button></template></el-table-column></el-table></div><el-dialog v-model="dialogFormVisible" title="配置" width="500" :close-on-press-escape="false":close-on-click-modal="false" :show-close="false"><el-form ref="formRef" :model="form" label-width="auto" class="demo-dynamic" :rules="rules"><el-form-item label="疏散名称" prop="title"><el-input v-model="form.title" placeholder="请输入" /></el-form-item><el-form-item label="疏散路线人数"><el-input-number :min="0" v-model="form.people" placeholder="请输入" /></el-form-item></el-form><template #footer><div class="dialog-footer"><el-button type="primary" @click="submitForm(formRef)"> 确定 </el-button></div></template></el-dialog></div>
</template><script setup lang="ts">
import { onMounted, onUnmounted, reactive, ref } from 'vue';
import { Cesium } from '/@/utils/cesium';
const props = defineProps(['viewer']);//是否显示弹框
const dialogFormVisible = ref(false);const formRef = ref();var entities: any = {};const rules = {title: { required: true, message: '请输入疏散名称', trigger: 'blur' },
};// 视图名称
const form = reactive({title: '',people: 20,
});// 视点列表数据
const dataList: any = reactive([]);/*** 点击表格一行*/
const rowClick = (row: any, column: any, event: Event) => {if (column && column.property) {let index = dataList.findIndex((v: any) => v.id === row.id);if (index !== -1) {props.viewer.flyTo(listEntities[index].entities[0].pointEntities[0], {offset: {heading: Cesium.Math.toRadians(10.0114629015290062),pitch: Cesium.Math.toRadians(-23.53661660731824),roll: Cesium.Math.toRadians(0.00324596311071617),},});}}
};//是否开始绘制火灾点
const drawing = ref(false);
var firePointEntity: any = [];
var firePrimitiveEntity: any = [];
//绘制火灾起点
const drawStartPosition = () => {drawing.value = true;var handler2 = new Cesium.ScreenSpaceEventHandler(props.viewer.scene.canvas);//鼠标左键handler2.setInputAction(function (event: any) {if (drawing.value) {var earthPosition = props.viewer.scene.pickPosition(event.position);if (Cesium.defined(earthPosition)) {//将笛卡尔坐标转化为经纬度坐标var cartographic = Cesium.Cartographic.fromCartesian(earthPosition);var longitude = Cesium.Math.toDegrees(cartographic.longitude);var latitude = Cesium.Math.toDegrees(cartographic.latitude);var height = cartographic.height;var entity44 = props.viewer.entities.add({position: Cesium.Cartesian3.fromDegrees(longitude, latitude, height),});//存储火灾点点位对象到集合firePointEntity.push(entity44);var firePrimitive = new Cesium.ParticleSystem({image: '/src/assets/cesium/fire.png',startColor: Cesium.Color.RED.withAlpha(0.7),endColor: Cesium.Color.YELLOW.withAlpha(0.3),startScale: 0,endScale: 10,minimumParticleLife: 1,maximumParticleLife: 6,minimumSpeed: 1,maximumSpeed: 4,imageSize: new Cesium.Cartesian2(55, 55),// Particles per second.emissionRate: 4,lifetime: 160.0,emitter: new Cesium.CircleEmitter(5.0),modelMatrix: computeModelMatrix(entity44, Cesium.JulianDate.now()),emitterModelMatrix: computeEmitterModelMatrix()});props.viewer.scene.primitives.add(firePrimitive);//存储火灾点图像对象到集合firePrimitiveEntity.push(firePrimitive);//移除左键监听handler2.destroy();// 确保视角没有被锁定 props.viewer.trackedEntity = undefined;}}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}const computeModelMatrix = (entity: any, time: any) => {var position = entity.position.getValue(Cesium.JulianDate.now());let modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);return modelMatrix;
}
const computeEmitterModelMatrix = () => {let hpr = Cesium.HeadingPitchRoll.fromDegrees(0, 0, 0);let trs = new Cesium.TranslationRotationScale();trs.translation = Cesium.Cartesian3.fromElements(2.5, 4, 1);trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr);let result = Cesium.Matrix4.fromTranslationRotationScale(trs);return result
}// 弧度转角度
const toDegrees = (radians: any) => {return (radians * 180) / Math.PI;
};//是否开始绘制火灾点
const drawingLine = ref(false);
var listEntities: any = [];
//绘制的所有地面的点线实体集合
var entities: any = [];
//临时一条数据的point实体列表
var pointEntities: any = [];
//临时一条数据的线实体列表
var linesEntities: any = [];
var activeShapePoints: any = [];
var floatingPoint: any = undefined;
var activeShape: any = undefined;
//绘制线路
const drawLineRoad = () => {drawingLine.value = true;var handler = new Cesium.ScreenSpaceEventHandler(props.viewer.scene.canvas);//鼠标左键handler.setInputAction(function (event: any) {if (drawingLine.value) {var earthPosition = props.viewer.scene.pickPosition(event.position);if (Cesium.defined(earthPosition)) {if (activeShapePoints.length === 0) {floatingPoint = createPoint(earthPosition);activeShapePoints.push(earthPosition);var dynamicPositions = new Cesium.CallbackProperty(function () {return activeShapePoints;}, false);activeShape = drawShape(dynamicPositions); //绘制动态图//线实体集合linesEntities.push(activeShape);}activeShapePoints.push(earthPosition);//点实体集合pointEntities.push(createPoint(earthPosition));}}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);//鼠标移动handler.setInputAction(function (event: any) {if (Cesium.defined(floatingPoint)) {var newPosition = props.viewer.scene.pickPosition(event.endPosition);if (Cesium.defined(newPosition)) {floatingPoint.position.setValue(newPosition);activeShapePoints.pop();activeShapePoints.push(newPosition);}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);handler.setInputAction(function () {if (drawingLine.value) {drawingLine.value = false;terminateShape();}//移除监听handler.destroy();// 确保视角没有被锁定 props.viewer.trackedEntity = undefined;}, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
};//绘制点
const createPoint = (worldPosition: any) => {var point = props.viewer.entities.add({position: worldPosition,point: {color: Cesium.Color.RED,pixelSize: 10,heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,},});return point;
};//绘制线
const drawShape = (positionData: any) => {var shape = props.viewer.entities.add({polyline: {with: 10,color: Cesium.Color.RED,positions: positionData,clampToGround: true,},});return shape;
};//双击后处理数据
const terminateShape = () => {linesEntities.push(drawShape(activeShapePoints)); //绘制最终图//因双击会触发俩次单机事件,去除最后一个点重复绘制,并删除多余的点props.viewer.entities.remove(pointEntities[pointEntities.length - 1]);pointEntities.pop();props.viewer.entities.remove(floatingPoint); //去除动态点图形(当前鼠标点)props.viewer.entities.remove(activeShape); //去除动态图形floatingPoint = undefined;activeShape = undefined;activeShapePoints = [];//点实体和线实体的集合entities.push({pointEntities: pointEntities,linesEntities: linesEntities,});pointEntities = [];linesEntities = [];
};//保存火灾点和疏散路径
var customMarks: any = [];
const save = () => {dialogFormVisible.value = true; //弹出对话框
}/*** 点击确定绘制*/
const submitForm = async (formEl: any) => {const valid = await formEl.validate();if (valid) {listEntities.push({firePointEntity: firePointEntity,firePrimitiveEntity: firePrimitiveEntity,entities: entities});dataList.push({id: new Date().getTime(),name: form.title,people:form.people});//设置为空对象以便创建新的列表数据firePointEntity = [];firePrimitiveEntity = [];entities = [];dialogFormVisible.value = false;form.title = '';}
};/*** 删除列表数据*/
const delEntity = (item: any, index: number) => {for (const item of listEntities[index].firePointEntity) {props.viewer.entities.remove(item);}for (const item of listEntities[index].firePrimitiveEntity) {props.viewer.scene.primitives.remove(item);}for (const iterator of listEntities[index].entities) {for (const item of iterator.pointEntities) {props.viewer.entities.remove(item);}for (const item of iterator.linesEntities) {props.viewer.entities.remove(item);}}dataList.splice(index, 1);listEntities.splice(index, 1);if (obj) {props.viewer.dataSources.remove(obj);obj = null;}};var obj: any;//开始疏散
const startShus = (item: any, index: number) => {var czml: any = [];czml.push({"id": "document","name": "CZML Path","version": "1.0"});var entities = listEntities[index].entities;var peopleNum = item.people;if (entities.length) {for (const [index2, item2] of entities.entries()) {customMarks = [];for (const [index, item] of item2.pointEntities.entries()) {const latitude = toDegrees(Cesium.Cartographic.fromCartesian(item.position._value).latitude);const longitude = toDegrees(Cesium.Cartographic.fromCartesian(item.position._value).longitude);customMarks.push((1 * index));customMarks.push(longitude);customMarks.push(latitude);customMarks.push(2);}for (let i = 0; i < peopleNum; ++i) {var iso8601DateString = '2024-07-04T10:00:00Z';var julianDate = Cesium.JulianDate.fromIso8601(iso8601DateString);if (Cesium.defined(julianDate)) {var newJulianDate = Cesium.JulianDate.addSeconds(julianDate, i * 0.5, new Cesium.JulianDate());// 如果你需要将 JulianDate 转换为 Date 对象 var date = Cesium.JulianDate.toDate(newJulianDate);czml.push({"id": "path" + index2 + i,"name": "路径" + index2 + i,"availability": "2024-07-04T10:00:00.000Z/2024-07-04T10:01:00.000Z","model": {id: 'man',gltf: '/src/assets/cesium/Cesium_Man.glb',scale: 10},"position": {"epoch": date.toISOString(),"cartographicDegrees": customMarks}});} else {console.error('无法从 ISO 8601 字符串解析日期');}}}}//清除上次数据props.viewer.dataSources.remove(obj);obj = null;//加载本次疏散czmlprops.viewer.dataSources.add(Cesium.CzmlDataSource.load(czml)).then(function (loadedDataSource) {obj = loadedDataSource;var entities = loadedDataSource.entities.values;for (var i = 0; i < entities.length; i++) {var s = entities[i];s.orientation = new Cesium.VelocityOrientationProperty(s.position);}})}onMounted(() => {
});onUnmounted(() => {//清除绘制的内容props.viewer.entities.removeAll();//绘制了火灾点切换的时候需要先清除if (firePrimitiveEntity.length) {for (const item of firePrimitiveEntity) {props.viewer.scene.primitives.remove(item);}}//绘制了多个火灾点并保存到了列表上离开时清除for (const iterator of listEntities) {for (const item of iterator.firePrimitiveEntity) {props.viewer.scene.primitives.remove(item);}}if (obj) {props.viewer.dataSources.remove(obj);obj = null;}});
</script><style scoped>
.page {position: absolute;right: 10px;top: 10px;color: #fff;background: #fff;padding: 10px;border-radius: 5px;width: 400px;
}
</style>相关文章:
【Cesium开发实战】火灾疏散功能的实现,可设置火源点、疏散路径、疏散人数
Cesium有很多很强大的功能,可以在地球上实现很多炫酷的3D效果。今天给大家分享一个可自定义的火灾疏散人群的功能。 1.话不多说,先展示 火灾疏散模拟 2.设计思路 根据项目需求要求,可设置火源点、绘制逃生路线、可设置逃生人数。所以点击火…...
imx6ull/linux应用编程学习(16)emqx ,mqtt创建连接mqtt.fx
在很多项目中都需要自己的私人服务器,以保证数据的隐私性,这里我用的是emqx。 1.进入emqx官网 EMQX:用于物联网、车联网和工业物联网的企业级 MQTT 平台 点击试用cloud 申请成功后可得:(右边的忽略) 进入…...
Debezium系列之:验证mysql、mariadb等兼容mysql协议数据库账号权限
Debezium系列之:验证mysql、mariadb等兼容mysql协议数据库账号权限 一、数据库需要开启binlog二、创建账号和账号需要赋予的权限三、账号具有权限查看日志信息四、验证账号权限五、验证账号能否执行show master status六、验证数据库是否开启binlog一、数据库需要开启binlog …...
Vue.js学习笔记(五)抽奖组件封装——转盘抽奖
基于VUE2转盘组件的开发 文章目录 基于VUE2转盘组件的开发前言一、开发步骤1.组件布局2.布局样式3.数据准备 二、最后效果总结 前言 因为之前的转盘功能是图片做的,每次活动更新都要重做UI和前端,为了解决这一问题进行动态配置转盘组件开发,…...
使用pip或conda离线下载安装包,使用pip或conda安装离线安装包
使用pip或conda离线下载安装包,使用pip或conda安装离线安装包 一、使用pip离线下载安装包1. 在有网络的机器上下载包和依赖2. 传输离线安装包 二、在目标机器上离线安装pip包三、使用conda离线下载安装包1. 在有网络的机器上下载conda包2. 传输conda包或环境包3. 在…...
产品访问分析
1、DWD产品访问明细 1.1、用户产品权限数据 --用户产品权限数据INSERT OVERWRITE TABLE temp_lms.dm_lms_platform_usergroup_app_tmpselect 仓储司南 as pro_name,CCSN as pro_code,c.user_name as user_name,d.account_name …...
【算法】代码随想录之链表(更新中)
文章目录 前言 一、移除链表元素(LeetCode--203) 前言 跟随代码随想录,学习链表相关的算法题目,记录学习过程中的tips。 一、移除链表元素(LeetCode--203) 【1】题目描述: 【2】解决思想&am…...
react 18中,使用useRef 获取其他组件的dom并操作节点,flushSync强制同步更新useState
React 不允许组件访问其他组件的 DOM 节点。甚至自己的子组件也不行!这是故意的。Refs 是一种脱围机制,应该谨慎使用。手动操作 另一个 组件的 DOM 节点会使你的代码更加脆弱。 相反,想要 暴露其 DOM 节点的组件必须选择该行为。一个组件可以…...
Jupyter Notebook基础:用IPython实现动态编程
Jupyter Notebook基础:用IPython实现动态编程 1. 引言 Jupyter Notebook是一个基于Web的交互式计算环境,允许用户创建和共享包含实时代码、方程式、可视化和文本叙述的文档。它广泛应用于数据清洗与转换、数值模拟、统计建模、机器学习以及其他数据科学…...
Python 爬虫:使用打码平台来识别各种验证码:
本课程使用的是 超级鹰 打码平台, 没有账户的请自行注册! 超级鹰验证码识别-专业的验证码云端识别服务,让验证码识别更快速、更准确、更强大 使用打码平台来攻破验证码难题, 是很简单容易的, 但是要钱! 案例代码及测…...
理解算法复杂度:空间复杂度详解
引言 在计算机科学中,算法复杂度是衡量算法效率的重要指标。时间复杂度和空间复杂度是算法复杂度的两个主要方面。在这篇博客中,我们将深入探讨空间复杂度,了解其定义、常见类型以及如何进行分析。空间复杂度是衡量算法在执行过程中所需内存…...
浅析Kafka Streams消息流式处理流程及原理
以下结合案例:统计消息中单词出现次数,来测试并说明kafka消息流式处理的执行流程 Maven依赖 <dependencies><dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-streams</artifactId><exclusio…...
QGroundControl的总体架构,模块化设计和主要组件的功能。
QGroundControl 总体架构详细描述 QGroundControl (QGC) 作为一个开源地面控制站软件,其设计原则是模块化、高扩展性和高可维护性。 总体架构 QGroundControl 由多个层次构成,每个层次负责不同的功能。这种分层结构确保了系统的高内聚性和低耦合性。 …...
oracle 表空间文件迁移
表空间文件迁移 背景 由于各种原因,在实际工作中可能会出现oracle服务器数据盘空间被占满的情况,这个时候单纯的添加新磁盘,后续表空间文件放新盘的方案已经不适用了,因为源盘已经占用满了,数据库服务会异常…...
JVM学习(day1)
JVM 运行时数据区 线程共享:方法区、堆 线程独享(与个体“同生共死”):虚拟机栈、本地方法栈、程序计数器 程序计数器 作用:记录下次要执行的代码行的行号 特点:为一个没有OOM(内存溢出&a…...
js项目生产环境中移除 console
1、terser-webpack-plugin webpack 构建的项目中安装使用 安装: npm install terser-webpack-plugin --save-dev 配置 在webpack.config.js文件中 new TerserPlugin({terserOptions: {output: {comments: false, // 去除注释},warnings: false, // 去除黄色警告,co…...
ROS2 + 科大讯飞 初步实现机器人语音控制
环境配置: 电脑端: ubuntu22.04实体机作为上位机 ROS版本:ros2-humble 实体机器人: STM32 思岚A1激光雷达 科大讯飞语音SDK 讯飞开放平台-以语音交互为核心的人工智能开放平台 实现步骤: 1. 下载和处理科大讯飞语音模…...
HTML5新增的input元素属性:placeholder、required、autofocus、min、max等
HTML5 大幅度地增加与改良了 input 元素的属性,可以简单地使用这些属性来实现 HTML5 之前需要使用 JavaScript 才能实现的许多功能。 下面将详细介绍这些新增的 input 元素的属性。 属性说明属性说明placeholder在输入框显示描述性或提示性文本autocomplete是否保…...
Cornerstone3D导致浏览器崩溃的踩坑记录
WebGL: CONTEXT_LOST_WEBGL: loseContext: context lost ⛳️ 问题描述 在使用vue3vite重构Cornerstone相关项目后,在Mac本地运行良好,但是部署测试环境后,在window系统的Chrome浏览器中切换页面会导致页面崩溃。查看Chrome的任务管理器&am…...
【鸿蒙学习笔记】Stage模型
官方文档:Stage模型开发概述 目录标题 Stage模型好处Stage模型概念图ContextAbilityStageUIAbility组件和ExtensionAbility组件WindowStage Stage模型-组件模型Stage模型-进程模型Stage模型-ArkTS线程模型和任务模型关于任务模型,我们先来了解一下什么是…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
