赞
踩
鉴于大疆司空平台和大疆无人机app高度绑定,导致很多东西没办法定制化。
从去年的时候就打算仿大疆开发一套完整的平台,包括无人机app以及仿司空2的管理平台,集航线规划、任务派发、实时图像、无人机管理等功能的平台。
当前阶段主要实现了:
1、无人机实时数据(包括视频、音频、拍照数据、位置信息以及无人机姿态)回传至web端,web端实时预览
2、web端实时编辑航线,编辑好的航线直接派发到无人机,无人机按照编辑航线进行作业;
3、......
后续我们还做了喊话、图像自动识别动功能
......
下面是基于Cesium开发的航线编辑功能,后面会对这个这个模块的实现进行记录,供大家参考。
当前我做的是三维空间的航线编辑,还有种方式是快速编辑(此处不做说明)。
简单操作说明:
航点编辑支持两种方式:键盘和鼠标点击。
W -- 向前
S -- 向后
A -- 向左
D -- 向右
并且相机姿态编辑,也支持键盘和鼠标操作:
⬆ -- 镜头抬升
⬇ -- 镜头降低
⬅ -- 镜头左转
➡ -- 镜头右转
具体操作大家可以参考司空2的平台,后续我会将此功能放到线上,大家也可以体验。
后续我写完了,统一放出核心代码。当前仅作记录。
- // 根据距离计算位置
- computeByDistance(offset) {
- // 根据相机的heading 计算前后左右的朝向
- let heading = this.startMoveHeading;
- const center = Cesium.Matrix4.multiplyByPoint(this.localMtx_inverse, this.localCenter, new Cesium.Cartesian3());
- const x = (offset.a.val || 0) - (offset.d.val || 0);
- const y = (offset.w.val || 0) - (offset.s.val || 0);
-
- const directionX = Cesium.Cartesian3.multiplyByScalar(new Cesium.Cartesian3(1, 0, 0), -1 * x, new Cesium.Cartesian3());
- const directionY = Cesium.Cartesian3.multiplyByScalar(new Cesium.Cartesian3(0, 1, 0), y, new Cesium.Cartesian3());
-
- let newc = Cesium.Cartesian3.add(center, directionX, new Cesium.Cartesian3());
- newc = Cesium.Cartesian3.add(newc, directionY, new Cesium.Cartesian3());
- const rotationZ = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(-1 * heading || 0), new Cesium.Matrix3());
- newc = Cesium.Matrix3.multiplyByVector(rotationZ, newc.clone(), new Cesium.Cartesian3());
- const res = Cesium.Matrix4.multiplyByPoint(this.localMtx, newc.clone(), new Cesium.Cartesian3());
- return res;
- }
-
- computeHeadingPitch(offset) {
- const heading = (offset.ArrowRight.val || 0) - (offset.ArrowLeft.val || 0);
- const pitch = (offset.ArrowUp.val || 0) - (offset.ArrowDown.val || 0);
- return { heading, pitch }
- }

--------------------------------------------- 2024-04-17 更新 ---------------------------------------------
这两天没写什么,主要新增了个方向罗盘
新增了相机范围显示功能,并且同步了相机窗口和主窗口的联动
当前在相机窗口进行鼠标按下拖动时,主窗口的锥体会同步进行运动,以下是核心代码:
-
- // viewer2 绑定鼠标事件,可通过鼠标控制镜头
- class ViewerClickHandler {
- constructor(viewer, opt) {
- this.viewer = viewer;
- this.opt = opt || {};
-
- this.startPX = undefined;
- this.handler = undefined;
-
- const dom = window.document.getElementById(this.viewer.container.id);
- this.width = dom.offsetWidth;
- this.height = dom.offsetHeight;
-
- // 禁止viewer的所有操作
- this.viewer.scene.screenSpaceCameraController.enableInputs = false;
-
- this.state = 'no'; // change end start
-
- this.bindHandler()
-
- }
-
- bindHandler() {
- if (!this.handler) this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
-
- this.handler.setInputAction((evt) => {
- // 初始化进入时,鼠标提示操作
- const px = evt.position;
- if (!this.startPX) {
- this.startPX = px;
- }
- if (this.opt.start) this.opt.start();
- this.state = 'start';
- }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
-
- this.handler.setInputAction((evt) => {
- // 初始化进入时,鼠标提示操作
- const px = evt.endPosition;
- if (!this.startPX) return;
- const heading = (px.x - this.startPX.x) * 30 / this.width;
- const pitch = - (px.y - this.startPX.y) * 30 / this.height;
- if (this.opt.change) this.opt.change(heading, pitch);
- this.state = 'change';
- }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
-
- this.handler.setInputAction((evt) => {
- // 初始化进入时,鼠标提示操作
- if (this.startPX) {
- this.startPX = undefined;
- }
- if (this.opt.end) this.opt.end();
- this.state = 'end';
- }, Cesium.ScreenSpaceEventType.LEFT_UP);
- }
-
- destroy() {
- if (this.handler) this.handler.destroy();
- this.handler = undefined;
- this.state = 'no';
- }
- }
-
- // frustum和camera同步
- const combineCamera = {
- isactivate: false,
- frustum: undefined,
- viewer: undefined,
- viewer2: undefined,
- activate(frustum, viewer, viewer2) {
- if (!this.isactivate) {
- this.isactivate = true;
- this.frustum = frustum;
- this.viewer = viewer;
- this.viewer2 = viewer2;
-
-
- this.bindListener();
- }
- },
- disable() {
- if (this.isactivate) {
- this.isactivate = false;
- this.unbindListener();
-
- if (this.viewerHandler) {
- this.viewerHandler.destroy();
- this.viewerHandler = undefined;
- }
-
- }
- },
- removeCallback: undefined,
- removeCallback2: undefined,
- viewerHandler: undefined,
- bindListener() {
- const camera2 = this.viewer2.camera;
- if (!this.viewerHandler) {
- let initHeading, initPitch;
- this.viewerHandler = new ViewerClickHandler(this.viewer2, {
- start: () => {
- // 添加初始hp 防止每次都从0度方向开始
- initHeading = this.frustum.heading || 0;
- initPitch = this.frustum.pitch || 0;
- },
- change: (heading, pitch) => {
- // 修改viewer1中的椎体角度
- console.log(heading, this.frustum.heading + (heading || 0));
- this.frustum.update('', {
- heading: initHeading + heading,
- pitch: initPitch + pitch
- })
- // 修改当前视角
- camera2.flyTo({
- destination: this.frustum.position,
- orientation: {
- heading: Cesium.Math.toRadians(initHeading + heading || 0),
- pitch: Cesium.Math.toRadians(initPitch + pitch || 0),
- roll: 0
- },
- duration: 0
- });
- },
- end: () => {
- initHeading = undefined;
- initPitch = undefined;
- }
- })
- }
-
-
- this.removeCallback = this.viewer.scene.postRender.addEventListener(() => {
- if (this.viewerHandler && this.viewerHandler.state == 'change') return; // 操作视角时 不再通过此处来进行椎体同步
- // frustum ---> camera
- if(!this.frustum) return ;
- const heading = this.frustum?.heading;
- const pitch = this.frustum?.pitch;
- camera2.flyTo({
- destination: this.frustum.position,
- orientation: {
- heading: Cesium.Math.toRadians(heading || 0),
- pitch: Cesium.Math.toRadians(pitch || 0),
- roll: 0
- },
- duration: 0
- });
- }, false)
-
-
-
- },
- unbindListener() {
- if (this.removeCallback) {
- this.removeCallback();
- this.removeCallback = undefined;
- }
- }
- }

未完待续。。。。。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。