Ceisum无人机巡检直播视频投射

接上次的视频投影,Leader告诉我这个视频投影要用在两个地方,一个是我原先写的轨迹回放那里,另一个在无人机起飞后的地图回显,要实时播放无人机拍摄的视频,还要能转镜头,让我把这个也接一下。
我的天!告诉我的时候人都傻了,这是一个功能嘛?
一个是拿到了全部的轨迹数据进行回显,播放的视频也是完整的资源,视频要求投射在地面上。另一个是接收实时的轨迹数据进行回显,播放的是实时的直播,视频居然还要求跟着镜头一起转。
这是两个完完全全不一样的功能好吧!!!
我拿着标书仔仔细细看过那行“演示无人机画面投影到地图上”,一时间陷入了沉默。
无语归无语,但特么还是要写,跟Leader据理力争这不是改改就能换上的功能,然后争取来两周的研发时间。
两周时间看起来很长,其实也就10天,有时候我写个计算方法都要两天,还不一定是最终版,所以只能拜托接下来运气很好,别让我遇到太多阻碍。
开工吧!

Step 0:
思路:最初都是想要拿原来的方法改改看,哪怕不成功,也绝了这个念想。
首先要解决的是视频投放的问题,原本这个投影方法只能投放视频,且只能投影到地面,我要优化成能投影直播并且不接触地面也能投放。
在这里插入图片描述
为了解决直播投放问题,我尝试修改了源码,发现困难重重,主要是两点,一个是原方法不依赖dom元素,这意味着我不能暴力篡改成直播通道,另一个是封装层级过多,我想在某几个关键步骤看下效果都不能被满足,只能盲写看最终效果。
卡在第一步我是万万没有想到,经过一下午的尝试,最终让我放弃了继续下去的想法。

Step0.1:当然,我也没有急着完全放弃之前的代码,我还记得我czml的无人机轨迹方法已经很完善了,从静态路径加载改为动态路径回显似乎并不难,如果成功的话只需要给视频材质连四根线,接着解决朝向转动的问题就完成了,大大减轻了工作量。

在这里插入图片描述
我将原有轨迹数据做成坐标发射器,通过动态接收点位组成路径,每次接收到数据就更新czml加载的点位集合,成功改成了动态路径回显。
然后我尝试将我之前做好的视椎体视频替换进去,然后切换朝向,发现在dataSource.then中格外难操作矩阵,需要多考虑很多问题,于是暂时搁置该方法,等待重启机会。

旧路已死,新步骤开始从0开始一点点搭建功能。

Step 1:
思路: 选择实体结合时间轴,更为灵活地构建动画,同时代码将更繁琐。
首先写一段简单动画,从一个点到另一个点。
在这里插入图片描述

部分代码:

var startPosition = Cesium.Cartesian3.fromDegrees(-75.0, 40.0, 1000.0);
var endPosition = Cesium.Cartesian3.fromDegrees(-75.0, 42.0, 1000.0);// 设置时间范围
var startTime = Cesium.JulianDate.now();
var endTime = Cesium.JulianDate.addSeconds(startTime,15,new Cesium.JulianDate()
);// 创建一个 SampledPositionProperty 来定义路径
var positionProperty = new Cesium.SampledPositionProperty();// 添加时间和位置样本
positionProperty.addSample(startTime, startPosition);
positionProperty.addSample(endTime, endPosition);// 创建一个 entity 并设置其 position 为定义的路径
var entity = viewer.entities.add({position: positionProperty,point: {pixelSize: 10,color: Cesium.Color.RED,},
});// 使视图跟踪 entity
viewer.trackedEntity = entity;// 设置时钟范围
viewer.clock.startTime = startTime.clone();
viewer.clock.stopTime = endTime.clone();
viewer.clock.currentTime = startTime.clone();
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; // 当到达结束时间时停止
viewer.clock.multiplier = 1; // 时间加速倍率
viewer.clock.clockRange = Cesium.ClockRange.CLAMPED;
viewer.clock.shouldAnimate = true;

