vue+cesium示例:地形开挖(附源码下载)

news2025/6/8 0:50:45

基于cesium和vue绘制多边形实现地形开挖效果,适合学习Cesium与前端框架结合开发3D可视化项目。

demo源码运行环境以及配置

运行环境:依赖Node安装环境,demo本地Node版本:推荐v18+。

运行工具:vscode或者其他工具。

配置方式:下载demo源码,vscode打开,然后顺序执行以下命令:
(1)下载demo环境依赖包命令:npm install
(2)启动demo命令:npm run dev
(3)打包demo命令: npm run build

技术栈

Vue 3.5.13

Vite 6.2.0

Cesium 1.128.0

示例效果
在这里插入图片描述
核心源码

<template>
  <div id="cesiumContainer" class="cesium-container">
    <!-- 模型调整控制面板 -->
    <div class="control-panel">
      <div class="panel-header">
        <h3>地形开挖</h3>
      </div>
      <div class="panel-body">
        <div class="control-group">
          <button @click="startDrawPolygon">绘制多边形</button>
        </div>
        <div class="control-group">
          <button @click="clearDrawing">清除绘制</button>
        </div>
        <div class="control-group" v-if="drawingInstructions">
          <span>{{ drawingInstructions }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { onMounted, onUnmounted, ref } from 'vue';
import * as Cesium from 'cesium';

Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxZjhjYjhkYS1jMzA1LTQ1MTEtYWE1Mi0zODc5NDljOGVkMDYiLCJpZCI6MTAzNjEsInNjb3BlcyI6WyJhc2wiLCJhc3IiLCJhc3ciLCJnYyJdLCJpYXQiOjE1NzA2MDY5ODV9.X7tj92tunUvx6PkDpj3LFsMVBs_SBYyKbIL_G9xKESA';
// 声明Cesium Viewer实例
let viewer = null;
// 声明变量用于存储事件处理器和绘制状态
let handler = null;
let activeShapePoints = [];
let activeShape = null;
let floatingPoint = null;
let excavateInstance = null;

// 绘制状态提示
const drawingInstructions = ref('');

// 组件挂载后初始化Cesium
onMounted(async () => {
  const files = [
    "./excavateTerrain/excavateTerrain.js"
  ];
  loadScripts(files, function () {
    console.log("All scripts loaded");
    initMap();
  });
});
const loadScripts = (files, callback) => {
  // Make Cesium available globally for the scripts
  window.Cesium = Cesium;

  if (files.length === 0) {
    callback();
    return;
  }
  const file = files.shift();
  const script = document.createElement("script");
  script.onload = function () {
    loadScripts(files, callback);
  };
  script.src = file;
  document.head.appendChild(script);
};
const initMap = async () => {
  // 初始化Cesium Viewer
  viewer = new Cesium.Viewer('cesiumContainer', {
    // 基础配置
    animation: false, // 动画小部件
    baseLayerPicker: false, // 底图选择器
    fullscreenButton: false, // 全屏按钮
    vrButton: false, // VR按钮
    geocoder: false, // 地理编码搜索框
    homeButton: false, // 主页按钮
    infoBox: false, // 信息框 - 禁用点击弹窗
    sceneModePicker: false, // 场景模式选择器
    selectionIndicator: false, // 选择指示器
    timeline: false, // 时间轴
    navigationHelpButton: false, // 导航帮助按钮
    navigationInstructionsInitiallyVisible: false, // 导航说明初始可见性
    scene3DOnly: false, // 仅3D场景
    terrain: Cesium.Terrain.fromWorldTerrain(), // 使用世界地形
  });
  // 隐藏logo
  viewer.cesiumWidget.creditContainer.style.display = "none";
  viewer.scene.globe.enableLighting = true;
  // 禁用大气层和太阳
  viewer.scene.skyAtmosphere.show = false;
  //前提先把场景上的图层全部移除或者隐藏 
  // viewer.scene.globe.baseColor = Cesium.Color.BLACK; //修改地图蓝色背景
  viewer.scene.globe.baseColor = new Cesium.Color(0.0, 0.1, 0.2, 1.0); //修改地图为暗蓝色背景
  // 设置抗锯齿
  viewer.scene.postProcessStages.fxaa.enabled = true;
  // 清除默认底图
  viewer.imageryLayers.remove(viewer.imageryLayers.get(0));
  // 加载底图 - 使用更暗的地图服务
  const imageryProvider = await Cesium.ArcGisMapServerImageryProvider.fromUrl("https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer");
  viewer.imageryLayers.addImageryProvider(imageryProvider);
  // 设置默认视图位置 - 默认显示全球视图
  viewer.camera.setView({
    destination: Cesium.Cartesian3.fromDegrees(104.0, 30.0, 10000000.0), // 中国中部上空
    orientation: {
      heading: 0.0,
      pitch: -Cesium.Math.PI_OVER_TWO,
      roll: 0.0
    }
  });

  // 启用地形深度测试,确保地形正确渲染
  viewer.scene.globe.depthTestAgainstTerrain = true;
  // 清除默认地形
  // viewer.scene.terrainProvider = new Cesium.EllipsoidTerrainProvider({});
  // 开启帧率
  viewer.scene.debugShowFramesPerSecond = true;
}
// 开始绘制多边形
const startDrawPolygon = () => {
  // 清除之前的绘制
  clearDrawing();
  // 设置绘制提示
  drawingInstructions.value = '左键点击添加顶点,右键完成绘制';
  // 创建新的事件处理器
  handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  // 监听左键点击事件 - 添加顶点
  handler.setInputAction((click) => {
    // 获取点击位置的笛卡尔坐标
    const cartesian = viewer.scene.pickPosition(click.position);
    if (!Cesium.defined(cartesian)) {
      return;
    }
    // 将点添加到活动形状点数组
    activeShapePoints.push(cartesian);

    // 如果是第一个点,创建浮动点
    if (activeShapePoints.length === 1) {
      floatingPoint = createPoint(cartesian);
      // 创建动态多边形
      activeShape = createPolygon(activeShapePoints);
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

  // 监听鼠标移动事件 - 更新动态多边形
  handler.setInputAction((movement) => {
    if (activeShapePoints.length >= 1) {
      const cartesian = viewer.scene.pickPosition(movement.endPosition);
      if (!Cesium.defined(cartesian)) {
        return;
      }
      // 更新浮动点位置
      if (floatingPoint) {
        floatingPoint.position.setValue(cartesian);
      }
      // 更新动态多边形
      if (activeShape) {
        const positions = activeShapePoints.concat([cartesian]);
        activeShape.polygon.hierarchy = new Cesium.PolygonHierarchy(positions);
      }
    }
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

  // 监听右键点击事件 - 完成绘制
  handler.setInputAction(() => {
    if (activeShapePoints.length < 3) {
      // 至少需要3个点才能形成多边形
      drawingInstructions.value = '至少需要3个点才能形成多边形,请继续绘制';
      return;
    }
    // 完成绘制
    terminateShape();
    // 执行地形开挖
    performExcavation(activeShapePoints);
    // 清除绘制状态
    drawingInstructions.value = '绘制完成,地形已开挖';
    // 清除事件处理器
    handler.destroy();
    handler = null;
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
};

// 创建点实体
const createPoint = (position) => {
  return viewer.entities.add({
    position: position,
    point: {
      color: Cesium.Color.WHITE,
      pixelSize: 10,
      heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
    }
  });
};

// 创建多边形实体
const createPolygon = (positions) => {
  return viewer.entities.add({
    polygon: {
      hierarchy: new Cesium.PolygonHierarchy(positions),
      material: new Cesium.ColorMaterialProperty(Cesium.Color.WHITE.withAlpha(0.3)),
      outline: true,
      outlineColor: Cesium.Color.WHITE,
      // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
      // 关键属性:贴地模式
      clampToGround: true,
      // 禁用挤压高度
      // height: 0,
      // height: 0,
      // perPositionHeight: false,
      // classificationType: Cesium.ClassificationType.BOTH,
      // zIndex: 100
    }
  });
};

// 完成绘制形状
const terminateShape = () => {
  // 移除动态实体
  if (floatingPoint) {
    viewer.entities.remove(floatingPoint);
    floatingPoint = null;
  }
  if (activeShape) {
    viewer.entities.remove(activeShape);
    activeShape = null;
  }

  // 创建最终的多边形
  // if (activeShapePoints.length >= 3) {
  //   const finalPolygon = viewer.entities.add({
  //     polygon: {
  //       hierarchy: new Cesium.PolygonHierarchy(activeShapePoints),
  //       material: new Cesium.ColorMaterialProperty(Cesium.Color.GREEN.withAlpha(0.3)),
  //       outline: true,
  //       outlineColor: Cesium.Color.GREEN,
  //       height: 0,
  //       perPositionHeight: false,
  //       classificationType: Cesium.ClassificationType.BOTH,
  //       zIndex: 100
  //     }
  //   });
  // }
};

// 执行地形开挖
const performExcavation = (positions) => {
  // 如果已有开挖实例,先尝试清除
  if (excavateInstance) {
    try {
      // 重置地形开挖
      viewer.scene.globe.clippingPlanes = undefined;
      viewer.entities.removeById("entityDM");
      viewer.entities.removeById("entityDMBJ");
    } catch (error) {
      console.error("清除之前的开挖失败", error);
    }
  }

  // 创建新的地形开挖实例
  excavateInstance = new excavateTerrain(viewer, {
    positions: positions,
    height: 50,
    bottom: "./excavateTerrain/excavationregion_side.jpg",
    side: "./excavateTerrain/excavationregion_top.jpg",
  });
};

// 清除绘制
const clearDrawing = () => {
  // 清除事件处理器
  if (handler) {
    handler.destroy();
    handler = null;
  }

  // 清除动态实体
  if (floatingPoint) {
    viewer.entities.remove(floatingPoint);
    floatingPoint = null;
  }
  if (activeShape) {
    viewer.entities.remove(activeShape);
    activeShape = null;
  }

  // 清空点数组
  activeShapePoints = [];

  viewer.entities.removeAll();

  // 清除绘制提示
  drawingInstructions.value = '';

  // 重置地形开挖
  if (excavateInstance) {
    try {
      viewer.scene.globe.clippingPlanes = undefined;
      viewer.entities.removeById("entityDM");
      viewer.entities.removeById("entityDMBJ");
      excavateInstance = null;
    } catch (error) {
      console.error("清除地形开挖失败", error);
    }
  }
};

// 组件卸载前清理资源
onUnmounted(() => {
  clearDrawing();
  if (viewer) {
    viewer.destroy();
    viewer = null;
  }
});
</script>

<style scoped>
.cesium-container {
  width: 100%;
  height: 100vh;
  margin: 0;
  padding: 0;
  overflow: hidden;
  position: relative;
}

.control-panel {
  position: absolute;
  top: 20px;
  left: 20px;
  width: 300px;
  background-color: rgba(38, 38, 38, 0.85);
  border-radius: 8px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
  color: white;
  z-index: 1000;
  overflow: hidden;
  transition: all 0.3s ease;
}

.panel-header {
  background-color: rgba(0, 0, 0, 0.5);
  padding: 10px 15px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.panel-header h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
}

.panel-body {
  padding: 15px;
}

.control-group {
  margin-bottom: 15px;
}

.control-group label {
  display: block;
  margin-bottom: 5px;
  font-size: 14px;
}

.control-group input[type="range"] {
  width: 100%;
  margin-bottom: 5px;
  background-color: rgba(255, 255, 255, 0.2);
  border-radius: 4px;
}

.control-group span {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.7);
  display: block;
  margin-top: 5px;
  line-height: 1.4;
}

.control-group span {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.7);
}

.control-group button {
  background-color: #4285f4;
  color: white;
  border: none;
  padding: 8px 15px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  width: 100%;
  transition: background-color 0.3s ease;
}

.control-group button:hover {
  background-color: #3367d6;
}
</style>

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

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

相关文章

升级:用vue canvas画一个能源监测设备和设备的关系监测图!

用vue canvas画一个能源电表和设备的监测图-CSDN博客 上一篇文章&#xff0c;我是用后端的数据来画出监测图。这次我觉的&#xff0c;用前端来控制数据&#xff0c;更爽。 本期实现功能&#xff1a; 1&#xff0c;得到监测设备和设备的数据&#xff0c;然后进行存库 2&…

深入理解 transforms.Normalize():PyTorch 图像预处理中的关键一步

深入理解 transforms.Normalize()&#xff1a;PyTorch 图像预处理中的关键一步 在使用 PyTorch 进行图像分类、目标检测等深度学习任务时&#xff0c;我们常常会在数据预处理部分看到如下代码&#xff1a; python复制编辑transform transforms.Compose([transforms.ToTensor…

爆炸仿真的学习日志

今天学习了一下【Workbench LS-DYNA中炸药在空气中爆炸的案例-哔哩哔哩】 https://b23.tv/kmXlN29 一开始 如果你的 ANSYS Workbench 工具箱&#xff08;Toolbox&#xff09;里 只有 SPEOS&#xff0c;即使尝试了 右键刷新、重置视图、显示全部 等方法仍然没有其他分析系统&a…

[华为eNSP] OSPF综合实验

目录 配置流程 画出拓扑图、标注重要接口IP 配置客户端IP 配置服务端IP 配置服务器服务 配置路由器基本信息&#xff1a;名称和接口IP 配置路由器ospf协议 测试结果 通过配置OSPF路由协议&#xff0c;实现跨多路由器的网络互通&#xff0c;并验证终端设备的访问能力。 …

完美搭建appium自动化环境

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 桌面版appium提供可视化操作appium主要功能的使用方式&#xff0c;对于初学者非常适用。 如何在windows平台安装appium桌面版呢&#xff0c;大体分两个步骤&…

c++中的输入输出流(标准IO,文件IO,字符串IO)

目录 &#xff08;1&#xff09;I/O概述 I/O分类 不同I/O的继承关系 不同I/O对应的头文件 &#xff08;2&#xff09;iostream 标准I/O流 iostream头文件中的IO流对象 iostream头文件中重载了<<和>> 缓冲区示意图 标准输入流 cin用法 cin&#xff1a;按空…

2025年渗透测试面试题总结-ali 春招内推电话1面(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 ali 春招内推电话1面 一、Web安全核心理解 二、熟悉漏洞及防御方案 三、UDF提权原理与防御 四、XSS Fuzz…

Reactor和Proactor

reactor的重要组件包括&#xff1a;Event事件、Reactor反应堆、Demultiplex事件分发器、Eventhandler事件处理器。

黄晓明新剧《潜渊》定档 失忆三面间谍开启谍战新维度

据悉&#xff0c;黄晓明领衔主演的谍战剧《潜渊》已于近日正式定档6月9日&#xff0c;该剧以“失忆三面间谍”梁朔为核心&#xff0c;打破传统谍战剧的框架和固有角度&#xff0c;以一种特别的视角将悬疑感推向极致。剧中&#xff0c;梁朔因头部受伤失去记忆&#xff0c;陷入身…

物联网嵌入式开发实训室建设方案探讨(高职物联网应用技术专业实训室建设)

一、建设背景与目标 在当今数字化时代&#xff0c;物联网技术正以前所未有的速度改变着人们的生活和工作方式。从智能家居到工业自动化&#xff0c;从智能交通到环境监测&#xff0c;物联网的应用场景无处不在。根据市场研究机构的数据&#xff0c;全球物联网设备连接数量预计…

集成学习三种框架

集成学习通过组合多个弱学习器构建强学习器&#xff0c;常见框架包括Bagging&#xff08;装袋&#xff09;、Boosting&#xff08;提升&#xff09; 和Stacking&#xff08;堆叠&#xff09; 一、Bagging&#xff08;自助装袋法&#xff09; 核心思想 从原始数据中通过有放回…

在UI界面内修改了对象名,在#include “ui_mainwindow.h“没更新

​原因​&#xff1a;未重新编译UI文件​​ Qt的UI文件&#xff08;.ui&#xff09;需要通过​​uic工具&#xff08;Qt的UI编译器&#xff09;​​生成对应的ui_*.h头文件。如果你在Qt Designer中修改了对象名&#xff0c;但没有​​重新构建&#xff08;Rebuild&#xff09;…

Neovim - 常用插件,提升体验(三)

文章目录 nvim-treelualineindent-blanklinetelescopegrug-far nvim-tree 官方文档&#xff1a;https://github.com/nvim-tree/nvim-tree.lua 以前我们都是通过 :e 的方式打开一个 buffer&#xff0c;但是这种方式需要记忆文件路径&#xff0c;因此这里可以通过 nvim-tree 插…

SOC-ESP32S3部分:31-ESP-LCD控制器库

飞书文档https://x509p6c8to.feishu.cn/wiki/Syy3wsqHLiIiQJkC6PucEJ7Snib ESP 系列芯片可以支持市场上常见的 LCD&#xff08;如 SPI LCD、I2C LCD、并行 LCD (Intel 8080)、RGB/SRGB LCD、MIPI DSI LCD 等&#xff09;所需的各种时序。esp_lcd 控制器为上述各类 LCD 提供了一…

【云安全】以Aliyun为例聊云厂商服务常见利用手段

目录 OSS-bucket_policy_readable OSS-object_public_access OSS-bucket_object_traversal OSS-Special Bucket Policy OSS-unrestricted_file_upload OSS-object_acl_writable ECS-SSRF 云攻防场景下对云厂商服务的利用大同小异&#xff0c;下面以阿里云为例 其他如腾…

读文献先读图:GO弦图怎么看?

GO弦图&#xff08;Gene Ontology Chord Diagram&#xff09;是一种用于展示基因功能富集结果的可视化工具&#xff0c;通过弦状连接可以更直观的展示基因与GO term&#xff08;如生物过程、分子功能等&#xff09;之间的关联。 GO弦图解读 ①内圈连线表示基因和生物过程之间的…

怎么让大语言模型(LLMs)自动生成和优化提示词:APE

怎么让大语言模型(LLMs)自动生成和优化提示词:APE https://arxiv.org/pdf/2211.01910 1. 研究目标:让机器自己学会设计提示词 问题:大语言模型(如GPT-3)很强大,但需要精心设计的“提示词”才能发挥最佳效果。过去靠人工设计提示词,费时费力,还可能因表述差异导致模…

实现单例模式的常见方式

前言 java有多种设计模式&#xff0c;如下图所示&#xff1a; 单例模式它确保一个类只有一个实例&#xff0c;并提供一个全局访问点。 1、单例模式介绍 1.1、使用原因 为什么要使用单例模式&#xff1f; 1. 控制资源访问 核心价值&#xff1a;确保对共享资源&#xff08;如…

day20 leetcode-hot100-38(二叉树3)

226. 翻转二叉树 - 力扣&#xff08;LeetCode&#xff09; 1.广度遍历 思路 这题目很简单&#xff0c;就是交换每个节点的左右子树&#xff0c;也就是相当于遍历到某个节点&#xff0c;然后交换子节点即可。 具体步骤 &#xff08;1&#xff09;创建队列&#xff0c;使用广…

OpenVINO环境配置--OpenVINO安装

TOC环境配置–OpenVINO安装 本节内容 OpenVINO 支持的安装方式有很多种&#xff0c;每一种操作系统以及语言都有对应的安装方法&#xff0c;在官网上有很详细的教程&#xff1a;   我们可以根据自己的需要&#xff0c;来点选环境配置和安装方法&#xff0c;然后网页会给出正…