Google虽然退出了中国大陆地区,但它仍是我最喜欢的搜索引擎,除了搜索服务外,Google Earth 3D地形也将是我最常用的演示工具,因此,在这方面的时间投入肯定是值得的。
Google Earth (以下简称GE)中目前提供有简单的路径绘制功能,但路径的数据无法直接的去编辑,通过一些软件,比如 GE Path、GE Graph 我们可以大致的实现一些典型的应用,除此以外,就需要自己动手来处理数据了。GE中绘制的路径可以保存为两种格式,一种是kmz,一种是kml,前者是后者的压缩格式,kml属于xml格式文本,因此可以直接用记事本打开。为简化编程,我直接用Flash去打开kml文件,截取坐标数据进行处理,处理结果显示到文本框中,再通过手工劳动将数据复制回kml文件中去,这样实现了路径的简单编辑。
下面介绍一种飞行演示上的典型应用:平滑下降的飞行路径。飞机从高空降到地面需要平滑的下降,通常这个路径有些抽象,但通过3D技术可以较直观的来显示结果。下面是完成后的效果图:
实现过程:
1、在GE中,将地形显示为平面,然后画出想要的路径,GE默认的路径是同高度的,并且在GE中无法编辑(将来的版本或许有此功能)。将路径保存为kml格式文件。
2、在Flash10中编程,核心函数代码如下:
import flash.events.Event;
import fl.controls.NumericStepper;
var segments:Number = segNum.value;
segNum.addEventListener(Event.CHANGE,onCalcu);
function onCalcu(evt) {
segments = segNum.value;
createAvgCoordinates( ) ;
}
var totalDist:Number = 100;
var stepDist:Number = totalDist / segments;
var cData:Array = new Array();
var request:URLRequest = new URLRequest("未命名路径.kml");
var loader = new URLLoader();
loader.load(request);
loader.addEventListener(Event.COMPLETE, loaderCompleteHandler);
function loaderCompleteHandler(event:Event):void {
var s:String = loader.data;
//首次拆分取出坐标段落,并删除末尾的" </" 三个字符
var tempArr:Array = s.split("coordinates>");
var str:String = tempArr[1];
str = str.substring(0,str.length - 3);
//二次拆分,以空格为界,取出单个坐标
cData = str.split(" ");
//三次拆分,以逗号为界,将每个坐标分成三个数据.
for (var i = 0; i<cData.length; i++) {
cData[i] = cData[i].split(",");
//gePath中小数位数共六位,
//ge中经度13位,纬度14位.
//将字串转为数字,取七位小数.
for (var j=0; j<cData[i].length; j++) {
cData[i][j] = Math.round(Number(cData[i][j]) * Math.pow(10,7));
}
}
//trace(cData[cData.length -1]);检测末位坐标是否被误删
for (i =1; i<cData.length; i++) {
totalDist += Math.sqrt(Math.pow(cData[i][0] - cData[i - 1][0],2) + Math.pow(cData[i][1] - cData[i - 1][1],2));
}
createAvgCoordinates();
}
function createAvgCoordinates( ) {
stepDist=totalDist/segments;//单段长度
var dist:Array = new Array();//新的坐标数组
var curPsn:Array=[cData[0][0],cData[0][1],cData[0][2]];//当前位置点
var k:Number;// 直线段的斜率
//trace( cData[0],cData[1]);
for (var i=1; i< cData.length; i++) {
var t=Math.sqrt(Math.pow(cData[i][0]-curPsn[0],2)+Math.pow(cData[i][1]-curPsn[1],2));
k=Math.atan2(cData[i][1]-curPsn[1],cData[i][0]-curPsn[0]);
//trace("the angle is :",k*180/Math.PI);
while (t>stepDist) {//当遇到一大段路要走的时候,就保持原来的方向,向前走,直到该段距离小于指定步长
//trace( curPsn );
dist.push( [curPsn[0],curPsn[1],curPsn[2]] );
curPsn[0]+=stepDist*Math.cos(k);
curPsn[1]+=stepDist*Math.sin(k);
//trace( curPsn );
t=Math.sqrt(Math.pow(cData[i][0]-curPsn[0],2)+Math.pow(cData[i][1]-curPsn[1],2));
}
}
//dist.push( cData[cData.length -1 ]);
//trace( "the following data is about dist",dist );
var s:String="";
for (var j=0; j<dist.length; j++) {
s+=String(Math.round(dist[j][0])/Math.pow(10,7))+",";
s+=String(Math.round(dist[j][1])/Math.pow(10,7))+",";
s+=String(Math.round(Number( startLvl.text) -j*(Number(startLvl.text) - Number(endLvl.text))/dist.length))+" ";
}
coorData.text=s;
}
3、利用文本框中输出的坐标数据,拷贝回kml文件对应的位置,之后保存,再双击打开kml文件,将会在GE中显示出前面的图片。
压缩包下载
前面所使用的 kml 文件中仅包含单一路径,因此只有一组"<coordinates> </coordinates>"多路径显示不是这段代码要解决的问题。GE中坐标点用两个数字表示,小数点后有很长的一段,因此,需要先“放大”些,我这里先放大了10的7次方倍,这样可以避免运算精度损失过大的问题。之后,将坐标数据当成是平面坐标系的数据(在小范围内误差不会太大),进行计算,首先是将路径中的每一段累计,求出总距离,再根据期望拆分的块数,这里是分成了一百段,计算出每一步要跨过的步长。尽管经度差与纬度差所代表的距离不是同的,但当分段很细的时候,误差会自动的“均分”,因此不影响最终效果。当我们知道了每一段的长度和方向之后,就可以“命令”计算机走到这一段的终点,再来计算下一段路径。遇到大段要走时,就需要设置一个while循环,在调试的时候,这一步是非常容易死机的,如果你的机器超过15秒还没有结果,那肯定的代码有问题,尽管Flash的运算速度不够快,但几百段的数据还是能很快算完的。
kml 格式其实是很规范的,Google网站上挂了相关的技术文档,简单的来说,每一组坐标数据之后,紧跟着的就是一个高度数据,表示该位置的高度,那么,当我们知道起点、终点的高度,计算出每一段的高度也就不成问题,最后的工作就是把数组中的数据组成字串输出到文本框中。Flash中的文件控制能力过于弱了,有时间的话我都想借VB来用用,但想想就算是软件做成了,用的人估计也不会有多少,所以还是“半自动”化好了,自己知道怎么处理就行了。如果大家对这样的内容感兴趣的话,欢迎来一起探讨。
实际的飞行中,在接近地面的时候是不会这样连续转弯并下降的,通常是水平转弯,再接一个稳定的下降坡度下降,如果用编程来实现,就需要对路径进行分段,指定出不同段落的高度落差,再采用同样的平均分段法进行分段,可以得到较均匀的路线效果来。在绘制路径的时候只需要给出关键点的位置即可,对于曲线段尽量多给一些位置点,这样会平滑一些。GE提供有沿路径游览的功能,对于模拟飞行是再好不过了,只是这里的运算结果尚不够“平滑”,速度快时明显感觉到抖动,解决的办法是对分段的路径进行平滑处理,如果两段间的角度变化小于一定的角度,就当成直线来处理,或者在转弯时每步只能固定的转某个角度,这样平滑处理以后,可以保证在游览时镜头不会来回的摆动。
Google Earth 的 3D 地图的确是很有前途的一种技术,现在唯一担心的是数据的敏感性问题,精确的机场数据是属于保密的范畴,通常是禁止与网络相联的,尽管很多的“好事者”已经将全国的机场坐标全给打包上传了,而不管是否是可以对外公布的国际机场,但做为从业人员,警惕性还是要有的。在此声明一下,前图中所示路线并非真实飞行轨迹,仅是为编程测试用的一段模拟路线。
谢谢我的老朋友们的来访,无论我写什么,老朋友们总是会常来看看,使我的博客保持了一定的热度,谢谢大家,希望我的一些思路对大家有所帮助,对GE的应用我也是刚刚起步,如果有此方面的合作项目,欢迎联系。