vue3 + ts + cesium:绘制、更新圆 ellipse

server/2024/10/4 15:35:59/

本文主要实现基础的绘制圆形,并且可以通过拖动圆心更新圆的位置,拖动圆上的边缘点改变圆的半径。

实现效果:

    (1)单击鼠标左键开始绘制,确定圆的圆心,移动鼠标,改变圆的半径;单击鼠标右键,结束绘制。

    (2)鼠标左键单击绘制的圆形,显示圆的圆心和边缘点;长按鼠标左键,拖动圆心,实时更新圆的位置;长按鼠标左键,拖动边缘点,实时更新圆的半径;单击鼠标右键,结束更新操作,不再显示圆心和边缘点。

1. components / CesiumViewer / hooks / drawCircle.ts(绘制/更新代码)

import * as Cesium from "cesium";
import {CallbackProperty} from "cesium";
import {cartesian2ToCartesian3,disableDefaultScreenSpaceEventHandlers,enableDefaultScreenSpaceEventHandlers
} from "@/components/CesiumViewer/hooks/utils";/* 绘制圆 */
export const drawCircle = () => {const handler = new Cesium.ScreenSpaceEventHandler(window.viewer.scene.canvas)const updateHandler = new Cesium.ScreenSpaceEventHandler(window.viewer.scene.canvas)let isDrawing = true // 是否处于绘制状态let centerPosition: any // 中心点的位置let centerPoint: any // 中心点let radius: any // 圆的半径let tempCircles: any[] = [] // 保存一次绘制过程中产生的圆let endPosition: any // 边缘点的位置let endPoint: any // 边缘点let pickedCircle: any // 选中的圆// 单击左键 —— 绘制圆 / 选中圆handler.setInputAction((event: any) => {const pickedObject = window.viewer.scene.pick(event.position) // 拾取实体if (Cesium.defined(pickedObject) && pickedObject.id && pickedObject.id.ellipse && !isDrawing) { // 选中圆pickedCircle = pickedObject.idconst centerEntity: any = {// position: centerPosition,position: new Cesium.CallbackProperty(() => centerPosition, false),point: {pixelSize: 20, // 点的大小color: Cesium.Color.YELLOW,/* 根据视角远近控制点的比例 */scaleByDistance: new Cesium.NearFarScalar(1.5e2, 2.0, 8.0e6, 0.0),heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND},type: 'center'}centerPoint = window.viewer.entities.add(centerEntity)const endEntity: any = {// position: endPosition,position: new CallbackProperty(() => endPosition, false),point: {pixelSize: 20, // 点的大小color: Cesium.Color.YELLOW,/* 根据视角远近控制点的比例 */scaleByDistance: new Cesium.NearFarScalar(1.5e2, 2.0, 8.0e6, 0.0),heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND},type: 'end'}endPoint = window.viewer.entities.add(endEntity)} else { // 绘制圆if (isDrawing) {centerPosition = window.viewer.camera.pickEllipsoid(event.position, window.viewer.scene.globe.ellipsoid) // cartesian3if (Cesium.defined(centerPosition) && isDrawing) {centerPoint = window.viewer.entities.add({position: centerPosition,point: {pixelSize: 20, // 点的大小color: Cesium.Color.YELLOW,/* 根据视角远近控制点的比例 */scaleByDistance: new Cesium.NearFarScalar(1.5e2, 2.0, 8.0e6, 0.0),heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND}})handler.setInputAction((movement: any) => {// 计算半径【movement.endPosition 为 cartesian2 坐标】radius = Cesium.Cartesian3.distance(centerPosition, <Cesium.Cartesian3>cartesian2ToCartesian3(movement.endPosition))const tempCircle = window.viewer.entities.add({position: centerPosition, // 圆心位置ellipse: {semiMinorAxis: new Cesium.CallbackProperty(() => radius, false), // 短半轴semiMajorAxis: new Cesium.CallbackProperty(() => radius, false), // 长半轴(设置为相等以形成圆形)material: new Cesium.ColorMaterialProperty(Cesium.Color.RED.withAlpha(0.5)), // 圆形的填充颜色和透明度/*// 圆环outline: true, // 轮廓线outlineColor: Cesium.Color.YELLOW, // 轮廓颜色fill: false // 无填充*/}})tempCircles.push(tempCircle)if (tempCircles.length > 1) {for (let i = 0; i < tempCircles.length - 1; i++) {window.viewer.entities.remove(tempCircles[i]) // 实时更新半径时会绘制多个圆,并且堆叠在一起,所以需要保证只球上只渲染最新的圆}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)}}}}, Cesium.ScreenSpaceEventType.LEFT_CLICK)// 单击右键 —— 结束绘制handler.setInputAction((event: any) => {handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)tempCircles = []window.viewer.entities.remove(centerPoint) // 结束绘制 / 结束更新后 移除中心点centerPoint = nullif (isDrawing) {endPosition = window.viewer.camera.pickEllipsoid(event.position, window.viewer.scene.globe.ellipsoid) // 保存圆的边缘点}isDrawing = falsewindow.viewer.entities.remove(endPoint) // 结束更新后 移除边缘点}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)// 长按左键 —— 更新绘制的圆圈handler.setInputAction((event: any) => {const pickedObject = window.viewer.scene.pick(event.position)if (Cesium.defined(pickedObject) && pickedObject.id && pickedObject.id.point) {disableDefaultScreenSpaceEventHandlers()updateHandler.setInputAction((movement: any) => {const newPosition = window.viewer.camera.pickEllipsoid(movement.endPosition, window.viewer.scene.globe.ellipsoid)if (Cesium.defined(newPosition)) {pickedObject.id.position = new Cesium.CallbackProperty(() => newPosition, false) // 实时更新拖动的点的位置if (pickedObject.id.type === 'center') { // 中心点 —— 拖动圆pickedCircle.position = new Cesium.CallbackProperty(() => newPosition, false) // 更新圆心位置centerPosition = newPosition // 更新中心点的位置// 计算新的边缘点位置let offsetDirection = Cesium.Cartesian3.subtract(endPosition, centerPosition, new Cesium.Cartesian3()) // 从中心点到边缘点的方向let normalizedDirection = Cesium.Cartesian3.normalize(offsetDirection, new Cesium.Cartesian3()) // 单位方向向量endPosition = Cesium.Cartesian3.add(centerPosition, Cesium.Cartesian3.multiplyByScalar(normalizedDirection, radius, new Cesium.Cartesian3()), new Cesium.Cartesian3())endPoint.position = new Cesium.CallbackProperty(() => endPosition, false)}if (pickedObject.id.type === 'end') { // 边缘点 —— 改变圆的半径radius = Cesium.Cartesian3.distance(centerPosition, <Cesium.Cartesian3>cartesian2ToCartesian3(movement.endPosition))pickedCircle.ellipse.semiMinorAxis = new Cesium.CallbackProperty(() => radius, false)pickedCircle.ellipse.semiMajorAxis = new Cesium.CallbackProperty(() => radius, false)endPosition = newPosition}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)}}, Cesium.ScreenSpaceEventType.LEFT_DOWN)// 抬起左键 —— 结束更新handler.setInputAction(() => {updateHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)enableDefaultScreenSpaceEventHandlers() // 恢复允许屏幕移动}, Cesium.ScreenSpaceEventType.LEFT_UP)
}

