google earth api 开发 - baiduimages.china-pub.com/ebook50001-55000/50503/ch05.pdf · 2010. 4....

111
Google Earth API 开发 章内容将针对如何使用 Google Earth API 中各个接口进行详细阐述,采用实例代码加详 解的方式,介绍 Google Earth 每个类的实际用途和 COM 的开发技巧。在阅读完本章之 后,我们希望开发者能够掌握 Google Earth 的开发,并且对 COM 也有一定的了解。 本章中的代码例子基本基于 Delphi 代码和 C sharp Visual Studio 2005 以下简称 C#),作 为教学语言, Delphi 是最棒的,而 C#也是目前非常流行的编程语言之一,用户可以轻松地将 这些代码移植到自己的程序中,也可以轻松地转换成其他的编码语言,所有的代码均通过 Delphi 7.0 Visual Studio 2005 的测试。但是,例子代码只是为了讲解 API 的使用,并没有 加入必要的容错逻辑,请读者加以注意。 5.1 概述 Google Earth Google 推出的第一款桌面地图产品,原先是 Keyhole 公司的产品,后为 Google 所收购,并分为了 3 个不同的版本,向公众免费开放的是 Free 版,加上 Google 的推 广,使其从一个本来的专业软件,成为了家喻户晓的地理空间搜索引擎, Google Earth 主界面 如图 5-1 所示。 近两年国内外基于 Google Earth 的开发应用非常广泛,例如有人将 Google Earth 包装成 ActiveX 组件,放置在网页上,使得 Web 网页也有了三维地图的功能;有人将建筑物的三 维实体模型放在 Google Earth 上,实现了三维虚拟城市;有的汽车俱乐部把 Google Earth GPS 结合起来,做成一套行车自驾游路线导航系统;国外有的地产商通过 Google Earth 的卫 星地图来规划设计地产项目,房地产经纪人使用 Google Earth 标出项目方位,展示给客户; 更有甚者推出了基于 Google Earth 的高尔夫游戏,正好利用三维卫星图片,实现了一个模拟 的高尔夫球场。诸如此类的应用远远不止这些,全世界的玩家都在开动脑筋想出各种各样的 5

Upload: others

Post on 07-Sep-2021

6 views

Category:

Documents


0 download

TRANSCRIPT

第 章

Google Earth API 开发

章内容将针对如何使用 Google Earth API 中各个接口进行详细阐述,采用实例代码加详

解的方式,介绍 Google Earth 每个类的实际用途和 COM 的开发技巧。在阅读完本章之

后,我们希望开发者能够掌握 Google Earth 的开发,并且对 COM 也有一定的了解。 本章中的代码例子基本基于 Delphi 代码和 C sharp(Visual Studio 2005 以下简称 C#),作

为教学语言,Delphi 是 棒的,而 C#也是目前非常流行的编程语言之一,用户可以轻松地将

这些代码移植到自己的程序中,也可以轻松地转换成其他的编码语言,所有的代码均通过

Delphi 7.0 和 Visual Studio 2005 的测试。但是,例子代码只是为了讲解 API 的使用,并没有

加入必要的容错逻辑,请读者加以注意。

5.1 概述

Google Earth 是 Google 推出的第一款桌面地图产品,原先是 Keyhole 公司的产品,后为

Google 所收购,并分为了 3 个不同的版本,向公众免费开放的是 Free 版,加上 Google 的推

广,使其从一个本来的专业软件,成为了家喻户晓的地理空间搜索引擎,Google Earth 主界面

如图 5-1 所示。 近两年国内外基于 Google Earth 的开发应用非常广泛,例如有人将 Google Earth 包装成

为 ActiveX 组件,放置在网页上,使得 Web 网页也有了三维地图的功能;有人将建筑物的三

维实体模型放在 Google Earth 上,实现了三维虚拟城市;有的汽车俱乐部把 Google Earth 和

GPS 结合起来,做成一套行车自驾游路线导航系统;国外有的地产商通过 Google Earth 的卫

星地图来规划设计地产项目,房地产经纪人使用 Google Earth 标出项目方位,展示给客户;

更有甚者推出了基于 Google Earth 的高尔夫游戏,正好利用三维卫星图片,实现了一个模拟

的高尔夫球场。诸如此类的应用远远不止这些,全世界的玩家都在开动脑筋想出各种各样的

5

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

292

花样。如图 5-2 所示的是驴友的徒步路线图。

图 5-1 Google Earth 主界面 图 5-2 驴友的徒步路线图

Google Earth 之所以能够拥有庞大而又令人振奋的应用前景,主要是因为 Google Earth是个很优秀的地图平台,不仅能够提供优异的地图图像传输功能,而且还提供了开发的 API接口,能够基于 API 控制地图的显示,操作地图要素,并且完成一定的空间分析。加上自己

的业务代码,完全可以架构一个满足日常业务需要的普通 GIS 系统。 基于 Google Earth 的应用程序,可以充分利用 Google 的免费卫星图片(商业应用需要付

费),而且其中的地图还无须自己维护,可节约大量的数据维护成本。Google Earth 还提供了

不少三维空间操控视点和地图要素的方法,稍加综合就可以做出超炫的效果,这是一般的地

图软件平台所不具备的。 但是基于 Google Earth 为平台做开发也有一定的风险,如政策因素。国家测绘管理部门

对于 Google Earth 提供的卫星图片的态度还不够明朗。目前 Google Earth 在政策上处于一个

灰色地带,是否开放商业领域应用还需要时间的验证。再如 Google Earth 应用的另一大方向

——GIS 系统,GIS 的各种地图数据库建设的国家标准目前还没有涉及 Google Earth 地图的

方方面面,因此 Google Earth 的应用在某一个特定行业的内部容易被边缘化。但是有理由相

信,随着地图产业的发展,Google 地图的触角会伸入到这个行业的每一个角落。

5.2 Google Earth API 开发基础

Google Earth 提供了 COM 接口,开发人员可以使用支持 COM 的可视化编程语言工具进

行开发。如用 Delphi、Visual Basic 等可视化编程语言来调用 COM 的接口、添加业务逻辑、

第 5 章 Google Earth API 开发

293

构建自己的程序,高级用户甚至可以使用 Python 来调用 Google Earth 的 COM 接口。 Google Earth的API函数遵循COM的规范,在开发研究之前,还需要搞清楚什么是COM。

1.什么是 COM

COM 是 Component Object Mode 的缩写,是微软定义的标准接口标准。而遵循 COM 标

准的小程序叫做 COM 组件,它是独立的可以动态加载的二进制可执行程序,可以是动态链

接库 DLL,也可以是 EXE 可执行程序。COM 组件的特点就是可以动态加载。打个通俗的比

方,COM 组件就像一个个电子集成块,内部有实现诸多功能的逻辑结构,外部有很多接口,

用户需要调用正确的接口完成相应的工作。 COM 组件的内部逻辑实现对于调用它的用户而言是透明的,用户无须知道 COM 组件是

如何完成计算的,只需要知道是如何调用组件所提供的接口即可。可以说 COM 的出现验证

了软件工业化或者说流水线化时代的到来。通过 COM 组件,工程师无须考虑那些自己不擅

长的领域,而把精力放在自己的专业上即可,然后编成 COM 组件或者调用第三方的组件来

构造自己的程序,这样做不仅效率高而且专业性强。 正如所有的 COM 组件一样,Google Earth 所提供的 COM 组件的内部逻辑对于用户也是

不可知的,但是可以通过学习如何调用其所提供的接口(也就是本章重点讲述的内容),来

构建自己的业务程序。 虽然目前已经是.NET 或者是 J2EE 的时代,但是 COM 作为一种相当成熟的软件标准仍

然不失其魅力,掌握好 COM 是进行 Google Earth API 开发的前提。

2.调用 Google Earth API 该用什么语言

任何支持 COM 规范的语言都可以编写 COM 组件并调用其接口,Google Earth 的 API也同样如此。开发人员可以用目前常见的任何一种支持 COM 的语言来调用,如 Delphi、Visual Basci、Visual C++、Java、Python 等。

本章中的所有代码都是基于Delphi和C#)的,选择Delphi的原因在于Delphi的前身Pascal语言是个极好的教学语言工具,并且 Delphi 在 COM 时代所创造的辉煌是那么耀眼夺目,在

这里采用 Delphi 是顺理成章的。而微软的 Visual Studio 2005 的 c#也是目前流行的编程语言,

程序员们可以直接使用本章中的例子代码而无须转换。

3.Google Earth 提供的 COM 组件

Google 并没有提供给用户独立的 COM 组件,而是在用户安装了 Google Earth 程序之后,

程序会将自带的动态链接库注册到用户的操作系统上,这时就可以调用 Google Earth API 了。 如果在如 Delphi 或者 VB 等可视化编程工具里没有发现 Google Earth API 的库文件,则

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

294

需要重新安装 Google Earth,或者重新注册 Google Earth 服务。Google 的官方网站上提供了

一个方法,即命令行的方式。 例如,Google Earth 程序安装在 C:\Program Files\Google\Google Earth 目录下,那么首先

在命令行窗口中进入这个目录,再运行“googleearth.exe /RegServer”,如图 5-3 所示。

图 5-3 注册服务

如果需要卸载,则输入“googleearth.exe /UnregServer”。

4.Google Earth 的 IDL 和对应的 TLB 文件

在 Google Earth 的官方网站上提供了 Google Earth API 的接口定义,这个接口定义是以

IDL 文件的方式展现的。IDL 是 Interface Definition Language 的首字母缩写,意思是接口定义

语言,而 IDL 文件则是用于定义接口的原型文件。 用户可以下载 Google Earth API 的 IDL 文件,并通过 VC++或者其他软件预编译成为运行

库 TLB 文件。VC++的 IDL 编译程序是 MIDL,这是一个命令行小程序,高级用户也可以直接

使用它来编译生成 TLB 文件。具体使用方法在这里不再赘述,请读者查阅相应的技术资料。 生成 TLB 文件后,用户可以利用 Visual Basic 或者 Delphi 导入 TLB 文件,生成相应的

代码,从而进一步使用。 在 Delphi 中使用 Google Earth API 的类型库,如图 5-4 所示,需要在调用的代码中加入

“uses EARTHLib_TLB;”代码,即要导入 Google Earth API 类型库代码文件。

图 5-4 Delphi 中的 API

第 5 章 Google Earth API 开发

295

5.在 Visual Studiao 2005 中引用 TLB 库文件

在 Visual Studiao 2005 中使用 TLB 库比较方便,用户可以直接引用,在菜单项【项目】

中选择【添加引用】,选择【浏览】选项页面,在打开窗口中有很多库类型选项,例如 DLL或者 TLB 或者 OCX 类型如图 5-5 所示。

图 5-5 库类型文件选择

选择 Google Earth 的 tlb 库文件,一般文件名为“GoogleEarth.tlb”添加引用即可,添加

后如图 5-6 所示。

图 5-6 添加引用

在 Visual Studio C#的类文件中,只需要加入对 EARTHLib 的引用即可,如 using EARTHLib,然后即可在编程中访问库中的接口和类了。

5.3 Google Earth API 详解

本节介绍的 Google Earth API 是目前 Goolge 官方网站上 新的 Google Earth API 接口定

义,也是 Google 所推荐使用的。与早期的 KeyHole API 相比有了很多新的特性,增加了很多

接口,这些接口基本都是基于 Keyhole API 封装的,我们将在以后的内容中介绍一些关于

Keyhole API 的应用,使得读者能够更加深入地理解 Google Earth API 的实质。

5.3.1 IApplicationGE 接口

IApplicationGE 接口是 Google Earth API 开发中 重要的一个接口,通过该接口可以控制

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

296

Google Earth 程序的开启、关闭、获取地图窗口的句柄、操作主窗体句柄,还可以进行获取

地图视场照相机对象、获取 Google Earth 版本号、转换坐标等一系列复杂操作。 在 IApplicationGE 接口中,可以找到后面 5.3.2~5.3.11 节中介绍的所有接口的影子,可以

说它是基于 Google Earth API 程序开发的基础。

1.初始化设置

打开 Google Earth 程序,首先要登录远程的 Google 地图服务器,Google Earth 会在本地

与服务器之间打开一个会话通道,然后等待十多秒钟之后,才能看见蓝黑色的地球。通常情

况下,进行 Google Earth API 的二次开发时,自己的程序也需要走这些步骤。 如何才能得知 Google Earth 已经注册好呢?Google 的 API 中提供了几个反馈 Google

Earth 是否已经登录到服务器上注册完毕的函数,通过这些函数,可以在 Google Earth 初始化

之后执行自己的业务代码,操作 Google Earth 完成相应动作。而没判断是否初始化结束就直

接操作 Google Earth,可能会导致错误。 这些与初始化相关的设置共有 4 个:IsInitialized、IsOnline、Login、Logout。

1)IsInitialized IsInitialized 介绍如下。

定义:返回一个布尔值,反馈 Google Earth 是否已经登录。 方程式:function IsInitialized: Integer; safecall。

Delphi 的实例代码: procedure TForm1.btnIsOnLineClick(Sender: TObject); begin if (F_AppGE.IsOnline <> 0) then begin showmessage('已经登录'); end else begin showmessage('尚未登录'); end; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void btloggin_Click(object sender, EventArgs e) { if (appGE.IsOnline() != 0) { MessageBox.Show("已经登录"); }else{

第 5 章 Google Earth API 开发

297

MessageBox.Show("尚未登录"); } }

执行以上代码,当 Google Earth 正在启动的时候,单击代码中名为【btnIsOnLine】的按

钮,会弹出【尚未登录】对话框,但是当 Google Earth 登录状态栏显示如图 5-7 所示的内容

的对话框之后,再单击按钮就会出现【已经登录】提示框了,如图 5-8 所示。这说明 Google Earth 在进行“Google Earth Initialization”动作过程中,实施了登录(IsInitialize)。

图 5-7 连接初始化 图 5-8 登录结果

2)IsOnline IsOnline 介绍如下。

定义:返回一个布尔值,反映 Google Earth 是否已经连接到数据服务器了。 方程式:function IsOnline: Integer; safecall;。

代码形式请参见上述 IsInitialized 中的代码,基本使用方法类似,在此不再赘述。

3)Login Login 介绍如下。

定义:登入,即开始一个与服务器之间的会话。 方程式:procedure Login; safecall;。

代码形式请参见上述 IsInitialized 中的代码,基本使用方法类似,在此不再赘述。

4)Logout Logout 介绍如下。

定义:登出,即离开与服务器之间的会话。 方程式:procedure Logout; safecall;。

代码形式请参见上述 IsInitialized 中的代码,基本使用方法类似,在此不再赘述。

2.视场相机设置

当用户观察 Google Earth 地图的时候,是没办法仅仅通过移动头部来获得不同观察体验

的。因为虽然我们看到的 Google 地球是个三维球体,但是地图窗口投射到屏幕上的影像是一

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

298

个不折不扣的平面,三维效果是通过计算模拟出来的。 要想看到不同方位的图像,例如看到地球的另一面,就必须用鼠标去拖曳,并且进行缩

放,缩放到某个地方,而此时用户无须转动头部和眼球。这是操纵视场照相机(ViewCamera)的结果。

“视场照相机”的详细介绍,请参见 ICameraInfo 接口。

IApplicationGE 接口提供了一个获得“视场照相机”的对象的方法 GetCamera。

1)GetCamera GetCamera 为取得当前视场的照相机。并不存在一个真实的照相机,只不过是通过当前

视场的内容和观察角度的反向推算,认为想像一个虚拟的照相机存在于视场之中。对于

ICameraInfoGE 接口的详细描述,见下面的方程式: function GetCamera(considerTerrain: Integer): ICameraInfoGE; safecall;

其参数如表 5-1 所示。

表 5-1 GetCamera 参数

参 数 输 入 方 向 值 类 型 定 义

considerTerrain In (Bool) 是否按照地形起伏而确定照相机焦点

参数 considerTerrain 有两个选择,当选择 true(非零)时,则根据地形的起伏计算照相

机焦点的位置;当选 false(零)时,则表示根据地球曲率计算。后一种不是很准确。 这个参数在照相机行进过程中起着重要的作用,特别是在山地多起伏的地区,照相机的

焦点需要根据需要设置。 Delphi 实例代码如下: GeFlag: boolean; …… function TGETest.Testfun: Double; var cm: ICameraInfoGE; begin result := 0; if GeFlag then begin cm := F_AppGE.GetCamera(1); //在 Delphi 中为整数型数值,非零表示 true

…… if cm <> nil then result := cm.Azimuth; end; end;

第 5 章 Google Earth API 开发

299

……

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private CameraInfoGE getCam() { CameraInfoGE cm = new CameraInfoGEClass(); cm = appGE.GetCamera(1); return cm; }

这个实例代码表示获取当前视场照相机对象,然后返回照相机的方位角。视场照相机除

了这个属性参数外还有其他的如移动速度、倾角、焦点经纬度等参数。

2)SetCamera IApplicationGE 还提供了设置视场照相机的方法 SetCamera,使用这个方法,开发人员可

以通过程序动态改变观察的方位和角度。 SetCamera 为设置照相机的焦点位置和移动速度,移动的效果如同用户坐在飞行中的飞

机从舷窗向外看一样。 其方程式如下: procedure SetCamera(const camera: ICameraInfoGE; speed: Double); safecall;

其参数如表 5-2 所示。

表 5-2 SetCamera 参数

参 数 输 入 方 向 值 类 型 定 义

Camera In ICameraInfoGE 照相机对象

Speed In Double 移动的速度

移动的速度从 0 开始,数字越大,移动越快。 Delphi 实例代码如下: GeFlag: boolean; …… procedure TGETest.Testfun(); var cm: ICameraInfoGE; begin if GeFlag then begin try cm := F_AppGE.GetCamera(1); //在 Delphi 中为整数型数值,非零表示 true if cm <> nil then begin F_AppGE.SetCamera(cm, 4); …… end;

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

300

except …… end; end; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void SetCam() { CameraInfoGE cm = new CameraInfoGEClass(); cm = appGE.GetCamera(1); if (cm != null) { appGE.SetCamera(cm, 4); } }

本例中首先获取当前的视场照相机对象,然后通过 SetCamera 设置已经获得的照相机对

象的速度,这仅仅是个演示程序。还有个类似的方法 SetCameraParams,此方法是设置照相

机各项参数的,在设置深度上要好于 SetCamera,请见下面的段落。

3)SetCameraParams SetCameraParams 为调整当前 Google Earth 的视场焦点的各个参数,无须重新定义照相

对象。 其方程式如下: procedure SetCameraParams(lat: Double; lon: Double; alt: Double; altMode:

AltitudeModeGE; Range: Double; Tilt: Double; Azimuth: Double; speed: Double); safecall;

其参数如表 5-3 所示。

表 5-3 SetCameraParams 参数