Step 2:
思路:两个点变多个点,写一个点位生成器,模拟实时接收数据,实现多点位连续飞行
在这里插入图片描述

Step 3:
思路:模拟点位飞行,点换成模型,视椎体跟随模型一起,并封装成class,效果很好,但视角连贯性有待提高
在这里插入图片描述
部分代码:

class PointMover {constructor(viewer) {this.viewer = viewer;this.pointQueue = [];this.isAnimating = false;this.videoEntity = null;// 添加模型this.entity = ...// 添加视椎体this.frustumPrimitive = viewer.scene.primitives.add(new Cesium.Primitive({geometryInstances: new Cesium.GeometryInstance({geometry: geo,attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED.withAlpha(0.5)),},}),appearance: new Cesium.PerInstanceColorAppearance({translucent: true,flat: true,}),asynchronous: false,}));// 初始化视频材质this.videoEntity = viewer.entities.add({name: "uav-tmp-fly-wxsimple",polygon: {hierarchy: new Cesium.CallbackProperty((time) => {// 添加安全检查if (!this.entity || !this.entity.position) {return null;}try {const position = this.entity.position.getValue(time);if (!Cesium.defined(position)) {return null;}// 计算视锥体的远截面四个角点// 返回新的多边形层次结构return new Cesium.PolygonHierarchy([upRightPt,upLeftPt,downLeftPt,downRightPt,]);} catch (error) {console.warn("Error calculating polygon positions:", error);return null;}}, false),perPositionHeight: true,material: videoElement,// 添加其他属性以提高渲染性能shadows: Cesium.ShadowMode.DISABLED,classificationType: Cesium.ClassificationType.BOTH,zIndex: 999,},});// 内部方法:启动动画startAnimation() {if (this.pointQueue.length > 2 && !this.isAnimating) {// 在 onTick 事件处理函数中更新视锥体位置const onTick = (clock) => {// 移除旧的视锥体// 添加新的视锥体// ...}// 添加 onTick 事件监听器this.viewer.clock.onTick.addEventListener(onTick);}}// 外部调用方法:更新点位并启动动画updatePositionsAndAnimate(newPosition) {this.pointQueue.push(newPosition);if (!this.isAnimating) {this.startAnimation();}}}
}

Step 4:
思路:加入虚线路径
在这里插入图片描述
部分代码:

class PointMover {constructor(viewer) {this.viewer = viewer;this.pointQueue = [];this.isAnimating = false;this.videoEntity = null;this.pathPoints = []; // 用于记录路径点this.pathPolyline = null; // 用于绘制路径// ...}// 绘制路径的方法createPathPolyline() {this.pathPolyline = this.viewer.entities.add({polyline: {positions: new Cesium.CallbackProperty((time) => {// 取当前记录的路径点return this.pathPoints;}, false),material: new Cesium.PolylineDashMaterialProperty({dashLength: 16.0, // 虚线的长度}),width: 3,},});}// 更新路径并添加新的位置updatePath(newPosition) {this.pathPoints.push(newPosition); // 将新位置加入到路径点// 更新虚线的路径if (this.pathPolyline) {this.pathPolyline.polyline.positions = new Cesium.CallbackProperty((time) => {return this.pathPoints;},false);}}// 内部方法:启动动画startAnimation() {if (this.pointQueue.length > 2 && !this.isAnimating) {// 在 onTick 事件处理函数中更新视锥体位置const onTick = (clock) => {// 将当前位置添加到路径数组this.updatePath(currentPosition);//...}}}
}

Step 4延伸:
思路:在Step 4基础上尝试扩展,显隐,销毁 show的配合
在这里插入图片描述
部分代码:

class PointMover {constructor(viewer, show) {this.viewer = viewer;this.pointQueue = [];this.isAnimating = false;this.videoEntity = null;this.pathPoints = [];this.pathPolyline = null; this.isFrustumShow = show; //用于显隐控制// ...if (this.frustumPrimitive) {if (!this.isFrustumShow) {this.frustumPrimitive.show = false;} else {this.frustumPrimitive.show = true;}}if (this.videoEntity) {if (!this.isFrustumShow) {this.videoEntity.show = false;} else {this.videoEntity.show = true;}}}// 内部方法:启动动画startAnimation() {if (this.pointQueue.length > 2 && !this.isAnimating) {// 在 onTick 事件处理函数中更新视锥体位置const onTick = (clock) => {// 将当前位置添加到路径数组//...this.frustumPrimitive = this.viewer.scene.primitives.add(new Cesium.Primitive({geometryInstances: new Cesium.GeometryInstance({geometry: newGeometry,attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED.withAlpha(0.5)),},}),appearance: new Cesium.PerInstanceColorAppearance({translucent: true,flat: true,}),asynchronous: false,}));if (this.frustumPrimitive) {if (!this.isFrustumShow) {this.frustumPrimitive.show = false;} else {this.frustumPrimitive.show = true;}}if (this.videoEntity) {if (!this.isFrustumShow) {this.videoEntity.show = false;} else {this.videoEntity.show = true;}}}}}// ...// 外部调用方法,更新显隐开关updateVisibleAndHidden(val) {this.isFrustumShow = val;}dispose() {if (this.frustumPrimitive) {viewer.scene.primitives.remove(this.frustumPrimitive);this.frustumPrimitive = null;}if (this.videoEntity) {viewer.entities.remove(this.videoEntity);this.videoEntity = null;}if (this.entity) {viewer.entities.remove(this.entity);this.entity = null;}if (this.pathPolyline) {viewer.entities.remove(this.pathPolyline);this.pathPolyline = null;}}
}
if (this.pointMover) {clearInterval(this.intervalId);this.intervalId = null;this.pointMover.dispose();this.pointMover = null;
}
this.pointMover = new PointMover(viewer, this.isFrustumShow);

Step 5:
思路:尝试改变视椎体朝向
在这里插入图片描述
部分代码:

class PointMover {constructor(viewer) {// ...this.currentHeading = 0;this.currentPitch = 0;this.currentRoll = 0;// ...}// 内部方法:启动动画startAnimation() {if (this.pointQueue.length > 2 && !this.isAnimating) {// 在 onTick 事件处理函数中更新视锥体位置const onTick = (clock) => {const heading = Cesium.Math.toRadians(this.currentHeading); // 偏航角const pitch = Cesium.Math.toRadians(this.currentPitch); // 俯仰角const roll = Cesium.Math.toRadians(this.currentRoll); // 翻滚角// 创建一个HeadingPitchRoll对象const headingPitchRoll = new Cesium.HeadingPitchRoll(heading,pitch,roll);// 创建一个旋转矩阵const rotationMatrix =Cesium.Transforms.headingPitchRollToFixedFrame(currentPosition,headingPitchRoll,Cesium.Ellipsoid.WGS84);// 从旋转矩阵计算四元数const orientation =Cesium.Quaternion.fromRotationMatrix(rotationMatrix);//...}}}// ...updateHeadingPitchRoll(heading, patch, roll) {this.currentHeading = heading;this.currentPitch = patch;this.currentRoll = roll;}
}

Step 5延伸:
思路:在Step 5基础上尝试,同样矩阵转动视频材质
在这里插入图片描述
发现视频材质无法贴合视椎体,方案终止

Step 6:
思路:换用另一种视椎体构建方法,采用相机视角重置视椎体视角的方法,消除地理位置的影响
在这里插入图片描述
部分代码:

class PointMover {constructor(viewer) {// ...this.videoEntity = viewer.entities.add({name: "uav-tmp-fly-wxsimple",polygon: {hierarchy: new Cesium.CallbackProperty((time) => {if (!this.entity || !this.entity.position) {return null;}try {const position = this.entity.position.getValue(time);if (!Cesium.defined(position)) {return null;}let frustum = this.camera.frustum;let Cartesian3 = Cesium.Cartesian3;let camera = this.camera;// ...return new Cesium.PolygonHierarchy([upRightPt,upLeftPt,downLeftPt,downRightPt,]);} catch (error) {console.warn("Error calculating polygon positions:", error);return null;}}, false),perPositionHeight: true,material: new Cesium.ImageMaterialProperty({image: videoElement, // 这里传入视频元素transparent: true, // 设置透明repeat: new Cesium.Cartesian2(1.0, 1.0), // 控制重复}),shadows: Cesium.ShadowMode.DISABLED,classificationType: Cesium.ClassificationType.BOTH,zIndex: 999,},});}// 内部方法:启动动画startAnimation() {if (this.pointQueue.length > 2 && !this.isAnimating) {// 在 onTick 事件处理函数中更新视锥体位置const onTick = (clock) => {var scene = this.viewer.scene;  this.camera = new Cesium.Camera(scene)//...}}}// ...
}

最终
接入实际项目,无人机航拍镜头实时同步反显,完结撒花°˖✧◝(⁰▿⁰)◜✧˖°
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/6768.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Day21-【软考】短文,计算机网络开篇,OSI七层模型有哪些协议?

文章目录 OSI七层模型有哪些?有哪些协议簇?TCP/IP协议簇中的TCP协议三次握手是怎样的?基于UDP的DHCP协议是什么情况?基于UDP的DNS协议是什么情况? OSI七层模型有哪些? 题目会考广播域 有哪些协议簇&#x…

媒体新闻发稿要求有哪些?什么类型的稿件更好通过?

为了保证推送信息的内容质量,大型新闻媒体的审稿要求一向较为严格。尤其在商业推广的过程中,不少企业的宣传稿很难发布在这些大型新闻媒体平台上。 媒体新闻发稿要求有哪些?就让我们来了解下哪几类稿件更容易过审。 一、媒体新闻发稿要求有哪…

Flutter_学习记录_导航和其他

Flutter 的导航页面跳转,是通过组件Navigator 和 组件MaterialPageRoute来实现的,Navigator提供了很多个方法,但是目前,我只记录我学习过程中接触到的方法: Navigator.push(), 跳转下一个页面Navigator.pop(), 返回上一…

mathematical-expression 实现 数学表达式解析 Java 篇(最新版本)

mathematical-expression (MAE) 切换至 中文文档 Community QQ group 访问链接进行交流信息的获取:https://diskmirror.lingyuzhao.top/DiskMirrorBackEnd/FsCrud/downLoad/18/Binary?fileNameArticle/Image/-56202138/1734319937274.jpg…

http的请求体各项解析

一、前言 做Java开发的人员都知道,其实我们很多时候不单单在写Java程序。做的各种各样的系统,不管是PC的 还是移动端的,还是为别的系统提供接口。其实都离不开http协议或者https 这些东西。Java作为编程语言,再做业务开发时&#…

Java 大视界 -- Java 大数据中的自然语言生成技术与实践(63)

💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…

计算机网络三张表(ARP表、MAC表、路由表)总结

参考: 网络三张表:ARP表, MAC表, 路由表,实现你的网络自由!!_mac表、arp表、路由表-CSDN博客 网络中的三张表:ARP表、MAC表、路由表 首先要明确一件事,如果一个主机要发送数据,那么必…

Git Bash 配置 zsh

博客食用更佳 博客链接 安装 zsh 安装 Zsh 安装 Oh-my-zsh github仓库 sh -c "$(curl -fsSL https://install.ohmyz.sh/)"让 zsh 成为 git bash 默认终端 vi ~/.bashrc写入: if [ -t 1 ]; thenexec zsh fisource ~/.bashrc再重启即可。 更换主题 …

【问题】Chrome安装不受支持的扩展 解决方案

此扩展程序已停用,因为它已不再受支持 Chromium 建议您移除它。详细了解受支持的扩展程序 此扩展程序已停用,因为它已不再受支持 详情移除 解决 1. 解压扩展 2.打开manifest.json 3.修改版本 将 manifest_version 改为3及以上 {"manifest_ver…

在 Windows 系统上,将 Ubuntu 从 C 盘 迁移到 D 盘

在 Windows 系统上,如果你使用的是 WSL(Windows Subsystem for Linux)并安装了 Ubuntu,你可以将 Ubuntu 从 C 盘 迁移到 D 盘。迁移过程涉及导出当前的 Ubuntu 发行版,然后将其导入到 D 盘的目标目录。以下是详细的步骤…

qt QNetworkRequest详解

1、概述 QNetworkRequest是Qt网络模块中的一个核心类,专门用于处理网络请求。它封装了网络请求的所有关键信息,包括请求的URL、HTTP头部信息等,使得开发者能够方便地在Qt应用程序中执行网络操作,如文件下载、网页内容获取等。QNe…

Python!从0开始学爬虫:(一)HTTP协议 及 请求与响应

前言 爬虫需要基础知识,HTTP协议只是个开始,除此之外还有很多,我们慢慢来记录。 今天的HTTP协议,会有助于我们更好的了解网络。 一、什么是HTTP协议 (1)定义 HTTP(超文本传输协议&#xff…

后盾人JS -- Map与WeakMap类型在JavaScript中的使用

Map类型特点与创建方法 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> &l…

python实现http文件服务器访问下载

//1.py import http.server import socketserver import os import threading import sys# 获取当前脚本所在的目录 DIRECTORY os.path.dirname(os.path.abspath(__file__))# 设置服务器的端口 PORT 8000# 自定义Handler&#xff0c;将根目录设置为脚本所在目录 class MyHTT…

[STM32 - 野火] - - - 固件库学习笔记 - - -十一.电源管理系统

一、电源管理系统简介 电源管理系统是STM32硬件设计和系统运行的基础&#xff0c;它不仅为芯片本身提供稳定的电源&#xff0c;还通过多种电源管理功能优化功耗、延长电池寿命&#xff0c;并确保系统的可靠性和稳定性。 二、电源监控器 作用&#xff1a;保证STM32芯片工作在…

二叉树相关oj题 1. 检查两颗树是否相同。

二叉树相关oj题 检查两颗树是否相同。OJ链接 另一颗树的子树。OJ链接 if(rootnull)易漏掉 会导致空指针异常翻转二叉树。OJ链接

批量提取多个 Excel 文件内指定单元格的数据

这篇文章将介绍如何从多个相同格式的Excel文件中&#xff0c;批量提取指定单元格的数据&#xff0c;合并后保存到新的工作薄。 全程0代码&#xff0c;可视化操作。 提取前&#xff1a; 提取后&#xff1a; 准备数据 这里准备了3个测试数据 开始提取 打开的卢易表&#xff0…

【真机调试】前端开发:移动端特殊手机型号有问题,如何在电脑上进行调试?

目录 前言一、怎么设置成开发者模式&#xff1f;二、真机调试基本步骤&#xff1f; &#x1f680;写在最后 前言 edge浏览器 edge://inspect/#devices 谷歌浏览器&#xff08;开tizi&#xff09; chrome://inspect 一、怎么设置成开发者模式&#xff1f; Android 设备 打开设…

GA-CNN-LSTM-Attention、CNN-LSTM-Attention、GA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比

GA-CNN-LSTM-Attention、CNN-LSTM-Attention、GA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比 目录 GA-CNN-LSTM-Attention、CNN-LSTM-Attention、GA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比预测效果基本介绍程序设计参考资料 预测效果 基本介绍 基于GA-CNN-LST…

C++入门14——set与map的使用

在本专栏的往期文章中&#xff0c;我们已经学习了STL的部分容器&#xff0c;如vector、list、stack、queue等&#xff0c;这些容器统称为序列式容器&#xff0c;因为其底层是线性序列的数据结构&#xff0c;里面存储的是元素本身。而本篇文章我们要来认识一下关联式容器。 &am…