2. components / CesiumViewer / hooks / utils.ts (禁止/允许屏幕拖动、屏幕坐标转世界坐标代码)

import * as Cesium from "cesium";// 保持地球不动
export function disableDefaultScreenSpaceEventHandlers() {window.viewer.scene.screenSpaceCameraController.enableRotate = false // 禁止旋转window.viewer.scene.screenSpaceCameraController.enableTranslate = false // 禁止平移window.viewer.scene.screenSpaceCameraController.enableZoom = false // 禁止缩放window.viewer.scene.screenSpaceCameraController.enableTilt = false // 禁止倾斜window.viewer.scene.screenSpaceCameraController.enableLook = false // 禁止观察(自由视角查看)
}// 允许地球移动
export function enableDefaultScreenSpaceEventHandlers() {window.viewer.scene.screenSpaceCameraController.enableRotate = truewindow.viewer.scene.screenSpaceCameraController.enableTranslate = truewindow.viewer.scene.screenSpaceCameraController.enableZoom = truewindow.viewer.scene.screenSpaceCameraController.enableTilt = truewindow.viewer.scene.screenSpaceCameraController.enableLook = true
}// 屏幕坐标转世界坐标(cartesian2 → cartesian3)
export function cartesian2ToCartesian3(cartesian2: Cesium.Cartesian2) {// 获取相机的射线const ray: any = window.viewer.camera.getPickRay(cartesian2)// 使用射线来获取地球表面上的位置return window.viewer.scene.globe.pick(ray, window.viewer.scene) // 返回 Cartesian3 坐标
}