参 数 输 入 方 向 值 类 型 定 义

lat In double 双精度小数 纬度

lon In double 双精度小数 经度

alt In double 双精度小数 高度

altMode In altMode 高度类型值类型 高度模式

Range In double 双精度小数 范围

tilt In double 双精度小数 倾角

Azimuth In double 双精度小数 方位角

speed In double 双精度小数 速度

第 5 章 Google Earth API 开发

301

纬度的取值在-90°~ 90°;经度的取值在-180°~ 180°,倾角的取值在为

0°~ 90°。速度值为 Google Earth 自行定义的,取值为 0~5,0 为最小速度,5为最大。

Delphi 代码如下: F_AppGE: IApplicationGE; …… procedure TForm1.SetCameraParamsClick(Sender: TObject); var tmplat,tmplng : double; tmpalt : double; tmprange : double; tmptilt : double; tmpAzimuth : double; tmpSpeed: double; begin tmplat := 32.0; //焦点纬度 tmplng := 118.0; //焦点经度 tmpalt := 0; //焦点高度 tmprange := 500; //视场范围 tmptilt := 45; //镜头倾角 tmpAzimuth := 0; //镜头方位角 tmpSpeed := 4; //照相机移动速度 F_AppGE.SetCameraParams(tmplat,tmplng,tmpalt,RelativeToGroundAltitudeGE,tmprange,

tmptilt,tmpAzimuth,tmpSpeed); end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void SetCamParm() { double tmplat, tmplng, tmpalt, tmprange, tmptilt, tmpAzimuth, tmpSpeed; tmplat = 32.0; //焦点纬度 tmplng = 118.0; //焦点经度 tmpalt = 0; //焦点高度 tmprange = 500; //视场范围 tmptilt = 45; //镜头倾角 tmpAzimuth = 0; //镜头方位角 tmpSpeed = 4; //相机移动速度 appGE.SetCameraParams(tmplat, tmplng, tmpalt, (AltitudeModeGE)1, tmprange,

tmptilt, tmpAzimuth, tmpSpeed); }

这个代码中要注意,不能直接像 Delphi 代码一样使用 RelativeToGroundAltitudeGE,而

是要采用强制转换的方式。在 C#中 AltitudeModeGE 是个枚举类型: RelativeToGroundAltitudeGE = 1, AbsoluteAltitudeGE = 2,

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

302

SetCameraParams 是个非常有用的方法,通过此方法,可以动态改变 Google 地图窗口视

点的移动。上面的代码中首先设置了目标地点的经度、纬度、高度,另外还包括范围和方位

角转角、速度等指标。然后操纵 Google Earth 的地图窗口“飞行”到经度为 118°,纬度为

32°的地点。 以上的例子只是个 简单的应用演示,读者可以自行修改代码以实现更加复杂的功能。 开发时要注意经纬度参数的前后位置,并且注意所有参数的值类型。 关于照相机移动还有个重要的属性,就是自动“飞行(Fly-To)”速度,这是个默认的移

动速度值,通过人工或者代码都可以设置。

4)AutoPilotSpeed AutoPilotSpeed 为自动飞行(比如搜索或者定位到某个地理要素时)的照相机焦点的速

度。使用方式为“读(Get)/写(Set)”。值类型为 Double。 其方程式如下: property AutoPilotSpeed: Double read Get_AutoPilotSpeed write Set_AutoPilotSpeed;

Delphi 代码如下: F_AppGE: IApplicationGE; …… procedure TForm1.Button3Click(Sender: TObject); var aspeed :double; begin aspeed := F_AppGE.AutoPilotSpeed; showmessage(floattostr(aspeed)); end;

C#代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private double getAutoPilotSpeed() { double sp = appGE.AutoPilotSpeed; return sp; }

代码执行后, Google Earth 的自动飞行模式被触发,就会按照此处设置好的 AutoPilot Speed 值飞行。自动飞行模式即通过单击某地理要素(如一个点)或者是执行了 KML 脚本后,

Google Earth 视场照相机会自动“飞行”到地理要素所在地。读者自己可以双击地址栏中的

某个要素实验一下。 AutoPilotSpeed 的结果对应的是【Tools】→【Options】菜单命令中的【Fly-To Speed】值,

第 5 章 Google Earth API 开发

303

如图 5-9 所示。

图 5-9 自动飞行速度

3.截屏设置

Google Earth 有个很有用的功能,按【Ctrl+Alt+S】组合键,可以保存当前地图的截图照

片,默认是 JPG 格式的彩色图片。IApplicationGE 接口也提供了一个 SavaScreenShot 方法,

可以获得当前地图窗口内容的灰度图片,是黑白的。 SaveScreenShot 为当前地图视场范围截屏,保存成黑白效果的图片。保存的黑白照片可

以定义清晰程度。 其方程式如下: procedure SaveScreenShot(const fileName: WideString; quality: Integer); safecall;

其参数如表 5-4 所示。

表 5-4 SaveScreenShot 参数

参 数 输 入 方 向 值 类 型 定 义

fileName In WideString 保存文件的完整路径,包括名称

quality In Integer 保存文件的质量级别

quality 参数表示图片的清晰度质量,对保存结果的清晰度有很大影响,数字越大越清晰。

如图 5-10 和图 5-11 所示,这两张图的清晰程度就有鲜明的对比。

图 5-10 高清晰度 图 5-11 低清晰度

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

304

4.加载 KML 操作

在 Google Earth 中选择【File】→【Open】命令,可以打开 KML/KMZ 文件。Google Earth的 API 中也提供了两个功能类似的方法——OpenKMLFile 和 LoadKMLData,这两个方法都

可以向 Google Earth 加载 KML 文件,都能操作 KMZ 文件,但是各自略有不同。

1)OpenKMLFile OpenKMLFile 可以使 Google Earth 打开 KML 文件。注意要和 LoadKMLData 方法区别

开。OpenKMLFile 会清空执行历史,而 LoadKMLData 却不会清空执行历史,这一点在开发

的时候一定要注意。 其方程式如下: procedure OpenKmlFile(const fileName: WideString; suppressMessages: Integer);

safecall;

其参数如表 5-5 所示。

表 5-5 OpenKMLFile 参数

参 数 输 入 方 向 值 类 型 定 义

filename In WideString 要打开的 KML 文件完整路径,包括名称

suppressMessages In Bool 是否关闭 Google Earth 在打开 KML 文件时提示或者报错

的窗口

Delphi 实例代码: F_AppGE: IApplicationGE; …… procedure TGETest.OpenKML(kmlpath: WideString); begin …… F_AppGE.OpenKmlFile(kmlpath, 1); end; ……

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… //<param name="fp">fp为 KML文件的地址</param> private void open_KMLfile(string fp) { appGE.OpenKmlFile(fp,1); }

本例中的参数 kmlpath 为 KML 文件地址,如“c:\test.kml”。这里的所有代码都未加入容

错机制,例如此处实际使用过程中可能还会出现文件不存在的情况,需要首先加入判断代码,

第 5 章 Google Earth API 开发

305

确保运行无误。

2)LoadKMLData LoadKMLData 可以使 Google Earth 加载 KML 文件。注意要和 OpenKMLFile 区别开来。 其方程式如下。 procedure LoadKmlData(var kmlData: WideString); safecall;

其参数如表 5-6 所示。

表 5-6 LoadKmlData 参数

参 数 输 入 方 向 值 类 型 定 义

kmlData In WideString 需要加载入 Google Earth 的 KML 文档

Delphi 实例代码: F_AppGE: IApplicationGE; …… procedure TGETest.LoadKMLData(kmlData: WideString); begin …… F_AppGE.LoadKmlData(kmlData); end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… // 加载 KML文件内容 // <param name="kmlstr">KML文件内容</param> private void load_KML(string kmlstr) { appGE.LoadKmlData(ref kmlstr); }

注意:C#中编程,在引用参数的时候为传址。

本段代码中的 LoadKMLData 方法的参数 kmlData 应该是一个 KML 文档实体,而不是

KML 文件名(OpenKMLFile 方法的参数为 KML 文件的文件名)。 例如,参数 kmlData 可以加载下面的 KML 语句。 <?xml version='1.0' encoding='UTF-8'?> <kml xmlns='http://earth.google.com/kml/2.1'> <Document> <Placemark> <name>CantonmentPoint_1</name> <LookAt>

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

306

<longitude>118.27715</longitude> <latitude>32.2517</latitude> <altitude>0</altitude> <range>2000</range> <tilt>-5.821565606503298e-015</tilt> <heading>7.29646319265843</heading> </LookAt> <Point> <coordinates>118.322,32.27,0</coordinates> </Point> </Placemark> <Placemark> <name>CantonmentPoint_2</name> <LookAt> <longitude>118.27715</longitude> <latitude>32.2517</latitude> <altitude>0</altitude> <range>2000</range> <tilt>-5.821565606503298e-015</tilt> <heading>7.29646319265843</heading> </LookAt> <Point> <coordinates>118.2323,32.2334,0</coordinates> </Point> </Placemark> </Document> </kml>

以上的 KML 语句,可以放在一个字符串变量中,然后将该变量作为 LoadKMLData 的参

数加载。

5.地理要素操作

获取 Google Earth 中加载的地理要素,可以采用 GetFeatureByName 方法,该方法通过要

素名称确定要素对象,请参考 IFeatureGE 的 name 属性。

1)GetFeatureByName 定义为按照要素的名称得到地图要素对象,返回值类型为 IFeatureGE 对象。 其方程式如下: function GetFeatureByName(const Name: WideString): IFeatureGE; safecall;

其参数如表 5-7 所示。

表 5-7 GetFeatureByName 参数

参 数 输 入 方 向 值 类 型 定 义

Name In WideString 要素的名称

Delphi 实例代码:

第 5 章 Google Earth API 开发

307

…… procedure TGETest.SetFeature(name: string; v: Integer); var myFeature: IFeatureGE; begin myFeature:= F_AppGE.GetFeatureByName(name); if myFeature <> nil then begin myFeature.Visibility := v; …… end; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… /// <summary> /// 设置某要素是否可见 /// </summary> /// <param name="f_name">要素名称</param> private void setFeatureVisibility(string f_name) { FeatureGE i_f = appGE.GetFeatureByName(f_name); if (i_f != null) { i_f.Visibility = 1; } }

myFeature 取到的是 IFeatureGE 对象,而不是对象名称,所以后面的代码可以直接针对

myFeature 进行操作,如设置是否可视(见代码)。

2)GetFeatureByHref 定义为按照要素的 HREF 得到地图要素对象,返回值类型为 IFeatureGE 对象。 其方程式如下。 function GetFeatureByHref(const href: WideString): IFeatureGE; safecall;

其参数如表 5-8 所示。

表 5-8 GetFeatureByHref 参数

参 数 输 入 方 向 值 类 型 定 义

href In WideString 要素对象的 HFEF

在 Google Earth 加载了 KML 文档之后,地址要素栏中会有响应的项目呈树状显示,此

时双击某一项要素之后,地图窗口会自动缩放和旋转,“飞行”到那个被双击要素的所在地。

这个过程其实是 Google Earth 首先判断该要素有无视场(View),有视场才能有“飞行”定

位的过程,无视场则无法定位。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

308

3)SetFeatureView IApplicationGE 接口也提供了一种“飞行”定位的功能 SetFeatureView。表示设置当前地

图照相机的焦点位置和移动速度,移动到某个要素处定焦。 其方程式如下: procedure SetFeatureView(const feature: IFeatureGE; speed: Double); safecall;

其参数如表 5-9 所示。

表 5-9 SetFeatureView 参数

参 数 输 入 方 向 值 类 型 定 义

feature In IFeatureGE 要素对象

speed In Double 相机焦点的移动速度

Delphi 实例代码: F_AppGE: IApplicationGE; …… procedure TForm1.btnsetFeatureViewClick(Sender: TObject); var tmpFeature :IFeatureGE; begin try tmpFeature := F_AppGE.getFeatureByName('testplacemark1'); F_AppGE.setFeatureView(tmpFeature,4.0); except //…… end; end;

C#的实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… /// <summary> /// 设置要素的视场 /// </summary> /// <param name="f_name">要素名称</param> private void setFeatureView(string f_name) { FeatureGE i_f = appGE.GetFeatureByName(f_name); if (i_f != null) { appGE.SetFeatureView(i_f, 4.0); } }

通过要素名称获取要素对象 tmpFeature,然后通过 setFeatureView 方法,实现从其他位

置飞行定位到 tmpFeature 所在的位置,并且飞行的速度设置为 4.0,如图 5-12 所示。

第 5 章 Google Earth API 开发

309

图 5-12 定焦后

4)GetHighlightedFeature IFeatureGE 接口中有高亮某个要素的方法 Highlight 及一个判断是否要素被高亮的属性,

这里提供了一个获取被高亮要素的方法 GetHighlightedFeature。 GetHighlightedFeature 表示得到当前高亮显示的地理要素。 其方程式如下: function GetHighlightedFeature: IFeatureGE; safecall;

此方法的使用请参见 Highlight 方法,Highlight 是高亮显示某一个要素。

6.要素的气泡信息窗口操作

地图窗口内的地理要素,绝大多数会拥有一个标记(Placemark),特别是点状要素。单

击这个标记,会弹出一个信息气泡窗口,这个窗口里可以包含各种各样的信息,如图片、文

字、表格、超链接等。这些信息可以通过 KML 定义要素的时候设置。 IApplicationGE 接口提供了显示和隐藏气泡窗口的两个方法,分别是 ShowDescription

Balloon 和 HideDescriptionBalloons。

1)ShowDescriptionBalloon ShowDescriptionBalloon 表示针对某一个地图要素,Google Earth 弹出一个带有相应的表

述信息的气泡窗口。 其方程式如下: procedure ShowDescriptionBalloon(const feature: IFeatureGE); safecall;

其参数如表 5-10 所示。

表 5-10 ShowDescriptionBalloon 参数

参 数 输 入 方 向 值 类 型 定 义

feature In IFeatureGE 地理要素对象

Delphi 实例代码:

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

310

F_AppGE: IApplicationGE; …… procedure TForm1.btnShowDescriptionBalloonClick(Sender: TObject); var tmpFeature :IFeatureGE; begin try tmpFeature := F_AppGE.getFeatureByName('testplacemark1'); F_AppGE.ShowDescriptionBalloon(tmpFeature); except //…… end; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void showDesBallon(string f_name) { FeatureGE i_f = appGE.GetFeatureByName(f_name); if (i_f != null) { appGE.ShowDescriptionBalloon(i_f); } }

这是一个很实用的方法,有很多 Web 应用中都使用到它。这个方法和 KML、HTML 结

合起来可以实现如弹出对话框这样的功能和显示效果。ShowDescriptionBalloon 的参数为要素

对象,而不是对象名称。 代码执行后的效果如图 5-13 所示。

图 5-13 气泡窗口

2)HideDescriptionBalloons HideDescriptionBalloons 为关闭所有地理要素的气泡窗口。 其方程式如下。 procedure HideDescriptionBalloons; safecall;

第 5 章 Google Earth API 开发

311

7.屏幕坐标和地理坐标的转换问题

进行 GIS 开发项目时常常遇到的问题,也是 头疼的问题之一就是屏幕坐标和地理坐标

之间的转换问题。如屏幕中点或者鼠标位置和地理坐标之间的关系算法等。Google Earth 虽

然谈不上是个 GIS 软件,但是也提供了一个初级的坐标转换方法 GetPointOnTerrainFrom ScreenCoords,它可以把屏幕的四角及中心点转换成地理坐标。

GetPointOnTerrainFromScreenCoords 为取得地面上某一点的屏幕坐标。 其方程式如下: function GetPointOnTerrainFromScreenCoords(screen_x: Double; screen_y: Double):

PSafeArray; safecall;

其参数如表 5-11 所示。

表 5-11 GetPointOnTerrainFromScreenCoords 参数

参 数 输 入 方 向 值 类 型 定 义

screen_x In Double 屏幕坐标 X

screen_y In Double 屏幕坐标 Y

Google Earth 很有意思,只提供了单向的屏幕坐标到地理坐标的装换。在这里 screen_x和 screen_y 的取值都是在-1~+1 的,屏幕坐标的取值如图 5-14 所示。

图 5-14 屏幕坐标

Delphi 实例代码: procedure TForm1.Button1Click(Sender: TObject); var tmpArr : IPointOnTerrainGE; begin tmpArr := F_AppGE.GetPointOnTerrainFromScreenCoords(0.0,0.0); //获得屏幕中心坐标 showmessage(floattostr(tmpArr.Latitude) + ',' + floattostr(tmpArr.Longitude)); end;

(1,1)

(0,0)

(-1, -1)

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

312

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void GetCoordinateFromScreen() { PointOnTerrainGE pt = appGE.GetPointOnTerrainFromScreenCoords(0.0, 0.0); if (pt != null) { double m_lat = pt.Latitude; double m_lng = pt.Longitude; MessageBox.Show(m_lng.ToString() + "," + m_lat.ToString()); } }

图 5-12 中已经表明,地图窗口的中心点坐标为(0.0, 0.0),代码执行后,弹出的提示框内容如图 5-15 所示,反

映的是目前地图窗口中心点的坐标。 所以要想获得鼠标当前在地图窗口中实地对应的位

置,就必须按照比例关系来确定。

8.要素文件夹操作

1)GetMyPlaces GetMyPlaces 介绍如下。

定义:得到 Google Earth 中的“My Places”。虽然它是个文件夹,但 Google Earth 也

将之视为一个要素。 方程式:function GetMyPlaces: IFeatureGE; safecall;。

Delphi 实例代码: F_AppGE: IApplicationGE; …… procedure TForm1.btnGetmyPlaceClick(Sender: TObject); var tmpFeature :IFeatureGE; begin try tmpFeature := F_AppGE.GetMyPlaces; showmessage(tmpFeature.Name); except //…… end; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass();

图 5-15 地图窗口中心点坐标

第 5 章 Google Earth API 开发

313

…… private FeatureGE getMyPlaceFeature() { FeatureGE ft = appGE.GetMyPlaces(); if (ft != null) { return ft; } else { return null; } }

执行上述代码后,程序弹出提示框,说明取到的要素是“My Places”,中文版 Google Earth中名称为“我的位置”,如图 5-16 所示。

2)GetTemporaryPlaces GetTemporaryPlaces 介绍如下。

定义:得到临时位置文件夹,中文版的 Google Earth 中文名称为“临时位置”。 方程式:function GetTemporaryPlaces: IFeatureGE; safecall;。

