Cesium 相机控制器(1)-wheel 实现原理简析

请添加图片描述

Cesium 相机控制器(1)-wheel 实现原理简析

已经做大量简化, 不是代码最终的样子.

Viewer┖ CesiumWidget┖ ScreenSpaceCameraController(_screenSpaceCameraController)CameraEventAggregator(_aggregator) // 相机事件代理┃  ┖ ScreenSpaceEventHandler(_eventHandler)┖ TweenCollection
1、注册事件监听器

注册事件 wheelmousemove

function registerListener() {element.addEventListener(domType, handleWheel);
}// 事件处理器, 提供设置监听者的能力。 分配活的。
class ScreenSpaceEventHandler {constructor(scene) {registerListener('"wheel"', handleWheel);registerListener('"pointermove"', handlePointerMove);}
}
2、事件监听器的实现
function handleWheel (delta) {const action = screenSpaceEventHandler.getInputAction(ScreenSpaceEventType.WHEEL,);action(delta);
}function handleMouseMove(screenSpaceEventHandler, event) {const modifier = getModifier(event);const position = getPosition();const previousPosition = screenSpaceEventHandler._primaryPreviousPosition;const action = screenSpaceEventHandler.getInputAction(ScreenSpaceEventType.MOUSE_MOVE,modifier);if (defined(action)) {Cartesian2.clone(previousPosition, mouseMoveEvent.startPosition);Cartesian2.clone(position, mouseMoveEvent.endPosition);action(mouseMoveEvent);}Cartesian2.clone(position, previousPosition);
}
3、事件监听的执行
// 事件代理器, 设置真正的监听者。真正干活的。
class CameraEventAggregator {constructor() {listenToWheel(this, undefined);listenMouseMove(this, undefined);}
}const listenToWheel = function (aggregator) {const key = getKey(CameraEventType.WHEEL);const update = aggregator._update;update[key] = true;let movement = aggregator._movement[key];let lastMovement = aggregator._lastMovement[key];movement.startPosition = new Cartesian2();movement.endPosition = new Cartesian2();Cartesian2.clone(Cartesian2.ZERO, movement.startPosition);aggregator._eventHandler.setInputAction(function (delta) {const arcLength = 7.5 * CesiumMath.toRadians(delta);movement.endPosition.x = 0.0;movement.endPosition.y = arcLength;Cartesian2.clone(movement.endPosition, lastMovement.endPosition);lastMovement.valid = true;update[key] = false;},ScreenSpaceEventType.WHEEL,);
}const listenMouseMove = function (aggregator) {const update = aggregator._update;const movement = aggregator._movement;const lastMovement = aggregator._lastMovement;const isDown = aggregator._isDown;aggregator._eventHandler.setInputAction(function (mouseMovement) {Cartesian2.clone(mouseMovement.endPosition,aggregator._currentMousePosition);},ScreenSpaceEventType.MOUSE_MOVE,);
}

可视化查看位置:

