多楼层室内定位可视化 Demo(A*路径避障)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>多楼层室内定位可视化 Demo(A*避障)</title>
<style>body { margin: 0; overflow: hidden; }#layerControls { position: absolute; top: 10px; left: 10px; z-index: 100; background: rgba(255,255,255,0.9); padding: 10px; border-radius: 5px; }#layerControls button { display: block; margin-bottom: 5px; width: 120px; }
</style>
</head>
<body>
<div id="layerControls"><button data-layer="all">显示全部</button><button data-layer="0">楼层 1</button><button data-layer="1">楼层 2</button><button data-layer="2">楼层 3</button>
</div><script src="https://cdn.jsdelivr.net/npm/three@0.125.2/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.125.2/examples/js/controls/OrbitControls.js"></script>
<script>
// ==================== THREE.js 基础 ====================
let scene, camera, renderer, controls;
let floors = [], floorMaterials = [];
let beacons = [], movingPoint;
let gridSize = 40, cellSize = 20; // 栅格参数
let mapGrid = []; // 每层栅格地图
let path = [], pathIndex = 0; // A*路径
let targetBeaconIndex = 0;init();
animate();function init() {scene = new THREE.Scene();scene.background = new THREE.Color(0xf0f0f0);camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 5000);camera.position.set(500, 800, 1500);renderer = new THREE.WebGLRenderer({antialias:true});renderer.setSize(window.innerWidth, window.innerHeight);document.body.appendChild(renderer.domElement);controls = new THREE.OrbitControls(camera, renderer.domElement);const gridHelper = new THREE.GridHelper(gridSize*cellSize, gridSize, 0x888888, 0xcccccc);scene.add(gridHelper);// 创建楼层for(let i=0;i<3;i++){const floorGroup = new THREE.Group();const width = gridSize*cellSize, height=50, depth=gridSize*cellSize;const geometry = new THREE.BoxGeometry(width, height, depth);const material = new THREE.MeshBasicMaterial({color:0x00ff00, transparent:true, opacity:0.2});floorMaterials.push(material);const mesh = new THREE.Mesh(geometry, material);mesh.position.y = 50 + i*100;floorGroup.add(mesh);const edges = new THREE.EdgesGeometry(geometry);const line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({color:0x00aa00}));line.position.copy(mesh.position);floorGroup.add(line);scene.add(floorGroup);floors.push(floorGroup);// 生成栅格地图(0通行,1障碍)let layerGrid = Array.from({length:gridSize},()=>Array(gridSize).fill(0));// 随机添加障碍物(墙)for(let w=0; w<60; w++){const x = Math.floor(Math.random()*gridSize);const z = Math.floor(Math.random()*gridSize);layerGrid[x][z] = 1;const wallGeo = new THREE.BoxGeometry(cellSize, 50, cellSize);const wallMat = new THREE.MeshBasicMaterial({color:0x444444});const wall = new THREE.Mesh(wallGeo, wallMat);wall.position.set((x-gridSize/2)*cellSize+cellSize/2, 50 + i*100, (z-gridSize/2)*cellSize+cellSize/2);scene.add(wall);}mapGrid.push(layerGrid);// 蓝牙信标const beaconGeo = new THREE.SphereGeometry(8,12,12);const beaconMat = new THREE.MeshBasicMaterial({color:0x0000ff});for(let b=0;b<5;b++){let bx, bz;do{bx = Math.floor(Math.random()*gridSize);bz = Math.floor(Math.random()*gridSize);}while(layerGrid[bx][bz]===1); // 避开障碍const beacon = new THREE.Mesh(beaconGeo, beaconMat);beacon.position.set((bx-gridSize/2)*cellSize+cellSize/2, 50 + i*100, (bz-gridSize/2)*cellSize+cellSize/2);scene.add(beacon);beacons.push({mesh: beacon, floor: i, gridX: bx, gridZ: bz});}}// 移动小球const pointGeo = new THREE.SphereGeometry(10,16,16);const pointMat = new THREE.MeshBasicMaterial({color:0xff0000});movingPoint = new THREE.Mesh(pointGeo, pointMat);movingPoint.position.set(0, 50, 0);scene.add(movingPoint);setNextTarget();// 楼层按钮document.querySelectorAll('#layerControls button').forEach(btn=>{btn.addEventListener('click',()=>{const layer = btn.getAttribute('data-layer');if(layer==='all'){floors.forEach(f=>f.visible=true);floorMaterials.forEach(m=>m.color.set(0x00ff00));movingPoint.visible = true;beacons.forEach(b=>b.mesh.visible=true);}else{floors.forEach((f,i)=>f.visible=i==layer);floorMaterials.forEach((m,i)=>m.color.set(i==layer?0xffaa00:0x00ff00));movingPoint.position.y = 50 + layer*100;movingPoint.position.x = 0;movingPoint.position.z = 0;movingPoint.visible = true;beacons.forEach(b=>b.mesh.visible=(b.floor==layer));}});});window.addEventListener('resize',()=>{camera.aspect=window.innerWidth/window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight);});
}// ==================== A* 路径规划 ====================
function setNextTarget(){if(beacons.length===0) return;targetBeacon = beacons[targetBeaconIndex % beacons.length];const layerGrid = mapGrid[targetBeacon.floor];path = findPath(layerGrid,gridPos(movingPoint.position.x),gridPos(movingPoint.position.z),targetBeacon.gridX,targetBeacon.gridZ);pathIndex=0;targetBeaconIndex++;
}function gridPos(coord){ return Math.floor((coord + gridSize*cellSize/2)/cellSize); }
function coordPos(grid){ return (grid - gridSize/2)*cellSize + cellSize/2; }function updateMovingPoint(){if(!path || pathIndex>=path.length) {setNextTarget();return;}const target = path[pathIndex];const tx = coordPos(target.x);const tz = coordPos(target.z);const speed = 4;const dx = tx - movingPoint.position.x;const dz = tz - movingPoint.position.z;const dist = Math.sqrt(dx*dx + dz*dz);if(dist<speed){movingPoint.position.x = tx;movingPoint.position.z = tz;pathIndex++;}else{movingPoint.position.x += dx/dist*speed;movingPoint.position.z += dz/dist*speed;}
}// ==================== 简单 A* 算法 ====================
function findPath(grid, startX, startZ, endX, endZ){const openList=[], closedList=[];const nodes = [];for(let x=0;x<gridSize;x++){nodes[x]=[];for(let z=0;z<gridSize;z++){nodes[x][z]={x,z,g:0,h:0,f:0,parent:null,walkable:grid[x][z]===0};}}function heuristic(a,b){ return Math.abs(a.x-b.x)+Math.abs(a.z-b.z); }openList.push(nodes[startX][startZ]);while(openList.length>0){openList.sort((a,b)=>a.f-b.f);const current = openList.shift();closedList.push(current);if(current.x===endX && current.z===endZ) {const ret=[];let c = current;while(c){ ret.push({x:c.x,z:c.z}); c=c.parent; }return ret.reverse();}const dirs=[[1,0],[-1,0],[0,1],[0,-1]];for(const d of dirs){const nx=current.x+d[0], nz=current.z+d[1];if(nx<0||nz<0||nx>=gridSize||nz>=gridSize) continue;const neighbor = nodes[nx][nz];if(!neighbor.walkable || closedList.includes(neighbor)) continue;const g = current.g+1;if(!openList.includes(neighbor) || g<neighbor.g){neighbor.g = g;neighbor.h = heuristic(neighbor,{x:endX,z:endZ});neighbor.f = neighbor.g + neighbor.h;neighbor.parent = current;if(!openList.includes(neighbor)) openList.push(neighbor);}}}return []; // 没路
}// ==================== 动画循环 ====================
function animate(){requestAnimationFrame(animate);updateMovingPoint();renderer.render(scene, camera);controls.update();
}
</script>
</body>
</html>

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

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