Delphi 实例代码如下: F_AppGE: IApplicationGE; …… procedure TForm1.btnGetTemporaryPlacesClick(Sender: TObject); var tmpFeature :IFeatureGE; begin try tmpFeature := F_AppGE.GetTemporaryPlaces; if (tmpFeature.HasView <> 0) then showmessage(tmpFeature.name +'有视场') else showmessage(tmpFeature.name +'无视场') except //…… end; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private FeatureGE getTempFeature() { FeatureGE ft = appGE.GetTemporaryPlaces(); if (ft != null) { return ft; } else { return null; }

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

314

}

本例 Delphi 代码指出了临时父要素的视场(View)情况,执行后的效果如图 5-17 所示。

3)GetLayersDatabases GetLayersDatabases 介绍如下。

定义:根据图层列表获取要素数据源集合,该数据源就是要素集合。 方程式:function GetLayersDatabases: IFeatureCollectionGE; safecall;。

Delphi 实例代码: F_AppGE: IApplicationGE; …… procedure TForm1.btnGetLayersDatabasesClick(Sender: TObject); var tmpFeatures :IFeatureCollectionGE; i:integer; tmpstr : string; begin try tmpFeatures := F_AppGE.GetLayersDatabases; for i := 1 to tmpFeatures.Count do begin tmpstr := tmpstr + #13#10 + tmpFeatures[i].name; end; showmessage(tmpstr); except //…… end; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… /// <summary> /// 获得图层列表名称 /// </summary> /// <returns>字符串数组</returns> private string[] getLayersDatabase() { FeatureCollectionGE lyDB = appGE.GetLayersDatabases(); if (lyDB != null) { int i; string[] namelist = new string[lyDB.Count]; for (i = 0; i < lyDB.Count - 1; i++) { namelist[i] = lyDB[i].Name; } return namelist; } else

第 5 章 Google Earth API 开发

315

{ return null; } }

执行后的效果如图 5-18 所示。

图 5-16 My Places 文件夹 图 5-17 临时位置 图 5-18 要素集合

9.窗口句柄操作

如果要开发一个包含 Google Earth 的程序,获得主窗口的句柄是必要的。例如,通过代

码控制 Google Earth 主窗口的大小和状态这种需求,首先就需要采用 GetMainHWnd 取得主

窗口的句柄再做处理。

1)GetMainHwnd GetMainHwnd 的介绍如下。

定义:取得 Google Earth 程序主窗口的句柄。 方程式:function GetMainHwnd: SYSUINT; safecall;。

在 Delphi 中,可以将句柄变量申明成 HWND 类型,其实 HWND 类型就是

LongWord 类型的派生,是整型的一种,取值范围为 0~4 294 967 295 之间。

Delphi 实例代码: var GEMainWinHandle:HWND; …… GEMainWinHandle := F_AppGE.GetMainHwnd; //主窗口句柄 ……

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private IntPtr getGEHandle() { try { int GEMainWinHandle = appGE.GetMainHwnd(); return new IntPtr(GEMainWinHandle); }

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

316

finally { } }

在获取了 Google Earth 的主窗口之后,有时候还需要对地图窗口进行操作,如需要移动

地图窗口到用户自己的程序上。这个时候就需要获得地图窗口句柄,然后调用 Windows 的

API 来移动和设置地图窗口句柄的父窗口,通过 GetRenderHwnd 可以获取地图窗口的句柄。 以前 Keyhole 版本的 API 没有提供这个方法,这时候只有通过其他的方法获取地图窗口

句柄,如利用第三方工具获取。

2)GetRenderHwnd GetRenderHwnd 的介绍如下。

定义:返回 Google Earth 的地图窗口。 方程式:function GetRenderHwnd: SYSUINT; safecall;。

在 Delphi 中,可以将句柄变量申明成 HWND 类型,其实 HWND 类型就是

LongWord 类型的派生,是整型的一种,取值范围在 0~4 294 967 295 之间。下

面例子中的两个句柄变量正好申明成了 HWND 类型和 LongWord 类型。

Delphi 实例代码: F_AppGE: IApplicationGE; …… procedure TForm1.getmaphandleClick(Sender: TObject); var GEMapWinHandle:LongWord; GEMainWinHandle,pnlMap:HWND; r: TRect; begin GEMainWinHandle := F_AppGE.GetMainHwnd; GEMapWinHandle := F_AppGE.GetRenderHwnd; pnlMap := Panel2.Handle; Windows.SetParent(GEMapWinHandle, pnlMap); //将地图的父窗口设置为 panel …… end;

如上面的例子,Google Earth 这一版本的 API 比较明确地突出了地图窗口的句柄,可以

通过这个方法获得地图子窗口句柄,并结合前面获取的 Google Earth 程序主窗口句柄的方法,

能够写出很多复杂的程序,如图 5-19 所示。

第 5 章 Google Earth API 开发

317

图 5-19 地图窗口句柄

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void button1_Click(object sender, EventArgs e) { try { int GEMapHandle = appGE.GetRenderHwnd(); IntPtr mapPtr = new IntPtr(GEMapHandle); Apilibs.SetParent(mapPtr, plmap.Handle); } finally { } }

在 C#中调用 Windows 的 API 有点麻烦,需要引入 User32.dll 动态链接库,

利用 DllImport 方法可以做到:

[DllImport("User32.dll")] public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

具体 Windows API 函数在.net 平台上的调用和使用,不同的编程语言和环境有所不同,

具体请自行参考相关文档,在此不做赘述。

C#代码执行后可得到如图 5-20 所示的效果。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

318

图 5-20 抓取地图窗口到 Panel 上

上图中 Google Earth 的地图窗口被嵌入到了用户自己编写的程序中。其实承载地图窗口

的是一个 Delphi 中的 panel,通过 Windows 的 API 将地图窗口的父窗口设置为 panel,得以在

自己的程序中嵌入地图,在本地后台仍然是启动了一个 Google Earth 进程。

10.IApplicationGE 属性。

1)Google Earth 版本 Google Earth 版本介绍如下。 ① VersionMajor

定义:Google Earth 程序的版本号主号。 使用方式:读(Get)。 值类型:Integer。 方程式:property VersionMajor: SYSINT

read Get_VersionMajor;。

② VersionMinor 定义:Google Earth 程序的版本号辅号。 使用方式:读(Get)。 值类型:Integer。 方程式:property VersionMinor: SYSINT

read Get_VersionMinor;。

第 5 章 Google Earth API 开发

319

③ VersionBuild 定义:Google Earth 程序的构建号。 使用方式:读(Get)。 值类型:Integer。 方程式:property VersionBuild: SYSINT

read Get_VersionBuild;。

以上介绍的几个版本操作方法的 Delphi 实例代码: F_AppGE: IApplicationGE; …… procedure TForm1.btnMajorVerClick(Sender: TObject); var tmpMajor,tmpMinor,tmpBuild, tmpVerApptype : integer; begin tmpMajor := F_AppGE.VersionMajor; tmpMinor := F_AppGE.VersionMinor; tmpBuild := F_AppGE.VersionBuild; tmpVerApptype := F_AppGE.VersionAppType; edVer.Text := inttostr(tmpMajor) + '.' + inttostr(tmpMinor) +'.' + inttostr(tmpBuild) + '.' + inttostr(tmpVerApptype); end;

以上代码的运行结果如图 5-21 所示。

对应的 C#代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void getVersonNumber() { int tmpMajor, tmpMinor, tmpBuild, tmpVerApptype; tmpMajor = appGE.VersionMajor; tmpMinor = appGE.VersionMinor; tmpBuild = appGE.VersionBuild; }

在如图 5-21 所示的 4.1.7087.5 中,第一段“4”是程序版本号主号,第二段“1”是辅号,

第三段“7087”是构建号, 后一段数字为版本类型编号。这 4 段数字构成了 Google Earth的版本全编号。

版本类型编号请参照后面的 VersionAppType 的详细解释,在 Dephi 中数值和版本号的对

应关系如表 5-12 所示。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

320

表 5-12 Google Earth 版本号

版 本 名 称 值

EnterpriseClientGE Google 0

ProGE Google 1

PlusGE Google 2

FreeGE Google 5

UnknownGE Unknown null

如图 5-22 所示的是 Google Earth 的“关于”窗口界面。

图 5-21 程序构建号 图 5-22 Google Earth 的“关于”窗口界面

④ VersionAppType 定义:Google Earth 程序版本类型,是免费版还是专业版或其他版本。此处该类型为

一个枚举值。 使用方式:读(Get)。 值类型:Integer。 方程式:property VersionAppType: AppTypeGE

read Get_VersionAppType;。

程序的版本类型如表 5-13 所示。

表 5-13 Google Earth 版本

版本类型枚举值 定 义

EnterpriseClientGE Google Earth 企业版客户端

ProGE Google Earth Pro 版

PlusGE Google Earth Plus 版

FreeGE Google Earth Free 版

UnknownGE 未知版本

例子代码请参看前面的 VersionMajor、VersionMinor、VersionBuild 的例子和图。

2)读取地图数据流进度 ① StreamingProgressPercentage

第 5 章 Google Earth API 开发

321

StreamingProgressPercentage 介绍如下。 定义:反映 Google Earth 获取当前地图数据流的进度。 使用方式:读(Get)。 值类型:Integer。 方程式:property StreamingProgressPercentage: Integer

read Get_StreamingProgressPercentage;。

Delphi 实例代码: F_AppGE: IApplicationGE; …… procedure TForm1.Button2Click(Sender: TObject); begin TimerStream.Enabled := true; end; procedure TForm1.TimerStreamTimer(Sender: TObject); var tepStream : Double; begin tepStream := F_AppGE.StreamingProgressPercentage; edStream.Text := floattostr(tepStream); end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private double getDownloadStreamProcess() { return appGE.StreamingProgressPercentage; }

通过 StreamingProgressPercentage 方法可以获取现时的地图传输完成率,这个完成率是和

地图窗口下方的“Streaming”联系起来的,如图 5-23 所示。

图 5-23 Google Earth 的数据读取进度

② ViewExtents ViewExtents 介绍如下。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

322

定义:返回当前视场区域,获取值是 IViewExtentsGE 接口对象。 使用方式:读(Get)。 值类型:IViewExtentsGE。 方程式:property ViewExtents: IViewExtentsGE

read Get_ViewExtents;。

此方法的实例请参见 IFeatureGE 接口的 HasView。 ③ ElevationExaggeration 传统 GIS 的三维模块的必备功能就是地形拉伸,介绍如下。

定义:纵向拉伸地形,使之被扩大。 使用方式:读(Get)/写(Set)。 值类型:Double。 方程式:property ElevationExaggeration: Double read Get_ElevationExaggeration writeSet

_ElevationExaggeration;。

该属性的取值可为 0~3。当取值为 0 的时候,地形是平的;当取值为 1 的时候,地形保

持真实的形状;当大于 1 的时候,以倍数拉伸地形。 Delphi 实例代码: F_AppGE: IApplicationGE; …… procedure TForm1.btnElevationExaggerationClick(Sender: TObject); begin F_AppGE.ElevationExaggeration := 1; end;

以上代码取值不同的时候,地形的拉伸效果也不同。如图 5-24 和图 5-25 所示,对比可

以发现地图起伏明显不同。图 5-24 中的地形起伏较大,是由于 ElevationExaggeration 取值为

3 的结果;图 5-25 地形起伏正常,是由于 ElevationExaggeration 取值为 1 的结果。

图 5-24 拉伸状态 图 5-25 真实状态

第 5 章 Google Earth API 开发

323

3)Google Earth 控件 ① TourController TourController 介绍如下。

定义:返回漫游控件。 使用方式:读(Get)。 值类型:ITourControllerGE。 方程式:property TourController: ITourControllerGE

read Get_TourController;。

例子代码请参见 5.3.11 节中对 ITourControllerGE 接口的描述与实例。

② SearchController SearchController 介绍如下。

定义:返回搜索控件。 使用方式:读(Get)。 值类型:ISearchControllerGE。 方程式:property SearchController: ISearchControllerGE

read Get_SearchController;。

例子代码请参见 5.3.9 节中对 ISearchControlerGE 接口的描述与实例。

③ AnimationController AnimationController 介绍如下。

定义:返回动画控件。 使用方式:读(Get)。 值类型:ISearchControllerGE。 方程式:property AnimationController: IAnimationControllerGE

read Get_AnimationController;。

例子代码请参见 5.3.2 节中对 IAnimationControllerGE 接口的描述与实例。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

324

5.3.2 ICameraInfoGE 接口

ICameraInfoGE 接口是 Google Earth 照相机的接口,表示 Google Earth 地图上的某一点位

置的照相机,可以获取并设置照相机的焦点位置、转角、仰角、方位角等参数。通过设置照

相机的焦点位置,可以达到移动照相机的目的。这些操作的效果与 IApplicationGE 接口的方

法 SetCameraParams 很类似。 地球移动和旋转的参照面此时就是屏幕,而并非人眼的视平面。所以在针对屏幕时,

Google Earth 提供了一个叫做“视场照相机”的对象。通过该对象,可以转换视角,获得不

同的视觉体验,如旋转角度、倾斜角度等。 目前所有的三维场景的算法,都是基于如图 5-26 所示的原理的。

图 5-26 视场参考面

视场照相机就是替代视平面的工具,通过视场照相机的移动、旋转和倾斜,将不同的视

觉场景展现出来。 一般来说,确定空间 3 个点的位置需要经纬度和高度,确定一个轴向需要方位角和倾角,

确定场景的大小还需要知道范围。以上这些确定准则,简称为“三确定”。Google Earth 视场

照相机的“三确定”一共需要 6 个参数,另外加上一个选项参数。

1.空间位置

1)FocusPointLatitude FocusPointLatitude 介绍如下。

定义:照相机焦点位置的纬度。 使用方式:读(Get)/写(Set)。

视线

“投射”

用户

需要显示的物体 电脑屏幕

第 5 章 Google Earth API 开发

325

值类型:Double。 方程式:property FocusPointLatitude: Double

read Get_FocusPointLatitude write Set_FocusPointLatitude;。

Delphi 实例代码: GeFlag: boolean; …… procedure TGETest.SetLat(lat: double); var cm: ICameraInfoGE; begin if GeFlag and (F_AppGE <> nil) then begin try cm := F_AppGE.GetCamera(1); if cm <> nil then begin cm.FocusPointLatitude := lat; F_AppGE.SetCamera(cm, 4); end; except …… end; end; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void setCamFocusLat(double cmlat) { CameraInfoGE cm = appGE.GetCamera(1); if (cm != null) { cm.FocusPointLatitude = cmlat; appGE.SetCamera(cm, 4); } }

2)FocusPointLongitude FocusPointLongitude 介绍如下。

定义:照相机焦点的经纬位置。 使用方式:读(Get)/写(Set)。 值类型:Double。 方程式:property FocusPointLongitude: Double

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

326

read Get_FocusPointLongitude write Set_FocusPointLongitude;。

Delphi 实例代码: …… procedure TGETest.SetLon(lng: double); var cm: ICameraInfoGE; begin if FConnected and (F_AppGE <> nil) and geGrabbed then begin try cm := F_AppGE.GetCamera(1); if cm <> nil then begin cm.FocusPointLongitude := lng; F_AppGE.SetCamera(cm, 5); end; except …… end; end; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void setCamFocusLng(double cmlng) { CameraInfoGE cm = appGE.GetCamera(1); if (cm != null) { cm.FocusPointLongitude = cmlng; appGE.SetCamera(cm, 4); } }

3)FocusPointAltitude FocusPointAltitude 介绍如下。

定义:照相机焦点位置的高度,不过返回值取决于 AltitudeMode 的设置,参见下面

对 AltitudeMode 的介绍。 使用方式:读(Get)/写(Set)。 值类型:Double。 方程式:property FocusPointAltitude: Double

read Get_FocusPointAltitude write Set_FocusPointAltitude;。

Delphi 实例代码:

第 5 章 Google Earth API 开发

327

…… function TFormCameraSample.GetAltitude: double; var cm: ICameraInfoGE; begin cm := F_AppGE.GetCamera(1); if cm <> nil then result:= cm.FocusPointAltitude; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void setCamFocusAlt(double cmAlt) { CameraInfoGE cm = appGE.GetCamera(1); if (cm != null) { cm.FocusPointAltitude = cmAlt; appGE.SetCamera(cm, 4); } }

4)FocusPointAltitudeMode FocusPointAltitudeMode 介绍如下。

定义:照相机焦点位置的高度模式。 使用方式:读(Get)/写(Set)。 值类型:AltitudeModeGE。 方程式:property FocusPointAltitudeMode: AltitudeModeGE

read Get_FocusPointAltitudeMode write Set_FocusPointAltitudeMode;。

Delphi 实例代码: function TForm1.GetAltitude: AltitudeModeGE; var cm: ICameraInfoGE; begin cm := FApplicationGE.GetCamera(1); if cm <> nil then result:= cm.FocusPointAltitudeMode; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void setCamAltMode() {

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

328

CameraInfoGE cm = appGE.GetCamera(1); cm.FocusPointAltitudeMode = (AltitudeModeGE)1; }

在 5.3.1(2)节中曾经说明,FocusPointAltitudeMode 是个枚举类型。 RelativeToGroundAltitudeGE = 1, AbsoluteAltitudeGE = 2,

2.轴向

1)Azimuth Azimuth 介绍如下。

定义:相机镜头的方位角。通常情况下方位角的取值范围在 0~360°,而 Google Earth中取值范围被定义在-180°~ +180°之间。

使用方式:读(Get)/写(Set)。 值类型:Double。 方程式:property Azimuth: Double

read Get_Azimuth write Set_Azimuth;。

Delphi 实例代码: GeFlag: boolean; …… function TGETest.GetAzimuth: Double; var cm: ICameraInfoGE; begin result := 0; if GeFlag then begin cm := F_AppGE.GetCamera(1); if cm <> nil then result := cm.Azimuth; end; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void setCamAzimuth() { CameraInfoGE cm = appGE.GetCamera(1); cm.Azimuth = 90.0; }

第 5 章 Google Earth API 开发

329

2)Tilt Tilt 介绍如下。

定义:照相机镜头的倾角。在 Google Earth 中倾角的取值范围在 0~90°之间。 使用方式:读(Get)/写(Set)。 值类型:Double。 方程式:property Tilt: Double

read Get_Tilt write Set_Tilt;。

如图 5-27 所示,可以很容易弄懂方位角 Azimuth 和倾角 Tilt 的区别。

图 5-27 方位角与倾角

Delphi 实例代码: function TGEPanel.GetTilt: Double; var cm: ICameraInfoGE; begin result := 0; if FConnected then begin cm := F_AppGE.GetCamera(1); result := cm.Tilt; //取得倾角 end; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void setCamTilt() { CameraInfoGE cm = appGE.GetCamera(1);

Tilt

Azimuth

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

330

cm.Tilt = 45.0; }

3.视场范围(三确定) Range 介绍如下。

定义:照相机到被观察点的距离,单位是“米”。 使用方式:读(Get)/写(Set)。 值类型:Double。 方程式:property Range: Double

read Get_Range write Set_Range;。

Delphi 实例代码: function TGEPanel.GetRange: Double; var cm: ICameraInfoGE; begin result := 0; if FConnected then begin cm := F_AppGE.GetCamera(1); result := cm.Range; end; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void setCamRange() { CameraInfoGE cm = appGE.GetCamera(1); cm.Range = 1000; }

4.一个视场照相机的完整例子

1)实例代码 下面给出了一个完整的关于 ICameraInfoGE 的 Delphi 代码: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs,

StdCtrls; type TFormCameraSample = class(TForm) ……

第 5 章 Google Earth API 开发

331

private { Private declarations } …… public { Public declarations } end; var FormCameraSample: TFormCameraSample; implementation uses EARTHLib_TLB; {$R *.dfm} var F_AppGE: IApplicationGE;

首先窗体运行,创建新的 Google Earth 的进程: //程序开始运行 procedure TFormCameraSample.FormCreate(Sender: TObject); begin try F_AppGE := CoApplicationGE.Create(); except showmessage('启动 Google Earth失败'); end; end;

先获取当前的视场照相机,并获取照相机的各个参数,显示在 TextBox 上,代码如下: //单击【获取】按钮 procedure TFormCameraSample.btnGetClick(Sender: TObject); begin if ((F_AppGE <> nil) and (F_AppGE.IsInitialized <> 0)) then begin edAlt.Text:= floattostr(GetAltitude()); edLng.Text := floattostr(GetLng()); edLat.Text := floattostr(GetLat()); edAzi.Text := floattostr(GetAzimuth()); edTilt.Text := floattostr(GetTilt()); edRan.Text := floattostr(GetRange()); end else begin showmessage('请稍等……'); end; end; //程序窗口关闭 procedure TFormCameraSample.FormClose(Sender: TObject; var Action: TCloseAction); begin F_AppGE := nil; end; function TFormCameraSample.GetAltitude: double; var cm: ICameraInfoGE;

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

332

begin cm := F_AppGE.GetCamera(1); if cm <> nil then result:= cm.FocusPointAltitude; end;

获取照相机各个参数的方法函数,如方位角、经纬度等信息的代码如下: //获取照相机方位角 function TFormCameraSample.GetAzimuth: double; var cm: ICameraInfoGE; begin cm := F_AppGE.GetCamera(1); if cm <> nil then result:= cm.Azimuth; end; //获取照相机纬度 function TFormCameraSample.GetLat: double; var cm: ICameraInfoGE; begin cm := F_AppGE.GetCamera(1); if cm <> nil then result:= cm.FocusPointLatitude; end; //获取照相机经度 function TFormCameraSample.GetLng: double; var cm: ICameraInfoGE; begin cm := F_AppGE.GetCamera(1); if cm <> nil then result:= cm.FocusPointLongitude; end; //获取照相机倾斜角 function TFormCameraSample.GetTilt: double; var cm: ICameraInfoGE; begin cm := F_AppGE.GetCamera(1); if cm <> nil then result:= cm.Tilt; end; //获取照相机高度 procedure TFormCameraSample.SetAltitude(v: double); var cm: ICameraInfoGE; begin cm := F_AppGE.GetCamera(1);

第 5 章 Google Earth API 开发

333

if cm <> nil then cm.FocusPointAltitude := v; end; //获取照相机范围 function TFormCameraSample.GetRange: double; var cm: ICameraInfoGE; begin cm := F_AppGE.GetCamera(1); if cm <> nil then result:= cm.Range; end;

设置 Google Earth 的视场照相机的各个参数,代码如下: //设置照相机方位角 procedure TFormCameraSample.SetAzimuth(v: double); var cm: ICameraInfoGE; begin cm := F_AppGE.GetCamera(1); if cm <> nil then cm.Azimuth := v; end; //设置照相机纬度 procedure TFormCameraSample.SetLat(v: double); var cm: ICameraInfoGE; begin cm := F_AppGE.GetCamera(1); if cm <> nil then cm.FocusPointLatitude := v; end; //设置照相机经度 procedure TFormCameraSample.SetLng(v: double); var cm: ICameraInfoGE; begin cm := F_AppGE.GetCamera(1); if cm <> nil then cm.FocusPointLongitude := v; end; //设置照相机倾斜角 procedure TFormCameraSample.SetTilt(v: double); var cm: ICameraInfoGE; begin cm := F_AppGE.GetCamera(1); if cm <> nil then cm.Tilt := v;

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

334

end; //设置照相机范围

procedure TFormCameraSample.SetRange(v: double); var cm: ICameraInfoGE; begin cm := F_AppGE.GetCamera(1); if cm <> nil then cm.Range := v; end;

单击按钮时调用的方法代码如下: //单击【设置】按钮 procedure TFormCameraSample.BtnSetClick(Sender: TObject); begin if (F_AppGE <> nil) then begin SetAltitude(strtofloat(edAlt.Text)); SetLat(strtofloat(edLat.Text)); SetLng(strtofloat(edLng.Text)); SetAzimuth(strtofloat(edAzi.Text)); SetTilt(strtofloat(edTilt.Text)); SetRange(strtofloat(edRan.Text)); SetGoogleEarthCamera; end else begin showmessage('请稍等……'); end; end; //设置照相机 procedure TFormCameraSample.SetGoogleEarthCamera; var cm: ICameraInfoGE; cmobj :ICameraInfoGE; begin cm := F_AppGE.GetCamera(1); if cm <> nil then begin cmobj := CoCameraInfoGE.create(); cmobj.FocusPointLatitude := cm.FocusPointLatitude; cmobj.FocusPointLongitude := cm.FocusPointLongitude; cmobj.FocusPointAltitude := cm.FocusPointAltitude; cmobj.Tilt := cm.Tilt; cmobj.Azimuth := cm.Azimuth; cmobj.Range := cm.Range; F_AppGE.SetCamera(cmobj, 5.0); end; end; end.

第 5 章 Google Earth API 开发

335

2)代码分析 本例子代码的逻辑主要包括两个方面:一是获取参数值;另一个是设置参数值。经纬度、

高度可以确定照相机的空间位置,而视线的方位则是通过方位角、倾角和范围确定的。 上面的这个例子,用户可以截获当前的 Google Earth 地图视场照相机的各个参数,也可

以通过设置自定义数值调整照相机的方位和视线方向。 代码执行后的效果如图 5-28 所示。

图 5-28 照相机参数

程序运行后会自动启动 Google Earth。当 Google Earth 启动之后,用户单击【获取】按

钮,程序能够获取当前地图视场照相机的各项参数。可以改动任何一个值,然后单击【设置】

按钮,反向控制 Google Earth 的视场焦点转移。

5.3.3 IFeatureGE 接口

IFeatureGE 接口是针对 Google Earth 要素对象操作的接口。所谓的 Google Earth 要素,

指的是加载的由 KML 描绘的地理要素。此接口提供的 终目的仅仅是捕获并显示,并没有

如添加、删除这种操作类型。地理要素在 Google Earth 中是由 KML 组织的,通过组织文字、

图片、超链接等资源,丰富 Google Earth 的附加资源。 这些要素包括:地标(Placemark)、图层(Overlay)、文件夹节点(Folder)、文档节点

(Document)、 超链接(NetworkLink),Google Earth 的官方资料上还提及了流层(Streamed Layers)要素。

1.IFeatureGE

1)子要素和父要素的操作 通常情况下,与 KML 的文档结构类似,在 Google Earth 中地理要素的层次分布呈现“树”

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

336

状结构——一个父要素可以包含一个或者多个子要素,其下的子要素还可以再包含子要素,

以此类推。这样一来,需要有一种方法,以获得某个父要素所拥有的子要素,并且以集合的

形式返回,Google Earth API 提供了 GetChildren 的方法。 ① GetChildren 定义为得到当前要素下所有子要素的集合。这是个集合,不是单个元素。 其方程式如下: function GetChildren: IFeatureCollectionGE; safecall;

方程式原型提供了这样的信息:GetChildren 返回值为 IFeatureCollectionGE 类型,而不

是 IFeature。前者是要素集合,后者为单个要素。在使用的时候要认清这一点,从下面的代

码中可以清楚地看到。 Delphi 实例代码: var F_AppGE: IApplicationGE; …… procedure TForm1.btngetChClick(Sender: TObject); var FFeatures :IFeatureCollectionGE; //要素集合 ParFeature : IFeatureGE; i: integer; tmpstr : string; begin ParFeature := F_AppGE.GetFeatureByName('folerTest'); FFeatures := ParFeature.GetChildren; for i := 1 to FFeatures.Count do begin tmpstr := tmpstr + #13#10 + FFeatures[i].Name; end; showmessage(tmpstr); end;

首先用 Google Earth 程序打开本书第 3 章的

KML 代码 Folder.kml,然后执行。 上述的 Delphi 代码中父要素取的是名为

“folderTest”的 Folder 元素,该要素有 7 个子要素,

程序中使用了 for 循环来遍历要素集合。例子中的

逻辑是取各个子要素的名字,然后用对话框显示出

来,如图 5-29 所示。

图 5-29 要素集合

第 5 章 Google Earth API 开发

337

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private string[] getFeatureChildren(string ft_name) { FeatureGE parentFt = appGE.GetFeatureByName(ft_name); string[] name_kids = null; if (parentFt != null) { FeatureCollectionGE childrenFt = parentFt.GetChildren(); if (childrenFt != null) { name_kids = new string[childrenFt.Count]; for (int i = 0; i < childrenFt.Count - 1; i++) { name_kids[i] = childrenFt[i].Name; } } } return name_kids; }

对照上面的这幅地图,代码执行后可显示如图 5-30 和图 5-31 所示的对话框。

图 5-30 要素框 图 5-31 结果集

图 5-30 中的要素框 上面的父要素是 foderTest,7 个子要素以树状形式展示开来。这里

讲述了如何根据父要素获取子要素集合。有时候也需要有反向获取的需求,如知道某一个子

要素,要想获知其他所有同级别的子要素的话,通常的做法是首先知道它们共同的父要素是

谁,再根据父要素查找子要素集合,Google Earth 提供了 GetParent 方法来反向获取。 ② GetParent 定义为得到包含当前要素的父要素。其方程式如下: function GetParent: IFeatureGE; safecall;

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

338

Delphi 实例代码: var F_AppGE: IApplicationGE; …… procedure TForm1.BtnGetParClick(Sender: TObject); var parentFeature : IFeatureGE; //父要素 childFeature : IFeatureGE; //子要素 tmpstr : string; begin childFeature := F_AppGE.GetFeatureByName('testplacemark2'); parentFeature := childFeature.GetParent; tmpstr := parentFeature.Name; showmessage(tmpstr); end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private FeatureGE getFeatureParent(string ft_name) { FeatureGE ft = appGE.GetFeatureByName(ft_name); return ft.GetParent(); }

首先用 Google Earth 程序打开本书第 3 章的 KML 代码 Folder.kml,然后执行。 代码中的子要素取的是名为“testplacemark2”的要素,其父要素是“folderTest”,在执

行程序后,程序按要求找到了父要素节点名称,如图 5-32 所示。

图 5-32 父要素

2)高亮选中要素 IFeartureGE 接口提供的 Highlight 方法,仅仅是使得在地址要素框中选中的项目呈现高

亮状态,而在地图窗口内要素的外观并没有发生改变。 Highlight 将当前的要素设置为被选中的高亮状态。其方程式如下: procedure Highlight; safecall;

Delphi 实例代码:

第 5 章 Google Earth API 开发

339

var F_AppGE: IApplicationGE; …… procedure TForm1.BtnHighLightClick(Sender: TObject); var SelFeature : IFeatureGE; tmpstr : string; begin SelFeature := F_AppGE.GetFeatureByName('testplacemark2'); SelFeature.Highlight; end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void setFeatureHighlight(string ft_name) { FeatureGE ft = appGE.GetFeatureByName(ft_name); ft.Highlight(); }

首先用 Google Earth 程序打开本书第 3 章的 KML 代码 Folder.kml,然后执行。 代码执行后,在地址栏中名为“testplacemark2”的要素被高亮显示,如图 5-33 所示。

图 5-33 高亮显示

该方法的使用,还可以参考和配合 IFeartureGE 的属性项 Highlighted,返回该要素是否

被高亮选中了。例如这样的需求:通过程序判断某个要素是否已经为选中状态,如果在被选

中状态则被高亮显示。

2.IFeatureGE 属性

1)高亮选中要素 Highlighted 介绍如下。

定义:返回一个布尔值,表示当前的要素是否被高亮选中。如果被高亮选中,返回

true,否则返回 false。 使用方式:读(Get)。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

340

值类型:Integer(Bool)。 方程式:property Highlighted: Integer

read Get_Highlighted;。

Delphi 实例代码: var F_AppGE: IApplicationGE; …… procedure TForm1.btnClick(Sender: TObject); var tmpFeature : IFeatureGE; tmpstr : string; boolflag : integer; begin tmpFeature := F_AppGE.GetFeatureByName('folerTest'); if (radfolerTest.Checked) then begin boolflag := tmpFeature.Highlighted; if (boolflag <> 0 ) then tmpstr := '高亮' else tmpstr := '没选中'; showmessage(tmpstr); end; end;

C#实例代码: FeatureGE ft = appGE.GetFeatureByName(ft_name); if (ft.Highlighted == 1) { MessageBox.Show("要素被选中高亮。"); }

首先用 Google Earth 程序打开本书第 3 章的 KML 代码 Folder.kml,然后执行。 上述的代码逻辑是,如果“folderTest”被选中则弹出“高亮”提示框,如图 5-34 所示。

图 5-34 “高亮”提示框

在遍历要素集合(Fearture Collection)的过程中,确定指定某个要素的 好方法是对比

要素名称(Name)。

第 5 章 Google Earth API 开发

341

2)视场 HasView 在使用 Google Earth 的时候,通常鼠标会发挥很巧妙的作用,例如,要仔细浏览某个要

素的时候,只需要双击该要素的标识,地图画面就会自动缩放并移动,“飞行”到那个要素

所在地。但是如果双击图 5-30 中的父要素 folderTest,会不会也能促使地图画面的“飞行”?

答案是否定的,因为父要素 folderTest 没有视场(View),IFeartureGE 接口提供了一个 HasView属性,来判断要素是否拥有视场。

HasView 介绍如下。 定义:返回一个布尔值,表示这个要素是否有视场,即能否操作 Google Earth“飞到”

要素的所在地。 使用方式:读(Get)。 值类型:Integer(Bool)。 方程式:property HasView: Integer

read Get_HasView;。

例如线段、标记、面等 KML 要素都有视场(View),而包含这些要素的文件夹节点却没

有视场,即 Google Earth 是不可能“飞到”文件夹节点那里的。返回 true 表示有视场,没有

视场则返回 false。 从 KML 的语法上分析原因,是因为<Folder>、<Document>等 KML 节点本身并不包含

经纬度点位信息,而如< Polygon >、<PlaceMark>等子节点反而包含经纬度点位信息,因此可

以控制 Google Earth“飞到”要素所在地。 Delphi 实例代码: var F_AppGE: IApplicationGE; …… procedure TForm1.Button1Click(Sender: TObject); var tmpFeature1,tmpFeature2 : IFeatureGE; //要素变量 tmpstr : string; boolflag : integer; //是否要素被选中了 begin tmpFeature1 := F_AppGE.GetFeatureByName('folerTest'); tmpFeature2 := F_AppGE.GetFeatureByName('testplacemark1'); if (radfolerTest.Checked) then begin boolflag := tmpFeature1.HasView; if (boolflag <> 0 ) then tmpstr := '有视场' else tmpstr := '无视场'; showmessage(tmpstr);

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

342

end else begin

…… end; end;

首先用 Google Earth 程序打开本书第 3 章的 KML 代码 Folder.kml,然后执行。 folderText 是父节点要素,是没有视场的,所以执行程序后,会弹出“无视场”提示框;

而 testplacemark1 是有视场的,所以执行程序后,会弹出如图 5-32 所示的“有视场”提示框。

图 5-35 “有视场”提示框

Highlighted 可参考 IFeartureGE 的方法 Highlight,该方法已经在前面介绍了。

3)四维空间和时间轴 Google Earth API 另一个亮点就是引入了四维空间的概念——除了通常意义上的三维,剩

下的一维是时间轴。 在前面 KML 的介绍中,说明了可以通过设置要素的有效性,将地理要素与时间进行绑

定,从而在Google Earth中展现不同历史时间段的切面。对于KML的有效期设置,Google Earth API 提供了 TimeInterval 属性来获取和判断。

① TimeInterval TimeInterval 介绍如下。

定义:表示要素的有效期,从 KML 的语法上分析,本书在第 3 章讲过关于 KML 时

间类的标签,这种标签拥有开始和结束时间,此属性的返回值为 ITimeIntervalGE 接

口类型。 使用方式:读(Get)。 值类型:ITimeIntervalGE。 方程式:property TimeInterval: ITimeIntervalGE

read Get_TimeInterval;。

第 5 章 Google Earth API 开发

343

Delphi 实例代码: var F_AppGE: IApplicationGE; …… procedure TForm1.BtnGetTimeIntervalClick(Sender: TObject); var FFeatures :IFeatureCollectionGE; ParFeature : IFeatureGE; i: integer; tmpstr : string; tmpYear,tmpMonth,tmpDay:integer; begin ParFeature := F_AppGE.GetFeatureByName('folerTest'); FFeatures := ParFeature.GetChildren; for i := 1 to FFeatures.Count do begin if (FFeatures[i].Highlighted <> 0) then begin tmpYear := FFeatures[i].TimeInterval.BeginTime.Year; tmpMonth := FFeatures[i].TimeInterval.BeginTime.Month; tmpDay := FFeatures[i].TimeInterval.BeginTime.Day; tmpstr := inttostr(tmpYear) + '-'+ inttostr(tmpMonth) + '-' +inttostr(tmpDay); end; end; showmessage('开始时间是:'+tmpstr); end;

C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private DateTime getFeatureTime(string ft_name) { try { FeatureGE ft = appGE.GetFeatureByName(ft_name); int myYear = ft.TimeInterval.BeginTime.Year; int myMonth = ft.TimeInterval.BeginTime.Month; int myDay = ft.TimeInterval.BeginTime.Day; DateTime tm = new DateTime(myYear, myMonth, myDay); return tm; } catch (Exception err) { MessageBox.Show(err.Message); } }

首先用 Google Earth 打开第 3 章的例子“TimeSpan.kml”,然后执行。 运行上述的 Delphi 程序之后,选择名为“nanjing”的要素,单击 Delphi 程序按钮,会

弹出提示框,返回要素“nanjing”的开始时间,如图 5-36 所示。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

344

图 5-36 时间段

② Name Name 介绍如下。

