您的位置:首页 > 其它

ArcGIS Flex API for 3D(转帖)

2012-06-14 17:20 357 查看
一.简介

基于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
plaincopy

package{

import flash.display.Sprite;

import org.papervision3d.cameras.Camera3D;

import org.papervision3d.render.BasicRenderEngine;

import org.papervision3d.scenes.Scene3D;

import org.papervision3d.view.Viewport3D;

public class Main extends Sprite{

private var viewport:Viewport3D;

private var scene:Scene3D;

private var camera:Camera3D;

private var renderer:BasicRenderEngine;

public function Main(){

initPapervision3D();

}

private function initPapervision3D():void{

viewport = new Viewport3D();

addChild(viewport);

scene = new Scene3D();

camera = new Camera3D();

renderer = new BasicRenderEngine();

renderer.renderScene(scene, camera, viewport);

}

}

}

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提供了很多不同的材质来渲染这些物体。
三. ArcGIS Flex API for 3D—实现思路

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

Plane的构造函数如下代码:

[javascript] view
plaincopy

Plane( material:MaterialObject3D=null, width:Number=0,height:Number=0,

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
plaincopy

//add esri map control to pv3d environment

movie.addChild(map);

mat = new MovieMaterial(movie, true, true, false, new Rectangle(0, 0, m_pv3dwidth, m_pv3dheight));

mat.smooth=true;

m_baseMapPlane = new Plane(mat, m_pv3dwidth, m_pv3dheight, 20, 20);

//make esri map control invisible in flex 2d environment

movieParent.addChild(movie);

movieParent.alpha = 0;

pv3d.rawChildren.addChild(movieParent);

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

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

柱状专题图

[javascript] view
plaincopy

//create chart map materia list

matList.addMaterial(red, "front");

matList.addMaterial(red, "back");

matList.addMaterial(blue, "left");

matList.addMaterial(blue, "right");

matList.addMaterial(green, "top");

matList.addMaterial(green, "bottom");

var pvCube:Cube = new Cube(matList, 20, 2 * pv3dz, 20);

饼状专题图

[javascript] view
plaincopy

var pvCylinder:Cylinder = new Cylinder(null, pv3dz / 1.5, 15, 20, 1, pv3dz / 1.5, true, true);

var bottomMaterial:ColorMaterial = new ColorMaterial(0xff0000);

var middleMaterial:ColorMaterial = new ColorMaterial(0x0000ff);

var topMaterial:ColorMaterial = new ColorMaterial(0xff0000);

var i:int;

//this is the bottom face

for (i = 0; i < 18; i++)

{

pvCylinder.geometry.faces[i].material = bottomMaterial;

}

//the middle of the cylinder

for (i = 18; i < pvCylinder.geometry.faces.length - 18; i++)

{

pvCylinder.geometry.faces[i].material = middleMaterial;

}

//the top

for (i = pvCylinder.geometry.faces.length - 18; i <

pvCylinder.geometry.faces.length; i++)

{

pvCylinder.geometry.faces[i].material = topMaterial;

}

看看结果什么样





五. 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
plaincopy

var bmpfm:BitmapFileMaterial = new BitmapFileMaterial("http://heyb/FlexData/pv3d-rs.jpg");

bmpfm.interactive = true;

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
plaincopy

urlloader.load(new URLRequest("E:\\ PaperVision3D\\pv3d-rs-dem.dbf"));

var bdfByteArray:ByteArray = urlloader.data as ByteArray;

var dbfhdr:DbfHeader = new DbfHeader(bdfByteArray);

var vertices:Array = new Array();

for( var ii : int = 0; ii < dbfhdr.recordCount; ii++)

{

var dbfRecord : DbfRecord = DbfTools.getRecord( bdfByteArray, dbfhdr, ii );

var vertex:Vertex3D = new Vertex3D(dbfRecord.values.X, dbfRecord.values.Y, dbfRecord.values.ELE);

vertices.push(vertex);

}

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

[b][b]Export To XML Recordset Document[/b][/b]

[b][b]


[/b][/b]

[b][b]处理XML文件[/b][/b]

[javascript] view
plaincopy

urlloader.load(new URLRequest("http://heyb/FlexData/pv3d-ele.xml"));

var xml:XML = new XML(e.target.data);

var fields:XMLList = xml.Data.Fields.FieldArray.Field;

var records:XMLList = xml.Data.Records.Record;

var vertices:Array = new Array();

for (var ii:int = 0; recordIndex < records.length(); ii++)

{

var recordValues:XMLList = records[recordIndex].Values.Value;

var vertex:Vertex3D = new Vertex3D(recordValues[1], recordValues[2], recordValues[3]);

vertices.push(vertex);

}

②ArcGIS Server服务

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

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

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

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

通过GP服务获取高程信息

[javascript] view
plaincopy

var params:Object = new Object();

gp.execute(params, new AsyncResponder(onDEMSampleResult, onFault));

var pv:ParameterValue = gpResult.parameterValues[0];

var fs:FeatureSet = pv.value as FeatureSet;

var attributes:Array = fs.attributes;

var vertices:Array = new Array();

for (var recordIndex:int = 0; recordIndex < attributes.length; recordIndex++)

{

var record:Object = attributes[recordIndex];

var vertex:Vertex3D = new Vertex3D(record.x, record.y, record.g_g_g2);

vertices.push(vertex);

}

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

其它具体实现参见代码。

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



[b][b]


[/b][/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: