WebGL+ArcGIS JS API实现Web城市地下管线三维场景浏览

2024-02-19 19:32

本文主要是介绍WebGL+ArcGIS JS API实现Web城市地下管线三维场景浏览,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

注:转载请注明出处

WebGL发展的如火如荼,未来的WebGIS也应该体现3D的趋势,本人的本科毕业论文是《Web城市地下管线三维场景浏览技术研究》,通过ArcGIS JS API获取地理数据,然后用WebGL框架Three.js将该地理数据进行三维展示。

本论文主要具有以下创新点:

(1)在传统的WebGIS的基础上,借助于主流的IT技术(WebGL)实现了在传统网页中嵌入三维GIS模块,并且可以在网页中导入三维模型,使得用户可以通过网页流畅的查看地下管线的详细信息,拓展了传统WebGIS的应用价值。

(2)本系统才用了WebGL开发技术用于创建三维场景,WebGL是GPU硬件加速的,降低了CPU的压力,因此三维体验更加流畅。并且浏览器是原生支持WebGL,不需要安装任何插件。

(3)在三维场景中可以实现三维场景的漫游(平移、缩放、旋转),并且还能够在三维场景中进行鼠标交互式查询。


虽然已经在网页中实现了管网的三维可视化,并在此基础上实现了三维漫游与交互式查询,但是系统还存在一些不足:

(1)没有实现专业的三维管线分析功能,这使得系统的空间分析功能受到了限制。

(2)并且系统的三维场景不能完全容纳整个二维地图中的所有管线与管点,每次都需要鼠标在二维地图中选择要创建三维管网的区域,比较麻烦。

为了解决上述问题,今后需要进行以下几方面的研究:

(1)由于本论文已经在三维场景中实现了三维对象的拾取功能,并且每个三维对象中都保存了对应的地理空间数据,所以可以利用三维对象的拾取功能在三维管线分析中进行鼠标交互式处理,并且根据三维对象保存的地理空间数据进行空间分析,将分析的结果再以三维对象的形式显示出来。以三维对象作为显示层,以三维对象中的地理空间数据作为数据分析层,将二者结合起来就可以进行多种专业的三维管线分析。

(2)由于系统的三维场景不能完全容纳整个二维地图中的所有管线与管点,所以需要研究算法实现通过键盘方向键进行三维场景动态内容的更新。


以下是系统截图,左侧为选定的二维区域,右侧为动态生成的对应的三维管网场景:


以下是三维单击查询截图:


以下是主要源码:

