开心人生

用今天的努力----实现我所向往的明天

导航

Google Earth API 讲解--02

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程序的开启、关闭、获取地图窗口的句柄、操作主窗体句柄,还可以进行获取地图视场照相机对象、获取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介绍如下。

l 定义:返回一个布尔值,反馈Google Earth是否已经登录。
l 方程式: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{

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

    }

}

执行以上代码,当Google Earth正在启动的时候,单击代码中名为【btnIsOnLine】的按钮,会弹出【尚未登录】对话框,但是当Google Earth登录状态栏显示如图5-7所示的内容的对话框之后,再单击按钮就会出现【已经登录】提示框了,如图5-8所示。这说明Google Earth在进行“Google Earth Initialization”动作过程中,实施了登录(IsInitialize)。

           

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

2)IsOnline

IsOnline介绍如下。

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

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

3)Login

Login介绍如下。

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

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

4)Logout

Logout介绍如下。

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

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

2.视场相机设置

当用户观察Google Earth地图的时候,是没办法仅仅通过移动头部来获得不同观察体验的。因为虽然我们看到的Google地球是个三维球体,但是地图窗口投射到屏幕上的影像是一个不折不扣的平面,三维效果是通过计算模拟出来的。

要想看到不同方位的图像,例如看到地球的另一面,就必须用鼠标去拖曳,并且进行缩放,缩放到某个地方,而此时用户无须转动头部和眼球。这是操纵视场照相机(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;

……

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;

    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双精度小数

速度

纬度的取值在-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,

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-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 低清晰度

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”。这里的所有代码都未加入容错机制,例如此处实际使用过程中可能还会出现文件不存在的情况,需要首先加入判断代码,确保运行无误。

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>

               <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实例代码:

……

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),有视场才能有“飞行”定位的过程,无视场则无法定位。

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-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实例代码:

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;

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所示。

(-1, -1)

图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;

       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-15 地图窗口中心点坐标图5-12中已经表明,地图窗口的中心点坐标为(0.0, 0.0),代码执行后,弹出的提示框内容如图5-15所示,反映的是目前地图窗口中心点的坐标。

所以要想获得鼠标当前在地图窗口中实地对应的位置,就必须按照比例关系来确定。

8.要素文件夹操作

1)GetMyPlaces

GetMyPlaces介绍如下。

l 定义:得到Google Earth中的“My Places”。虽然它是个文件夹,但Google Earth也将之视为一个要素。
l 方程式: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();

……

private FeatureGE getMyPlaceFeature()

{

    FeatureGE ft = appGE.GetMyPlaces();

    if (ft != null)

    {

        return ft;

    }    else    {

        return null;

    }

}

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

2)GetTemporaryPlaces

GetTemporaryPlaces介绍如下。

l 定义:得到临时位置文件夹,中文版的Google Earth中文名称为“临时位置”。
l 方程式: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;

    }

}

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

3)GetLayersDatabases

GetLayersDatabases介绍如下。

l 定义:根据图层列表获取要素数据源集合,该数据源就是要素集合。
l 方程式: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

    {

        return null;

    }

}

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

                          

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

9.窗口句柄操作

如果要开发一个包含Google Earth的程序,获得主窗口的句柄是必要的。例如,通过代码控制Google Earth主窗口的大小和状态这种需求,首先就需要采用GetMainHWnd取得主窗口的句柄再做处理。

1)GetMainHwnd

GetMainHwnd的介绍如下。

l 定义:取得Google Earth程序主窗口的句柄。
l 方程式: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);

    }

    finally { }

}

在获取了Google Earth的主窗口之后,有时候还需要对地图窗口进行操作,如需要移动地图窗口到用户自己的程序上。这个时候就需要获得地图窗口句柄,然后调用Windows的API来移动和设置地图窗口句柄的父窗口,通过 GetRenderHwnd可以获取地图窗口的句柄。

以前Keyhole版本的API没有提供这个方法,这时候只有通过其他的方法获取地图窗口句柄,如利用第三方工具获取。

2)GetRenderHwnd

GetRenderHwnd的介绍如下。

l 定义:返回Google Earth的地图窗口。
l 方程式: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-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所示的效果。

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

上图中Google Earth的地图窗口被嵌入到了用户自己编写的程序中。其实承载地图窗口的是一个Delphi中的panel,通过Windows的API将地图窗口的父窗口设置为panel,得以在自己的程序中嵌入地图,在本地后台仍然是启动了一个Google Earth进程。

10.IApplicationGE属性。

1)Google Earth版本

Google Earth版本介绍如下。

① VersionMajor

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

read Get_VersionMajor;。

② VersionMinor

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

read Get_VersionMinor;。

③ VersionBuild

l 定义:Google Earth程序的构建号。
l 使用方式:读(Get)。
l 值类型:Integer。
l 方程式: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所示。

表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

l 定义:Google Earth程序版本类型,是免费版还是专业版或其他版本。此处该类型为一个枚举值。
l 使用方式:读(Get)。
l 值类型:Integer。
l 方程式: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