const e = document.querySelector(".end");
const pos = viewer.scene._screenSpaceCameraController._aggregator._currentMousePosition
setInterval(() => {e.style.top = pos.y + "px";e.style.left = pos.x + "px";
}, 10);
4、控制器的更新
`Scene``render`Scene.prototype.initializeFrame()this._screenSpaceCameraController.update();update3D(this);reactToInput()zoom3D()
5、zoom3D 实现细节
function zoom3D(controller: ScreenSpaceCameraController,startPosition: Cartesian2,movement) {// 屏幕中心位置let windowPosition;windowPosition.x = canvas.clientWidth / 2;windowPosition.y = canvas.clientHeight / 2;//  得到射线const ray = camera.getPickRayPerspective(windowPosition, zoomCVWindowRay);// 相机的当前高度let distance = ellipsoid.cartesianToCartographic(camera.position,zoom3DCartographic).height;const unitPosition = Cartesian3.normalize(camera.position,zoom3DUnitPosition);handleZoom(controller,startPosition,movement,controller._zoomFactor,distance,Cartesian3.dot(unitPosition, camera.direction));
}
6、getPickRayPerspective 实现细节
function getPickRayPerspective(camera, windowPosition, result) {const canvas = camera._scene.canvas;const width = canvas.clientWidth;const height = canvas.clientHeight;const tanPhi = Math.tan(camera.frustum.fovy * 0.5);// tanTheta 是相机视角张角的正切值,表示近平面的宽度与近平面距离的比值const tanTheta = camera.frustum.aspectRatio * tanPhi;const near = camera.frustum.near;// 屏幕空间 转 NDC 空间, [-1, 1]const x = (2.0 / width) * windowPosition.x - 1.0;const y = (2.0 / height) * (height - windowPosition.y) - 1.0;const position = camera.positionWC;Cartesian3.clone(position, result.origin);// near * tanTheta 表示近平面的宽度,将其乘以 x 就可以得到近平面上某个点的水平距离。const nearCenter = Cartesian3.multiplyByScalar(camera.directionWC,near,pickPerspCenter);Cartesian3.add(position, nearCenter, nearCenter);const xDir = Cartesian3.multiplyByScalar(camera.rightWC,x * near * tanTheta,pickPerspXDir);const yDir = Cartesian3.multiplyByScalar(camera.upWC,y * near * tanPhi,pickPerspYDir);const direction = Cartesian3.add(nearCenter, xDir, result.direction);Cartesian3.add(direction, yDir, direction);Cartesian3.subtract(direction, position, direction);Cartesian3.normalize(direction, direction);return result;
}
7、pickPosition 实现细节
const pickGlobeScratchRay = new Ray();
const scratchDepthIntersection = new Cartesian3();
const scratchRayIntersection = new Cartesian3();function pickPosition(controller, mousePosition, result) {const scene = controller._scene;const globe = controller._globe;const camera = scene.camera;let depthIntersection;if (scene.pickPositionSupported) {depthIntersection = scene.pickPositionWorldCoordinates(mousePosition,scratchDepthIntersection);}if (!defined(globe)) {return Cartesian3.clone(depthIntersection, result);}const cullBackFaces = !controller._cameraUnderground;const ray = camera.getPickRay(mousePosition, pickGlobeScratchRay);const rayIntersection = globe.pickWorldCoordinates(ray,scene,cullBackFaces,scratchRayIntersection);const pickDistance = defined(depthIntersection)? Cartesian3.distance(depthIntersection, camera.positionWC): Number.POSITIVE_INFINITY;const rayDistance = defined(rayIntersection)? Cartesian3.distance(rayIntersection, camera.positionWC): Number.POSITIVE_INFINITY;if (pickDistance < rayDistance) {return Cartesian3.clone(depthIntersection, result);}return Cartesian3.clone(rayIntersection, result);
}
8、handleZoom 实现细节

请添加图片描述

viewer.scene.screenSpaceCameraController._zoomWorldPosition
function handleZoom(distanceMeasure) {let percentage = 1.0;// startPosition 是固定的 (0,0)// endPosition.y 是滚轮距离const diff = movement.endPosition.y - movement.startPosition.y;const minHeight = 0;const maxHeight = Infinity;const minDistance = distanceMeasure - minHeight;let zoomRate = zoomFactor * minDistance;let rangeWindowRatio = diff / object._scene.canvas.clientHeight;let distance = zoomRate * rangeWindowRatio;pickedPosition = pickPosition(object,startPosition,scratchPickCartesian);if (defined(pickedPosition)) {object._useZoomWorldPosition = true;object._zoomWorldPosition = Cartesian3.clone(pickedPosition,object._zoomWorldPosition);} else {object._useZoomWorldPosition = false;}const positionNormal = Cartesian3.normalize(centerPosition,scratchPositionNormal);const pickedNormal = Cartesian3.normalize(controller._zoomWorldPosition,scratchPickNormal);const dotProduct = Cartesian3.dot(pickedNormal, positionNormal);if (dotProduct > 0.0 && dotProduct < 1.0) {const angle = CesiumMath.acosClamped(dotProduct);const axis = Cartesian3.cross(pickedNormal,positionNormal,scratchZoomAxis);const denom =Math.abs(angle) > CesiumMath.toRadians(20.0)? camera.positionCartographic.height * 0.75: camera.positionCartographic.height - distance;const scalar = distance / denom;camera.rotate(axis, angle * scalar);
}
9、相机的旋转
/*** Rotates the camera around <code>axis</code> by <code>angle</code>. The distance* of the camera's position to the center of the camera's reference frame remains the same.** @param {Cartesian3} axis The axis to rotate around given in world coordinates.* @param {number} [angle] The angle, in radians, to rotate by. Defaults to <code>defaultRotateAmount</code>.** @see Camera#rotateUp* @see Camera#rotateDown* @see Camera#rotateLeft* @see Camera#rotateRight*/
Camera.prototype.rotate = function (axis, angle) {const turnAngle = defaultValue(angle, this.defaultRotateAmount);const quaternion = Quaternion.fromAxisAngle(axis,-turnAngle,rotateScratchQuaternion);const rotation = Matrix3.fromQuaternion(quaternion, rotateScratchMatrix);Matrix3.multiplyByVector(rotation, this.position, this.position);Matrix3.multiplyByVector(rotation, this.direction, this.direction);Matrix3.multiplyByVector(rotation, this.up, this.up);Cartesian3.cross(this.direction, this.up, this.right);Cartesian3.cross(this.right, this.direction, this.up);
};

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

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

相关文章

Notion爆红背后,笔记成了AI创业新共识?

在数字化时代&#xff0c;笔记软件已成为我们记录、整理和创造知识的得力助手。本文将带您深入了解Notion以及其他五个AI笔记产品&#xff0c;它们如何通过AI重塑笔记体验&#xff0c;满足我们快速记录、捕捉灵感、智能整理、情感陪伴和自动撰写文章的五大核心需求。 ———— …

golang国内proxy设置

go env -w GOPROXYhttps://goproxy.cn,direct经常使用的两个, goproxy.cn 和 goproxy.io 连接分别是 https://goproxy.cn https://goproxy.io 如果遇到某些包下载不下来的情况&#xff0c;可尝试更换数据源 更推荐使用https://goproxy.cn 速度快&#xff0c;缓存的包多 提醒…

如何建立与众不同的市场洞察能力【深度】

来源&#xff1a;战略研发领航 建立与众不同的市场洞察机制&#xff0c;展示了如何在组织中建立一种以数据和洞察为核心的文化&#xff0c;并通过4S周期&#xff08;架构、探查、塑造、成型&#xff09;的洞察工作方法论&#xff0c;指导领导者和团队在各个层级上进行更有效的思…

Upload-labs靶场Pass01-Pass21全解

文章目录 Pass-01 前端JSJS绕过上传或者用burp抓包的方式 Pass-02 MIME检测Pass-03 特殊文件后缀黑白名单绕过特殊文件名绕过 Pass-04 .htacess上传Pass-05 user.ini文件上传Pass-06 大小写绕过Pass-07 空格绕过Pass-08 .绕过Pass-09 ::$DATA绕过Pass-10 .空格.绕过Pass-11 双写…

深度体验:IntelliJ Idea自带AI Assistant,开启面向AI编程新纪元!

首发公众号&#xff1a; 赵侠客 引言 JetBrains AI Assistant 是 JetBrains 集成开发环境&#xff08;IDE&#xff09;中嵌入的一款智能开发助手工具&#xff0c;旨在通过人工智能技术来简化和提升软件开发过程&#xff0c;我深度体验了一下在IntelliJ IDEA 2024.2 Beta (Ulti…

hive 中编写生成连续月sql