相关文章

vue2+jessibuca播放h265视频(能播h264)

文档地址&#xff1a;http://jessibuca.monibuca.com/api.html#background 1,文件放在public中 2,在html中引入 3&#xff0c;子组件 <template><div :id"container id"></div> </template><script> export default {props: [url,…

Docker命令大全:从基础到高级实战指南

Docker命令大全&#xff1a;从基础到高级实战指南 Docker作为现代容器化技术的核心工具&#xff0c;其命令体系是开发运维的必备技能。本文将系统整理常用命令&#xff0c;助您高效管理容器生态。一、基础命令篇 1. 镜像管理 # 拉取镜像 $ docker pull nginx:latest# 查看本地镜…

不邻排列:如何优雅地避开“数字CP“

排列组合奇妙冒险&#xff1a;如何优雅地避开"数字CP"&#xff1f; ——容斥原理教你破解连续数对排列难题 &#x1f4dc; 问题描述 题目&#xff1a;求1,2,3,4,5,6,7,81,2,3,4,5,6,7,81,2,3,4,5,6,7,8的排列个数&#xff0c;使得排列中不出现连续的12,23,34,45,56,6…

S7-200 SMART PLC 安全全指南:配置、漏洞解析与复现防护

在工业自动化领域&#xff0c;PLC&#xff08;可编程逻辑控制器&#xff09;作为核心控制单元&#xff0c;其安全性直接关系到生产系统的稳定运行与数据安全。西门子 S7-200 SMART 系列 PLC 凭借高性价比、易用性等优势&#xff0c;广泛应用于中小型自动化项目。但实际使用中&a…