<!DOCTYPE HTML>
<html>
<head><title></title><meta http-equiv="Content-Type" content="text/html" /><meta name="charset" content="utf-8"/><!--<link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.8/js/dojo/dijit/themes/claro/claro.css">--><link rel="stylesheet" type="text/css" href="http://localhost/arcgis_js_api/library/2.7/jsapi/js/dojo/dijit/themes/claro/claro.css"><style type="text/css">/*@import "http://serverapi.arcgisonline.com/jsapi/arcgis/2.8/js/dojo/dijit/themes/claro/claro.css";*/@import "http://localhost/arcgis_js_api/library/2.7/jsapi/js/dojo/dijit/themes/claro/claro.css";@import "iSpring/widgets/themes/MapToolbar.css";@import "iSpring/widgets/themes/PipeToolbar.css";@import "iSpring/widgets/themes/PipeTOC.css";@import "iSpring/widgets/themes/PipeIdentify.css";@import "iSpring/widgets/themes/SystemMenu.css";html,body,div{margin:0;padding:0}</style><script type="text/javascript">dojoConfig = {parseOnLoad:true,baseUrl:'./',modulePaths: { 'iSpring.widgets': 'iSpring/widgets' }};</script><!--<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.8"></script>--><script type="text/javascript" src="http://localhost/arcgis_js_api/library/2.7/jsapi/"></script><script type="text/javascript" src="three.js"></script><script type="text/javascript" src="Detector.js"></script><script type="text/javascript">dojo.require("esri.map");dojo.require("dijit.dijit");dojo.require("esri.toolbars.draw");dojo.require("esri.tasks.identify");dojo.require("iSpring.widgets.MapToolbar");dojo.require("iSpring.widgets.PipeToolbar");dojo.require("iSpring.widgets.PipeTOC");dojo.require("iSpring.widgets.PipeIdentify");dojo.require("iSpring.widgets.SystemMenu");var map,drawToolbar,extentSymbol,identifyTask,identifyParas;var scene,camera,renderer;var bLeftButtonDown=false;var handleMouseMove;var previousX=-1,previousY=-1;var mapService = "http://localhost/ArcGIS/rest/services/Pipe/MapServer";var StaticRotateRadianY = Math.PI / 180;function init(){map = new esri.Map('mapId');var layer = new esri.layers.ArcGISDynamicMapServiceLayer(mapService);map.addLayer(layer);dojo.connect(map,"onLoad","mapOnLoad");init3D();			animateRefresh();}function animateRefresh(){requestAnimationFrame(animateRefresh);renderer.render(scene,camera);}function mapOnLoad(){drawToolbar = new esri.toolbars.Draw(map);dojo.connect(drawToolbar,"onDrawEnd","drawEnd");dojo.connect(map,'onResize',map,map.resize);extentSymbol = drawToolbar.fillSymbol;drawToolbar.activate(esri.toolbars.Draw.EXTENT);systemMenu.setMap(map);initIdentify();}function createMapToolbar(Map){var bar = new iSpring.widgets.MapToolbar({map:Map});bar.placeAt(dojo.body());bar.startup();}function createPipeToolbar(Scene){var bar = new iSpring.widgets.PipeToolbar({scene:Scene});bar.placeAt(dojo.body());bar.startup();}function createPipeTOC(Scene){var toc = new iSpring.widgets.PipeTOC({scene:Scene});toc.placeAt(dojo.body());toc.startup();}function createPipeIdentify(Attributes){var pipeIdentify = new iSpring.widgets.PipeIdentify({attributes:Attributes});pipeIdentify.placeAt(dojo.body());pipeIdentify.startup();}function initIdentify(){identifyTask = new esri.tasks.IdentifyTask(mapService);identifyParas = new esri.tasks.IdentifyParameters();identifyParas.mapExtent = map.extent;identifyParas.tolerance = 3;identifyParas.returnGeometry = true;identifyParas.layerOption = esri.tasks.IdentifyParameters.LAYER_OPTION_ALL;identifyParas.width = map.width;identifyParas.height = map.height;dojo.connect(identifyTask,"onComplete","identifyCallback");//注意上下文dojo.connect(identifyTask,"onError","identifyErrorback");//注意上下文}function drawEnd(geometry){map.graphics.clear();var graphic = new esri.Graphic(geometry,extentSymbol);map.graphics.add(graphic);doIdentify(geometry);}function doIdentify(geometry){identifyParas.geometry = geometry;identifyTask.execute(identifyParas);}function identifyCallback(results){var center = identifyParas.geometry.getCenter();identifyParas.geometry = null;            if(!scene.initCenter){scene.initCenter = center;}create3D(scene.initCenter,results);}function identifyErrorback(error){identifyParas.geometry = null;console.log(error);}function init3D(){if (!Detector.webgl) {if (Detector.canvas) {renderer = new THREE.CanvasRenderer();}else {alert('Sorry,您的浏览器不支持3D!')}} else {renderer = new THREE.WebGLRenderer({antialias: true});//开启WebGL抗锯齿}scene = new THREE.Scene();var container = dojo.byId("container");var width = dojo.style(container,"width");var height = dojo.style(container,"height");var viewAngle = 45;var aspect = width / height;var near = 0.1;var far = 10000;camera = new THREE.PerspectiveCamera(viewAngle,aspect,near,far);camera.position.set(10,70,80);scene.add(camera);renderer.setSize(width,height);container.appendChild(renderer.domElement);var pointLight = new THREE.PointLight(0xFFFFFF);pointLight.position.x = 10;pointLight.position.y = 50;pointLight.position.z = 130;scene.add(pointLight);camera.target = scene.position;camera.lookAt(scene.position);dojo.connect(window,'resize',function(){var container = dojo.byId("container");var width = dojo.style(container,"width");var height = dojo.style(container,"height");camera.aspect = width / height;camera.updateProjectionMatrix();});dojo.connect(container,'mousedown',onSceneMouseDown);			dojo.connect(container,'mouseup',onSceneMouseUp);dojo.connect(container,'mousewheel',onMouseWheel);dojo.connect(container,'DOMMouseScroll',onMouseWheel);scene.pipeOperationMode="PAN";renderer.render(scene,camera);systemMenu.setScene(scene);}function create3D(center,results){dojo.forEach(results,function(item,index,results){var graphic = item.feature;var uniqueId = graphic.attributes.LayerName+graphic.attributes.OBJECTID;var bExist = checkExist(uniqueId);if(!bExist){if(item.geometryType == "esriGeometryPolyline" && item.layerName.indexOf('管线')>=0){var mesh = createPipeCylinderByGraphic(graphic,center);if(mesh != null){mesh.graphic = item.feature;mesh.uniqueId = uniqueId;scene.add(mesh);}}else if(item.geometryType == "esriGeometryPoint" && item.layerName.indexOf('管点')>=0){createValveModelByGraphic(graphic,center);}}});			}function checkExist(uniqueId){var bExist = dojo.some(scene.children,function(item){if(item instanceof THREE.Mesh){if(item.uniqueId){return item.uniqueId==uniqueId ? true:false;}}});return bExist;}function findMeshByUniqueId(uniqueId){dojo.forEach(scene.children,function(child){if(child instanceof THREE.Mesh){if(child.uniqueId){if(child.uniqueId == uniqueId)return child;}}});return null;}function isZero(number){if(Math.abs(number) < 0.000001){return true;}else{return false;}}function createPipeCylinderByGraphic(graphic,center){Radius = 0.4;var pntNumber = graphic.geometry.paths[0].length;var firstPnt = graphic.geometry.getPoint(0,0);					var x1 = firstPnt.x - center.x;var y1 = parseFloat(graphic.attributes.SCEN_H);var z1 = center.y - firstPnt.y;var lastPnt = graphic.geometry.getPoint(0,pntNumber-1);var x2 = lastPnt.x - center.x;var y2 = parseFloat(graphic.attributes.ECEN_H);var z2 = center.y - lastPnt.y;var color = GetColorByPipeType(graphic.attributes.LayerName);var mesh = createCylinderMesh(x1,y1,z1,x2,y2,z2,Radius,color);mesh.graphic = graphic;mesh.uniqueId = graphic.attributes.LayerName+graphic.attributes.OBJECTID;return mesh;			}function createCylinderMesh(x1,y1,z1,x2,y2,z2,radius,Color){		var x0 = (x1 + x2) / 2;var y0 = (y1 + y2) / 2;var z0 = (z1 + z2) / 2;var p1 = new THREE.Vector3(x1,y1,z1);var length = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2));var material = new THREE.MeshBasicMaterial( { color: Color } );var geometry = new THREE.CylinderGeometry(radius,radius,length);geometry.applyMatrix( new THREE.Matrix4().setRotationFromEuler( new THREE.Vector3( Math.PI / 2, Math.PI, 0 ) ) );var mesh = new THREE.Mesh(geometry,material);mesh.position.set(x0, y0, z0);		mesh.lookAt(p1);return mesh;}function createValveModelByGraphic(graphic,center){var topH = parseFloat(graphic.attributes.top_h);var bottomH = parseFloat(graphic.attributes.bottom_h);var valveX = graphic.geometry.x - center.x;var valveY = (topH+bottomH)/2 + 1;var valveZ = center.y - graphic.geometry.y;var loader = new THREE.JSONLoader();loader.load('valve.js',function(geometry){var mesh = new THREE.Mesh(geometry,new THREE.MeshFaceMaterial());mesh.position.set(valveX,valveY,valveZ);mesh.rotation.set(1.6,0,0);mesh.scale.set(0.07,0.07,0.07);mesh.graphic = graphic;mesh.uniqueId = graphic.attributes.LayerName+graphic.attributes.OBJECTID;scene.add(mesh);});}function onMouseWheel(evt){var scale = 0.0;if (evt.wheelDelta ){if(evt.wheelDelta > 0){scale = 0.9;}else if(evt.wheelDelta < 0){scale = 1.1;}           }else if(evt.detail){if(evt.detail < 0){scale = 0.9;}else if(evt.detail > 0){scale = 1.1;}}var PreDelta = new THREE.Vector3(camera.position.x - camera.target.x,camera.position.y - camera.target.y,camera.position.z - camera.target.z);var NewDelta = new THREE.Vector3(PreDelta.x * scale, PreDelta.y * scale, PreDelta.z * scale);camera.position.set(camera.target.x + NewDelta.x,camera.target.y + NewDelta.y,camera.target.z + NewDelta.z);camera.lookAt(camera.target);}function onSceneMouseDown(evt){previousX=evt.layerX||evt.offsetX;previousY=evt.layerY||evt.offsetY;bLeftButtonDown = true;handleMouseMove = dojo.connect(dojo.byId("container"),'mousemove',onSceneMouseMove);if(scene.pipeOperationMode=="IDENTIFY"){console.log("scene.pipeOperationMode==IDENTIFY");onIdentifySceneMouseDown(previousX,previousY);}}function onIdentifySceneMouseDown(clickX,clickY){var width=dojo.style("container","width");var height=dojo.style("container","height");var vector = new THREE.Vector3( ( clickX / width ) * 2 - 1, - ( clickY / height ) * 2 + 1, 0.5 );var projector = new THREE.Projector();projector.unprojectVector( vector, camera );var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );var intersects = ray.intersectObjects( scene.children );if ( intersects.length > 0 ) {//intersects[ 0 ].object.material.color.setHex( Math.random() * 0xffffff );//var particleMaterial = new THREE.ParticleBasicMaterial( {  color: 0x000000});//var particle = new THREE.Particle( particleMaterial );//particle.position = intersects[ 0 ].point;//particle.scale.x = particle.scale.y = 20;//scene.add( particle );createPipeIdentify(intersects[0].object.graphic.attributes);}}function onSceneMouseMove(evt){var currentX=evt.layerX||evt.offsetX;var currentY=evt.layerY||evt.offsetY;if(bLeftButtonDown){if(scene.pipeOperationMode=="PAN"){onPanSceneMouseMove(currentX,currentY);}else if(scene.pipeOperationMode=="ROTATE"){onRotateSceneMouseMove(currentX,currentY);}}previousX = currentX;previousY = currentY;}function onPanSceneMouseMove(currentX,currentY){//左右平移if(currentX != previousX){var bLeft = currentX < previousX ? true:false;var plumbVector	= GetPlumbVector(camera.position, camera.target, bLeft);camera.position.x += plumbVector.x;camera.position.z += plumbVector.z;camera.target.x += plumbVector.x;camera.target.z += plumbVector.z;camera.lookAt(camera.target);}//前后平移if(currentY != previousY){var bForward = currentY < previousY ? true:false;var ForwardVector = GetForwardVector(camera.position,camera.target, bForward);camera.position.x += ForwardVector.x;camera.position.y += ForwardVector.y;camera.position.z += ForwardVector.z;camera.target.x += ForwardVector.x;camera.target.y += ForwardVector.y;camera.target.z += ForwardVector.z;camera.lookAt(camera.target);}}function onRotateSceneMouseMove(currentX,currentY){var RotateRadianY = 0.0;//围绕Y轴旋转的角度var height = parseFloat(dojo.style('container','height'));var deltaY = 0.0;if (currentY >= height/2){if (previousX < currentX){RotateRadianY = StaticRotateRadianY;}if (previousX > currentX){RotateRadianY = -StaticRotateRadianY;}}else if (currentY < previousY){if (previousX > currentX){RotateRadianY = StaticRotateRadianY;}if (previousX < currentX){RotateRadianY = -StaticRotateRadianY;}}if (scene.pipeOperationMode == "ROTATE")//只绕Y轴旋转{camera.position.x = camera.position.x * Math.cos(RotateRadianY) + camera.position.z * Math.sin(RotateRadianY);camera.position.z = -camera.position.x * Math.sin(RotateRadianY) + camera.position.z * Math.cos(RotateRadianY);camera.target.x = camera.target.x * Math.cos(RotateRadianY) + camera.target.z * Math.sin(RotateRadianY);camera.target.z = -camera.target.x * Math.sin(RotateRadianY) + camera.target.z * Math.cos(RotateRadianY);camera.lookAt(camera.target);}}function onSceneMouseUp(evt){bLeftButtonDown = false;currentX=-1;currentY=-1;dojo.disconnect(handleMouseMove);}function GetPlumbVector(FromPoint,ToPoint,bLeft){var Vector3D = new THREE.Vector3(ToPoint.x-FromPoint.x,ToPoint.y-FromPoint.y,ToPoint.z-FromPoint.z);var PlumbVector2D;var FromPoint2D = new THREE.Vector3(FromPoint.x,0,FromPoint.z);var ToPoint2D = new THREE.Vector3(ToPoint.x,0,ToPoint.z);var Vector2D = new THREE.Vector3(ToPoint2D.x-FromPoint2D.x,0,ToPoint2D.z-FromPoint2D.z);Vector2D.normalize();PlumbVector2D = new THREE.Vector3(-Vector2D.z,0,Vector2D.x);PlumbVector2D.normalize();if (bLeft) {var K = Vector2D.z / Vector2D.x;if (PlumbVector2D.z > K * PlumbVector2D.x) {PlumbVector2D.x *= -1;PlumbVector2D.z *= -1;}}else {var K = Vector2D.z / Vector2D.x;if (PlumbVector2D.z < K * PlumbVector2D.x){PlumbVector2D.x *= -1;PlumbVector2D.z *= -1;}}            return PlumbVector2D;}function GetForwardVector(FromPoint, ToPoint, bForward){var Vector3D = new THREE.Vector3(FromPoint.x-ToPoint.x,FromPoint.y-ToPoint.y,FromPoint.z-ToPoint.z);var FromPoint2D = new THREE.Vector3(FromPoint.x,0,FromPoint.z);var ToPoint2D =  new THREE.Vector3(ToPoint.x,0,ToPoint.z);var Vector2D = new THREE.Vector3(ToPoint2D.x - FromPoint2D.x,ToPoint2D.y - FromPoint2D.y,ToPoint2D.z - FromPoint2D.z);Vector2D.normalize();if (bForward){Vector2D.x *= -1;Vector2D.z *= -1;}           return Vector2D;}function GetColorByPipeType(PipeType){var PipeColor;var type = PipeType;if (PipeType.indexOf("管线")>=0){type = PipeType.replace(/管线/, "");} else if (PipeType.indexOf("管点")>=0){type = PipeType.replace(/管点/, "");}switch (type){case "工业":{PipeColor = 0x000000;break;}case "污水":case "雨水":{PipeColor = 0xD85B00;break;}case "煤气":{PipeColor = 0x19E2E8;break;}case "电信":{PipeColor = 0x00ff00;break;}case "电力":case "路灯":{PipeColor = 0xff0000;break;}case "给水":{PipeColor = 0x0000ff;break;}}return PipeColor;}dojo.addOnLoad(init);</script>
</head>
<body class="claro"><div data-dojo-type="iSpring.widgets.SystemMenu" jsId="systemMenu"></div><div style="position:absolute;top:120px;"><div id="mapId" style="width:600px;height:500px;float:left;border:solid 2px #000"></div><div id="container" style="width:600px;height:500px;float:left;margin-left:20px;border:solid 2px #000"></div></div>
</body>
</html>



