ArcGIS Flex API for 3D(转帖)

一.简介

基于AS 3、ArcGISServer Flex API 、Papervision3D等实现了ArcGIS 3D Flex API。能够将ArcGIS Server Flex API的Map Control放置在三维的环境中,并且能保留2D环境下的功能,实现三维的柱状、饼状专题图;能够基于DEM和RS影像实现3D仿真,根据高程数据进行3D拉伸,并和RS影像叠加,获得很好的3D效果。

二. ArcGIS Flex API for 3D—Papervision3D

Papervision3D是由巴西人Carlos差不多凭借一人之力开发出的Flash领域比较成熟的3D引擎(当然后面的版本有很多的贡献者),现在很多商业网站使用这套引擎来开发应用。

PV3D有几个优点:

①可以直接导入dae和ase文件(这些文件用3DMAX或其他3D工具安装一个小插件就可以导出的了),这意味着可以直接使用大部分专业3D工具制作出来的模型;

②性能不错;

③功能强,能够支持很多振奋人心的高级3D效果;

④使用简单,基本上看一看例子就知道怎么做了;

⑤开源的,能够看到源代码。 

Papervision3D的坐标系统和我们在Flex2D环境下的不一样。2D环境下的坐标系是传统的计算机坐标系:左上角是原点,X轴向右为正,Y轴向下为正;而在PV3D环境就不一样了,原点位于场景的中心,Y轴的方向和2D环境下是相反的,并且多了一个Z轴。


每个PV3D程序中都至少要包含四个类:Viewport3D,Scene3D,Camera3D,BasicRenderEngine(可选),一个典型PV3D程序如下:

[javascript]  view plain copy
  1. package{  
  2.    import flash.display.Sprite;  
  3.    import org.papervision3d.cameras.Camera3D;  
  4.    import org.papervision3d.render.BasicRenderEngine;  
  5.    import org.papervision3d.scenes.Scene3D;  
  6.    import org.papervision3d.view.Viewport3D;  
  7.   
  8.    public class Main extends Sprite{  
  9.         private var viewport:Viewport3D;  
  10.         private var scene:Scene3D;  
  11.         private var camera:Camera3D;  
  12.         private var renderer:BasicRenderEngine;  
  13.         public function Main(){  
  14.                initPapervision3D();  
  15.         }  
  16.   
  17.         private function initPapervision3D():void{  
  18.                viewport = new Viewport3D();  
  19.                addChild(viewport);  
  20.                scene = new Scene3D();  
  21.                camera = new Camera3D();  
  22.                renderer = new BasicRenderEngine();  
  23.                renderer.renderScene(scene, camera, viewport);  
  24.         }  
  25.    }  
  26. }  

Viewport3D视口:可以将Viewport3D视口看成是PV3D的一扇窗户,透过这扇窗户我们才能看见PV3D世界里的东西。

Scene3D场景:Scene3D通过窗口展示所有你能看见的3D物体:天空,大地,以及这之间的一切。然而Scene3D只是一个空的场景,要显示的内容需要创建后逐一添加到场景。

Camera3D镜头:所有的场景设置好了之后必须得有一双眼睛去欣赏,PV3D的开发者创建了Camera3D来捕捉动作,Camera3D也允许你设置X、Y、Z坐标来确定从哪个角度来欣赏这个美景,移动镜头,那么整个Scene3D根据Camera3D当前的位置调整。

BasicRenderEngine基本渲染引擎:BasicRenderEngine通过设置的Camera3D的位置来渲染场景里的所有的物品,就可以看到自己畅游在Flex的3D世界里了。

到目前为止,已经创建好了3D的环境,接下来就是要在3D的环境中设计要显示的物体。PV3D已经有很多现成的3DObjects,Plane平面,Sphere球体,Cube正方体,Cylinder圆柱体等等,有些我们在做专题图的时候会用到,这些3D Objects不只是一个单单空的对象,还可以让它们变得充实美观点,PV3D提供了很多不同的材质来渲染这些物体。

首先介绍下PV3D的Plane对象。对PV3D来说Plane是非常有用的3D物体,特别是如果该项目是交互式的。记住Scene3D保存了所能观察到的所有的物体,如果要使用Plane,那么不要忘了,创建了它之后将其添加到Scene3D里去。

Plane的构造函数如下代码:

[javascript]  view plain copy
  1. Plane( material:MaterialObject3D=null, width:Number=0,height:Number=0,   
  2. segmentsW:Number=0, segmentsH:Number=0, initObject:Object=null )  

材料,宽,高,这些属性很容易就能理解。SegmentsW 和 segmentsH,就比较重要了,字面上的意思是在宽度和高度方向上的段数,SegmentsW 和 segmentsH的增大可以避免Plane在旋转的时候发生扭曲,但是过大的话也会导致严重耗费计算机资源,因此一般控制在不超过2000。最后一个可选的属性参数,initObject存储3D对象的x,y, z,rotationX,rotationY,rotationZ,scaleX,scaleY,scaleZ属性,在创建了3D对象之后你可以直接设置这个值。

事实上Plane是由很多个三角形构成,三角形的个数与SegmentsW、segmentsH有关系,为2*SegmentsW*segmentsH,下图是一个3×3的Plane示例,甚至每一个三角形都可以独立的定义其渲染方式,PV3D中其它的3D Objects也具有相似的性质。


Plane有一个重要的属性geometry,geometry中存储了Plane所有的顶点vertices,这些顶点除了有x、y坐标之外,还有z坐标,这个是实现DEM&RS很好的方法。不过特别指出vertices是一个数组,这个数组里面点排列的方式和我们想象可能不大一样,左下角是第一个点,然后依次由下而上,自左而右。

四. ArcGIS Flex API for 3D—3D Map Control

要完全从0开始实现3D环境下的Map Control当然也可以,不过既然已经有了ArcGIS Server Flex API的Map Control,并且还有一整套现成的功能,那么将ArcGIS Server Flex API的Map Control加到PV3D的环境中是一个不错的选择。

但是要实现也不是非常容易的事情,在测试的过程中发现了一些问题。

①3D环境下显示Map Control必须保证同样添加到2D环境下,但是无法隐藏2D环境下的Map Control,或者是隐藏了2D环境下的Map Control,3D环境下显示的Map Control默认事件(双击、滚轮、移动)就无效;

②在Map Control上绘制图形对象会发生偏移,和鼠标点击的位置不一致。

最终的解决方法:将Map Control作为Plane的MovieMaterial,Map Control并不是直接加到MovieMaterial中,而是通过MovieClip,并且用一个ParentMovie Clip处理2D环境下的Map Control的隐藏,这样既能在2D环境下隐藏Map Control,还会保证Map Control在3D环境下保留原先的功能。

[javascript]  view plain copy
  1. //add esri map control to pv3d environment  
  2. movie.addChild(map);  
  3. mat = new MovieMaterial(movie, truetruefalsenew Rectangle(0, 0, m_pv3dwidth, m_pv3dheight));  
  4. mat.smooth=true;  
  5. m_baseMapPlane = new Plane(mat, m_pv3dwidth, m_pv3dheight, 20, 20);  
  6.               
  7. //make esri map control invisible in flex 2d environment  
  8. movieParent.addChild(movie);  
  9. movieParent.alpha = 0;  
  10. pv3d.rawChildren.addChild(movieParent);  

图形的绘制要在Map Control没有变形的时候进行,能够保证所绘即所得。

柱状图(createBarChartHeatMap)、饼状图(createPieChartHeatMap)的实现原理:通过QueryTask查询出需要做专题的对象,通过PV3D绘制出3D的柱状(Cube 3D object)、饼状(Cylinder 3D object)。考虑到柱状图和饼状图的三维效果,要对Cube、Cylinder不同面以不同的方式渲染。

柱状专题图

[javascript]  view plain copy
  1. //create chart map materia list  
  2. matList.addMaterial(red, "front");  
  3. matList.addMaterial(red, "back");  
  4. matList.addMaterial(blue, "left");  
  5. matList.addMaterial(blue, "right");  
  6. matList.addMaterial(green, "top");  
  7. matList.addMaterial(green, "bottom");  
  8.   
  9. var pvCube:Cube = new Cube(matList, 20, 2 * pv3dz, 20);  
饼状专题图

[javascript]  view plain copy
  1. var pvCylinder:Cylinder = new Cylinder(null, pv3dz / 1.5, 15, 20, 1, pv3dz / 1.5, truetrue);  
  2.                   
  3. var bottomMaterial:ColorMaterial = new ColorMaterial(0xff0000);  
  4. var middleMaterial:ColorMaterial = new ColorMaterial(0x0000ff);  
  5. var topMaterial:ColorMaterial = new ColorMaterial(0xff0000);   
  6. var i:int;  
  7.                   
  8. //this is the bottom face  
  9. for (i = 0; i < 18; i++)  
  10. {  
  11.      pvCylinder.geometry.faces[i].material = bottomMaterial;  
  12. }  
  13.                   
  14. //the middle of the cylinder  
  15. for (i = 18; i < pvCylinder.geometry.faces.length - 18; i++)  
  16. {  
  17.      pvCylinder.geometry.faces[i].material = middleMaterial;  
  18. }  
  19.                   
  20. //the top  
  21. for (i = pvCylinder.geometry.faces.length - 18; i <   
  22. pvCylinder.geometry.faces.length; i++)  
  23. {  
  24.       pvCylinder.geometry.faces[i].material = topMaterial;  
  25. }  
