vue3 + potree 渲染点云数据记录

potree 官网示例
在这里插入图片描述

前置条件:

potree 无法直接加载 LAS,LCD,PLY等格式的点云文件,
需要通过 PotreeConverte 转换为 octree 数据格式,前端渲染中加载转换后的 json 格式

格式转换方向
.las ---- potreeConverter ----> .json

结合 vue3 使用

1、模板 html 引入 potree 官网示例中的所有 js 依赖

potree 示例中的 js 依赖如下:
在这里插入图片描述
确保能在 vue 项目中,window 中有 potree

2、创建渲染视图区域组件

在这里插入图片描述
组件挂载后初始化 viewer

// 全局常量
const Potree = window.Potree;
const THREE = window.THREE;
const i18next = window.i18next;
const TWEEN = window.TWEEN;const viewer: Ref = ref(null); // viewer 容器// 初始化视图容器const initViewer = () => {if (!Potree || viewer.value) return;let viewerArgs = {noDragAndDrop: true,};viewer.value = new Potree.Viewer(document.getElementById(`potree_render_area${areaIdIndex}`),viewerArgs,);// 创建原始引用const Viewer = toRaw(viewer.value)// 设置裁剪属性Viewer.setClipTask(Potree.ClipTask.SHOW_INSIDE);Viewer.loadGUI();// 禁用 edlViewer.setEDLEnabled(false);// 设置视场角Viewer.setFOV(60);// viewer最大可视点云数量固定Viewer.setPointBudget(50 * 1000 * 1000);Viewer.loadSettingsFromURL();// 设置天背景Viewer.setBackground('black');Viewer.setDescription('');Viewer.setMinNodeSize(0);Viewer.setControls(Viewer.earthControls);// 官方 自带 GUi// this.viewer.loadGUI(() => {//   this.viewer.setLanguage('zh');//   window.$('#menu_tools').next().show();//   window.$('#menu_clipping').next().show();//   this.viewer.toggleSidebar();// });// 注册 Sidebarsidebar = new Sidebar(Viewer)sidebar.init()console.log('viewer initialized');};onMounted(() => {nextTick(() => {// 挂载后初始化视图initViewer();});});
3、加载点云数据
      Potree.loadPointCloud(path).then((e: any) => {// PointCloudOctree实例// 该实例有唯一的uuid,可以保存起来方便后续对该实例进行操作let pointcloud = e.pointcloud;// console.log(pointcloud)appStore.setOriginFileUuid(fileId, pointcloud.uuid)// 材质let material = pointcloud.material;// name赋值// pointcloud.name = 'fileName';// 检查是否有彩色信息let hasRGBA =pointcloud.getAttributes().attributes.find((a: any) => a.name === 'rgba') !== undefined;if (hasRGBA) {material.activeAttributeName = 'rgba';} else {material.activeAttributeName = 'color';}// 点云点大小material.size = 1;material.minSize = 1;material.maxSize = 16;material.pointSizeType = Potree.PointSizeType.FIXED;// 设置高程渐变方案material.gradient = Potree.Gradients.TURBO;// 将点云数据添加到场景viewer.value.scene.addPointCloud(pointcloud);viewer.value.setBackground('black');// 设置相机viewer.value.zoomTo(e.pointcloud);// 设置控制器// viewer.value.setControls(viewer.value.earthControls);// 设置视场角viewer.value.setFOV(60);// 设置最小节点大小,值越小越清晰viewer.value.setMinNodeSize(0);// 打开高质量渲染viewer.value.useHQ = false;// 点云数量fetch(path).then((response) => response.json()).then((jsonData) => {// name赋值pointcloud.name = jsonData.name;// 点云数量// 根据导入的点云数据来设置对应的点云数量// viewer.value.setPointBudget(jsonData.points);// 设置点云数量pointcloud.pointBudget = jsonData.points;// 设置初始视角viewer.value.scene.view.setView(new THREE.Vector3(6.44, -6.70, 5.52), new THREE.Vector3(-0.53, 0.55, -0.63));viewer.value.scene.view.lookAt(-0.53, 0.55, -0.63);});})
4、结合官网提供的 工具栏代码,进行其他深入操作
export class Sidebar {viewer: anymeasuringTool: anyprofileTool: anyvolumeTool: anyconstructor(viewer: any) {this.viewer = viewer;this.measuringTool = viewer.measuringTool;this.profileTool = viewer.profileTool;this.volumeTool = viewer.volumeTool;}initScene() {// 监听点云追加let onPointCloudAdded = (e: any) => {let pointcloud: any = e.pointcloud;console.log('initScene--pointcloud------>')console.log(pointcloud)SceneObj.pointclouds.push(pointcloud)// let cloudIcon = `${Potree.resourcePath}/icons/cloud.svg`;// let node = createNode(pcID, pointcloud.name, cloudIcon, pointcloud);pointcloud.addEventListener("visibility_changed", () => {console.log(pointcloud.visible)if (pointcloud.visible) {// tree.jstree('check_node', node);} else {// tree.jstree('uncheck_node', node);}});};// 监听测量对象let onMeasurementAdded = (e: any) => {let measurement = e.measurement;console.log('添加测量对象')// console.log(measurement);nextTick(() => {setTimeout(() => {const meItem = {checked: true,label: measurement.name,id: measurement.uuid,}console.log(e.scene.measurements);// 追加测量对象数appStore.addMeasurementsTreeData(meItem, measurement.uuid)// let icon = Utils.getMeasurementIcon(measurement);// createNode(measurementID, measurement.name, icon, measurement);}, 0);})};// 监听体积增加let onVolumeAdded = (e: any) => {let volume = e.volume;// let icon = Utils.getMeasurementIcon(volume);// let node = createNode(measurementID, volume.name, icon, volume);volume.addEventListener("visibility_changed", () => {console.log(volume)if (volume.visible) {// tree.jstree('check_node', node);} else {// tree.jstree('uncheck_node', node);}});};// 监听高度坡面增加let onProfileAdded = (e: any) => {let profile = e.profile;// let icon = Utils.getMeasurementIcon(profile);// createNode(measurementID, profile.name, icon, profile);};// 监听标注事件let onAnnotationAdded = (e: any) => {let annotation = e.annotation;// let annotationIcon = `${Potree.resourcePath}/icons/annotation.svg`;// let parentID = this.annotationMapping.get(annotation.parent);// let annotationID = createNode(parentID, annotation.title, annotationIcon, annotation);// this.annotationMapping.set(annotation, annotationID);// annotation.addEventListener("annotation_changed", (e) => {//   let annotationsRoot = $("#jstree_scene").jstree().get_json("annotations");//   let jsonNode = annotationsRoot.children.find(child => child.data.uuid === annotation.uuid);//   $.jstree.reference(jsonNode.id).rename_node(jsonNode.id, annotation.title);// });};// 相机动作let onCameraAnimationAdded = (e: any) => {const animation = e.animation;// const animationIcon = `${Potree.resourcePath}/icons/camera_animation.svg`;// createNode(otherID, "animation", animationIcon, animation);};// 向导图let onOrientedImagesAdded = (e: any) => {const images = e.images;// const imagesIcon = `${Potree.resourcePath}/icons/picture.svg`;// const node = createNode(imagesID, "images", imagesIcon, images);images.addEventListener("visibility_changed", () => {console.log('images.visible', images.visible)if (images.visible) {// tree.jstree('check_node', node);} else {// tree.jstree('uncheck_node', node);}});};// img 360let onImages360Added = (e: any) => {const images = e.images;// const imagesIcon = `${Potree.resourcePath}/icons/picture.svg`;// const node = createNode(imagesID, "360° images", imagesIcon, images);images.addEventListener("visibility_changed", () => {console.log('360images.visible', images.visible)if (images.visible) {// tree.jstree('check_node', node);} else {// tree.jstree('uncheck_node', node);}});};// 地质const onGeopackageAdded = (e: any) => {const geopackage = e.geopackage;// const geopackageIcon = `${Potree.resourcePath}/icons/triangle.svg`;// const tree = $(`#jstree_scene`);// const parentNode = "vectors";// for (const layer of geopackage.node.children) {//   const name = layer.name;//   let shpPointsID = tree.jstree('create_node', parentNode, {//     "text": name,//     "icon": geopackageIcon,//     "object": layer,//     "data": layer,//   },//     "last", false, false);//   tree.jstree(layer.visible ? "check_node" : "uncheck_node", shpPointsID);// }};this.viewer.scene.addEventListener("pointcloud_added", onPointCloudAdded);this.viewer.scene.addEventListener("measurement_added", onMeasurementAdded);this.viewer.scene.addEventListener("profile_added", onProfileAdded);this.viewer.scene.addEventListener("volume_added", onVolumeAdded);this.viewer.scene.addEventListener("camera_animation_added", onCameraAnimationAdded);this.viewer.scene.addEventListener("oriented_images_added", onOrientedImagesAdded);this.viewer.scene.addEventListener("360_images_added", onImages360Added);this.viewer.scene.addEventListener("geopackage_added", onGeopackageAdded);this.viewer.scene.addEventListener("polygon_clip_volume_added", onVolumeAdded);this.viewer.scene.annotations.addEventListener("annotation_added", onAnnotationAdded);/*** 删除操作*/// let onMeasurementRemoved = (e) => {//   let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");//   let jsonNode = measurementsRoot.children.find(child => child.data.uuid === e.measurement.uuid);//   tree.jstree("delete_node", jsonNode.id);// };// let onVolumeRemoved = (e) => {//   let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");//   let jsonNode = measurementsRoot.children.find(child => child.data.uuid === e.volume.uuid);//   tree.jstree("delete_node", jsonNode.id);// };// let onPolygonClipVolumeRemoved = (e) => {//   let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");//   let jsonNode = measurementsRoot.children.find(child => child.data.uuid === e.volume.uuid);//   tree.jstree("delete_node", jsonNode.id);// };// let onProfileRemoved = (e) => {//   let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");//   let jsonNode = measurementsRoot.children.find(child => child.data.uuid === e.profile.uuid);//   tree.jstree("delete_node", jsonNode.id);// };// this.viewer.scene.addEventListener("measurement_removed", onMeasurementRemoved);// this.viewer.scene.addEventListener("volume_removed", onVolumeRemoved);// this.viewer.scene.addEventListener("polygon_clip_volume_removed", onPolygonClipVolumeRemoved);// this.viewer.scene.addEventListener("profile_removed", onProfileRemoved);// {//   let annotationIcon = `${Potree.resourcePath}/icons/annotation.svg`;//   this.annotationMapping = new Map();//   this.annotationMapping.set(this.viewer.scene.annotations, annotationsID);//   this.viewer.scene.annotations.traverseDescendants(annotation => {//     let parentID = this.annotationMapping.get(annotation.parent);//     let annotationID = createNode(parentID, annotation.title, annotationIcon, annotation);//     this.annotationMapping.set(annotation, annotationID);//   });// }const scene = this.viewer.scene;for (let pointcloud of scene.pointclouds) {onPointCloudAdded({ pointcloud: pointcloud });}for (let measurement of scene.measurements) {onMeasurementAdded({ measurement: measurement });}for (let volume of [...scene.volumes, ...scene.polygonClipVolumes]) {onVolumeAdded({ volume: volume });}for (let animation of scene.cameraAnimations) {onCameraAnimationAdded({ animation: animation });}for (let images of scene.orientedImages) {onOrientedImagesAdded({ images: images });}for (let images of scene.images360) {onImages360Added({ images: images });}for (const geopackage of scene.geopackages) {onGeopackageAdded({ geopackage: geopackage });}for (let profile of scene.profiles) {onProfileAdded({ profile: profile });}// {//   createNode(otherID, "Camera", null, new Camera());// }this.viewer.addEventListener("scene_changed", (e: any) => {// propertiesPanel.setScene(e.scene);e.oldScene.removeEventListener("pointcloud_added", onPointCloudAdded);e.oldScene.removeEventListener("measurement_added", onMeasurementAdded);e.oldScene.removeEventListener("profile_added", onProfileAdded);e.oldScene.removeEventListener("volume_added", onVolumeAdded);e.oldScene.removeEventListener("polygon_clip_volume_added", onVolumeAdded);// e.oldScene.removeEventListener("measurement_removed", onMeasurementRemoved);e.scene.addEventListener("pointcloud_added", onPointCloudAdded);e.scene.addEventListener("measurement_added", onMeasurementAdded);e.scene.addEventListener("profile_added", onProfileAdded);e.scene.addEventListener("volume_added", onVolumeAdded);e.scene.addEventListener("polygon_clip_volume_added", onVolumeAdded);// e.scene.addEventListener("measurement_removed", onMeasurementRemoved);});}init() {this.initScene();}
}

参考学习:potree 使用手册
鸣谢作者;

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

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

相关文章

算法练习第15天|226.翻转二叉树

226.翻转二叉树 力扣链接https://leetcode.cn/problems/invert-binary-tree/description/ 题目描述: 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 示例 1: 输入:root [4,2,7,1,3,6,9] 输出&am…

关于无人机,你必须知道的事!!(科技篇)

飞行器的五脏六腑 电机:无人机的动力单元,俗称“马达”。通过电机转动来驱动螺旋桨旋转,最终让飞机上天。 电调:无人机的动力单元,是接收油门信号并调整电机转速的控制枢纽,俗称电机的“黑屋调教师” 飞…

探索计算机的小数世界:从二进制到无限精度

前言 不知道你是否和我一样,遇到这个情况。在刚开始学习编程。计算0.3-0.20.1这个小学都知道,但是如果你在计算机执行,发现结果并不是0.1 。这个时候会疑问到底是为什么呢。 System.out.println("0.3-0.2"(0.3-0.2)); 0.3-0.20.09…

Linux中home、var、opt、data、swap、根目录空间怎么分配

#Linux中home、var、opt、data、swap、根目录空间怎么分配 在Linux系统中,/home、/var、/opt和/data是几个常见的目录,它们通常用于存储不同类型的文件和数据。合理分配这些目录的空间对于系统的性能和数据管理非常重要。以下是一些关于如何分配这些目录…

算法基础--时间/空间复杂度

目录 前言一、时间复杂度1.1 时间复杂度公式1.2 常见的时间复杂度量级1.3 时间复杂度量级示例1.3.1 常数阶O(1)1.3.2 对数阶O(logN)1.3.3 线性阶O(n)1.3.4 线性对数阶O(nlogN)1.3.5 平方阶O(n)1.3.6 立方阶O(n)、K次方阶O(n^k) 二、空间复杂度2.1 O(1)2.2 O(n)2.3 O(n) 三、常用…

API管理平台:你用的到底是哪个?

Apifox是不开源的,在github的项目只是readme文件,私有化需要付费。当然saas版目前是免费使用的。 一、Swagger 为了让Swagger界面更加美观,有一些项目可以帮助你实现这一目标。以下是一些流行的项目,它们提供了增强的UI和额外的功…

Qt 容器类整理与使用

Qt提供了哪些容器类 Qt 提供了丰富的容器类,这些容器类主要用于存储和管理数据,按照其内部组织结构和功能特性,大致可分为顺序容器和关联容器两大类:顺序容器: QList - 动态数组,支持快速的头部和尾部插入…

OSCP靶场-- Sybaris

OSCP靶场–Sybaris 考点(redis MODULE LOAD命令执行) 1.nmap扫描 ## ┌──(root㉿kali)-[~/Desktop] └─# nmap 192.168.158.93 -sV -sC -Pn --min-rate 2500 -p- Starting Nmap 7.92 ( https://nmap.org ) at 2024-04-11 04:24 EDT Nmap scan report for 192.168.158.93…

照片转漫画的软件有吗?分享4款热门的软件!

在数字化时代,我们总是追求新鲜、有趣、创意十足的方式来展现自我。其中,将普通照片转化为漫画风格的图像已成为许多年轻人的新宠。这种既能保留原照片中的人物特征,又能赋予其独特艺术气息的方式,让许多人趋之若鹜。那么&#xf…

PHP7垃圾回收算法

前提 本文为了梳理PHP GC工作流程,所以从引用计数、部分标记清除算法做引子,然后介绍PHP GC工作流程,最后介绍性能更高的GC算法 引用计数 概述 引用计数算法中引入了一个概念计数器。计数器代表对象被引用的次数 基本原理 为了记录一个对象有没有被…

APB协议中的PSEL、PSTROB、PENABLE、PREADY这4个信号的作用与用法

在详细探讨APB(Advanced Peripheral Bus)协议中的这四个信号之前,让我们先简单了解一下APB协议。APB是ARM公司的一种简单但高效的总线协议,主要用于低带宽和低性能需求的外围设备连接,如定时器、接口控制、UART等。它是…

微信公众号第三方平台-公众号扫码授权接入代运营

文章目录 接入目的效果展示技术积累如何成为服务商如何搭建第三方后端服务传统模式V云服务模式如何完成商家授权授权逻辑介绍 环境准备注册开发者平台-个人类型 传统模式后端代码接收公众号个人三方平台的票据根据票据获取三方平台访问令牌根据访问令牌获取预授权码通过预授权码…

OJ 【难度1】【Python】完美字符串 扫雷 A-B数对 赛前准备 【C】精密计时

完美字符串 题目描述 你可能见过下面这一句英文: "The quick brown fox jumps over the lazy dog." 短短的一句话就包含了所有 2626 个英文字母!因此这句话广泛地用于字体效果的展示。更短的还有: "The five boxing wizards…

[Linux] 权限控制命令 chmod、chown和chgrp

文章目录 chmodchownchgrp chmod 在Linux系统中,root用户可以使用chmod命令来修改文件的权限,并且root用户也可以授权普通用户来执行chmod命令。要将权限授予普通用户修改一个文件的权限,可以使用以下步骤: 使用root用户登录到L…

网络——初识网络

在现如今,网络已经成了一种基础设施,大到国家,小到个人,网络已经充斥在我们每个人的身 边,如果一个人突然失去了网络,那么它的生活或多或少会出现一些不方便的地方,网络现在已 经伴随着我们的吃…

axios-mock-adapter使用

文章目录 1. 安装 axios-mock-adapter2. 引入所需的库3. 创建一个模拟适配器实例4. 定义模拟响应5. 在你的代码中使用 axios6. 在测试或开发完成后清理模拟 axios-mock-adapter 是一个用于模拟 axios HTTP 请求的库。它允许你在测试或开发过程中,为 axios 实例提供…

Solana主网使用自定义的RPC进行转账

1、引言 如果用 browser 连接主网的 RPC server 会收到 error code 403 message 為 Access forbidden, contact your app developer or supportrpcpool.com. 错误,因为主网的 RPC server 会检查 HTTP Header 如果判断出來是 browser 就会报告 403 錯誤。 要解決这…

【LeetCode热题100】53. 最大子数组和(数组)

一.题目要求 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组 是数组中的一个连续部分。 二.题目难度 中等 三.输入样例 示例 1: 输入:nu…

N 皇后 - 蓝桥杯?-Lua 中文代码解题第6题

n 皇后问题 研究的是如何将 n 个皇后放置在 n n 的棋盘上,并且使皇后彼此之间不能相互攻击。 给你一个整数 n ,返回 n 皇后问题 不同的解决方案的数量。 示例 1: 输入:n 4 输出:2 解释:如上图所示&…

吴恩达2022机器学习专项课程(一) 5.2 向量化(1) 5.3 向量化(2)

问题预览/关键词 什么是向量化?向量化的好处是?如何向量化多元线性回归函数的参数?如何在Python中向量化参数?计算机底层是如何计算向量化的?向量化示例 笔记 1.向量化 一种在数学和计算中广泛使用的概念&#xff…