StreamingProgressPercentage介绍如下。

l 定义:反映Google Earth获取当前地图数据流的进度。
l 使用方式:读(Get)。
l 值类型:Integer。
l 方程式: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介绍如下。

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

read Get_ViewExtents;。

此方法的实例请参见IFeatureGE接口的HasView。

③ ElevationExaggeration

传统GIS的三维模块的必备功能就是地形拉伸,介绍如下。

l 定义:纵向拉伸地形,使之被扩大。
l 使用方式:读(Get)/写(Set)。
l 值类型:Double。
l 方程式: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 真实状态

3)Google Earth控件

① TourController

TourController介绍如下。

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

read Get_TourController;。

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

② SearchController

SearchController介绍如下。

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

read Get_SearchController;。

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

③ AnimationController

AnimationController介绍如下。

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

read Get_AnimationController;。

说明

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

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介绍如下。

l 定义:照相机焦点位置的纬度。
l 使用方式:读(Get)/写(Set)。
l 值类型:Double。
l 方程式: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介绍如下。

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

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介绍如下。

l 定义:照相机焦点位置的高度,不过返回值取决于AltitudeMode的设置,参见下面对AltitudeMode的介绍。
l 使用方式:读(Get)/写(Set)。
l 值类型:Double。
l 方程式:property FocusPointAltitude: Double

read Get_FocusPointAltitude write Set_FocusPointAltitude;。

Delphi实例代码:

……

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介绍如下。

l 定义:照相机焦点位置的高度模式。
l 使用方式:读(Get)/写(Set)。
l 值类型:AltitudeModeGE。
l 方程式: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()

{

    CameraInfoGE cm = appGE.GetCamera(1);

    cm.FocusPointAltitudeMode = (AltitudeModeGE)1;

}

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

        RelativeToGroundAltitudeGE = 1,

        AbsoluteAltitudeGE = 2,

2.轴向

1)Azimuth

Azimuth介绍如下。

l 定义:相机镜头的方位角。通常情况下方位角的取值范围在0~360°,而Google Earth中取值范围被定义在-180°~ +180°之间。
l 使用方式:读(Get)/写(Set)。
l 值类型:Double。
l 方程式: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;

}

2)Tilt

Tilt介绍如下。

l 定义:照相机镜头的倾角。在Google Earth中倾角的取值范围在0~90°之间。
l 使用方式:读(Get)/写(Set)。
l 值类型:Double。
l 方程式: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);

    cm.Tilt = 45.0;

}

3.视场范围(三确定)

Range介绍如下。

l 定义:照相机到被观察点的距离,单位是“米”。
l 使用方式:读(Get)/写(Set)。
l 值类型:Double。
l 方程式: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)

……

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;

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);

    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;

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.

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 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;

文本框: 图5-29 要素集合首先用Google Earth程序打开本书第3章的KML代码Folder.kml,然后执行。

上述的Delphi代码中父要素取的是名为“folderTest”的Folder元素,该要素有7个子要素,程序中使用了for循环来遍历要素集合。例子中的逻辑是取各个子要素的名字,然后用对话框显示出来,如图5-29所示。

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;

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实例代码:

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

介绍如下。

l 定义:返回一个布尔值,表示当前的要素是否被高亮选中。如果被高亮选中,返回true,否则返回false。
l 使用方式:读(Get)。
l 值类型:Integer(Bool)。
l 方程式: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)。

2)视场HasView

在使用Google Earth的时候,通常鼠标会发挥很巧妙的作用,例如,要仔细浏览某个要素的时候,只需要双击该要素的标识,地图画面就会自动缩放并移动,“飞行”到那个要素所在地。但是如果双击图5-30中的父要素folderTest,会不会也能促使地图画面的“飞行”?答案是否定的,因为父要素folderTest没有视场(View),IFeartureGE接口提供了一个HasView属性,来判断要素是否拥有视场。

HasView介绍如下。

l 定义:返回一个布尔值,表示这个要素是否有视场,即能否操作Google Earth“飞到”要素的所在地。
l 使用方式:读(Get)。
l 值类型:Integer(Bool)。
l 方程式: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);

   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介绍如下。

l 定义:表示要素的有效期,从KML的语法上分析,本书在第3章讲过关于KML时间类的标签,这种标签拥有开始和结束时间,此属性的返回值为ITimeIntervalGE接口类型。
l 使用方式:读(Get)。
l 值类型:ITimeIntervalGE。
l 方程式:property TimeInterval: ITimeIntervalGE

read Get_TimeInterval;。

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所示。

图5-36 时间段

② Name

Name介绍如下。

l 定义:返回一个字符串,表示当前的要素的名称。
l 使用方式:读(Get)。
l 值类型:字符串(string)。
l 方程式: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介绍如下。

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

read Get_Visibility

write Set_Visibility;。

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来创建地理要素。


posted on 2010-07-20 22:23  hai  阅读(2901)  评论(0)    收藏  举报