多樓層室內定位可視化 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
英文地址,請注明出處:http://en.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 不展開歸檔文件&…