http://www.ppmy.cn/server/127003.html

相关文章

力扣(leetcode)每日一题 1845 座位预约管理系统| treeSet和priority Queue的区别|线段树

之前发过一篇&#xff0c;感觉还有深挖的地方&#xff0c;于是又补充一些信息 这题目虽然是middle难度题目&#xff0c;要解答出来是只要easy的时间&#xff0c;但是深挖可以有hard的难度 题解1 可以帮助复习线段树的使用&#xff0c;题解2 可以复习一下java基础知识 题解1 线…

仿RabbitMQ实现消息队列服务端(一)

文章目录 交换机数据管理队列数据管理绑定信息(交换机-队列)管理队列消息管理虚拟机管理交换机路由管理队列消费者/订阅者管理 整体框架&#xff1a;工具模块及项目整体模块框架 交换机数据管理 交换机数据管理就是描述了交换机应该有哪些数据 定义交换机数据类 1、交换机的名…

66 使用注意力机制的seq2seq_by《李沐:动手学深度学习v2》pytorch版

系列文章目录 文章目录 系列文章目录动机加入注意力总结代码定义注意力解码器训练小结练习 我们来真的看一下实际应用中&#xff0c;key&#xff0c;value&#xff0c;query是什么东西&#xff0c;但是取决于应用场景不同&#xff0c;这三个东西会产生变化。先将放在seq2seq这个…

Llama 3.2 使用指南:工作原理及示例

Meta AI 宣布发布 Llama 3.2,该版本引入了系列中的首批多模态模型。Llama 3.2 专注于两个关键领域: 启用视觉的大型语言模型(LLM):11B 和 90B 参数的多模态模型现在可以处理并理解文本和图像。为边缘和移动设备设计的轻量级 LLM:1B 和 3B 参数模型旨在轻量化和高效,允许…

基于php摄影门户网站

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

SLF4J报错log4j又报错

项目场景&#xff1a; 搭建一个spirngboot项目&#xff0c;启动运行时&#xff0c;SLF4J报错 解决后 ~ log4j又报错了。 问题描述 首先是SLF4J报错了&#xff0c;解决完SL4J报错问题后&#xff0c;再次启动项目&#xff0c;log4j又报错了 。。。 报错信息&#xff1a; SLF4J…

sql-labs:42~65

less42&#xff08;单引号闭合、报错回显&#xff09; login_useradmin login_password123 and if(11,sleep(2),1) # # 单引号闭合 ​ login_useradmin login_password123and updatexml(1,concat(0x7e,database(),0x7e),1)# # 报错回显…

[linux] 磁盘清理相关

在 CentOS 7 中清理磁盘空间可以通过多种方法实现&#xff0c;以下是一些常用的步骤和命令&#xff1a; 1. 查找和删除大文件 你可以使用 find 命令查找占用大量空间的文件&#xff1a; find / -type f -size 100M 2>/dev/null这条命令会查找大于 100 MB 的文件。你可以根…