【计算机网络 | 第14篇】应用层协议

文章目录 应用层协议的核心定义&#xff1a;“通信合同”的关键内容&#x1f95d;应用层协议的分类&#xff1a;公共标准 vs 专有协议&#x1f9fe;公共标准协议专有协议 应用层协议与网络应用的关系&#x1f914;案例1&#xff1a;Web应用案例2&#xff1a;Netflix视频服务 应…

小迪web自用笔记33

再次提到预编译&#xff0c;不会改变固定逻辑。id等于什么的只能更换页面。过滤器&#xff1a;代码一旦执行在页面中&#xff0c;就会执行&#xff0c;xss跨站。Js的特性是显示在页面中之后开始执行&#xff0c;那个代码是打印过后然后再渲染。是的&#xff0c;核心是**“打印&…

Zynq开发实践(FPGA之第一个vivado工程)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】数字电路设计&#xff0c;如果仅仅是写写代码&#xff0c;做做verilog仿真&#xff0c;那么其实是不需要转移到fpga上面的。这就好比是算法工程师&a…

【Selenium】Selenium 测试失败排查:一次元素定位超时的完整解决之旅

Selenium 测试失败排查:一次元素定位超时的完整解决之旅 在自动化测试过程中,我们经常会遇到元素定位超时的问题。本文记录了一次完整的 Selenium TimeoutException 排查过程,从问题发现到最终解决,涵盖了各种常见陷阱和解决方案。 问题背景 测试用例在执行过程中失败,…

32.网络基础概念(二)

局域网网络传输流程图两台主机在同一个局域网&#xff0c;是否能够直接通信&#xff1f;以太网原理举例&#xff1a;上课&#xff0c;老师点名小王让他站起来回答问题。教室里的其他人是可以听见的&#xff0c;为什么其他人不响应&#xff1f;因为老师叫的是小王&#xff0c;和…

【高并发内存池】六、三种缓存的回收内存过程

文章目录前言Ⅰ. thread cache的内存回收Ⅱ. central cache的内存回收Ⅲ. page cache的内存回收前言 ​ 前面我们将内存的申请流程都走通了&#xff0c;现在就是内存回收的过程&#xff0c;主要是从 thread cache 开始&#xff0c;一层一层往下回收&#xff0c;因为我们调用的…

DeerFlow 实践:华为IPD流程的评审智能体设计

目录 一、项目背景与目标 二、IPD 流程关键评审点与 TR 点解析 &#xff08;一&#xff09;4 个关键评审点 &#xff08;二&#xff09;6 个 TR 点 三、评审智能体详细设计与协作机制 机制设计核心原则 &#xff08;一&#xff09;概念评审&#xff08;CDCP&#xff09;…

