Google Static Maps API

Google Static Maps API概述

Google Maps提供了强大的地图调用函数。对于普通用户来说,须要了解一定的JavaScript语法,才可以完全使用Google Maps所提供的各种功能。

对于部分地图使用者 来说,仅希望在站点或应用中嵌入静态的地图,并不需要Google Maps提供的缩放、拖曳等具备多种Ajax效果的复杂功能。对于这样的需求,不必编写JavaScript代码,使用在站点嵌入静态地图的Google Static Maps API便是最好的选择。

静态地图API极大地方便了用户将Google Maps提供的地图嵌入应用中,Google Maps还为用户提供了一个静态地图的辅助生成器(http://gmaps-samples.googlecode.com/svn/trunk/ simplewizard/makestaticmap.html),帮助用户在不使用动态脚本的情况下定制所需位置和缩放级别的静态地图。

在辅助生成器中,可通过地址译码查找所需的地图位置、定义静态地 图图片的缩放尺度、图片大小、地图类型、标识点位置,以及标注显示的大小、颜色和显示的字母。在上述设定之后,用户定制的静态地图会在线实时刷新,给出图 片的预览和图片调用的URL地址。用户复制URL地址后,便可以轻易将所需地图嵌入到页面中显示。

目前,静态地图支持 Google Maps所提供的4种地图类型,即行政区划图(Map)、卫星影像(Satellite)、混合模式(Hybrid)及地形地貌图(Terrain)。如 果需要设定路径,还可以在地图上单击来绘制一条需要显示的路径。我们在搜索框输入“Beijing”来调用北京的静态地图,结果如图33-1所示。

图33-1  查找北京所对应的静态地图图片

接下来设定返回图片的大小为500像素×300像素,标记点使用橙色,显示字母A。设定好之后,就可以在下方的浏览窗口中得到一幅对应的静态地图,如图33-2所示。

图33-2  Google Maps静态地图辅助生成器中得到的图片

要注意的是,调用Google Maps静态地图同样要申请地图的API_Key,申请的地址为:http://code.google.com/apis/maps/signup.html,API_Key与使用Google Maps的授权码是相同的。在填入使用者申请的API_Key之后,上例我们所调用的静态地图对应的访问地址如下:

http://maps.google.com/staticmap?center=39.908173,116.397947&markers=39.908173,116.397947,orangea&zoom=13&size=500x300&key=YOUR_KEY_HERE

通过静态地图调用API,可以进一步增加电子地图的应用范围,同时也使获得地图的方法变得更为简洁直接。

 

Google Static Maps API常用参数

Google Static Maps的图像都是通过特定的URL地址返回的,在URL请求中用户可以指定请求的位置、地图大小、缩放级别、地图类型及标记点的设置。

常见的Google Static Maps请求地址串可以表示如下:

http://maps.google.com/staticmap?center=经纬度&markers=经纬度,颜色&zoom=缩放级别&size=尺寸&key=申请的KEY值

由于地图请求是由标准HTTP提交的,所有参数都须要使用&字符作为间隔,其中某些参数是可选的。地址串中所附带的参数及其取值如下。

n        Center:如果图标没有出现在地图中央,需要用center来定义地图的中心位置,后面所跟的纬度和经度须要使用逗号作为分隔。

n        Zoom:用以定义地图的缩放级别,可以通过数字选择0~18的缩放级别。

n        Size:用以定义地图图像的大小,分别用横向和纵向的像素来表示。

n        Format(可选):定义生成的影像格式。默认情况下,静态地图API将生成GIF格式的图像,其他可选的格式类型为JPEG和PNG类型。相对来说,GIF和PNG格式包含的图像细节更多,但JPEG格式的压缩比更大。

n        Maptype(可选):可以选择的地图类型包含有卫星影像、地形图、混合地图及适于便携设备的地图。在默认情况下,我们获得的是正常的行政交通图。

n        Markers(可选):用来定义附加在地图图层之上的一个或多个地点标记,标记之间可以使用标记分隔符( | )进行划分。

n        Path(可选):通过两点或多点的链接来定义显示在地图之上的道路路径,同样,一系列的点之间也使用标记( | )来进行分隔。

n        Frame(可选):为返回的地图图像添加一个可以设定颜色的边界。

n        Key:填入为站点申请的Google Maps API授权码,这个API Key与使用Google Maps时的授权码相同,可以在Google开发者站点免费申请。

在使用Google Static Maps API时,我们还须要注意的是目前Google Static Maps API的查询调用限制为每天1000次请求,这样的设定是为了限制用户大量获取静态地图而移作他用。如果发现有滥用API获取静态地图的站 点,Google可能会暂停对站点地图请求的响应。

 

 

Google Static Maps API的支持服务

在使用Google Static Maps API来获取地图时,往往仅知道请求位置的地址而对其所处的经纬度信息并不了解。这样,我们可以通过Google提供的地址译码(Geocoding)服务来将用户输入的地址转换成为对应的经纬度坐标。

在Google Maps的API之中已经包含了地址译码功能,使用者可以在HTTP请求中调用GClientGeocoder对象来完成地址译码的操作。

在Google提供的官方示例http://code.google.com/apis/maps/documentation/examples/ geocoding-simple.html中,我们可以使用如下的代码来完成输入地名的地址译码操作,其地址译码界面如图33-3所示。

图33-3  地名到经纬度的地址译码操作

上述的地址译码操作是通过Google Maps API的调用实现的。首先,在地图初始化时,通过GMap2类生成一幅新的地图,之后使用GClientGeocoder类创建地理译码器的实例,与Google服务器建立连接来获得地址译码的转换。代码段如下:

 function initialize() {

   if (GBrowserIsCompatible()) {

     map = new GMap2(document.getElementById("map_canvas"));

     map.setCenter(new GLatLng(37.4419, -122.1419), 13);

     geocoder = new GClientGeocoder();

   }

 }

目前,中国国内地图的地址解析器支持市、县、区级别,在美国可以支持到街区门牌号。在接下来的showAddress函数中,我们取得geocoder返回结果对应的经纬度,进行判断之后将得到的经纬度标注在地图之上。其代码如下:

    function showAddress(address) {

      if (geocoder) {

        geocoder.getLatLng(

          address,

          function(point) {

            if (!point) {

              alert(address + " not found");

            } else {

              map.setCenter(point, 13);

              var marker = new GMarker(point);

              map.addOverlay(marker);

              marker.openInfoWindowHtml(address);

            }

          }

        );

      }

    }

转换地址到经纬度后,我们就可以根据得到的经纬度设置地图显示的中心位置,以及进行记号点标注等操作。

当然,如果不希望在代码中调用GClientGeocoder类来实现地址译码的功能,还可以直接通过浏览器URL提交的HTTP请求来获得地址译码。

在URL中实现地址译码仅须要将请求提交到:http://maps.google.com/maps/geo?,并添加相对应的浏览器请求参数。常用的请求参数如下。

n        q(必需):后面跟将要译码的地址字串。

n        Key(必需):申请的Google API授权码。

n        output(必需):生成输出文件的格式,可选的格式为json(默认)、xml、kml、csv。

n        gl(可选):可以用来指定国家代码。

下面举例说明。

我们通过请求得到Google总部山景城的经纬度位置如下:

http://maps.google.com/maps/geo?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA&output=xml&key=

现在得到的输出格式是XML文档的形式,其代码如下:

 <?xml version="1.0" encoding="UTF-8" ?>

<kml xmlns="http://earth.google.com/kml/2.0">

<Response>

     <name>1600 Amphitheatre Parkway, Mountain View, CA</name>

<Status>

 <code>200</code>

 <request>geocode</request>

 </Status>

<Placemark id="p1">

 <address>1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA</address>

 <AddressDetails Accuracy="8" xmlns="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0">

<Country>

 <CountryNameCode>US</CountryNameCode>

<AdministrativeArea>

 <AdministrativeAreaName>CA</AdministrativeAreaName>

<Locality>

 <LocalityName>Mountain View</LocalityName>

<Thoroughfare>

 <ThoroughfareName>1600 Amphitheatre Pkwy</ThoroughfareName>

 </Thoroughfare>

<PostalCode>

 <PostalCodeNumber>94043</PostalCodeNumber>

 </PostalCode>

 </Locality>

 </AdministrativeArea>

 </Country>

 </AddressDetails>

<Point>

 <coordinates>-122.085121,37.423088,0</coordinates>

 </Point>

 </Placemark>

 </Response>

</kml>

如果不指定输出格式,则按照默认的JSON格式输出内容。上述内容的JSON格式输出后,我们在JSON格式化工具(http://lab.gracecode.com/format_json/)中查看时内容如图33-4所示。

图33-4  JSON格式化后查看包含的内容

除此之外,在Google Maps提供的服务中,还包含XML和数据解析服务、使用Flash的方式展现街景图,以及Google Earth浏览器插件的支持。更多的细节可以参考Google Maps提供服务的页面:http://code.google.com/apis/maps/documentation/services.html

对于熟悉Ruby和Rails的开发者,进行地图Mashup应用开发可借助名为StaticGmaps(http://static-gmaps.rubyforge.org/)的gems封装,它为Google Static Maps API提供了Ruby的访问接口,可帮助用户节省开发过程中的工作量。

 

开发环境简介

在了解Goolge Static Maps API基本函数的使用之后,下面着手制作一个可以调用静态地图的小程序,应用所要实现的功能描述如下:

n        设计一个包含输入框、确认按钮和静态地图图片显示面板的应用程序界面。

n        应用启动后,用户可以在文本框中输入所要查找的地名。点击确定按钮之后,组合静态地图的URL请求串,取得请求的静态地图,并显示在窗体之中。

n        静态地图生成后,可以保存在程序运行的当前位置目录中。

简单的需求描述如上,让我们看看上述嵌入Goolge Static Maps的小应用是如何编码实现的。

为了保持应用的简明和趣味性,在这里我们使用Python语言、PyQt图形库,以及NetBeans IDE的NBPython编程环境来完成这个调用静态地图的小例子。

Python语言和Qt图形库开发的应用程序具备跨平台特性,示例中我们使用Windows开发环境,开发所使用的软件环境搭建如下:

n        NBPython Milestone 6
https://nbpython.dev.java.net/

n        Python 2.5.2 Windows installer
http://www.python.org

n        PyQt(PyQt-Py2.5-gpl-4.4.3-1.exe)
http://www.riverbankcomputing.co.uk/

在开始之前,让我们对于Qt及程序中将使用的PyQt图形库先有 个简单的认识。Qt是一套成熟稳定的GUI工具箱,Qt跨平台的图形库可以运行在Windows、Linux、Mac OSX及多种便携式设备平台之上。著名的Google Earth应用的界面也是使用Qt图形库进行设计的,Qt图形库分别针对Linux、Windows及Mac平台发布了不同的版本。

Qt在设计上具备良好的面向对象结构,以及众多实用的API。而PyQt则为Python 程序员开发基于Qt图形库的跨平台应用搭建了桥梁。

相对于Python 默认使用的图形库Tk(由Tkinter绑定),PyQt具备众多的优点,如Qt使用信号/插槽(Signals/Slots)的机制在窗口构件(以及其 他对象)之间传递事件和消息,让编写事件触发的代码段变得十分轻松;并且PyQt包含300多个类和近6000个函数和方法,功能十分强大。

至于PyQt的安装,相对来说较为复杂,通常须要下载源代码之后在本机编译为二进制的代码,编译的过程在Linux环境下出错的概率较小,但在Windows环境下编译时往往须要多尝试几次才可以编译通过。

在环境搭建方面不必有过多的担心,在这里我们使用PyQt提供的已经编译好的二进制安装版本PyQt-Py2.5-gpl-4.4.3-1.exe。除了Python的解析器须要单独安装之外,这个版本包含了使用PyQt进行应用开发需要的所有要素,包含的主要要素如下:

n        PyQt库。

n        Qt库。

n        Qt Designer(界面设计器)。

n        Qt Assistant(编程助手)。

n        Qt Linguist(国际化翻译工具)。

n        pyuic4(ui界面文件的编译器)。

n        QScintilla(Scintilla编辑器类的Qt接口)。

编程环境使用了NetBeans的Python IDE,NBPython可以作为一个插件加入到NetBeans环境之中,也可以单独下载46MB的Netbeans Python专用IDE。在这个IDE中,计划添加的Python支持功能有:

n        语法高亮显示。

n        代码补全。

n        Python与Jython的支持。

n        PyUnit单元测试支持。

n        Python代码断点调试。

n        Python类库管理。

n        Python控制台。

n        Python脚本执行。

n        Python版本管理。

NetBeans的Python IDE同样提供了不同平台下的安装版本,在Windows环境下的运行版本如图33-5所示。

图33-5  NetBeans的Python IDE

使用Qt进行跨平台GUI应用开发的优势之一就是它有方便的Qt界面设计器,可以很快地设计出美观大方的程序窗体布局。

下面我们打开Qt Designer,新建一个对话框,然后在对话框中添加一个名为Address的Lable标签(QLable)、一个文本输入框 (QLineEdit),以及一个确定按钮(QPushButton)。在应用程序的窗口主体也加入一个Lable标签,用于显示从Google获得的静 态地图。最后使用栅格布局(Grid Layout)调整各个部件的位置。设计好之后的对话框如图33-6所示。

在使用Qt设计器的同时,还可以随时点击“窗体—预览”(Ctrl+R)来预览当前窗体的模样。窗体的预览如图33-7所示。

保存之后,Qt设计器生成了一个拓展名为.ui的文件。在Qt中,UI文件以XML的格式记录了QT Designer所生成界面的相关内容,包含在UI文件中的内容如下:

图33-6  Qt设计器中进行应用程序窗体设计

图33-7  Qt设计器中预览设计的窗体

n        Widget属性,包含的元素(如按钮、文本框、下拉列表,等等),Layout布局方式等相关属性。

n        引用的头文件(使用C++时会编译生成头文件)。

n        变量。

n        槽(Slot)。

n        函数。

UI文件保存之后,可以使用Qt提供的UIC(user interface compiler)编译器将UI文件内容转换成标准.h和.cpp文件。在PyQt中,UI文件将被转换为.py文件。

UI文件编译器位于PyQt的安装目录(Windows环境下, 通常是C:\Python25\Lib\site-packages\PyQt4)中,在终端模式的命令行提示符下,使用目录中的pyuic4.bat命 令即可将UI文件编译为Python的代码。使用方法如下:

pyuic4.bat UI_FILE -o PY_FILE

在这里,UI_FILE为UI文件的路径,PY_FILE为计划生成的Python文件的路径。例如,可以使用ui_myapp.py来命名生成的Python文件。

除此之外,pyuic4命令后还可以添加参数。参数-p(-preview)将会生成UI文件转换后的预览,而不生成代码文件;参数-x(-execute)生成用来测试和显示类的额外代码;参数-d(-debug)用以显示调试输出。

我们将UI生成的Python代码命名为ui_staticmap.py。下面在NetBeans中新建一个工程,为设计的窗体添加事件相应代码。

NetBeans的Python IDE安装之后,首先须要在菜单Tools—Python Platforms中设置Python解释器的路径,如图33-8所示。

图33-8  IDE中设置Python解释器路径

 

 

 定制静态地图应用

下面我们在NetBeans的Python IDE中新建一个Python工程,点击创建工程,出现的界面如图33-9所示。

图33-9  新建Python工程

输入工程的名称为staticmap,Python IDE会为我们创建名为staticmap.py的代码文件,并将其设定为主文件,如图33-10所示。

图33-10  设定工程名称和存储位置

下面为生成的主文件staticmap.py添加相应的代码,首先在程序的开始加载所需的模块,引用部分代码段如下:

from PyQt4.QtCore import *

from PyQt4.QtGui import *

import urllib

引入QtCore和QtGui所包含的类,PyQt4的基本模块都包含在QtGui中。由于静态地图的请求还须要对URL地址进行解析,所以再引入urllib类库处理HTTP相关的部分。

主程序部分也不复杂,其代码如下:

def main():

    app = QApplication(sys.argv)

    w = MyWindow()

    w.show()

    sys.exit(app.exec_())

对于PyQt4程序来说,要创建一个application对象。application类位于QtGui模块中,程序的主体就是这个QApplication,sys.argv用于传入命令行参数。

MyWindow是用于定义窗体的类,w.show()的作用是将定义的窗体显示出来。最后,主程序会进入application的事件循环。循环不断从窗口接受要处理的事件,然后将其分发给对应的事件处理方法。

事件循环的终止须要通过调用exit()方法或销毁widget来结束,调用sys.exit()方法可以确保程序正确退出,并且在退出时会告知系统。由于exec是python的一个关键字,所以在exec_()方法后会有一个下划线来表示与关键字的区别。

在MyWindow 类中,我们指定QDialog是刚才在Qt设计器中通过UI文件生成的Ui_Dialog(须要与UI设计器中指定的名称保持一致),其代码如下:

class MyWindow(QDialog):

    def __init__(self, *args):

        QDialog.__init__(self, *args)

        self.ui = Ui_Dialog()

        self.ui.setupUi(self)

        # create connection

        self.connect(self.ui.pushButton, SIGNAL("clicked()"), self.run_command)

__init__内的代码段定制界面的外观,我们引用了Qt设计器中通过UI文件编译生成的Ui_Dialog。当然,如果不是很复杂的界面,完全可以在函数中通过手工编写来加入窗体中要显示的文本框、按钮等部件。

在这里,我们通过信号槽的机制将确认按钮与接下来执行命令的操作run_command进行连接,也就是说,当按钮被点击时,触发的事件交由run_command函数进行处理。

run_command函数的代码段如下:

def run_command(self):

        addr = str(self.ui.le.text().toUtf8())

        self.getGeoCode(addr)

在函数中取得从输入栏获取的地址作为查询条件传递给getGeoCode函数,QLineEdit.text()回传的QString字符串与Python字串不同,可以转成Unicode字串后再赋值给字符串变量。

getGeoCode函数取得坐标的代码段如下:

def getGeoCode(self, addr):

geo_url='http://maps.google.com/maps/geo?'+urllib.urlencode({'q':addr})+'&output=csv&key='+google_key

        try:

           g=urllib.urlopen(geo_url)

           ret=g.read().split(',')          

           if(ret[0]!='200'):

            QMessageBox.warning(None, "Error", addr+" not found", QMessageBox.Yes)

           else:

            self.showMap(ret[2], ret[3])  

        except urllib.HTTPError:

           QMessageBox.warning(None, "Error", "Http error", QMessageBox.Yes)

在静态地图请求中,输入项为请求地址的地名,须要通过Google提供的地址译码功能将地名对应的位置转换为经纬度,所以,我们使用的URL字串为“http://maps.google.com/ maps/geo?”后面带的参数是查询的地址,output是输出的格式。目前的输出格式支持xml、kml、csv、Json,在这里使用的是以逗号分隔的csv格式,后面再添加之前申请的Google Maps API Key就可以得到解析后的地址坐标。

在urllib库的支持下,我们得到请求位置的地址坐标。如果没有找到地址对应的坐标,则使用QMessageBox来弹出一个消息以提示用户。如果找到地址对应的坐标,就将经纬度坐标作为参数传递给函数showMap来显示对应的地图。

函数showMap的代码段如下:

def showMap(self, lat,lang):

stmap_url='http://maps.google.com/staticmap?center='+lat+','+lang+'&markers='+lat+','+lang+',red&zoom=14&size=512x512&maptype=mobile&key='+google_key

        urllib.urlretrieve(stmap_url, "stmap.gif")

        image = QImage("stmap.gif")

        self.ui.imageLabel.setPixmap(QPixmap.fromImage(image))

        self.ui.imageLabel.adjustSize()

正确取得坐标后,我们将纬度(lat)和经度(lang)传递给 showMap函数,以组装请求静态地图的字符串。在这里定义的缩放等级为14。在Google Maps中缩放的范围是0~18,0级即为整个地球,18级为最精细的地图。但除了美国、加拿大等国,往往无法获得最精细的地图。

取回的地图大小设置为512像素×512像素,同时512像素×512像素也是可以获取的最大图片。MapType种类设置为mobile,比较适合在便携式设备上查看, 此外还可以在地图上放置自定义的图标。本例采用在图片中心显示默认图标。

得到的静态地图使用urllib.urlretrieve()函数保存为名为stmap.gif的图片,然后将图片填充到imageLabel所对应的显示标签之中。这样,取得的地图就可以显示在程序对应的视窗上了。

下面我们在NetBeans中点击运行(F6)来启动应用,在弹出的对话框中输入Los Angeles的简称“LA”,点击确定之后,就可以在程序中获取Google静态地图返回的地图,如图33-11所示。

图33-11  在程序中调用Google的静态地图

应用程序的完整代码如下:

import os

import sys

from PyQt4.QtCore import *

from PyQt4.QtGui import *

import urllib

from ui_staticmap import Ui_Dialog

google_key='YOU_API_KEY_HERE'

def main():

    app = QApplication(sys.argv)

    w = MyWindow()

    w.show()

    sys.exit(app.exec_())

    

class MyWindow(QDialog):

    def __init__(self, *args):

        QDialog.__init__(self, *args)

        self.ui = Ui_Dialog()

        self.ui.setupUi(self)

        # create connection

        self.connect(self.ui.pushButton, SIGNAL("clicked()"), self.run_command)

def getGeoCode(self, addr):

geo_url='http://maps.google.com/maps/geo?'+urllib.urlencode({'q':addr})+'&output=csv&key='+google_key

        try:

           g=urllib.urlopen(geo_url)

           ret=g.read().split(',')          

           if(ret[0]!='200'):

                QMessageBox.warning(None, "Error", addr+" not found", QMessageBox.Yes)

           else:

                self.showMap(ret[2], ret[3])  

        except urllib.HTTPError:

           QMessageBox.warning(None, "Error", "Http error", QMessageBox.Yes)

def showMap(self, lat,lang):

stmap_url='http://maps.google.com/staticmap?center='+lat+','+lang+'&markers='+lat+','+lang+',red&zoom=14&size=512x512&maptype=mobile&key='+google_key

        urllib.urlretrieve(stmap_url, "stmap.gif")

        image = QImage("stmap.gif")

        self.ui.imageLabel.setPixmap(QPixmap.fromImage(image))

        self.ui.imageLabel.adjustSize()

    def run_command(self):

        addr = str(self.ui.le.text().toUtf8())

        self.getGeoCode(addr)

 

if __name__ == "__main__":

    main()

至此,Google静态地图功能只发挥了一小部分,感兴趣的朋友还可以对程序进一步拓展,为应用加上地图缩放等级的调整、手动位置的调整,甚至可以加入在静态地图上进行路径设置等功能。

 

原文:http://book.csdn.net/bookfiles/1071/100107131985.shtml

 

 

posted @ 2009-10-22 17:44  Sunny Peng  阅读(6763)  评论(0编辑  收藏  举报