看看结果什么样



五. ArcGIS Flex API for 3D—DEM&RS

基本的思路是,前面提到Plane的geometry是存储了一个vertices数组,这个数组代表的是所有Plane的顶点,Plane本身就是一个三角网,一旦这些vertices的z值代表了实际的高程数据,就会实现真实的高低起伏,因此就是要将DEM的高程信息赋给相应的点;Plane是可以选用不同材料渲染的,使用BitmapFileMaterial可以将RS影像与DEM叠加。

如何获取RS影像和DEM信息:本地数据和ArcGISServer服务两种方式。

①本地数据

影像获取比较简单,支持jpg、png、bmp等格式,只需要其地址(虚拟地址or本地地址)。


获取影像

[javascript]  view plain copy
  1. var bmpfm:BitmapFileMaterial = new BitmapFileMaterial("http://heyb/FlexData/pv3d-rs.jpg");  
  2. bmpfm.interactive = true;  
  3. m_heatMapPlane = new Plane(bmpfm, 460, 500, 46, 50);  

DEM的信息获取是个难点,AS没有办法直接读取DEM的文件格式。ArcGIS提供了一个GP工具Sample,对DEM重采样,输出为一个GeodatabseTable表。


Sample工具


目前能够处理dbf格式的本地路径Table表(Tips:测试发现,将dbf文件的后缀改为swf,可以处理虚拟路径),处理dbf的核心程序位于src\org\vanrijkom\dbf。


处理dbf文件

[javascript]  view plain copy
  1. urlloader.load(new URLRequest("E:\\ PaperVision3D\\pv3d-rs-dem.dbf"));  
  2.   
  3. var bdfByteArray:ByteArray = urlloader.data as ByteArray;  
  4. var dbfhdr:DbfHeader = new DbfHeader(bdfByteArray);  
  5. var vertices:Array = new Array();  
  6. forvar ii : int = 0; ii < dbfhdr.recordCount; ii++)  
  7. {   
  8. var dbfRecord : DbfRecord = DbfTools.getRecord( bdfByteArray, dbfhdr, ii );  
  9. var vertex:Vertex3D = new Vertex3D(dbfRecord.values.X, dbfRecord.values.Y, dbfRecord.values.ELE);   
  10.     vertices.push(vertex);  
  11. }          

如果要以虚拟路径的方式load,可以将Sample后的Table存储在geodatabase当中,然后导出为XMLRecordset Document,AS处理XM文件就轻松多了。


Export To XML Recordset Document


处理XML文件

[javascript]  view plain copy
  1. urlloader.load(new URLRequest("http://heyb/FlexData/pv3d-ele.xml"));  
  2.   
  3. var xml:XML = new XML(e.target.data);         
  4. var fields:XMLList = xml.Data.Fields.FieldArray.Field;    
  5. var records:XMLList = xml.Data.Records.Record;    
  6. var vertices:Array = new Array();                 
  7. for (var ii:int = 0; recordIndex < records.length(); ii++)  
  8. {  
  9.     var recordValues:XMLList = records[recordIndex].Values.Value;  
  10.     var vertex:Vertex3D = new Vertex3D(recordValues[1], recordValues[2], recordValues[3]);  
  11.      vertices.push(vertex);  
  12. }         

②ArcGIS Server服务

同样,影像获取比较简单,mapserver的export方法,可以获取图片的虚拟地址,其它实现类似①。

DEM的信息获取有几个思路:

a、等待rest的支持,如果未来ESRI能够支持rest直接获取dem的信息(比如返回json的字符串),那会简单得多。

b、GP服务的方式,构建一个Sample模型发布成服务。


通过GP服务获取高程信息

[javascript]  view plain copy
  1. var params:Object = new Object();  
  2. gp.execute(params, new AsyncResponder(onDEMSampleResult, onFault));    
  3.   
  4. var pv:ParameterValue = gpResult.parameterValues[0];                      
  5. var fs:FeatureSet = pv.value as FeatureSet;    
  6. var attributes:Array = fs.attributes;         
  7. var vertices:Array = new Array();  
  8. for (var recordIndex:int = 0; recordIndex < attributes.length; recordIndex++)  
  9. {  
  10. var record:Object = attributes[recordIndex];  
  11. var vertex:Vertex3D = new Vertex3D(record.x, record.y, record.g_g_g2);   
  12. vertices.push(vertex);  
  13. }  


c、其它,最终DEM的高程信息是用来改变Plane的z坐标的,如果有其它任何方式使得DEM的高程信息被AS很简单地处理,就可以考虑。

其它具体实现参见代码。

功能如图,DEM&RS还具有飞行模式,沿设定飞行路径改变相机参数,拍摄到的场景也会改变:



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值