【ubuntu】ubuntu中找不到串口设备问题排查

ubuntu中找不到串口问题排查1. 检查设备识别情况2. 检查并安装驱动3. 检查内核消息4. 禁用brltty服务1. 停止并禁用 brltty 服务2. 完全移除 brltty 包3. 重启系统或重新插拔设备5.输出结果问题&#xff1a;虚拟机ubuntu中&#xff0c;已经显示串口设备连接成功&#xff0c;但是…

Unity 性能优化 之 静态资源优化 (音频 | 模型 | 纹理 | 动画)

Unity 之 性能优化 -- 静态资源优化参考性能指标静态资源资源工作流程资源分类原理小结Audio 实战优化建议模型导入工作流程DCC中模型导出.DCC中Mesh生产规范模型导出检查流程模型优化建议纹理优化纹理基础概念纹理类型纹理大小纹理颜色空间纹理压缩纹理图集纹理过滤纹理Mipmap…

GitHub 热榜项目 - 日榜(2025-09-13)

GitHub 热榜项目 - 日榜(2025-09-13) 生成于&#xff1a;2025-09-13 统计摘要 共发现热门项目&#xff1a;18 个 榜单类型&#xff1a;日榜 本期热点趋势总结 本期GitHub热榜项目呈现三大技术热点&#xff1a;AI开发工具化&#xff08;如GenKit、ROMA多智能体框架&#xff…

Pytest 常见问题及其解决方案

常见问题及解决方案 1. 测试通过了,但覆盖率不达标 现象: 虽然所有测试都通过了,但覆盖率报告显示某些代码没有被覆盖。 解决方案: 检查覆盖率配置:确保 .coveragerc 或 pytest.ini 中正确设置了要分析的源代码路径。 使用标记(markers)排除测试文件本身:避免测试代…

直击3D内容创作痛点-火山引擎多媒体实验室首次主持SIGGRAPH Workshop,用前沿技术降低沉浸式内容生成门槛

当3D、VR技术在游戏、教育、医疗、文化领域遍地开花&#xff0c;“内容短缺”却成了制约行业爆发的关键瓶颈——传统3D/4D创作不仅耗时耗力、依赖专业技能&#xff0c;还难以适配消费级设备&#xff0c;让许多创作者望而却步。近日&#xff0c;由火山引擎多媒体实验室联合领域顶…

华为基本命令

我们使用的是华为官方的模拟器eNSP 一、华为设备的模式 华为的设备有两种模式&#xff1a; 用户视图和系统视图 用户视图只能读取&#xff0c;或者进行一些基础查询 系统视图能对设备和接口进行一些配置管理&#xff0c;和一些高级操作 在“用户视图”下使用system-view系统可…

2025.9.14英语红宝书【必背16-20】

单词组合 中文速记句子 英文句子 confine, misery, necessitate, negotiate, preach, precaution, precision, stretch 病人被 confine(限制) 在床上,感受 misery(痛苦),情况 necessitate(需要) 医生 negotiate(商讨),牧师 preach(布道) 并提醒 precaution(预防)…

HUST-STAR电控组视觉任务

视觉任务 注意&#xff1a;视觉部分建议采用 python 完成&#xff0c;下面教程也大多针对 python。其原因在于 python 配置相应环境更为轻松&#xff0c;且内置库较为丰富&#xff0c;属于初学者友好类型。没接触过 python 也不必担心&#xff0c;它的大体逻辑与 C 相近&#…

压缩和归档 文件传输

压缩和归档压缩&#xff1a;4G----1.5Gbzip2-bunzip2 gzip-gunzip xz-unxzgzip 要压缩的文件原来的文件就会被删除 (压缩和解压缩)会生成一个 aaa.gz 的文件归档&#xff1a; 4G----4G 打包tarc 创建归档文件 v 看到创建的详细过程 f 文件类型 t 不展开归档文件&…