注:转载请注明出处

这篇关于WebGL+ArcGIS JS API实现Web城市地下管线三维场景浏览的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/725724

相关文章

windos server2022里的DFS配置的实现

《windosserver2022里的DFS配置的实现》DFS是WindowsServer操作系统提供的一种功能,用于在多台服务器上集中管理共享文件夹和文件的分布式存储解决方案,本文就来介绍一下wi... 目录什么是DFS?优势:应用场景:DFS配置步骤什么是DFS?DFS指的是分布式文件系统(Distr

NFS实现多服务器文件的共享的方法步骤

《NFS实现多服务器文件的共享的方法步骤》NFS允许网络中的计算机之间共享资源,客户端可以透明地读写远端NFS服务器上的文件,本文就来介绍一下NFS实现多服务器文件的共享的方法步骤,感兴趣的可以了解一... 目录一、简介二、部署1、准备1、服务端和客户端:安装nfs-utils2、服务端:创建共享目录3、服

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

Python实现高效地读写大型文件

《Python实现高效地读写大型文件》Python如何读写的是大型文件,有没有什么方法来提高效率呢,这篇文章就来和大家聊聊如何在Python中高效地读写大型文件,需要的可以了解下... 目录一、逐行读取大型文件二、分块读取大型文件三、使用 mmap 模块进行内存映射文件操作(适用于大文件)四、使用 pand

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码

《在MyBatis的XML映射文件中<trim>元素所有场景下的完整使用示例代码》在MyBatis的XML映射文件中,trim元素用于动态添加SQL语句的一部分,处理前缀、后缀及多余的逗号或连接符,示... 在MyBATis的XML映射文件中,<trim>元素用于动态地添加SQL语句的一部分,例如SET或W

Python xmltodict实现简化XML数据处理

《Pythonxmltodict实现简化XML数据处理》Python社区为提供了xmltodict库,它专为简化XML与Python数据结构的转换而设计,本文主要来为大家介绍一下如何使用xmltod... 目录一、引言二、XMLtodict介绍设计理念适用场景三、功能参数与属性1、parse函数2、unpa

C#实现获得某个枚举的所有名称

《C#实现获得某个枚举的所有名称》这篇文章主要为大家详细介绍了C#如何实现获得某个枚举的所有名称,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... C#中获得某个枚举的所有名称using System;using System.Collections.Generic;usi

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

C# 读写ini文件操作实现

《C#读写ini文件操作实现》本文主要介绍了C#读写ini文件操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、INI文件结构二、读取INI文件中的数据在C#应用程序中,常将INI文件作为配置文件,用于存储应用程序的