定义:返回一个字符串,表示当前的要素的名称。 使用方式:读(Get)。 值类型:字符串(string)。 方程式:property Name: WideString

read Get_Name;。

这个属性很容易令人联想到 IApplicationGE 中的另一个方法 GetFeatureByName(),该方

法也是通过要素的名称获得要素对象的。下面 Delphi 的例子,说明了如何使用 Name 属性来

完成同样的效果: …… F_FeartureCollectionGE := coFeatureCollectionGE.Create; for i:=0 to F_FeartureCollectionGE.Count -1 do begin F_FeartureGE := F_FeartureCollectionGE.Item[i]; if (F_FeartureGE.Name = 'testFeature') then begin showmessage('找到了!'); //如果名称为“'testFeature'”,则说明找到了该要素 end; end;

③ Visibility Visibility 介绍如下。

定义:定义了要素的可见性。 使用方式:读(Get)/写(Set)。 值类型:Integer。 方程式:property Visibility: Integer

read Get_Visibility write Set_Visibility;。

第 5 章 Google Earth API 开发

345

Delphi 实例代码: var F_AppGE: IApplicationGE; …… procedure TForm1.btnVisibiltyClick(Sender: TObject); var tmpFeature : IFeatureGE; begin tmpFeature := F_AppGE.GetFeatureByName('folerTest'); if (tmpFeature.Visibility <>0 ) then begin tmpFeature.Visibility := 0; //不显示 end else begin tmpFeature.Visibility := 1; //显示 end; end;

首先用 Google Earth 程序打开本书第 3 章的 KML 代码 Folder.kml,然后执行。这段代码

可以控制 Google Earth 上地标的显示。 C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… // 检查某个要素是否可见,0为检查不成功,1为可见,2为不可见 private int isFeatureVisible(string ft_name) { int isFtVi = 0; FeatureGE ft = appGE.GetFeatureByName(ft_name); if (ft != null) if (ft.Visibility == 1) { isFtVi = 1; } else { isFtVi = 2; } return isFtVi; }

IFeatureGE 接口提供了操作地图要素的方法,如高亮选中、获取名称操作,

但 Google Earth 并没有进一步深入对要素的支持,对比 Google Maps 丰富的要

素方法和属性,IFeatureGE 接口仅仅提供了几个对于现有要素对象的操作,其

他例如创建要素对象这样的方法却未能提供。这的确是 Google Earth API 的一

大不足,开发人员只能通过 KML 或者 Google Earth Plus 本身提供的工具,甚至

Google SetchUp 来创建地理要素。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

346

5.3.4 ITimeGE 接口

ITimeGE 接口是 Google Earth 内部控制日期和时间的接口。Google Earth 的时间计算均

是根据 UTC 时区计算的。UTC 是 Universal Time Coordinated 的英文缩写,中文译为“协调

世界时”,是由国际无线电咨询委员会规定和推荐,由 BIH 负责保持的时间标度。 采用 UTC 的时区划分方法,把全时间按照每 15°一个时区的划分原则,共分为 24 个时

区,每一个时区都有各自的编号。例如北京位置在东经 116°左右,时区处于东 8 区,用 UTC+8表示,而美国旧金山处于西 8 区,则为 UTC-8,以此类推,这个常识比较重要,在进行 Itime接口开发的时候经常用到。

1.ITimeGE 方法

1)Clone Clone 介绍如下。

定义:克隆,通常用做对于有只读属性的对象。 方程式:function Clone: ITimeGE; safecall;。

Delphi 实例代码请见下面的代码。

2)ConvertToZone ConvertToZone 介绍如下。

定义:通过给定的时区重新计算,即转换时区的计算。 方程式:function ConvertToZone(TimeZone: Double): ITimeGE; safecall;。

其参数如表 5-14 所示。

表 5-14 ConvertToZone 参数

参 数 输 入 方 向 值 类 型 定 义

TimeZone In Double 给定的 UTC 时区

Delphi 实例代码: var F_AppGE: IApplicationGE; …… procedure TForm1.BtnTimeZoneClick(Sender: TObject); var FFeatures :IFeatureCollectionGE; ParFeature : IFeatureGE; i: integer; tmpstr : string; tmpYear,tmpMonth,tmpDay:integer; tmpTimeZone : ITimeGE;

第 5 章 Google Earth API 开发

347

begin ParFeature := F_AppGE.GetFeatureByName('nanjing'); FFeatures := ParFeature.GetChildren; for i := 1 to FFeatures.Count do begin if (FFeatures[i].Highlighted <> 0) then begin tmpTimeZone := FFeatures[i].TimeInterval.BeginTime; tmpTimeZone := tmpTimeZone.ConvertToZone(-10.0); tmpYear := tmpTimeZone.Year; tmpMonth := tmpTimeZone.Month; tmpDay := tmpTimeZone.Day; tmpstr := inttostr(tmpYear) + '-' + inttostr(tmpMonth) + '-' +inttostr(tmpDay); end; end; showmessage('开始时间是:' + tmpstr); end;

首先操作 Google Earth,打开第 3 章中的 KML 文件“TimeSpan.kml”,然后执行,下同。 C#实例代码: ApplicationGEClass appGE = new ApplicationGEClass(); …… private void coverTimeFromAnotherTZ() { FeatureGE ft = appGE.GetFeatureByName(ft_name); if (ft != null) { DateTime tm = ft.TimeInterval.BeginTime.ConvertToZone(-6.0); } }

可以看到原始的 BeginTime 中日期是 2004-01-01,而转换过后的日期为 2003-12-31,说

明根据时区的不同,Google Earth 时间计算的结果是不同的,如图 5-37 所示。

图 5-37 Google 时间

2.ITimeGE 属性

1)Type Type 介绍如下。

定义:读取或设置时间类型,无限或有限的。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

348

使用方式:读(Get)/写(Set)。 值类型:TimeTypeGE。 方程式:property type_: TimeTypeGE

read Get_type_ write Set_type_;。

Delphi 代码请参见 ConvertToZone 中的例子。

2)Year Year 介绍如下。

定义:表示时间日期的“年份”。 使用方式:读(Get)/写(Set)。 值类型:SYSINT。 方程式:property Year: SYSINT

read Get_Year write Set_Year;。

Delphi 代码请参见 ConvertToZone 中的例子。

3)Month Month 介绍如下。

定义:表示时间日期的“月”。 使用方式:读(Get)/写(Set)。 值类型:SYSINT。 方程式:property Month: SYSINT

read Get_Month write Set_Month;。

Delphi 代码请参见 ConvertToZone 中的例子。

4)Day Day 介绍如下。

定义:表示时间日期的“日”。 使用方式:读(Get)/写(Set)。 值类型:SYSINT。 方程式:property Day: SYSINT

第 5 章 Google Earth API 开发

349

read Get_Day write Set_Day;。

Delphi 代码请参见 ConvertToZone 中的例子。

5)Hour Hour 介绍如下。

定义:表示时间日期的“小时”。 使用方式:读(Get)/写(Set)。 值类型:SYSINT。 方程式:property Hour: SYSINT

read Get_Hour write Set_Hour;。

6)Minute Minute 介绍如下。

定义:表示时间日期的“分钟”。 使用方式:读(Get)/写(Set)。 值类型:SYSINT。 方程式:property Minute: SYSINT

read Get_Minute write Set_Minute;。

7)Second Second 介绍如下。

定义:表示时间日期的“秒”。Google Earth 采用的 UTC 时间基数是 1。 使用方式:读(Get)/写(Set)。 值类型: SYSINT。 方程式:property Second: SYSINT

read Get_Second zrite Set_Second;。

8)TimeZone 定义:返回一个布尔值,表示当前的要素是否被高亮选中。如果被高亮选中,返回

true,否则返回 false。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

350

使用方式:读(Get)/写(Set)。 值类型:Double。 方程式:property TimeZone: Double

read Get_TimeZone write Set_TimeZone;。

3.一个完整的 ITimeGE 的 Delphi 小程序

首先程序开始的时候初始化,生成或者捕获一个 Google Earth 进程,代码如下: unit Unit1; …… //程序窗口开始创建 procedure TFormTime.FormCreate(Sender: TObject); begin try F_AppGE := CoApplicationGE.Create(); except showmessage('启动 Google Earth失败'); end; end;

对应的 C#代码: private void Form1_Load(object sender, EventArgs e) { try { appGE = new ApplicationGEClass(); } catch (Exception err) { MessageBox.Show("未能启动 Google Earth程序"); } }

Delphi 代码: //程序窗口关闭 procedure TFormTime.FormClose(Sender: TObject; var Action: TCloseAction); begin F_AppGE := nil; end; //获取要素的时间 procedure TFormTime.btnGetClick(Sender: TObject); var …… begin try ParFeature := F_AppGE.GetFeatureByName('nanjing');

第 5 章 Google Earth API 开发

351

FFeatures := ParFeature.GetChildren; //获得子要素集合 for i := 1 to FFeatures.Count do //遍历 begin if (FFeatures[i].Highlighted <> 0) then begin tmpTimeZone := FFeatures[i].TimeInterval.BeginTime; tmpYear := tmpTimeZone.Year; //获取当前时区时间的“年” tmpMonth := tmpTimeZone.Month; //获取当前时区时间的“月” tmpDay := tmpTimeZone.Day; //获取当前时区时间的“天” tmpstr := inttostr(tmpYear) + '-' + inttostr(tmpMonth) + '-' +inttostr(tmpDay);

…… end; end; except end; end;

这里主要是时间的赋值,克隆时间对象至另一个变量,然后更改被赋值时间变量的属性,

主要是以展示时间参数的用法为目的: //时间赋值,主要是用到了 ITimeGE.Clone方法 procedure TFormTime.btnSetClick(Sender: TObject); var …… begin try ParFeature := F_AppGE.GetFeatureByName('nanjing'); FFeatures := ParFeature.GetChildren; for i := 1 to FFeatures.Count do begin if (FFeatures[i].Highlighted <> 0) then begin tmpTimeBegin := FFeatures[i].TimeInterval.BeginTime.Clone; //克隆“开始时间” …… edZoneClone.Text := 'UTC ' + floattostr(tmpTimeBegin); //在文本框中显示克隆的时间 end; end; except //…… end; end;

下面的代码就是根据时区转换时间,代码中的 timezoneNum 指时区号码,例如北京时间

为东八区,那么 timezoneNum 就取值+8,美国休斯顿为西 6 区,则取值-6: //根据给定的时区计算时间 procedure TFormTime.btnConvertClick(Sender: TObject); var …… begin try ParFeature := F_AppGE.GetFeatureByName('nanjing'); FFeatures := ParFeature.GetChildren;

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

352

timezoneNum := strtofloat(edZoneNum.Text); for i := 1 to FFeatures.Count do begin if (FFeatures[i].Highlighted <> 0) then begin tmpTimeBegin := FFeatures[i].TimeInterval.BeginTime.Clone; //克隆开始时间 tmpTimeEnd := FFeatures[i].TimeInterval.EndTime.Clone; //克隆结束时间 ZoneTimeBegin := tmpTimeBegin.ConvertToZone(timezoneNum); //时区转换后的开始时间 ZoneTimeEnd := tmpTimeEnd.ConvertToZone(timezoneNum);// 时区转换后的结束时间 …… end; end; except //…… end; end;

转换时间对应的 C#代码段: private void ftTimeZoneChange(string ft_name) { FeatureGE ft = appGE.GetFeatureByName(ft_name).GetChildren()[1]; if (ft != null) { try { //没转换前的时间 TimeGE ftBeginTime1 = ft.TimeInterval.BeginTime; TimeGE ftEndTime1 = ft.TimeInterval.EndTime; double ftTZ1 = ft.TimeInterval.BeginTime.TimeZone; //转换后的时间 TimeGE ftBeginTime2 = ft.TimeInterval.BeginTime.ConvertToZone(-6.0); TimeGE ftEndTime2 = ft.TimeInterval.EndTime.ConvertToZone(-6.0); double ftTZ2 = ft.TimeInterval.BeginTime.ConvertToZone(-6.0).TimeZone; //把这些时间显示出来 txtBeginTime1.Text = ftBeginTime1.Year.ToString() + "年" +

ftBeginTime1.Month.ToString() + "月" + ftBeginTime1.Day.ToString() + "天";

txtEndTime1.Text = ftEndTime1.Year.ToString() + "年" + ftEndTime1.Month.ToString() + "月" + ftEndTime1.Day.ToString() + "天";

txtTimeZone1.Text = "UTC" + ftTZ1.ToString(); txtBeginTime2.Text = ftBeginTime2.Year.ToString() + "年" +

ftBeginTime2.Month.ToString() + "月" + ftBeginTime2.Day.ToString() + "天";

txtEndTime2.Text = ftEndTime2.Year.ToString() + "年" + ftEndTime2.Month.ToString() + "月" + ftEndTime2.Day.ToString() + "天";

txtTimeZone2.Text = "UTC" + ftTZ2.ToString(); } catch { throw (new Exception("转换出错")); } } else { throw ( new Exception("找不到要素"));

第 5 章 Google Earth API 开发

353

} }

本例中,通过运行第 3 章中的 KML 文件“TimeSpan.kml”,Google Earth 创建了一个具

有时间段特性的地标,执行后的效果如图 5-38 所示。

图 5-38 时区转换

5.3.5 IAnimationControllerGE 接口

IAnimationControllerGE 接口定义了 Google Earth 动画的各种基本的操作方式和属性,这

个接口使用较少,因此在这里只做个简单介绍。

1.IAnimationControllerGE 方法

IAnimationControllerGE 方法介绍如下。 Play。

定义:播放动画。 方程式:procedure Play; safecall;。

Pause。 定义:停止播放当前的动画。 方程式:procedure Pause; safecall;。

2.IAnimationControllerGE 属性

IAnimationControllerGE 属性介绍如下。 SliderTimeInterval。

定义:动画的整个时长,针对的是整个动画文件夹的时长。 使用方式:读(Get)。 值类型:ITimeIntervalGE。 方程式:property SliderTimeInterval: ITimeIntervalGE

read Get_SliderTimeInterval;。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

354

CurrentTimeInterval。 定义:动画的当前时长。 使用方式:读(Get)/写(Set)。 值类型:ITimeIntervalGE。 方程式:property CurrentTimeInterval: ITimeIntervalGE

read Get_CurrentTimeInterval write Set_CurrentTimeInterval;。

5.3.6 IFeatureCollectionGE 接口

IFeatureCollectionGE 接口定义了要素的集合。Google Earth 的官方文档提到了

IFeatureCollectionGE 接口可以支持如 JavaScript 或者 VBScript 脚本,并给出了调用的方法。

其实对于服务器端生成的此类集合形式的数组,只要可以取到每一个元素,利用其他的方法

也可以通过 HTTP 浏览器进行操作,如利用 AJAX 或者 WebService 均可以对其进行操作。 此接口代表像 GetChildren 返回的子要素集合等概念,但是此集合的开头序号是从 1 开

始的,而非 0,在使用时要加以注意。

1.单个子要素

本节前面介绍了 IfeatureGE 接口,代表单个地理要素,对于 IFeatureCollectionGE 要素集

合来说,Item 属性可以得到某一个确定的要素,如通过遍历要素的序号得到要素。

1)Item Item 介绍如下。

定义:要素集合中的子项,返回的是要素对象,index 为要素集中的序号,从 1 开始。 使用方式:读(Get)。 值类型:IFeatureGE。 方程式:property Item[index: Integer]: IFeatureGE

read Get_Item; default;。

关于 Item 的 Delphi 代码请参见 IApplicationGE 接口的 GetLayersDatabases 方法的实例。

2)Count Count 介绍如下。

定义:要素集中的总数,返回的是一个整数,如果为空,则返回 0。 使用方式:读(Get)。

第 5 章 Google Earth API 开发

355

值类型:ITimeIntervalGE。 方程式:property Count: Integer

read Get_Count;。

3)Clone Clone 介绍如下。

定义:克隆,通常用做对于有只读属性的对象。 方程式:function Clone: ITimeGE; safecall;。

2.子要素的操作

要得到 IFeatureCollectionGE 要素集合的子要素,可以采用 GetChildren 方法,这个方法

的返回值也是 IFeatureCollectionGE 类型,表示所有子要素的集合。 其定义为得到当前要素,所有子要素的集合。 其方程式为 function GetChildren: IFeatureCollectionGE; safecall;。

3.实例分析

这里给出一个实用的小例子的代码:在窗口上有文本框,里面填入父要素的名称,单击

按钮得到该父要素下所有子要素,反填到列表框中,用鼠标选择列表框中的选项,同时 Google Earth 的地址要素栏中的相同要素也会被高亮显示。

代码如下: unit Unit1; …… //程序窗口开始创建 procedure TFormFC.FormCreate(Sender: TObject); begin try F_AppGE := CoApplicationGE.Create(); except showmessage('启动 Google Earth失败'); end; end;

对应的 C#代码可参考前面的例子。 //程序窗口关闭 procedure TFormFC.FormClose(Sender: TObject; var Action: TCloseAction); begin F_AppGE := nil; end;

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

356

这里通过文本框中的父要素名称,得到要素“parFeature”,然后得到所有其他的子要素,

通过 for 循环遍历所有的子要素,再将子要素逐一添加到列表框 lbFeatures 中: //获取要素列表 procedure TFormFC.btnGetListClick(Sender: TObject); var FFeatures :IFeatureCollectionGE; ParFeature : IFeatureGE; i: integer; tmpstr : string; begin //清空列表框 lbFeartures.Items.Clear; tmpstr := trim(edParFeature.Text); ParFeature := F_AppGE.GetFeatureByName(tmpstr); //获得所有的子要素 FFeatures := ParFeature.GetChildren; //添加到列表框 for i := 1 to FFeatures.Count do begin lbFeartures.Items.Add(FFeatures[i].Name); end; end;

C#代码参考: private string[] getFeatureChildrenNameList(string ft_name) { FeatureGE ft = appGE.GetFeatureByName(ft_name); string[] ftNameList = null; if (ft != null) { ftNameList = new string[ft.GetChildren().Count]; FeatureCollectionGE ftlist = ft.GetChildren(); for (int i = 0; i < ft.GetChildren().Count - 1; i++) { ftNameList[i] = ft.GetChildren()[i].Name; } return ftNameList; } else { return null; } }

这里利用了 IFeatureGE 接口的 Selected 属性,通过 for 循环遍历所有的子要素,判断该

要素是否被鼠标选中,因为这段代码是写在鼠标按下(MouseDown)事件中的,所以当鼠标

按下的时候,程序会反向控制 Google Earth,从而高亮选择相同的地理要素项目: //单击要素列表框,操作 Google Earth高亮显示该要素 procedure TFormFC.lbFearturesMouseDown(Sender: TObject;

第 5 章 Google Earth API 开发

357

Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var i:integer; tmpFeature : IFeatureGE; begin for i := 0 to lbFeartures.Items.Count-1 do begin if (lbFeartures.Selected[i]) then begin tmpFeature := F_AppGE.GetFeatureByName(lbFeartures.Items[i]); tmpFeature.Highlight; break; end; end; end; end.

C#代码参考: private void highlightFtbyName(FeatureCollectionGE ftlist,string ftname) { for (int i = 0; i < ftlist.Count - 1; i++) { if (ftlist[i].Name == ftname) { ftlist[i].Highlight(); } else { continue; } } }

本程序的逻辑主要是实现如下两个主要功能: 取得子要素列表,如图 5-39 所示。 根据 Delphi 程序中选中的要素,反向控制 Google Earth 高亮显示该要素。

图 5-39 子要素集合

这个例子稍加改动就可以拓展成其他项目的一部分。通过这个例子可以发现当前版本

Google Earth 的 API 接口结构很清晰,只要找到正确的接口,开发 Google Earth 程序就不会太难。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

358

5.3.7 IViewExtentsGE 接口

IViewExtentsGE 接口描述了 Google Earth 地图视场的经纬度范围。它仅仅是一个范围的

定义而已,并不包含其他的如视角在内的视场定义参数。 所谓视场的四边,是指东、南、西、北 4 个顶边的经纬度,如图 5-40 所示。

图 5-40 视场四边

该接口提供的所有属性都是只读型的,所以不能通过这个接口操作 Google Earth 改变

视场。

1.IViewExtentsGE 属性

IViewExtentsGE 属性如下。 North。

定义:视场的北边,为纬度值。 使用方式:读(Get)。 值类型:Double。 方程式:property North: Double

read Get_North;。

South。 定义:视场的南边,为纬度值。 使用方式:读(Get)。 值类型:Double。 方程式:property South: Double

read Get_South;。

地图窗口

North(纬度)

South(纬度)

East(经度) West(经度)

第 5 章 Google Earth API 开发

359

East。 定义:视场的东边,为经度值。 使用方式:读(Get)。 值类型:Double。 方程式:property East: Double

read Get_East;。

West。 定义:视场的西边,为经度值。 使用方式:读(Get)。 值类型:Double。 方程式:property West: Double

read Get_West;。

该接口因为只有 4 个属性,非常简单,因此在此给出一个 Delphi 代码。例子中 tmpViewExt为一个 IViewExtentsGE 类型的变量,然后分别获得当前地图视场的东、南、西、北 4 个边的

经纬度数值,显示在文本框中。

2.实例代码

Delphi 实例代码: var F_AppGE: IApplicationGE; …… procedure TFormViewExtens.btnGetClick(Sender: TObject); var tmpViewExt : IViewExtentsGE ; begin try

tmpViewExt := F_AppGE.ViewExtents; edNorth.Text := floattostr(tmpViewExt.North ); edSouth.Text := floattostr(tmpViewExt.South ); edEast.Text := floattostr(tmpViewExt.East ); edWest.Text := floattostr(tmpViewExt.West ); except //…… end; end;

C#代码参考: private void getMapViewExtents() { ViewExtentsGE vt = appGE.ViewExtents; double vt_north = vt.North; double vt_south = vt.South;

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

360

double vt_west = vt.West; double vt_east = vt.East; MessageBox.Show("东至:" + vt_east.ToString() + "西至:" + vt_west.ToString() + "北至:" + vt_north.ToString() + "南至:" + vt_south.ToString()); }

代码执行后的效果如图 5-41 所示。

图 5-41 四边经纬度

5.3.8 IPointOnTerrainGE 接口

IPointOnTerrainGE 接口是 IApplicationGE.GetPointOnTerrainFromScreenCoords 方法的返

回值接口类型,重点突出点位的地理特征,提供了关于地形和点位的操作,对于地球空间上

的一点,必然和地形发生着千丝万缕的联系,一个点位必然包括经纬度、高度、投影关系。 但是 Google Earth 没有提供获取屏幕坐标的操作方法,关于屏幕坐标的操作方法或者属

性其实是比较重要的,这一点比较奇怪。虽然程序员可以通过 Windows 提供的 API 实现捕捉

地图窗口内要素的屏幕点位信息,但是实现起来成本较高,可能 Google 认为无须给用户提供

这个接口。 本接口提供的所有属性都是只读属性。

1.IPointOnTerrainGE 属性

1)Latitude Latitude 介绍如下。

定义:点位的纬度值。取值从-90°到 90°。 使用方式:读(Get)。 值类型:Double。 方程式:property Latitude: Double

第 5 章 Google Earth API 开发

361

read Get_Latitude;。

2)Longitude Longitude 介绍如下。

定义:点位的经度值。取值从-180°到 180° 使用方式:读(Get)。 值类型:Double。 方程式:property Longitude: Double

read Get_Longitude;。

3)Altitude Altitude 介绍如下。

定义:点位的高度值。 使用方式:读(Get)。 值类型:Double。 方程式:property Altitude: Double

read Get_Altitude;。 Google Earth 中点位的高度值的设定和 Google Maps 有相似的地方,Google Earth 的高度

属性值受到 ElevationExaggeration 的影响,如表 5-15 所示。

表 5-15 高度设定关系

ElevationExaggeration >0 0

ZeroElevationExaggeration true false

Altitude 真实高度 0

4)ProjectedOntoGlobe ProjectedOntoGlobe 介绍如下。

定义:判断一个点位是否为投影点,返回值是布尔型。 使用方式:读(Get)。 值类型:Integer(Bool)。 方程式:property ProjectedOntoGlobe: Integer

read Get_ProjectedOntoGlobe;。

5)ZeroElevationExaggeration ZeroElevationExaggeration 介绍如下。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

362

定义:是否被顺着地形拉伸而起伏。 使用方式:读(Get)。 值类型:Integer(Bool)。 方程式:property ZeroElevationExaggeration: Integer

read Get_ZeroElevationExaggeration;

2.实例代码分析

此处仅给出了主要代码片段: //拉伸地形 3倍 procedure TForm1.btnExaggerationClick(Sender: TObject); begin try F_AppGE.ElevationExaggeration := 3; except //…… end; end;

对应的 C#代码参考: private void setExaggeration() { …… appGE.ElevationExaggeration = 3; }

在 IApplicationGE 中有一个坐标转换的方法 GetPointOnTerrainFromScreenCoords,可以

把屏幕的像素坐标转换为经纬度坐标。下面的例子采用该方法把屏幕中心点转换成经纬度

坐标: //取得屏幕中心点的地理坐标 procedure TForm1.btnTerrainCorrClick(Sender: TObject); var tmpPointOnTer: IPointOnTerrainGE; tmpstr: string; begin

//从屏幕坐标转换成地理坐标 tmpPointOnTer := F_AppGE.GetPointOnTerrainFromScreenCoords(0,0); tmpstr := '经

度:' + floattostr(tmpPointOnTer.Longitude) + #13#10; tmpstr := tmpstr + '纬度:' + floattostr(tmpPointOnTer.Latitude) + #13#10; tmpstr := tmpstr + '高度:' + floattostr(tmpPointOnTer.Latitude) + #13#10; tmpstr := tmpstr + '是否为投影点:' + ConvertIntToBool(tmpPointOnTer.Projected

OntoGlobe) + #13#10; tmpstr := tmpstr + '是否拉伸:' + ConvertIntToBool(tmpPointOnTer.ZeroElevationExag

geration) + #13#10; showmessage(tmpstr); end;

第 5 章 Google Earth API 开发

363

……

以上的Delphi代码中 tmpPointOnTer为从屏幕坐标转换而来的地理坐标(用经纬度表示),

以上代码对应的 C#参考代码: private PointOnTerrainGE covertCoordinatesFromScreen() { PointOnTerrainGE pt = appGE.GetPointOnTerrainFromScreenCoords(0.0, 0.0); return pt; }

代码执行后的效果如图 5-42 所示。

图 5-42 地形点参数

5.3.9 ISearchControllerGE 接口

ISearchControllerGE 接口是 Google Earth 的核心功能之一。Google Earth 的成功一方面是

具有遍布全球的精美的卫星图片;另一方面就是具有几乎无所不能的搜索功能。Isearch ControllerGE 是一个搜索控件接口,提供类似与 Goolge Earth 主界面上“搜索栏”一样的功

能,但比“搜索栏”更加灵活,可以通过它,将 Google Earth 的搜索功能嵌入到自己的程

序中。

1.地名搜索

1)Search Search 介绍如下。

定义:执行 Google Earth 搜索。 方程式:procedure Search(const searchString: WideString); safecall;。

其参数如表 5-16 所示。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

364

表 5-16 Search 参数

参 数 输 入 方 向 值 类 型 定 义

searchString In WideString 需搜索的地名字词

地名搜索、路线地址搜索都有一个时间超时的阈值,从开始搜索到返回结果这一过程的

耗时如果在这个超时阈值之内,可以返回相对应的结果;如果超过这个阈值,则返回

E_USAGE_LIMIT_EXCEEDED,表明搜索超时。 终的搜索结果将在 Google Earth 的地图窗口或者地址栏中反映出来。

Delphi 实例代码: procedure TForm1.searchClick(Sender: TObject); var tmpSearchstr : string; Isearch : ISearchControllerGE; begin tmpsearchstr := edsearch.Text; Isearch := coSearchControllerGE.Create(); Isearch.Search(tmpsearchstr); end;

C#代码参考: private void searchFunction(string searchStr) { SearchControllerGE scGe = new SearchControllerGEClass(); scGe.Search(searchStr.Trim()); } //调用查询函数 private void btnSearch_Click(object sender, EventArgs e) { searchFunction("nanjing "); }

在这里,用户自定义的程序窗口代替了 Google Earth 原来的搜索窗口,输入“beijing”后单击【Search】按钮,程序会自动“飞行”到北京地区,如图 5-43 所示。

图 5-43 搜索接口

在搜索的时候需要使用 IsSearchInProgress 来验证搜索过程是否完全执行

完毕。

第 5 章 Google Earth API 开发

365

2)IsSearchInProgress 因为 Google Earth 的搜索过程相对耗时,所以用户不可能“立即”获得搜索结果。通常

需要有个等待过程,程序中需要有一个判断是否正在搜索状态中的方法 IsSearchInProgress。介绍如下。

定义:得到当前要素下所有子要素的集合。 方程式:function IsSearchInProgress: Integer; safecall;。

Delphi 实例代码请看后面的完整实例。

2.获得结果

ISearchControllerGE 接口所获得的结果 终只有两个归结点:搜索结果栏和地图窗口。

在搜索结果栏中,会列出所有结果项目,而地图则会“飞行”(fly-To)到 可能的那个结果

的所在地,通过调用 GetResults 方法可以获得结果。 由于返回的结果类型是 IFeatureCollectionGE 要素集合类型,所以开发人员可以根据需要

将要素的名称或者其他属性以多种方式显示在自己的界面上。 获得结果介绍如下。

GetResults。 定义:得到符合搜索的所有要素的集合。 方程式:function GetResults: IFeatureCollectionGE; safecall;。

Delphi 实例代码请看后面的完整实例。 ClearResults。

定义:清空所有搜索要素集合。 方程式:procedure ClearResults; safecall;。

3.实例分析

unit Unit1; …… uses EARTHLib_TLB; {$R *.dfm} var F_AppGE: IApplicationGE; tmpSearch : ISearchControllerGE;

单击【搜索】按钮,将名为【edSearchStr】的文本框中的搜索内容作为搜索的条件,在

搜索之后,将搜索的结果添加入列表框中: procedure TFormSearch.btnSearchClick(Sender: TObject); var

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

366

searchStr : string; IFeaList: IFeatureCollectionGE; i:integer; begin //清空要素列表框 lbSearch.Items.Clear; searchStr := Trim(edSearchStr.Text); //搜索 tmpSearch := coSearchControllerGE.Create; tmpSearch.Search(searchStr); IFeaList := tmpSearch.GetResults; //往搜索框中添加结果要素 for i := 1 to IFeaList.Count do begin lbSearch.Items.Add(IFeaList[i].Name); end; //检查搜索是否完毕 if (tmpSearch.IsSearchInProgress <> 0) then begin showmessage('查询完毕!'); end; end;

C#代码参考: private FeatureCollectionGE searchFunction(string searchStr) { //新的搜索对象 SearchControllerGE scGe = new SearchControllerGEClass(); scGe.Search(searchStr.Trim()) ; //得到搜索结果 FeatureCollectionGE ftList = scGe.GetResults(); if (scGe.IsSearchInProgress() == 0) { MessageBox.Show("查询完毕!"); return ftList; } else { return null; } }

窗体启动的时候,启动一个 Google Earth 进程: procedure TFormSearch.FormCreate(Sender: TObject); begin try F_AppGE := CoApplicationGE.Create(); except showmessage('启动 Google Earth失败'); end; end;

关于上面这段 C#代码请参考前面 5.3.1 节中的 Google Earth 启动代码:

第 5 章 Google Earth API 开发

367

关闭窗体时候,释放 Google Earth 的进程控制,代码如下: procedure TFormSearch.FormClose(Sender: TObject; var Action: TCloseAction); begin F_AppGE := nil; end;

在大部分情况下需要清空搜索的结果,可使用 ClearResults 来完成清空结果工作,此时

Google Earth 的搜索结果界面上就会有相应的清空动作,如下: procedure TFormSearch.btnClearClick(Sender: TObject); begin try tmpSearch.ClearResults; showmessage('已经清空 Google Earth搜索结果。'); except end; end; end.

C#代码参考: private void clearSearch() { scGe.ClearResults(); }

5.3.10 ITimeIntervalGE 接口

ITimeIntervalGE 接口表示 Google Earth 中的时间段。接口中提供的属性全部为只读属性。

1.属性

ITimeIntervalGE 属性如下。 BeginTime。

定义:表示时间段的开始时间,返回时间类型为 ITimeGE。 使用方式:读(Get)。 值类型:ITimeGE。 方程式:property BeginTime: ITimeGE

read Get_BeginTime;。

EndTime。 定义:表示时间段的结束时间,返回时间类型为 ITimeGE。 使用方式:读(Get)。 值类型:ITimeGE。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

368

方程式:property EndTime: ITimeGE read Get_EndTime;。

2.实例代码

Delphi 实例代码: procedure TForm1.BtnGetTimeIntervalClick(Sender: TObject); var FFeatures :IFeatureCollectionGE; ParFeature : IFeatureGE; i: integer; tmpstrBegin,tmpstrEnd : string; tmpYear,tmpMonth,tmpDay:integer; begin ParFeature := F_AppGE.GetFeatureByName('nanjing'); FFeatures := ParFeature.GetChildren; for i := 1 to FFeatures.Count do begin if (FFeatures[i].Highlighted <> 0) then begin tmpYear := FFeatures[i].TimeInterval.BeginTime.Year; tmpMonth := FFeatures[i].TimeInterval.BeginTime.Month; tmpDay := FFeatures[i].TimeInterval.BeginTime.Day; tmpstrBegin := inttostr(tmpYear) + '-'+ inttostr(tmpMonth) + '-' +inttostr

(tmpDay); tmpYear := FFeatures[i].TimeInterval.EndTime.Year; tmpMonth := FFeatures[i].TimeInterval.EndTime.Month; tmpDay := FFeatures[i].TimeInterval.EndTime.Day; tmpstrEnd := inttostr(tmpYear) + '-'+ inttostr(tmpMonth) + '-' +inttostr

(tmpDay); end; end; showmessage('开始时间是:' + tmpstrBegin + #13#10 + '结束时间是:' + tmpstrEnd); end;

此处的 C#代码可参考 5.3.4 节中的 TimeInterval 的操作实例。

首先用 Google Earth 程序打开本书第 3 章的 KML 代码 TimeSpan. kml,然后执行。

以上的 Delphi 代码,分别取出了开始和结束时间的年、月、日的

参数值,执行结果如图 5-44 所示。

5.3.11 ITourControllerGE 接口

ITourControllerGE 是设置和控制 Google Earth 漫游的接口。

图 5-44 时间段

第 5 章 Google Earth API 开发

369

1.ITourControllerGE 属性 1)speed speed 介绍如下。

定义:描述了 Google Earth 视场移动的速度,Speed 是取值在 0~5 之间的双精度型小

数,无法通过程序修改。 使用方式:读(Get)。 值类型:Double。 方程式:property speed: Double

read Get_speed write Set_speed;。

Delphi 实例代码: procedure TForm1. getFlySpeedDelayClick (Sender: TObject); var flycycle : double; begin flycycle := F_AppGE.TourController.speed; showmessage(floattostr(flycycle)); end;

C#代码参考: private double getSpeed() { TourControllerGE TourGE = appGE.TourController; if (TourGE != null) { return TourGE.speed; } else { return -1; } }

执行后的效果如图 5-45 所示,这里的取值是【Tools】→【Options】命令中【Fly-To Speed】设置框中的数值。中文版 Google Earth 的菜单对应项目为【工具】菜单项中的【选项】,然后

在弹出窗口中选择【导航】页面即可。

2)PauseDelay PauseDelay 介绍如下。

定义:描述了每次视点“飞行”停止的时长。 使用方式:读(Get)。 值类型:Double。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

370

方程式:property PauseDelay: Double

read Get_PauseDelay write Set_PauseDelay;。

以 1/10 秒计,取值为 0.0~60.0。 Delphi 实例代码: procedure TForm1. getFlyPauseDelayClick(Sender: TObject); var flycycle : double; begin flycycle := F_AppGE.TourController.PauseDelay; showmessage(floattostr(flycycle)); end;

C#代码参考: private double getFlyPauseTime () { TourControllerGE TourGE = appGE.TourController; if (TourGE != null) { return TourGE.PauseDelay; } else { return -1; } }

执行后的效果如图 5-46 所示,这里的取值是【Tools】→【Options】命令中【Tour Pause】设置框中的数值。

图 5-45 飞行速度 图 5-46 暂停时间

3)Cycles Cycles 介绍如下。

定义:漫游飞行的循环次数。 使用方式:读(Get)。 值类型:Double。 方程式:property Cycles: SYSINT

第 5 章 Google Earth API 开发

371

read Get_Cycles write Set_Cycles;。

取值范围是 0~9 999,超过 9 999 则表示无限循环漫游。 Delphi 实例代码: procedure TForm1.getFlyCyclesClick(Sender: TObject); var flycycle : integer; begin flycycle := F_AppGE.TourController.Cycles ; showmessage(inttostr(flycycle)); end;

C#的代码参考: private int getFlyCycles() { TourControllerGE TourGE = appGE.TourController; if (TourGE != null) { return TourGE.Cycles; } else { return -1; } }

执行后的效果如图 5-47 所示,这里的取值是【Tools】→【Options】命令中【Tour Pause】设置框中的数值。

图 5-47 循环次数

2.ITourControllerGE 方法

