【CesiumJS入门】(7)绘制多段线(动态实时画线)

前言

鼠标左键添加点、右键完成绘制,单击右侧弹窗关闭按钮清空绘制。参考沙盒示例:Drawing on Terrain
在这里插入图片描述

直接上代码了

/*
 * @Date: 2023-07-12 18:47:18
 * @LastEditors: ReBeX  420659880@qq.com
 * @LastEditTime: 2023-07-16 16:26:19
 * @FilePath: \cesium-tyro-blog\src\utils\Entity\Draw\polyline.js
 * @Description: 绘制多段线
 */
import { viewer } from '@/utils/createCesium.js' // 引入地图对象

import * as Cesium from 'cesium'


export class PolylineDrawer {
  activeLine // 动态线
  activePoint // 动态点
  constructor(callback) {
    if (!PolylineDrawer.instance) { // 首次使用构造器实例
      this.callback = callback
      // 新建DataSource用来管理entities
      this.nodeCollection = new Cesium.CustomDataSource("nodeEntityCollection");
      this.lineCollection = new Cesium.CustomDataSource("lineEntityCollection");
      viewer.dataSources.add(this.nodeCollection);
      viewer.dataSources.add(this.lineCollection);

      this.addHandler = this.createScreenSpaceEventHandler(); // 新增点位的交互句柄
      this.finHandler = this.createScreenSpaceEventHandler(); // 完成点选的交互句柄
      this.moveHandler = this.createScreenSpaceEventHandler(); // 完成点选的交互句柄

      viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); // 关闭左键双击事件
      PolylineDrawer.instance = this // 将this挂载到PolylineDrawer这个类的instance属性上
    }
    return PolylineDrawer.instance // 返回单例
  }

  // 返回交互句柄
  createScreenSpaceEventHandler() {
    return new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  }
  // 开始绘制
  start() {
    this.activePoint = this.createCursorPoint({ x: 0, y: 0, z: 0 }); // 默认显示动态点
    this.activePoint.position.setValue(undefined); // 隐藏指针点

    let pointList = []; // 初始化当前的线坐标数组
    // 绘制打点时的事件
    this.addHandler.setInputAction(event => {
      // 获取地形表面经纬度和高度
      const ray = viewer.camera.getPickRay(event.position || event.endPosition);
      const cartesian = viewer.scene.globe.pick(ray, viewer.scene);
      // // 获取椭球体表面的经纬度
      // const cartesian = viewer.camera.pickEllipsoid(event.position || event.endPosition, viewer.scene.globe.ellipsoid);
      if (Cesium.defined(cartesian)) {
        this.nodeCollection.entities.add(this.createNodePoint(cartesian)); // 添加节点
        // 绘制动态线:首次点击后触发
        if (pointList.length === 0) {
          pointList.push(cartesian) // 加入一个动态点
          const dynamicPositions = new Cesium.CallbackProperty(() => pointList.slice(-2), false);
          this.activeLine = this.createActiveLine(dynamicPositions); // 添加动态线
        }
        // 绘制线:点击2次后触发
        if (pointList.length === 1) {
          const dynamicPositions = new Cesium.CallbackProperty(() => pointList.slice(0, -1), false);
          this.lineCollection.entities.add(this.createNormalLine(dynamicPositions)) // 绘制线
        }
        pointList.push(cartesian);
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    // 鼠标移动时的事件
    this.moveHandler.setInputAction(event => {
      if (Cesium.defined(this.activePoint)) {
        // 获取地形表面经纬度和高度
        const ray = viewer.camera.getPickRay(event.endPosition || event.position);
        const cartesian = viewer.scene.globe.pick(ray, viewer.scene);
        // // 获取椭球体表面的经纬度
        // const cartesian = viewer.camera.pickEllipsoid(event.position || event.endPosition, viewer.scene.globe.ellipsoid);
        if (Cesium.defined(cartesian)) {
          this.activePoint.position.setValue(cartesian);
          if (pointList.length > 0) {
            pointList.pop();
            pointList.push(cartesian);
          }
        } else {
          this.activePoint.position.setValue(undefined); // 指针超出地球外了就隐藏指针点
        }
      }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    // 完成绘制时的事件
    this.finHandler.setInputAction(event => {
      if (pointList.length < 2) { // 一个节点都没添加
        alert('请至少选2个点')
      } else if (pointList.length < 3) { // 如果点击了一次,就会马上创建点和线,那么就需要清除掉最末的entity,否则会污染数据集
        alert('请至少选2个点')
        this.nodeCollection.entities.remove(this.nodeCollection.entities.values[this.nodeCollection.entities.values.length - 1]);
        this.lineCollection.entities.remove(this.lineCollection.entities.values[this.lineCollection.entities.values.length - 1]);
      }
      this.stop()
      this.start()
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
  }

  // 结束绘制
  stop() {
    this.addHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
    this.moveHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
    this.finHandler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
    viewer.entities.remove(this.activeLine); // 移除动态线
    viewer.entities.remove(this.activePoint); // 移除动态点
    
    this.callback && this.callback(this.lineCollection) // 如果需要,就把线集合给回调函数
  }

  // 绘制:动态点
  createCursorPoint(cartesian, show) {
    const point = viewer.entities.add({
      position: cartesian,
      point: {
        pixelSize: 5, // 像素大小,默认: 1 
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 表示相对于地形的位置
        color: Cesium.Color.SKYBLUE, // 默认: 白
        disableDepthTestDistance: Number.POSITIVE_INFINITY,
      },
    });
    return point;
  }

  // 绘制:节点
  createNodePoint(cartesian) {
    return new Cesium.Entity({
      position: cartesian,
      point: {
        pixelSize: 3, // 像素大小,默认: 1 
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 表示相对于地形的位置
        color: Cesium.Color.BLUE, // 默认: 白
        disableDepthTestDistance: Number.POSITIVE_INFINITY,
      }
    })
  }

  // 绘制:动态线
  createActiveLine(list) {
    const shape = viewer.entities.add({
      polyline: {
        positions: list,
        clampToGround: true,
        width: 2,
        material: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.RED,
          dashLength: 10,
          dashPattern: 255,
        }),
      },
    });
    return shape;
  }

  // 绘制:线
  createNormalLine(list) {
    return new Cesium.Entity({
      polyline: {
        positions: list,
        clampToGround: true,
        width: 2,
      },
    })
  }

  // 销毁:清空绘制与监听
  destroy() {
    this.stop()
    this.nodeCollection.entities.removeAll()
    this.lineCollection.entities.removeAll()
  }
}

调用:

// 引入
import { PolylineDrawer } from '@/utils/Entity/Draw/polyline.js'

// 声明实例:无回调函数
const polylineDrawer = new PolylineDrawer();

// 声明实例:有回调函数
const polylineDrawer = new PolylineDrawer((lineList)=> {
	console.log(lineList)
);

// 开始绘制
polylineDrawer.start()

// 结束绘制并清除所有点和线
polylineDrawer.destroy()

补充:修改点或线的样式

如果你需要修改节点或动态点的样式,你可以参考如下Entity Point相关参数:

  const PointOptions = {
    show: true,
    pixelSize: 10, // 像素大小,默认: 1 
    heightReference: Cesium.HeightReference.NONE, // 表示相对于地形的位置
    color: Cesium.Color.SKYBLUE, // 默认: 白
    outlineColor: Cesium.Color.BLACK, // 边框颜色,默认: 黑
    outlineWidth: 3, // 边框宽度,默认: 0
    scaleByDistance: new Cesium.NearFarScalar(1.0e3, 10.0, 2.0e3, 1.0), // 随着相机的距离改变大小
    translucencyByDistance: new Cesium.NearFarScalar(1.0e3,1.0,2.0e3,0.1), // 随着相机的距离改变透明度
    distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0,2.0e3), // 在指定距离区间内可见
    // 获取或设置与相机的距离,在深度处禁用深度测试
    // 设置为零时,将始终应用深度测试。设置为Number.POSITIVE_INFINITY时,永远不会应用深度测试。
    disableDepthTestDistance: Number.POSITIVE_INFINITY,
  }

如果你需要修改线或动态线的样式,你可以参考如下Entity Polyline相关参数:

  const LineOptions = {
    show: true,
    // 定义线条的 Cartesian3 位置的数组
    positions: Cesium.Cartesian3.fromDegreesArray([-75, 35, -125, 35]),
    width: 5,
    // 如果arcType不是ArcType.NONE,则指定每个纬度和经度之间的角距离
    granularity: Cesium.Math.RADIANS_PER_DEGREE,
    material: Cesium.Color.RED,
    // 线低于地形时用于绘制折线的材质
    depthFailMaterial: Cesium.Color.WHITE,
    // 折线段必须遵循的线型
    arcType: Cesium.ArcType.GEODESIC,
    clampToGround: true, // 是否贴地
    shadows: Cesium.ShadowMode.DISABLED, // 折线是投射还是接收光源的阴影
    distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
      1.0e3,
      2.0e3
    ),
    // 在地面上时将对地形,3D tiles还是对两者进行分类  type:ClassificationType  default:ClassificationType.BOTH
    // TERRAIN 将仅对地形进行分类;CESIUM_3D_TILE 将仅对3D Tiles进行分类;BOTH	将同时对Terrain和3D Tiles进行分类。
    classificationType: Cesium.ClassificationType.BOTH,
    // 指定用于订购地面几何形状的z索引。仅在多边形为常数且未指定高度或拉伸高度的情况下才有效  type:ConstantProperty
    zIndex: 0,
  }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Verdi之波形展示nWave

6.nWave 6.1 添加波形文件 1.打开nWave界面&#xff0c;具体操作如下&#xff1a; 2.正式添加波形&#xff0c;使用快捷键G或者点击以下图标&#xff0c;选择需要的信号。 也可以在 n Trace中选中信号后&#xff0c;鼠标中键拖拽&#xff0c;或者ctrlw进行添加&#xff1b; 6…

R和python中dataframe读取方式总结

首先我有一个如图所示的文件 如果在python中读取 import pandas as pd df pd.read_csv("./6group_count.csv",index_col0) df而在R中读取的方式如下 df read.csv("./6group_count.csv",row.names 1)

MySQL---索引

目录 一、索引的分类 二、索引的底层原理是什么&#xff1f; 2.1、Innodb和MyIsAM两种引擎搜索数据时候的区别&#xff1a; 2.2、为什么MySQL&#xff08;MyIsAM、Innodb&#xff09;索引选择B树而不是B树呢&#xff1f; 2.3、Innodb的主键索引和二级索引&#xff08;辅助…

【Ajax】笔记-Ajax案例准备与请求基本操作

案例准备HTML 按钮div <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>AJAX GET 请求</title&g…

2D、3D机器视觉各有优势与局限,融合应用将成工业领域生产新方式

在智能制造的浪潮中&#xff0c;制造行业生产线亟需转型升级&#xff0c;为国内机器视觉市场释放出了惊人的机器视觉技术及产品需求。在自动化工业质量控制和在线检测领域&#xff0c;2D机器视觉与3D机器视觉都具有重要的作用。那在机器视觉自动化场景中该如何选择合适的机器视…

python 乘法口诀

下面是一个用Python打印乘法口诀表的代码&#xff1a; print("乘法口诀表:")for i in range(1, 10):for j in range(1, i1):print(f"{j} {i} {i*j}", end"\t")print()

Blazor前后端框架Known-V1.2.4

V1.2.4 Known是基于C#和Blazor开发的前后端分离快速开发框架&#xff0c;开箱即用&#xff0c;跨平台&#xff0c;一处代码&#xff0c;多处运行。 Gitee&#xff1a; https://gitee.com/known/KnownGithub&#xff1a;https://github.com/known/Known 概述 基于C#和Blazor…

【图像处理】Python判断一张图像是否亮度过低,图片模糊判定

文章目录 亮度判断模糊判断 亮度判断 比如&#xff1a; 直方图&#xff1a; 代码&#xff1a; 这段代码是一个用于判断图像亮度是否过暗的函数is_dark&#xff0c;并对输入的图像进行可视化直方图展示。 首先&#xff0c;通过import语句导入了cv2和matplotlib.pyplot模块…

Element-Plus搭建CMS页面结构 引入第三方图标库iconfont(详细)

Element-Plus组件库使用 element plus组件库是由饿了么前端团队专门针对vue框架开发的组件库&#xff0c;专门用于电脑端网页的。因为里面集成了很多组件&#xff0c;所以使用他可以非常快速的帮我们实现网站的开发。 安装&#xff1a; npm install element-plus --save 引入…

jenkins 采用ssh方式连接gitlab连接不上

一、gitlab 添加jenkins服务器的公钥 jenkins 生成秘钥命令 ssh-keygen -t rsa2.jenkins 秘钥地址&#xff1a; cd /root/.ssh3.复制公钥 到gitlab 添加 cat id_rsa_pub4.添加私钥到jenkins cat id_rsa5.绑定&#xff08;顺利的话到这里就结束了&#xff09; &#xff0…

Linux下Lua和C++交互

前言 lua&#xff08;wiki 中文 官方社区&#xff1a;lua-users&#xff09;是一门开源、简明、可扩展且高效的弱类型解释型脚本语言。 由于其实现遵循C标准&#xff0c;它几乎能在所有的平台&#xff08;windows、linux、MacOS、Android、iOS、PlayStation、XBox、wii等&…

【条件与循环】——matlab入门

目录索引 if&#xff1a;else与elseif&#xff1a; for&#xff1a; if&#xff1a; if 条件语句块 endelse与elseif&#xff1a; if 条件代码块 elseif 条件代码块 else 代码块 endfor&#xff1a; for 条件循环体 end在matlab里面类似的引号操作都是包头又包尾的。上面的c…

postman测试接口出现404

postman测试接口出现404 1.用postman调试接口的过程中&#xff0c;出现404的情况&#xff0c;但是接口明明已调到了&#xff0c;而且数据也已经存入数据库了&#xff0c;这让我感到很疑惑。看网上的解决办法检查了我的路径&#xff0c;提交方式、参数类型等都是正确的&#xf…

安装adobe系列产品,提示错误代码81解决办法

安装adobe系列软件&#xff0c;如Photoshop、Premiere Pro、Illustrator等时&#xff0c;出现如下图提示错误代码81&#xff0c;如何解决呢&#xff1f;一起来看看。 解决方法一 (重启电脑等待5分钟再安装&#xff01;) 解决方法二 应用程序中打开Adobe Creative Cloud 点击…

Linux系统终端窗口ctrl+c,ctrl+z,ctrl+d的区别

时常在Linux系统上&#xff0c;执行某命令停不下来&#xff0c;就这几个ctrl组合键按来按去&#xff0c;今天稍微总结下具体差别&#xff0c;便于以后linux系统运维操作 1、ctrlc强制中断程序&#xff0c;相应进程会被杀死&#xff0c;中断进程任务无法恢复执行 2、ctrlz暂停正…

【运维工程师学习】Centos中MySQL替换MariaDB

【运维工程师学习】Centos8中MySQL替换MariaDB 1、查看已有的mysql2、MySQL官网tar包下载3、找到下载路径解压4、移动解压后的文件夹到/usr/local/mysql5、创建data文件夹&#xff0c;一般用于存放数据库文件数据6、创建用户组7、更改用户文件夹权限8、生成my.cnf文件9、编辑my…

ZooKeeper ZAB

文章首发地址 在接收到一个写请求操作后&#xff0c;追随者会将请求转发给群首&#xff0c;群首将探索性地执行该请求&#xff0c;并将执行结果以事务的方式对状态更新进行广播。一个事务中包含服务器需要执行变更的确切操作&#xff0c;当事务提交时&#xff0c;服务器就会将这…

23家企业推出昇腾AI系列新品 覆盖云、边、端智能硬件

[中国&#xff0c;上海&#xff0c;2023年7月6日] 昇腾人工智能产业高峰论坛在上海举办。论坛现场&#xff0c;大模型联合创新启动&#xff0c;26家行业领军企业、科研院所与华为将共同基于昇腾AI进行基础大模型与行业大模型应用创新。同时&#xff0c;华为携手伙伴联合发布昇腾…

数据从发出到接收的细节介绍{封装与解封装}

系列文章目录 数通王国历险记&#xff08;5&#xff09; 目录 前言 一&#xff0c;数据封装的全过程 1.1&#xff0c;应用层的封装形式 1.2&#xff0c;传输层的封装形式 理解&#xff1a; 1.3&#xff0c;网络层的封装形式 理解&#xff1a; 1.4&#xff0c;数据链路层…

IDEA设置自动导包功能

IDEA设置自动导包功能 选择File--Settings--Edotor-General-Auto Import&#xff0c;勾选上下图中的选项后点击 OK 即可。导包无忧~~ Add unambiguous imports on the fly&#xff1a;自动导入不明确的结构 Optimize imports on the fly&#xff1a;自动帮我们优化导入的包