记录一下 sql 编写生成从一个确定的起始月份到当前月份的连续月份序列 SELECT substr(add_months(table1.start_dt,table2.pos),1,4) AS INDICT_YEAR,substr(add_months(table1.start_dt,table2.pos),1,7) AS INDICT_MON FROM (SELECT 2024-01-01 AS start_dt,substr(CURRE…

CVPR24《Neural Markov Random Field for Stereo Matching》

论文地址&#xff1a; https://arxiv.org/abs/2403.11193 源码地址&#xff1a; https://github.com/aeolusguan/NMRF 概述 手工设计的MRF模型在传统的立体匹配中占据主导地位&#xff0c;但与端到端的深度学习模型相比&#xff0c;其建模准确性不足。尽管深度学习大大改进了MR…

GraphSAGE (SAmple and aggreGatE)知识总结

1.前置知识 inductive和transductive 模型训练&#xff1a; Transductive learning在训练过程中已经用到测试集数据&#xff08;不带标签&#xff09;中的信息&#xff0c;而Inductive learning仅仅只用到训练集中数据的信息。 模型预测&#xff1a; Transductive learning只能…

作业练习1

要求&#xff1a;R1-R2-R3-R4-R5 RIP 100 运行版本2 R6-R7 RIP 200 运行版本1 1.使用合理IP地址规划网络&#xff0c;各自创建环回接口 2.R1创建环回 172.16.1.1/24 172.16.2.1/24 172.16.3.1/24 3.要求R3使用R2访问R1环回 4.减少路由条目数量&#xff0c;R1-R2之间增加路由传递…

C++进阶之C++11

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 算法 C进阶 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂 目录 一.列表初始化 1.1一切皆可用列表初始化 1.2init…

U盘数据丢失?一招教你如何使用四种技巧轻松找回!

每一个打工人可能都是被各种文件所困扰的&#xff0c;而且现在不仅仅是工作上&#xff0c;还有学习以及日常的生活记录也需要接触到各类的数据&#xff0c;拿我们平时用软件时产生的文件、图片、视频等等来说&#xff0c;就占据了磁盘的大部分空间&#xff0c;当然有时候也会选…

CTFHub——XSS——反射型

1、反射型&#xff1a; 发现为表单式&#xff0c;猜测哪个可能存在注入漏洞&#xff0c;分别做测试注入发现name框存在xss漏洞 输入发现有回显但不是对方cookie&#xff0c;参考wp发现要用xss线上平台 将xss平台测试语句注入&#xff0c;将得到的url编码地址填入url框&#xf…

《学会 SpringMVC 系列 · 写入拦截器 ResponseBodyAdvice》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

MATLAB画散点密度图(附代码和测试数据的压缩包)

1. 有关 Matlab 获取代码关注WZZHHH回复关键词&#xff0c;或者咸鱼关注&#xff1a;WZZHHH123 怀俄明探空站数据解算PWV和Tm&#xff1a;怀俄明探空站数据解算PWV和Tm 怀俄明多线程下载探空站数据&#xff08;包括检查和下载遗漏数据的代码&#xff09;&#xff1a;怀俄明多线…

VMware安装Win10系统(保姆级教程)

需要自己先下载并安装VMware 和Win10系统镜像&#xff1a; VMware官网&#xff1a;VMware - Delivering a Digital Foundation For Businesses Win10下载地址&#xff1a;MSDN,我告诉你 1.新建虚拟机设置 2.启动Win10虚拟机设置 注意&#xff1a; 当出现有字体的时候&#…

一款绿色免费免安装的hosts文件编辑器

BlueLife Hosts Editor 是一款免费的 Hosts 文件编辑工具&#xff0c;主要用于管理和修改电脑系统的 Hosts 文件。该软件具有多种功能&#xff0c;包括添加、删除和更新域名记录&#xff0c;以及调整 IP 与网域名称的交叉对应关系&#xff0c;类似于 DNS 的功能。 该软件特别适…

filebeat

1、作用 1、可以在本机收集日志2、也可以远程收集日志3、轻量级的日志收集系统&#xff0c;可以在非java环境运行。logstash是在jmv环境中运行&#xff0c;资源消耗很大&#xff0c;启动一个logstash要消耗500M左右的内存&#xff0c;filebeat只消耗10M左右的内存。收集nginx的…

Qt 学习第四天:信号和槽机制(核心特征)

信号和槽的简介 信号和插槽用于对象之间的通信。信号和插槽机制是Qt的核心特征&#xff0c;可能是不同的部分大部分来自其他框架提供的特性。信号和槽是由Qt的元对象系统实现的。介绍&#xff08;来自Qt帮助文档Signals & Slots&#xff09; 在GUI编程中&#xff0c;当我们…

使用 Rough.js 创建动态可视化网络图

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 使用 Rough.js 创建动态可视化网络图 应用场景 Rough.js 是一个 JavaScript 库&#xff0c;它允许开发人员使用毛边风格创建可视化效果。该库适用于各种应用程序&#xff0c;例如&#xff1a; 数据可视化地图…

计算机基础(Windows 10+Office 2016)教程 —— 第8章 多媒体技术及应用

多媒体技术及应用 8.1 多媒体技术的概述8.1.1 多媒体技术的定义和特点8.1.2  多媒体的关键技术8.1.3 多媒体技术的发展趋势8.1.4 多媒体文件格式的转换8.1.5 多媒体技术的应用 8.2 多媒体计算机系统的构成8.2.1 多媒体计算机系统的硬件系统8.2.2 多媒体计算机系统的软件系统…