1)PlayOrPause PlayOrPause 介绍如下。

定义:继续飞行或者暂停,每执行一次,就重复一次飞行和暂停。 方程式:procedure PlayOrPause; safecall;。

Delphi 实例代码: procedure TForm1.flypauseClick(Sender: TObject); begin

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

372

F_AppGE.TourController.PlayOrPause; end;

C#的代码参考: private void PauseFly() { appGE.TourController.PlayOrPause(); }

2)Stop Stop 介绍如下。

定义:停止飞行。 方程式:procedure Stop; safecall;。 Delphi 实例代码:

procedure TForm1.flystopClick(Sender: TObject); begin F_AppGE.TourController.Stop; end;

C#的代码参考: private void stopFly() { appGE.TourController.Stop();}

5.4 Keyhole API 接口介绍

从运行库中可以发现,Google Earth 目前提供的 COM API 基本上都是基于 Keyhole API的,不过 Google 做了大量的工作用于封装,特别是照相机接口,新的接口很大程度上方便了

用户的使用。 以前版本的 Keyhole API 接口分类上虽然有些混淆,个别函数的功能特征也不是很明显,

但是作为目前 Google Earth API 的基础,还是有一定的学习必要的。

5.4.1 Keyhole 接口

Keyhole 提供的接口一共包括 4 个部分,如表 5-17 所示。

表 5-17 Keyhole 组成部分

1 IKHFeature 作用类似于 IFeatureGE

2 IKHInterface 作用类似于 IApplicationGE

3 IKHViewExtents 作用类似于 IViewExtentsGE

4 IKHViewInfo 作用类似于 ICameraInfoGE

第 5 章 Google Earth API 开发

373

5.4.2 IKHInterface 接口

IKHInterface 接口类似于 Google Earth API 中的 IApplicationGE,但所提供的属性和方法

要少于后者。

1.IKHInterface 属性

1)streamingProgressPercentage streamingProgressPercentage 介绍如下。

定义:Google Earth 中当前地图流数据读取进度。 使用方式:读(Get)。 值类型:Integer。 方程式:property streamingProgressPercentage: Integer

read Get_streamingProgressPercentage;。 Delphi 实例代码: var FKHInterface : IKHInterface; …… procedure TForm1.btnStreamProgressClick(Sender: TObject); var tmpProgress : integer; begin tmpProgress := FKHInterface.streamingProgressPercentage; showmessage(inttostr(tmpProgress)); end;

类似于 IApplicationGE 中的方法,执行后的效果如图 5-48 所示。

图 5-48 地图数据流读取百分比(单位%)

2)autopilotSpeed autopilotSpeed 介绍如下。

定义:描述了 Google Earth 照相机漫游“飞行”时的速度。 使用方式:读(Get)/ 写(Set)。 值类型:Double。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

374

方程式:property autopilotSpeed: Double

read Get_autopilotSpeed write Set_autopilotSpeed;。

照相机飞行时的速度取值为 0.0~5.0,数值越大速度越快。

Delphi 实例代码: var FKHInterface : IKHInterface; …… procedure TForm1.btnGetClick(Sender: TObject); begin edSpeed.Text := floattostr(FKHInterface.autopilotSpeed); end; procedure TForm1.btnSetClick(Sender: TObject); var tmpSpeedStr : string; begin tmpSpeedStr := edSpeed.Text; FKHInterface.autopilotSpeed := strtofloat(trim(tmpSpeedStr)); end;

autopilotSpeed 所对应的是 Google Earth 的【Tools】→【Options】命令中“Fly-To Speed”设置框中心参数,通过本实例代码可以互操作这个参数,如图 5-49 和图 5-50 所示。

图 5-49 飞行速度 图 5-50 【Fly-To Speed】选项数值

3)currentViewExtents currentViewExtents 介绍如下。

定义:描述了当前 Google Earth 地图窗口的视场范围。 使用方式:读(Get)。 值类型:IKHViewExtents。 方程式:property currentViewExtents: IKHViewExtents

read Get_currentViewExtents;。 Delphi 实例代码:

第 5 章 Google Earth API 开发

375

var FKHInter face : IKHInterface; …… procedure TForm1.btnViewExtClick(Sender: TObject); var tmpStr : string; tmpLatLng : double; begin tmpLatLng := FKHInterface.currentViewExtents.east; tmpstr := '东:'+ floattostr(tmpLatLng) + #13#10 + tmpstr; tmpLatLng := FKHInterface.currentViewExtents.west; tmpstr := '西:'+ floattostr(tmpLatLng) + #13#10 + tmpstr; tmpLatLng := FKHInterface.currentViewExtents.south; tmpstr := '南:'+ floattostr(tmpLatLng) + #13#10 + tmpstr; tmpLatLng := FKHInterface.currentViewExtents.north; tmpstr := '北:'+ floattostr(tmpLatLng) + #13#10 + tmpstr; showmessage(tmpstr); end;

执行后的效果如图 5-51 所示。

图 5-51 视场的四边

2.IKHInterface 方法

1)currentView currentView 介绍如下。

定义:取得当前 Google Earth 的地图照相机,前面的表格说明了这个接口类似于

Google Earth API 中的 ICameraInfoGE 接口。 方程式:function currentView(terrain: Integer): IKHViewInfo; safecall;。

Delphi 实例代码: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) ……

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

376

private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation uses KEYHOLELib_TLB; {$R *.dfm} var FKHInterface : IKHInterface; procedure TForm1.FormCreate(Sender: TObject); begin FKHInterface := CoKHInterface.Create; end; procedure TForm1.btnViewGetClick(Sender: TObject); var tmpView : IKHViewInfo; begin tmpView := FKHInterface.currentView(1); edazimuth.text := floattostr(tmpView.azimuth); edlatitude.text := floattostr(tmpView.latitude); edlongitude.text := floattostr(tmpView.longitude); edrange.text := floattostr(tmpView.range); edtilt.text := floattostr(tmpView.tilt); end; procedure TForm1.btnViewSetClick(Sender: TObject); var tmpView : IKHViewInfo; begin try tmpView := coKHViewInfo.Create; tmpView.azimuth := strtofloat(edazimuth.Text); tmpView.latitude := strtofloat(edlatitude.text); tmpView.longitude := strtofloat(edlongitude.text); tmpView.range := strtofloat(edrange.text); tmpView.tilt := strtofloat(edtilt.text); FKHInterface.setView(tmpView,0,5); except //…… end; end; end.

该程序可以操控 Google Earth 的地图窗口的焦点移动,稍加改动就可以实现互动效果,

所以这个接口方法是很多目前 Internet 上 Google Earth 玩家喜欢的 GE 小游戏的基础。通过这

第 5 章 Google Earth API 开发

377

个方法设置视点的参数,甚至可以实现如第一人称射击等游戏。 焦点参数设置如图 5-52 所示。

图 5-52 焦点参数设置

从图 5-53 和图 5-54 的两幅图中可以看出 Google Earth 的视场随着照相机的参数改变而

变动。

图 5-53 焦点变动前 图 5-54 焦点变动后

2)SaveScreenShot SaveScreenShot 介绍如下。

定义:将地图窗口当前的卫星图片内容保存成一个黑白图像文件。 方程式:procedure SaveScreenShot(const fileName: WideString; quality: Integer);

safecall;。 其参数如表 5-18 所示。

表 5-18 SaveScreenShot 参数

参 数 输 入 方 向 值 类 型 定 义

fileName In WideString 图片文件地址

quality In Integer 图片精细程度

Delphi 实例代码类似于 Google 版的 IApplicationGE 接口的截屏方法,在此不再赘述。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

378

3)OpenFile OpenFile 介绍如下。

定义:停止播放。 方程式:procedure OpenFile(const fileName: WideString); safecall;。

Delphi 实例代码: var FKHInterface : IKHInterface; …… procedure TForm1.btnOpenFileClick(Sender: TObject); var KMLpath: widestring; begin KMLpath := 'C:\Documents and Settings\Administrator\My Documents\placemark.kml'; try FKHInterface.OpenFile(KMLpath); except //…… end; end;

代码执行后的效果如图 5-55 所示。与 Google 版的 OpentFile 方法类似,也是在 Google Earth 中加载一个 KML 文件。

图 5-55 OpenFile 结果

4)QuitApplication QuitApplication 介绍如下。

定义:退出程序,关闭 Google Earth。 方程式:procedure QuitApplication; safecall;。

关闭 Google Earth 的时候如果当前用户打开了 KML 或者没有保存地标文件,Google Earth 会弹出提示。如果用户单击了【Cancel】按钮则 Delphi 程序会捕捉到错误。请用户在开

发程序时注意容错。 Delphi 实例代码: var FKHInterface : IKHInterface;

第 5 章 Google Earth API 开发

379

…… procedure TForm1.btnQuitApplicationClick(Sender: TObject); begin try FKHInterface.QuitApplication; except showmessage('关闭 Google Earth程序被取消或出错。') end; end;

5)SetRenderWindowSize SetRenderWindowSize 介绍如下。

定义:设置地图窗口的大小。 方程式:procedure SetRenderWindowSize(width: Integer; height: Integer); safecall;。

其参数如表 5-19 所示。

表 5-19 SetRanderWindowSize 参数

参 数 输 入 方 向 值 类 型 定 义

Width In Integer 窗口宽度

Height In Integer 窗口高度

Delphi 实例代码: procedure TForm1.btnResizeMapClick(Sender: TObject); var ViewWidth, ViewHeight : integer; begin ViewWidth := 300; ViewHeight := 200; try FKHInterface.SetRenderWindowSize(ViewWidth,ViewHeight); except //…… end; end;

6)setView setView 介绍如下。

定义:根据给定的照相机参数、地形参数、速度参数,设置当前视场。 方程式:procedure setView(const view: IKHViewInfo; terrain: Integer; speed: Double);

safecall;。 其参数如表 5-20 所示。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

380

表 5-20 setView 参数

参 数 输 入 方 向 值 类 型 定 义

view In IKHViewInfo 视场对象

terrain In Integer 地形值

speed In Double 速度值

Delphi 实例代码: procedure TForm1.btnSetViewClick(Sender: TObject); var tmpview : IKHViewInfo; begin try tmpview := coKHViewInfo.Create; tmpview.tilt := 30; tmpview.azimuth:= 0; tmpview.range :=800; tmpview.latitude := 32.2323; tmpview.longitude := 118.2332; FKHInterface.setView(tmpview,1,4.0); except //…… end; end;

执行后的效果如图 5-56 所示。

图 5-56 设定视场

7)LoadKml LoadKml 介绍如下。

定义:加载 KML 文档。 方程式:procedure LoadKml(var kmlData: WideString); safecall;。

其参数如表 5-21 所示。

第 5 章 Google Earth API 开发

381

表 5-21 LoadKml 参数

参 数 输 入 方 向 值 类 型 定 义

kmlData In WideString KML 文档

Delphi 实例代码: var FKHInterface : IKHInterface; …… procedure TForm1.btnOpenFileClick(Sender: TObject); var KMLpath: widestring; begin KMLpath := 'C:\Documents and Settings\Administrator\My Documents\TimeSpan.kmll'; try FKHInterface. LoadKml(KMLpath); except //…… end; end;

8)getFeatureByName getFeatureByName 介绍如下。

定义:根据要素名称获得要素对象。 方程式:function getFeatureByName(const name: WideString): IKHFeature; safecall;。

其参数如表 5-22 所示。

表 5-22 getFeatureByName 参数

参 数 输 入 方 向 值 类 型 定 义

Name In WideString 要素名称

Delphi 实例代码与 Google 版 IApplicationGE 接口中的方法相同,在此不再赘述。

9)setViewParams setViewParams 介绍如下。

定义:设置视场的参数。 方程式:procedure setViewParams(lat: Double; lon: Double; range: Double; tilt: Double;

azimuth: Double; terrain: Integer; speed: Double); safecall;。 其参数如表 5-23 所示。

表 5-23 setViewParams 参数

参 数 输 入 方 向 值 类 型 定 义

lat In Double 纬度

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

382

(续表)

参 数 输 入 方 向 值 类 型 定 义

lon In Double 经度

tilt In Double 倾角

azimuth In Double 方位角

terrain In Integer 地形值

speed In Double 速度

Delphi 实例代码: procedure TForm1.btnsetViewParamsClick(Sender: TObject); var tmpLat,tmplon,tmpAzi,tmptilt,tmpran : double; tmpflyspeed : double; tmpTerrain :integer; begin try //定义照相机参数 tmpLon := 118.2452; tmplat := 32.3453; tmpran := 20000; tmpAzi := 0; tmptilt := 60; //定义飞行速度 tmpflyspeed := 4.0; //定义地形夸张度 tmpTerrain := 2; //设置视场

FKHInterface.setViewParams(tmplat,tmplon,tmpran,tmptilt,tmpAzi,tmpTerrain,tmpflyspeed); except //…… end; end;

执行后的效果如图 5-57 所示。

图 5-57 停止播放

第 5 章 Google Earth API 开发

383

10)setFeatureView setFeatureView 介绍如下。

定义:设置“飞行到”某要素的视场,第二个参数为飞行速度,取值 0~5。 方程式:procedure setFeatureView(const feature: IKHFeature; speed: Double); safecall;。

Delphi 实例代码: var FKHInterface : IKHInterface; …… procedure TForm1.btnsetFeatureViewClick(Sender: TObject); var tmpFeature :IKHFeature; begin try tmpFeature := FKHInterface.getFeatureByName('testplacemark1'); FKHInterface.setFeatureView(tmpFeature,4.0); except //…… end; end;

执行后的效果如图 5-58 所示。

图 5-58 运行效果

11)getPointOnTerrainFromScreenCoords getPointOnTerrainFromScreenCoords 介绍如下。

定义:取得地面上某一点的屏幕坐标。 方程式:function getPointOnTerrainFromScreenCoords(screen_x: Double; screen_y:

Double): PSafeArray; safecall;。 其参数如表 5-24 所示。

表 5-24 getPointOnTerrainFromScreenCoords 参数

参 数 输 入 方 向 值 类 型 定 义

screen_x In Double 屏幕坐标 X

screen_y In Double 屏幕坐标 Y

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

384

screen_x 和 screen_y 的取值都在-1~+1 之间,具体说明请参看前面的 Google Earth API。

5.4.3 IKHFeature 接口

IKHFeature 接口类似于 Google Earth API 的 IFeatureGE 接口,不过少了很多属性,如高

亮显示、获取子要素集等。 IKHFeature 属性如下。

1)visibility visibility 介绍如下。

定义:描述了每次视点“飞行”停止的时长。 使用方式:读(Get)。 值类型:Double。 方程式:property visibility: Integer

read Get_visibility write Set_visibility;。

Delphi 实例代码: procedure TForm1.btnVisibleClick(Sender: TObject); var tmpFeature :IKHFeature; begin try tmpFeature := FKHInterface.getFeatureByName('testplacemark1'); if (tmpFeature.visibility <>0) then tmpFeature.visibility := 0 else tmpFeature.visibility :=1; except //…… end; end;

2)hasView hasView 介绍如下。

定义:描述了要素是否有视场。 使用方式:读(Get)。 值类型:Double。 方程式:property hasView: Integer

第 5 章 Google Earth API 开发

385

read Get_hasView;。

Delphi 实例代码: procedure TForm1.btnhasViewClick(Sender: TObject); var tmpFeature :IKHFeature; begin tmpFeature := FKHInterface.getFeatureByName('testplacemark1'); if (tmpFeature.hasView <>0) then begin showmessage('有视场'); FKHInterface.setFeatureView(tmpFeature,4.0); end else begin showmessage('无视场'); end; end;

5.4.4 IKHViewExtents 接口

表示 Google Earth 当前地图视场的范围,此接口为 IKHInterface.currentViewExtents 的返

回值,一般用 4 个方向的属性值来表示范围,并且这 4 个方向的属性值都是只读的。

1)North North 介绍如下。

定义:视场的北边界。 使用方式:读(Get)。 值类型:Double。 方程式:property north: Double

read Get_north;。

2)South South 介绍如下。

定义:视场的南边界。 使用方式:读(Get)。 值类型:Double。 方程式:property south: Double

read Get_south;。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

386

3)East East 介绍如下。

定义:视场的东边界。 使用方式:读(Get)。 值类型:Double。 方程式:property east: Double

read Get_east;。

4)West West 介绍如下。

定义:视场的西边界。 使用方式:读(Get)。 值类型:Double。 方程式:property west: Double

read Get_west;。

Delphi 实例代码: procedure TForm1.btnViewExtentsClick(Sender: TObject); var tmpViewExt : IKHViewExtents ; tmpstr: string; begin try tmpViewExt := FKHInterface.currentViewExtents; tmpstr := 'N: ' + floattostr(tmpViewExt.North ) + #13#10 + tmpstr; tmpstr := 'S: ' + floattostr(tmpViewExt.South ) + #13#10 + tmpstr; tmpstr := 'E: ' + floattostr(tmpViewExt.East ) + #13#10 + tmpstr; tmpstr := 'W: ' + floattostr(tmpViewExt.West ) + #13#10 + tmpstr; showmessage(tmpstr); except //…… end; end;

执行后的效果如图 5-59 所示。

图 5-59 视场四边

第 5 章 Google Earth API 开发

387

5.4.5 IKHViewInfo 接口

IKHViewInfo 接口类似于 Google Earth API 的 ICameraInfoGE 接口,IKHViewInfo 属性介

绍如下。

1)latitude latitude 介绍如下。

定义:描述了 Google Earth 照相机的纬度。 使用方式:读(Get)/ 写(Set)。 值类型:Double。 方程式:property latitude: Double

read Get_latitude write Set_latitude;。

2)longitude longitude 介绍如下。

定义:描述了 Google Earth 照相机的经度。 使用方式:读(Get)/ 写(Set)。 值类型:Double。 方程式:property longitude: Double

read Get_longitude write Set_longitude;。

3)range range 介绍如下。

定义:描述了 Google Earth 照相机的视场范围。 使用方式:读(Get)/ 写(Set)。 值类型:Double。 方程式:property range: Double

read Get_range write Set_range;。

4)tilt tilt 介绍如下。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

388

定义:描述了 Google Earth 照相机镜头的倾角。 使用方式:读(Get)/ 写(Set)。 值类型:Double。 方程式:property tilt: Double

read Get_tilt write Set_tilt;。

5)azimuth azimuth 介绍如下。

定义:描述了 Google Earth 照相机镜头的方位角。 使用方式:读(Get)/ 写(Set)。 值类型:Double。 方程式:property azimuth: Double

read Get_azimuth write Set_azimuth;。

Delphi 实例代码: interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) …… private { Private declarations } function GetLat():double; function GetLng():double; function GetAzimuth():double; function GetTilt():double; function GetRange():double; public { Public declarations } end; var Form1: TForm1; implementation uses KEYHOLELib_TLB; {$R *.dfm}

第 5 章 Google Earth API 开发

389

var FKHInterface: IKHInterface; procedure TForm1.btnGetClick(Sender: TObject); begin if (FKHInterface <> nil) then begin edLng.Text := floattostr(GetLng()); edLat.Text := floattostr(GetLat()); edAzi.Text := floattostr(GetAzimuth()); edTilt.Text := floattostr(GetTilt()); edRan.Text := floattostr(GetRange()); end else begin showmessage('请稍等……'); end; end; //获取相机方位角 function TForm1.GetAzimuth: double; var cm: IKHViewInfo; begin cm := FKHInterface.currentView(1); if cm <> nil then result:= cm.Azimuth; end; //获取照相机纬度 function TForm1.GetLat: double; var cm: IKHViewInfo; begin cm := FKHInterface.currentView(1); if cm <> nil then result:= cm.latitude; end; //获取照相机经度 function TForm1.GetLng: double; var cm: IKHViewInfo; begin cm := FKHInterface.currentView(1); if cm <> nil then result:= cm.longitude; end; //获取照相机倾斜角 function TForm1.GetTilt: double; var cm: IKHViewInfo;

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

390

begin cm := FKHInterface.currentView(1); if cm <> nil then result:= cm.Tilt; end; //获取照相机的现场范围 function TForm1.GetRange: double; var cm: IKHViewInfo; begin cm := FKHInterface.currentView(1); if cm <> nil then result:= cm.Range; end; procedure TForm1.FormCreate(Sender: TObject); begin try FKHInterface := coKHInterface.Create; Except showmessage('启动失败'); end; end; end.

执行后的效果如图 5-60 所示。

图 5-60 相机参数

5.5 例子

本章通过两个与 Google Maps + Ajax 类似的宿营例子,展示一下 Google Earth 开发的乐

趣所在,第一个是 Delphi 开发的例子,重点在与 KML 联动,第二个是 C#开发的例子,重点

在于设置地图视场相机的视角,实现虚拟飞行。与 Google Maps API 不同的是,Google Earth并没有提供有关添加点(Point)、线(Line)、面(Polygon)的接口,而是通过其他途径,如

KML、自带的创建工具、第三方工具创建的。

第 5 章 Google Earth API 开发

391

第一个例子通过读取数据库中的二维关系表,列出所有参加野营活动的组别信息,每个

组别的信息包括宿营地的经纬度、组别名称、人员组成等简单信息。将组别信息编写成 KML脚本,并在 Google Earth 中执行,执行后的效果如图 5-61 所示。

如图 5-62 所示的是第三营队的宿营地在 Google Earth 上的截图。

图 5-61 野营例子主界面 图 5-62 Google Earth 上的截图

第二个例子通过数据库中保存的野营各营队经纬度信息来调整地图视场相机的每一步

的视角位置,从第一个宿营点自动“飞行”到 后一个宿营点。这个例子稍加更改,就是一

个很有用的应用,例子的界面如图 5-63 所示,图 5-64 是运行后的效果。

图 5-63 例子主界面 图 5-64 Google Earth 上的截图

另外在源代码中还有关于第二个例子“飞行”效果的演示视频。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

392

5.5.1 开发环境配置

第一个例子采用 Delphi 语言+Google Earth 的典型开发方案,数据库连接采用了 Windows平台的优秀连接方式 ADO。如表 5-25 所示的是开发环境配置简表。

表 5-25 第一个例子开发配置

数据库 Access 2003

数据库连接方式 ADO

Delphi 7.0 开发平台

Google Earth

KML 2.1 版本

Delphi 的 ADO 开发,请读者参考其他相关资料,在此不再详细描述。

第二个例子采用Visual Studio 2005的C# + Google Earth联合开发,数据库采用 SQLserver 2000,采用 ADO.net 的方式连接,如表 5-26 所示是开发环境配置简表。

表 5-26 第二个例子开发配置

SQLServer

数据库实例:getest 数据库

用户名:sa 密码:123

数据库连接方式 ADO.net

Visual Studio 2005 C# 开发平台

Google Earth

KML 2.2 版本

5.5.2 数据库设置

两个例子的数据库结构完全一致,第一个例子在名为“DATA.mdb”的 Aceess 数据库中

建立一张名为“cantonment”的表,表的构建可以通过手工,也可以通过 SQL 语言建立,第

二个例子在 SQLServer 中建立起一个名为“getest”的数据库。 数据表共有包括主键在内的 5 个字段:id、经度 lng、纬度 lat、组别 org、人员信息备注

remark。 建表的 SQL 语句如下:

第 5 章 Google Earth API 开发

393

CREATE TABLE [cantonment] ( [id] [int] NOT NULL , [lng] [float] NULL , [lat] [float] NULL , [org] [nvarchar] (8) COLLATE Chinese_PRC_CI_AS NULL , [remark] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL ) ON [PRIMARY] GO

表中的内容如图 5-65 所示。

图 5-65 数据表内容

DATA.mdb 数据库放置在程序的根目录中,本例会自动找到它。

5.5.3 代码分析

本例只有一个窗体,其上设置了一个组别选择框,列出了所有参与这次野营活动的小组

名称。根据组别名称,开启 ADO 连接,选择出与组别相符合的数据,列在 DBGrid 中。 另外还有两个按钮,一个是生成 KML 的按钮,其作用是根据列出在 Grid 中的数据动态

生成 KML 脚本,并将脚本显示在文本框中;另一个按钮为【绘制】按钮,其作用是根据 KML脚本调用 Google Earth,执行 KML 并在地图上有所显示。

在程序窗口开始的时候,首先创建一个 Google Earth 进程,这是一些辅助程序,如读取

程序根目录、执行一个 ADOQuery 等,如下: unit Unit1; …… var fromMian: TfromMian; tmpLng,tmpLat :string; implementation uses EARTHLib_TLB; var F_AppGE: IApplicationGE; {$R *.dfm} …… function TfromMian.AppPath: widestring;

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

394

begin result := extractfilepath(application.ExeName); end; //----------------------------------------------------- function TfromMian.QryStr(var Qry: Tadoquery; SQLstr: string): boolean; begin try with Qry do begin close; sql.clear; sql.add(SQLstr); active := true; end; result := true; except result := false; raise; end; end;

窗口启动,在窗口启动的同时启动 Google Earth,并且配置 ADO Connection,建立连接: procedure TfromMian.FormCreate(Sender: TObject); var constr :string; pathstr : widestring; begin try F_AppGE := CoApplicationGE.Create(); except showmessage('启动 Google Earth失败'); end; pathstr := AppPath; constr := 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source='+ pathstr

+'DATA.mdb;Persist Security Info=False'; con.ConnectionString := constr; con.Connected := true; end;

选择框内容变更,打开 ADOQuery 执行一个相应的 SQL 查询,返回与选择组别对应的

宿营地记录,代码如下: procedure TfromMian.cmbChange(Sender: TObject); begin QryStr(qry,'select * from cantonment where org=''' + cmb.Text + ''''); QryStr(QryEXE ,'select avg(lng) as avglng, avg(lat) as avglat from cantonment where

org ='''+ cmb.Text + ''''); with QryEXE do begin First; //取经纬度平均值,便于观看全局 tmpLng := fieldbyname('avglng').AsString;

第 5 章 Google Earth API 开发

395

tmpLat := fieldbyname('avglat').AsString; Close; end; end;

单击【生成 KML 语句】按钮,代码如下: procedure TfromMian.btnKMLClick(Sender: TObject); begin //在 memo中显示 KML脚本 mm.Text := CreateKML; end;

单击【绘制】按钮,其实质是调用 OpendKmlFile 方法, 终 Google Earth 会在执行后展

示 KML 内容: procedure TfromMian.btnDrawClick(Sender: TObject); var kmlstr:string; begin kmlstr := CreateKML; SaveKMLFile(kmlstr); F_AppGE.OpenKmlFile(AppPath + 'test.kml', 1); end;

生成 KML 语句函数,代码如下: function TfromMian.CreateKML: string; var kmlstr:string; i:integer; begin kmlstr := '<?xml version=''1.0'' encoding=''UTF-8''?>'; kmlstr := kmlstr + #13#10 + '<kml xmlns=''http://earth.google.com/kml/2.1''>'; kmlstr := kmlstr + #13#10 + ' <Document>'; //循环取值,拼接 KML语句 qry.First; for i := 0 to qry.RecordCount -1 do with qry do begin kmlstr := kmlstr + #13#10 + ' <Placemark>'; kmlstr := kmlstr + #13#10 + ' <name>CantonmentPoint_'+ inttostr(i+1)

+'</name>'; kmlstr := kmlstr + #13#10 + ' <LookAt>'; kmlstr := kmlstr + #13#10 + ' <longitude>'+ tmpLng +'</longitude>'; kmlstr := kmlstr + #13#10 + ' <latitude>'+ tmpLat +'</latitude>'; kmlstr := kmlstr + #13#10 + ' <altitude>0</altitude>'; kmlstr := kmlstr + #13#10 + ' <range>2000</range>'; kmlstr := kmlstr + #13#10 + ' <tilt>-5.821565606503298e-015</tilt>'; kmlstr := kmlstr + #13#10 + ' <heading>7.29646319265843</heading>'; kmlstr := kmlstr + #13#10 + ' </LookAt>'; kmlstr := kmlstr + #13#10 + ' <Point>'; kmlstr := kmlstr + #13#10 + ' <coordinates>'+

fieldbyname('lng').AsString +','+ fieldbyname('lat').AsString +',0</coordinates>';

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

396

kmlstr := kmlstr + #13#10 + ' </Point>'; kmlstr := kmlstr + #13#10 + ' </Placemark>'; qry.Next; end; kmlstr := kmlstr + #13#10 + ' </Document>'; kmlstr := kmlstr + #13#10 + '</kml>'; result := kmlstr; end;

保存 KML 至文件,文件名为“test.kml”,可以在程序的根目录下发现这个 KML 文件。

读者也可以自己用 Google Earth 打开 test.kml 文件,效果一样: procedure TfromMian.SaveKMLFile(kmldata:string); var FileName:string; OutFile:TextFile; begin FileName := AppPath + 'test.kml'; AssignFile(OutFile,Filename); reset(OutFile); try {if FileExists(Filename) then begin Append(OutFile); Writeln(OutFile); end else } Rewrite(OutFile); Writeln(OutFile,kmldata); finally CloseFile(OutFile); end; end; end.

运行程序后,单击【绘制】按钮,在 Google Earth 的界面上会出现加载的几个 tesk.kml,以及每个 KML 文档中包含的地标子项,如图 5-66 所示。

图 5-66 地标结构

这个动态生成的 KML 文档内容如下: <?xml version='1.0' encoding='UTF-8'?> <kml xmlns='http://earth.google.com/kml/2.1'> <Document>

第 5 章 Google Earth API 开发

397

下面是 3 个点,分别用<Placemark />标注: <Placemark> <name>CantonmentPoint_1</name> <LookAt> <longitude>118.329966666667</longitude> <latitude>32.4382266666667</latitude> <altitude>0</altitude> <range>2000</range> <tilt>-5.821565606503298e-015</tilt> <heading>7.29646319265843</heading> </LookAt> <Point> <coordinates>118.3533,32.43564,0</coordinates> </Point> </Placemark> <Placemark> <name>CantonmentPoint_2</name> <LookAt> <longitude>118.329966666667</longitude> <latitude>32.4382266666667</latitude> <altitude>0</altitude> <range>2000</range> <tilt>-5.821565606503298e-015</tilt> <heading>7.29646319265843</heading> </LookAt> <Point> <coordinates>118.3233,32.43264,0</coordinates> </Point> </Placemark> <Placemark> <name>CantonmentPoint_3</name> <LookAt> <longitude>118.329966666667</longitude> <latitude>32.4382266666667</latitude> <altitude>0</altitude> <range>2000</range> <tilt>-5.821565606503298e-015</tilt> <heading>7.29646319265843</heading> </LookAt> <Point> <coordinates>118.3133,32.4464,0</coordinates> </Point> </Placemark> </Document> </kml>

如图 5-67 所示的是第一营队宿营地在 Google Earth 上的截图。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

398

图 5-67 Google Earth 截图

这个例子可以结合 IApplicationGE 接口,稍加改动便可以成为自己程序的一部分。 第二个例子中的 KML 部分与第一个例子相似,在此不再赘述,重点在于“自动飞行”

方面的代码讲解。 Google Earth 新版中添加了一些激动人心的小应用,例如飞行模拟器,用户可以在【工

具】菜单中选择【输入飞行模拟器】来调出飞行界面,然后按动方向键来控制飞机的上下左

右飞行,获得类似驾驶飞机的身临其境的感受,结果这个小游戏一经推出大受欢迎。 其实这个小游戏的编写不难实现, 主要的是要掌握对地图视场相机的控制,Google

Earth 是假设有个相机对着“地面”的,用户可以通过鼠标或者键盘来控制相机视角来观察地

图的,所以如果要想使得 Google Earth 的地图按照某种规律“自动”被浏览的话,就需要不

断设置和调整视场相机的参数。 Google Earth API 提供了一种方法 SetCameraParams,该方法一共包含 8 个参数,分别是

lat 纬度,lon 经度,alt 高度,altMode 高度模式,Range 范围,tilt 倾角,Azimuth 方位角,

speed 速度,具体的讲解请参见表 5-3。本例通过在 timer 中按照每个间隔调整一次参数,来

实现飞行的目的,下面讲解代码。 首先需要设置一些全局变量: bool isfly = false; //是否已经开始“飞行” int recordpace = 0; //飞行的步骤间距 double lat1; //飞行在两点间,前一个点的纬度 double lat2; //飞行在两点间,后一个点的纬度 double lng1; //飞行在两点间,前一个点的经度 double lng2; //飞行在两点间,后一个点的经度 double tmp_lat = 0; //每步“飞行”的纬度(不断累加) double tmp_lng = 0; //每步“飞行”的经度(不断累加) int i = 0; //飞行计数

在例子程序窗口打开的时候,需要创建 GE 对象实例,并且连接数据库,执行 SQL 语句,

将数据表中的数据取出,并且调用生成 KML 的函数段,生成 KML 终将 KML 文本内容显

示在程序窗体上: private void Form1_Load(object sender, EventArgs e)

第 5 章 Google Earth API 开发

399

{ try { appGE = new ApplicationGEClass(); ConnDB tmpDb = new ConnDB("server=127.0.0.1;database=getest;uid=sa;pwd=123;"); dbset = tmpDb.ReturnDataSet("select * from cantonment"); dbview.DataSource = dbset.Tables[0]; txtKML.Text = makeKML(dbset); lat1 = (double)dbset.Tables[0].Rows[recordpace]["lat"]; lat2 = (double)dbset.Tables[0].Rows[recordpace + 1]["lat"]; lng1 = (double)dbset.Tables[0].Rows[recordpace]["lng"]; lng2 = (double)dbset.Tables[0].Rows[recordpace + 1]["lng"]; tmp_lat = lat1; tmp_lng = lng1; } catch (Exception err) { MessageBox.Show("未能启动 Google Earth程序"); } }

上面的代码涉及到了 ADO.net 的操作: new ConnDB("server=127.0.0.1;database=getest;uid=sa;pwd=123;");

这个代码在程序方案的 db 项目中有相关的源代码,请自行参阅相关代码和文档。下面

是生成 KML 文本的函数与 Delphi 例子中的类似,请参见 Delphi 的例子,下面是生成 KML文档后在键盘上建立 ge.kml 文件的代码:

private void CreateKMLFile(string textContent, string filepath) { try { FileStream kmlfile = File.Create(filepath); byte[] strdata = new UTF8Encoding().GetBytes(textContent); kmlfile.Write(strdata, 0, strdata.Length); kmlfile.Flush(); kmlfile.Close(); } catch (Exception err) { throw (err); } }

而生成 KML 之后,程序代码中还赋值了“飞行”中第一个点和第二个点的经纬度信息,

目的是为了以后的“飞行”每一步经纬度的计算做准备,在程序中设置为:将每两点间的距

离分成 50 步来走,每一步的飞行间隔为 100 毫秒(0.1 秒),这一切是通过一个 Timer 对象

来完成的,如图 5-68 所示。

智慧地球:Google Earth/Maps/KML 核心开发技术揭秘

400

图 5-68 Timer 的属性设置

下面的 Timer 执行代码中体现了 50 步走的设置,以及每一步要走多远的计算: private void timerFly_Tick(object sender, EventArgs e) { if (isfly == true) { i = i + 1; tmp_lat = tmp_lat - calcLatDelta(lat1, lat2); tmp_lng = tmp_lng - calcLngDelta(lng1, lng2); SetCameraView(tmp_lat, tmp_lng, 200, 20, 80, 4.9); if (i == 50) //分为 50步走 { recordpace = recordpace + 1; if (recordpace < dbset.Tables[0].Rows.Count-1) { lat1 = (double)dbset.Tables[0].Rows[recordpace]["lat"]; lat2 = (double)dbset.Tables[0].Rows[recordpace + 1]["lat"]; lng1 = (double)dbset.Tables[0].Rows[recordpace]["lng"]; lng2 = (double)dbset.Tables[0].Rows[recordpace + 1]["lng"]; i = 0; tmp_lat = lat1; tmp_lng = lng1; } } } }

代码中的 calcLatDelta 为计算每一步走多远的函数,通过将前后两个点的经纬度相减后

的差除以 50 后得到,同样这里也能反映出分为 50 步走的思路: private double calcLngDelta(double lng1, double lng2) { return (lng1 - lng2) / 50; }

本例设置为 100 毫秒走一步,共分 50 步走完一个点,是出于用户体验的考虑,在实际

应用中可根据需要自行调节快慢。 后,在【飞行】按钮中,设置 timerFly.Start();开启 Timer 对象,实现每 100 毫秒触发

一次的“飞行”,执行后,在地图窗口会自动平滑地从宿营点 1“浏览飞行”到宿营点 6,就好像有一个无形的鼠标在控制着 Google Earth 一样。

第 5 章 Google Earth API 开发

401

5.6 小结

本章详细讲述了 Google Earth API 的两个版本:Google 版和 Keyhole 版。重点讲解了当

前的 Google 发行的版本,这个版本也是将来唯一支持的版本。 本章中提到了很多概念,如四维时空、视场(View)、飞行(Fly-To)等,需要读者深入

理解。 同时也指出开发 Googel Earth 程序需要具备的基础知识,并结合了大量实例与插图,阐

述每一个接口的方法和属性。对于理解 Google Earth API,需要重点掌握 IApplcationGE 接口,

因为它是所有基于 GE API 开发的基础,在此基础上应逐步掌握 ICameraInfoGE 和 IFeatureGE接口,这两个接口可以操作 Googel Earth 的地图视场和地理要素。