显示标签为“ArcGIS Desktop”的博文。显示所有博文
显示标签为“ArcGIS Desktop”的博文。显示所有博文

2013年8月23日星期五

ArcMap加载WMTS服务后显示空白的可能原因

在ArcMap(10.1/10.2)中,加载一个WMTS服务后,如果显示空白,但用fiddler查看请求,已经下载了正确的图片,那么很可能是WMTS规范中要求的WMTSCapabilities.xml文件输出了错误的图片格式所导致的。
比如在ArcMap中,添加由Portable Basemap Server输出的WMTS服务时,Google Map街道图无法显示(空白),
image  用Fiddler查看,其实已经下载了正确的切片,
image 而产生此问题的原因正如上图两处红框所示,目前版本(3.0)的PBS输出的WMTS服务,将在线地图的切片格式在WMTSCapabilities.xml文件中统一指定成了JPG格式,而Google街道图的切片实际上是PNG格式的。对于Google影像图来说,切片格式是JPG,所以在ArcMap中可以正常显示:
image 有网友反映QGIS中也无法加载PBS的部分WMTS服务, 原因也是如此。下个版本的Portable Basemap Server会将图片格式选项留在CustomOnlineMaps.xml文件中由用户自己指定,所以会修复此bug。
当然PBS还将继续加入更多实用功能,敬请期待。

2012年12月21日星期五

ArcGIS中读取.bil文件

客户现有一应用程序可读取.bil栅格文件作为高程背景显示,如下图:
planetbil 
数据文件有:demo.bil文件(2,077,616字节),index文件(74字节),projection文件(58字节)。现需要转入ArcGIS平台来进行显示,查看帮助,ArcGIS对.bip栅格格式有原生支持。但在ArcMap中加载该文件时,确报错无法打开。
查看ArcGIS关于.bil格式的帮助说明,得知.bil是一种未经过压缩的二进制文件。存储格式如下图:
bilformat 是按行依次存储每个波段每列像元信息的。要在ArcGIS中显示,必须有一个.hdr头文件描述其所需的一些元数据信息才行。而拿到的数据中并没有这个.hdr文件,所以要构造出该文件。查看.hdr文件的说明,是以文本方式记录了该栅格文件的行、列数,每个像元值所占的大小等内容。而原来的应用程序之所以能够读取该图像,也离不开这些信息。用记事本打开index文件,内容如下:

demo.bil 641890.000000 656130.000000 3251870.000000 3281050.000000 20.000000

乍一看并没有.hdr文件中所需的信息,但能看出上述的5个数字分别代表了.bil文件空间范围和空间分辨率。由此我们来推导.hdr文件所需的元数据信息:

  • NROWS:栅格文件的行数,(3281050-3251870)/20=1459;
  • NCOLS:栅格文件的列数,(656130-641890)/20=712;
  • NBANDS和NBITS:分别代表栅格文件的波段数和存储一个波段中每个像元值所需的比特数(pixel depth),index文件中并没有这两个信息。但.bil文件是未经过压缩的,所以我们用.bil文件的大小除以行数再除以列数,2077616/1459/712=2,得知每个像元位置上所有波段值共占2个字节(16bit)空间。理论上可以是NBANDS等于1,NBITS等于2×8=16,也可以是NBANDS等于2,NBITS=8。但我们知道逻辑上此图记录的是高程信息,相当于dem,所以应该只有一个波段,由此得知NBANDS=1,NBITS=16;
  • PIXELTYPE:由于是高程信息,所以pixel value都是正值,因此此处是UNSIGNEDINT;
  • BYTEORDER:存储每个像元值字节的排列顺序。可以由高位到低位的M,也可以是由低位到高位的I。结合原程序代码,得知此处是M。

由此创建的.hdr文件如下:
image  有了正确的.hdr文件后,就可以在ArcMap中直接加载了(projection文件用于设置正确的投影信息):
image

感谢@红毛小屁孩的指导帮助,比帮助文件好用得多。

2012年6月1日星期五

GIS中公交数据的下载和处理

  前两天讲座的Demo中,演示了一个可以在等公交时查看将要到站车辆信息的移动应用,其中用到了北京若干条公交线路的数据。不少朋友都想知道这些数据是如何获取的,我把方法共享出来,希望能为大家GIS应用的道路上扫清一些不必要的障碍。
  为了获取公交数据,我对比了几个具有查询公交线路功能的在线地图网站,查看http的请求结果,发现百度地图的http响应最接近成品状态,它的结果是标准的json数据,含有查询公交线路上所有的站点信息和公交路线信息等。简单验证了一下,如果从百度地图网站上发起请求,可得到所有明文信息,如果从其他站点发起请求,所有涉及到地理坐标的值会被加密。
  我想完成的事情是,获取关心的公交线路数据,然后把他们做成Geodatabase中的FeatureClass来使用。只要能得到有效的JSON数据,就可以利用ArcGIS中的Python脚本来完成我想要的结果。
  第一步需要获取JSON数据。为了获取批量的结果,我们需要使用百度地图的API。我学习了酸奶小妹妹写的一篇现成的文章,知道了从Javascript中可获取我想要的JSON信息。下一步就是如何将js中的JSON结果保存成文本文件。js直接写txt不太好办,借助Silverlight与html内容的交互功能,就可以办到这点。我写了一个Silverlight应用来完成这个工作,首先填写想要查询的目标城市,比如“西安”,然后填写想要查询的公交线路,多条线路间需要用英文半角逗号隔开,点击“开始下载”就会从百度得到JSON结果,保存成txt文件以备后用。
  第二步需要用Python处理JSON数据以生成FeatureClass。我写了一个python脚本来完成这个工作,并把它制作成了Script Tool,这样就可以通过调用GP工具的形式来生成我们的地理数据了。
  第三步数据后处理。百度API中得到的地理数据是经纬度坐标,生成FeatureClass后可利用Project工具投影到我们想要的坐标系中,比如WGS 1984 Web Mercator。对于火星坐标,一个城市范围内的偏移可以认为是线性的,只需在Arcmap中参照底图整体平移即可。
  比如,我在这个网站上参照页面源码可以得到西安市所有公交线路列表,简单处理后变成这样:

地铁1号线,地铁2号线,地铁3号线,地铁4号线,地铁5号线,地铁6号线,机场快轨,环山1号线,环山2号线,二环1号线,二环2号线,高新1号线,高新草堂专线,教育专线,五龙专线,泾渭环线,1,2,4,K5,6,7,K8,9,10,11,12,13,14/K14,15,16,17/K17,K18,19,20,20区间,21,22,23,24,25,26,27,28,29/K29,30/K30,31,32,33,34,K35,36,37,38,39,40,41,42,K43,44,45,46/K46,47,48,50,102,103,104,105,106,107,108,117,118,161,162,163,201,202/K202,K203,204,K205,206,207,207区间,K208,209,K210,211,212,213,214,215/K215,215区间,216,217,218,219,220,22,222,223,224,225,226,226区间,227,K228,229,230,230区间,231,232,233,234,K235,236,237,238,239,240,241,242,243,251,252,260,260区间,261,262,263,264,265,266,300/K300,301,302,303,307,308,309,311,312,313,315,316,318(车城),318(全程),319,321,322,323,324,规划325,规划326,328,330,331,336,351,规划356,K400,401,402,403,405,406,407,408,409,410,411,416,500,501,502,503,504,506,507,508,509,510,511,512,规划513,规划515,517,518,519,521,522,523,525,526,527,528,530,600,601,602,603,604,604区间,K605,606,606区间,607,608,K609,611,612,K616,K618,619,K630,630区间,K631,K700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,728,729,800/K800,801,规划802,规划821,规划822,900,900区间,901,901区间,902,903,904,905,906,907,908,910,911,912,913,914,915,916,917,918,919,920(汤峪),920(焦岱),921,922,923,924,926,927,928,929,930,东南专线,宏华线,安运线,西高客运,规划西阎线,通宵1号线,通宵2号线,通宵3号线,通宵4号线,游1,游2,游3,游4,游5(306),游6,游7,游8(610),游9,游10,盛唐之旅,曲江新景线,曲江旅游观光轻轨,世园环线,世园1号线,世园2号线,世园3号线,世园4号线,世园5号线,世园6号线,世园7号线,世园8号线,世园9号线,世园10号线,世园12号线,世园13号线,3-18,4-04,4-05,4-06,4-07,4-08,4-09,4-10,4-11,4-12,4-13,4-14,4-15,4-16,4-17,4-18,4-19,4-20,4-21,4-22,4-23,4-25,临潼101,临潼102,临潼201,临潼301,临潼826,阎良601,阎良901,高陵101,高陵102,高陵103,高陵105,高陵106,高陵108,高陵109,高陵201,高陵801,高陵802,高陵803,户县801,户县802,户县803,户县804,户县805,户县806,户县808,户县809,户县810,户县811,户县812,户县813,户县819,户县820,咸阳13,咸阳15,咸阳21,咸阳22,咸阳28,咸阳29,咸阳59,咸阳副59,
  利用这个Silverlight应用即可下载到JSON结果,再用一下GP工具,就可生成西安市公交线路的地理数据。
image
imageimage
image  当然你也可以把它导出成shapefile,方便其他同事,同学或老板使用。
  GP工具,Python脚本,示例FeatureClass可在这里下载:http://arcgis.com/home/item.html?id=e0f8316d91fb43d49a81a76946f9a03c

2012年3月31日星期六

ArcGIS Runtime性能

  可能你已经了解到了一些要随ArcGIS 10.1版本发布的新产品ArcGIS Runtime的信息,比如它的跨平台,高便携,64位,可扩展等。
  Esri刚刚结束的developer summit上,以WPF为例,演示了最新的prerelease版本中ArcGIS Runtime的性能。视频中prerelease版中同时加载了10,000个带动画的复杂渲染的graphic。

  Web API中一直被偏执狂们诟病的graphic性能有了长足的提升,ArcGIS Runtime更加让人期待了。
  ps:期待更多有社会价值的公交车,出租车,物流监控系统出现。

2011年11月2日星期三

解读ArcGIS Runtime SDKs

  本文试图解读新的ArcGIS Runtime SDKs及其本质,与ArcGIS移动SDK,for iOS/Windows Phone/Android,之间的关系,以及这三种移动SDK后续发展的一些猜想。
  ArcGIS Runtime SDKs是随ArcGIS 10.1 beta一起发布的一套横跨桌面和移动端的,跨平台,轻量级的GIS开发SDK的总称。
image

  从上图中我们可以看出,ArcGIS Runtime SDKs家族包括了以下内容:

  • ArcGIS Runtime SDK for Android
  • ArcGIS Runtime SDK for iOS
  • ArcGIS Runtime SDK for Windows Phone
  • ArcGIS Runtime SDK for Windows Mobile
  • ArcGIS Runtime SDK for Java
  • ArcGIS Runtime SDK for Qt
  • ArcGIS Rutnime SDK for WPF

  之所以说ArcGIS Runtime SDKs横跨桌面和移动端,是因为它既包含了iOS/Windows Phone/Android等移动平台的开发SDK,也包含了可以开发传统桌面程序(C/S程序)的WPF、Java、QT等SDK;而后三种SDK则可开发出Windows和Linux平台下的具有丰富交互效果和良好体验的应用程序。其实ArcGIS Runtime还包括了一些现成的应用程序,比如iOS/Windows Phone/Android各自市场上都能下载到的“ArcGIS”程序,ArcGIS Mobile中的“ArcGIS”程序等。
  说起轻量级,首先要看看ArcGIS 10.1产品架构的一些变化。

image

  ArcGIS 10.1中,产品的划分更加明确和简单。主要分为四个部分,桌面GIS(传统的ArcMap,ArcGlobe等),ServerGIS(全新架构的ArcGIS Server),轻量级GIS(ArcGIS Explorer,Runtime SDKs及其对应的应用程序)和ArcGIS Online。前三部分都是围绕ArcGIS Online这个云GIS平台的,在不同程度上都与ArcGIS Online有交互,或可将数据直接部署上去,或作为它的客户端(云+端)。而轻量级GIS就是为了能够在任何地点,任何平台,任何设备上访问云平台提供的GIS能力。
  ArcGIS Runtime SDKs正是在这种背景下诞生的。其实它也分为狭义和广义上的两种解释。狭义的ArcGIS Runtime SDK是指桌面上的WPF,Java和Qt,它们的消息早在半年前就已经流出。它们的出现,是为了逐步替代强大而相对臃肿的ArcGIS Engine这个产品。做过Engine开发的朋友都知道,即使是最简单的显示地图的需求,理论上都必须在客户机上安装ArcGIS Engine Runtime这个运行时(注意不是ArcGIS Runtime),安装包通常400m左右。而利用新的ArcGIS Runtime SDK for WPF/Java/Qt开发出的程序,完全是绿色程序,不需要在客户机上安装任何部件(.Net Framework和JRE不计)即可运行,因为所有的依赖库直接和程序拷贝在一起即可。如果你喜欢ArcGIS Runtime SDK开发的程序的部署过程——拷贝到u盘里/插入目标计算机/运行,那么你一定也喜欢它的卸载过程——关闭程序/拔掉u盘。
  广义上的ArcGIS Runtime SDKs是上述列表中,诸多SDKs的统称。除了包含狭义的ArcGIS Runtime SDK,可以看到加入了移动端部分:ArcGIS Runtime SDK for iOS/Windows Phone/Android/Windows Mobile,而它们其实是新瓶装旧酒,分别对应以前的ArcGIS SDK for iOS/Windows Phone/Android和ArcGIS Mobile,只是换了产品名称而已。为什么会换名称?为什么还有ArcGIS Mobile这个“另类”的东西?这得从ArcGIS Runtime SDK的功能说起。
  做过ArcGIS Web API(ArcGIS API for Javascript/Flex/Silverlight)开发的朋友,应该可以很快理解狭义Runtime这个产品的所有功能。目前ArcGIS Runtime的功能与ArcGIS Web API,ArcGIS移动API(iOS/Windows Phone/Android)基本相同,都是基于ArcGIS REST API的。比如地图服务(动态/缓存)的加载,GraphicsLayer/FeatureLayer,基于FeatureService的数据编辑,Identify/Find/Query操作,GeometryService,Geoprocessing Service的调用等。它们的开发思路和代码编写几乎是一样的,比如ArcGIS API for Silverlight和目前的ArcGIS Runtime SDK for WPF,如出一辙(后者的前身就是ArcGIS API for WPF)。但狭义上的ArcGIS Runtime SDK与ArcGIS Web API不同之处在于,前者可以加载本地数据,包括Map Package/Tile Package/Locator Package/Geoprocessing Package。Map Package是包括.mxd文档和所有引用数据在内的压缩包,其余类似。最早的Package是9.3.1产品中的LayerPackage,它不仅包含了.lyr图层配置信息,还打包了图层所引用的实际数据。早期的ArcGIS Online平台允许用户上传LayerPackage以便分享,现在看来,直到此时Runtime产品的出现才将Package的概念发扬光大,并且为以后的所谓云GIS提供了更多的数据共享途径。对本地数据的读取是否破坏了基于ArcGIS REST API的框架呢?其实没有。ArcGIS API for WPF/Java/QT中,都内置了一个c++写的Web Server,读取本地数据后,会自动发布成这个Web Server上的REST服务来供Runtime SDK使用,所以一切功能,还是由REST API提供的。收起题外话,ArcGIS Runtime SDK的框架,是针对轻量级GIS产品(不包括ArcGIS Web API)的,它拥有统一的编程模型,可以用一致的开发思路,做出C/S,及移动端应用(Web API开发出B/S应用),为开发人员提供了极大的便利。这也是为什么将它们统称为ArcGIS Runtime SDKs的原因。
  在来说说ArcGIS Runtime for Windows Mobile(原来的ArcGIS Mobile)这个产品。之所以将它也归为ArcGIS Runtime SDK,是不无道理的。使用过ArcGIS Mobile的朋友一定知道,它的一个核心理念就是将数据划分为Basemap Layer和Operational Layer。前者是指起可视化参考作用的数据,一般是栅格底图或地图服务切片;后者是包含矢量信息在内的业务数据。ArcGIS Runtime中所涉及到Package,恰好与之对应。Tile Package对应Basemap Layer,Map Package对应Operational Layer。可以说,ArcGIS Mobile的设计理念,在整个ArcGIS Runtime产品家族中,得到了很好的延续。其实ArcGIS Mobile是个十分优秀的产品……
  到此,新的三个移动SDK(iOS/Windows Phone/Android)也归为ArcGIS Runtime SDKs的原因也就明了了,主要原因是都基于REST API的框架。另外基本可以肯定,它们都会使用相同的数据模型,即各种Package。由此不难推断,以后iOS/Windows Phone/Android平台上移动SDK的离线功能,也会依赖于Tile Package和Map Package。上周刚刚发布的ArcGIS API for iOS 2.1(以后要叫ArcGIS Runtime SDK for iOS)版本中,已经印证了这种猜测——加入了对Tile Package的支持,实现了原生的底图数据离线功能。其它两个移动平台的离线功能,敬请期待。
  由iPad这个产品引发的变革已经展开,移动设备数量正在爆炸性的增长,桌面设备和移动设备之间的概念会越来越模糊。Windows 8的发布预示着微软已经做出了改变,它即可以运行在桌面电脑上,也可以运行在平板设备中。有人说Windows 8的意义对于微软不亚于当年的Windows 95,我同意这个观点。Esri也做出了积极的改变,新的产品体系,新的产品命名,新的ArcGIS Runtime。

2010年7月2日星期五

ArcGIS 10中的Python

介绍ArcGIS 10中Python的新特性和新功能。
下载地址:http://bbs.esrichina-bj.cn/ESRI/thread-70723-1-1.html

2010年5月10日星期一

ArcGIS Desktop 10中的License借出和归还问题

        以前版本的ArcGIS Desktop中,如果使用服务器上的floating license,那么必须保持与服务器的连通性后,才能使用上面的许可。借助于10的新特性,现在可从服务器上“借出”许可,离线使用;使用完毕后将许可归还回服务器即可。令人头疼的license问题终于有了更灵活的使用途径。现将简单步骤与大家共享一下:
      1、确保Desktop可以使用服务器上的License;打开ArcGIS Administrator;
      2、展开想要借出License的产品(Desktop或Enigne)文件夹,Borrow/Return;
      3、这里会列出服务器上可以借出的License及其数量,勾选想要接触的License,ok,完成之后就可再不连接服务器的情况下使用这些Licnese了;
      4、归还时重复以上步骤,勾选掉借出的License,ok即可。
      注:
      1、License Manager 10默认许可借出的期限是30天(可修改);逾期不还的话借出的所有许可会作废,服务器将上将生成新的使用许可;
      2、借出和归还License都是有日志(audit文件)记录的,想偷偷借可是不行的。。。
      3、License Manger 10可以装在Windows,Linux和Unix平台上,用来管理Windows(Desktop,Engine Rutime),Linux、Unix(Engine Runtime)平台上的产品许可。

2010年4月18日星期日

File Geodatabase中的lock文件

        与Personal GDB的单个.mdb文件表现形式不同,File GDB是以文件夹的形式存放在磁盘中的,进入File GDB的文件夹可以看到许多凭我们肉眼凡胎无法辨认的文件(你要是能认出来叫你犀利哥~),这向你传递一个信息,没事别到里面瞎逛。
        当一个ArcGIS程序,比如ArcMap、ArcCatalog或者ArcGIS Server(将其中的数据发布成了服务),正在访问File GDB时,ArcGIS会给其中相应的数据加上(悲观)锁,表现出来就是在该File GDB的文件夹里多了若干.lock结尾的文件。当数据被锁定时,你是无法对其进行修改或删除的。比如ArcMap里加载了一个FeatureClass,这时你无法用ArcCatalog删除它;在ArcCatalog中预览一个FeatureClass,这时你无法用ArcMap编辑它。
        除了正在使用的数据会肯定被锁以外,以下情况中还有其他数据也会被锁住:1、正在访问包含在DataSet中的某个FeatureClass时,这个DataSet内的其他FeatureClass也会被锁;2、单独的FeatureClass之间如果做了Relate,那么访问其中一个时其他的也会被锁。
        9.3+sp1以后,每个.lock文件的文件名会至少带有以下两个信息:产生该锁的进程的ID号(任务管理器,查看,选择列,勾选PID可查看),以及该进程所在的机器名。当数据被锁定时,除了以上标志明显的.lock文件外,还会有一些系统锁文件。所以根据这些.lock文件的命名,你就能判断出是哪个进程占用了数据,从而做出正确的处理。
        一般来说,.lock文件会在生成它的进程正常退出时被自动删除掉。但如果进程没有正常退出,比如崩溃后,由该进程生成的.lock文件则会继续存在,但已经没有任何作用。清除这些因意外状况遗留下的.lock文件的方法:1、重新开启该进程,则会清理上一次遗留的.lock文件;2、用Compact Database工具或ArcCatalog中的右键菜单;3、手动删除。方法1不一定灵验,推荐方法2,方法3慎用。除非你有备份,否则误删File GDB文件夹下一个哪怕0k的文件,都有极大的可能造成整个数据库损坏而无法修补。
        如果非要用方法3,建议在命令行下用del *.lock命令删除;如果非要用资源管理器删,建议左手在按住ctrl或shift时,右手食指不要发抖。

2009年11月27日星期五

Python魅力之地理数据快速处理方法

        Python作为一种成熟的脚本语言,发展势头迅猛,长期徘徊在“编程语言谱”排行前5的位置,在脚本语言中仅次于php。通过Python,开发人员可以快速试验一个想法、研究一种对象属性或不同算法,而无需编译、执行和测试任何代码。正是因为跨平台、简洁、优美的特点,它也如同GIS应用渗透于各各个行业一样,渗透在科学计算的各个领域。在GIS领域,几乎可以说开源言必称Python;而ArcGIS则将Python称为the scientific programming language for GIS:ArcGIS Server的猛将Geoprocessing Service依赖于Python,从9.4将Python IDE集成到ArcMap中也可见一斑。
        前一阵Flyingis贴出了一篇类似的文章,不过还是通过动手完成一个实例,来看看它在ArcMap中的数据快速处理能力吧。描述:上传到Panoramio的照片都会有位置信息(经纬度坐标),有些朋友非常可敬,上传的照片数量可达上万张。分析一下某个用户拍照的活动范围,是件有趣和有意义的事情。思路:1、利用Panoramio的API,获取指定用户的所有照片信息;2、将关心的信息,比如作者、照片名称、照片文件链接提取出来,并将其存储到地理数据库中。
        第一步:获取照片信息。先看一下Panoramio的API,REST风格,返回JSON字符串。比如通过http://www.panoramio.com/map/get_panoramas.php?order=popularity&set=public&from=0&to=20&minx=-180&miny=-90&maxx=180&maxy=90&size=medium,即可按点击次数排序获得世界范围内所有受欢迎的照片。

{
"count": 773840,"photos": [
{
"photo_id": 532693,
"photo_title": "Wheatfield in afternoon light",
"photo_url": "http://www.panoramio.com/photo/532693",
"photo_file_url": "http://static2.bareka.com/photos/medium/532693.jpg",
"longitude": 11.280727,
"latitude": 59.643198,
"width": 500,
"height": 333,
"upload_date": "22 January 2007",
"owner_id": 39160,
"owner_name": "Snemann",
"owner_url": "http://www.panoramio.com/user/39160",
},
{
"photo_id": 505229,
"photo_title": "Etangs près de Dijon",
"photo_url": "http://www.panoramio.com/photo/505229",
"photo_file_url": "http://static2.bareka.com/photos/medium/505229.jpg",
"longitude": 5.168552,
"latitude": 47.312642,
"width": 350,
"height": 500,
"upload_date": "20 January 2007",
"owner_id": 78506,
"owner_name": "Philippe Stoop",
"owner_url": "http://www.panoramio.com/user/78506"
}, ...
]
}


        Panoramio文档说有773840张,但是JSON里的count只有338张,搜其论坛,发现这是一个bug。当然,为了安全起见,一次请求最多只能返回100张照片的信息,Python刚好来完成若干个“100”的拼装任务。代码如下:

import arcgisscripting,json,urllib,os,threading
lphotos=[]#list saves all photo json objects
lock=threading.Lock()

#function to construct the panoramio request url and retrieve the corresponding photos as json array
#for eg: http://www.panoramio.com/map/get_panoramas.php?order=upload_date&set=139922&from=0&to=20&minx=108.355671725&miny=33.807692976&maxx=109.475020647&maxy=34.732003828&size=medium
#set: public (popular photos); full (all photos); user ID number
#size: original; medium (default value) ;small ; thumbnail ; square ; mini_square
def retrievephotos(set,fromindex,toindex,size):
global lphotos,gp
#extent=r"&minx=108.355671725&miny=33.807692976&maxx=109.475020647&maxy=34.732003828"
extent=r"&minx=-180&miny=-90&maxx=180&maxy=90"
url=r"http://www.panoramio.com/map/get_panoramas.php?order=upload_date&set="+set+"&from="+str(fromindex)+"&to="+str(toindex)+extent+"&size="+size
try:
jsonresult=json.read(urllib.urlopen(url).read())
except:
raise Exception,"get panoramio result error"
photos=jsonresult["photos"]
if len(photos)<toindex-fromindex:
print "warning: can't get photos from server "+str(fromindex)+"--"+str(toindex)
#gp.addwarning("warning: can't get photos from server "+str(fromindex)+"--"+str(toindex))#typeerror:'no type' object is not callable
else:
for photo in photos:
lock.acquire()
lphotos.append(photo)
lock.release()
return jsonresult["count"]#the total of photos of the specified set

#use multithread to retrieve photos, the number of threads=(end-start)/100
#start: 0 in usual
#end: the total of photos
def getphotolist(set,start,end,size):
list=[start]
while list[-1]<end:
list.append(list[-1]+100)
threads=[]
gp.addmessage(str(len(list))+" threads has launched...")
for i in list:
threads.append(threading.Thread(target=retrievephotos,args=(set,i,i+100,size),name=str(i)))
for t in threads:
t.start()
for t in threads:
t.join()#suspend the parent(main) thread until this thread is over

        在运行过程中,发送请求(请求100张照片的信息)后等待服务器响应会花费一些时间,于是就采用Python中的多线程,来同时发送多个请求。Threading是Python的一个标准模块,麻雀虽小,五脏俱全。单线程请求时,5000张照片的结果大约需要8分多钟,多线程请求时需要只需要40多秒即可。请求全部被相应后,即完成了所有照片信息的拼装工作:结果存储在类型为List的lphotos变量中。List是Python中使用最广泛的变量之一,灵活好用,一个顶5个~不过这里有个问题没有解决:在子线程的函数中,调用geoprocessor的addmessage()方法会报错(代码中注释掉的一句),非目前能力所能解决。
        题外话:上述多线程的工作也可以用并行计算来解决,这里有一篇出自Flyingis的关于Python中并行计算的文章,供大家学习。随着多核CPU的普及(ps:硅谷小公司推出100核CPU 性能是英特尔四倍),并行计算将会成为开发人员的新宠,微软.NET Framework 4.0中的Parallel Extention也说明了这一点。至于并行计算和多线程之间的区别,援引科班出身的同学胖胖鼠的话:
两者针对性不同。多线程技术是操作系统中的概念,是软件的概念。指进程中的一部分。以前并行计算主要更侧重硬件CPU,现在泛指同时使用多个计算资源解决问题。我感觉两者都用到了并发性并行性的概念。
个人感觉可简单理解为,并行计算是对细枝末节的多线程技术更优的抽象,与一个CPU里的多线程不同,它能利用多个CPU(不同服务器)资源,回归到网格计算的概念。下面继续主题。
        第二步:保存数据。之后我们便可以利用geoprocessor完成数据处理工作。首先通过调用Toolbox中的工具创建存储数据的FeatureClass,并调用工具添加相应的字段:

#create the 9.3 geoprocessor
gp=arcgisscripting.create(9.3)
gp.OverwriteOutput=True
myuserid=gp.getparameterastext(0)#"305320"
gp.Workspace=gp.getparameterastext(1)
myfile=os.path.basename(gp.getparameterastext(2))

#create 2 result featureclasses
try:
gp.addmessage("creating featureclasses...")
sr=gp.CreateObject("SpatialReference")
sr.Createfromfile(r"E:\Program Files\ArcGIS\Coordinate Systems\Geographic Coordinate Systems\World\WGS 1984.prj")
gp.Createfeatureclass(gp.workspace,myfile,"POINT","","","",sr)
gp.Addfield(myfile,"owner","TEXT","","",100)
gp.Addfield(myfile,"title","TEXT","","",100)
gp.Addfield(myfile,"photourl","TEXT","","",150)
#gp.Createfeatureclass(gp.workspace,xafile,"POINT",myfile,"","",sr)
del sr
except:
gp.adderror("creating featureclasses error")
raise Exception,"creating featureclasses error"

#push the photos into the featureclass
gp.addmessage("dealing my photos")
dealphotos(myuserid,myfile)

        最后两句便是整个功能的入口点了。dealphotos函数如下:

#function to push photos into featureclass
def dealphotos(set,fc):
photoscount=retrievephotos(set,0,1,"medium")
gp.addmessage("start to retrieving photos...")
getphotolist(set,0,photoscount,"medium")
gp.addmessage("retrieving photos completed")
cur=gp.InsertCursor(fc)
descfc=gp.Describe(fc)
print "begin insert features..."
gp.addmessage("begin insert features...")
for photo in lphotos:
row=cur.NewRow()
pnt=gp.CreateObject("POINT")
pnt.x=photo["longitude"]
pnt.y=photo["latitude"]
row.Setvalue(descfc.shapefieldname,pnt)
row.Setvalue("owner",photo["owner_name"])
row.Setvalue("title",photo["photo_title"])http://www.blogger.com/post-edit.g?blogID=21848155&postID=4114083803361112294#
row.Setvalue("photourl",photo["photo_file_url"])
cur.InsertRow(row)
print "insert features completed"
gp.addmessage("insert features completed")
del cur,descfc

        好啦,Python部分结束,添加到ArcMap中,便可成为一个Script Tool,与他人分享了。运行界面:

        运行结果:

        似乎不明显,那就利用空间分析中的Point Density工具抽象一下位置分布信息:

        也可以利用Model,将两部分连接起来,做成一个工具来用:

        有了地理数据,就可以继续在其他平台下进行处理和展示了:

最后总结一下标题:通过Python,不需要一个stand-alone的程序,就可以快速试验一个想法。
btw:附上最近google map tile的获取方法:

public override string GetTileUrl(int level, int row, int col)
{
int servernum = (col + 2 * row) % 4;
string sec2 = "&s="; // after &zoom=...
string secword = "Galileo";
int seclen = ((col * 3) + row) % 8; // corrected from int seclen = ( col + 3 * row ) % 8;
sec2 += secword.Substring(0, seclen);

//google maps map:
//http://mt1.google.com/vt/lyrs=m@114&hl=zh-CN&x=13&y=5&z=4&s=Gali
//http://mt1.google.com/vt/lyrs=m@114&hl=zh-CN&x=13&y=6&z=4&s=Galil
//http://mt1.google.com/vt/lyrs=m@114&hl=zh-CN&x=13&y=8&z=4&s=Galileo
string baseUrl = "http://mt" + servernum.ToString() + ".google.com/vt/lyrs=m@114&hl=zh-CN&x=";
string url = baseUrl + col.ToString() + "&y=" + row.ToString() + "&z=" + level.ToString() + sec2;
return url;

////google maps satallite
////http://khm1.google.com/kh/v=49&x=3&y=5&z=4&s=Galile
//string baseUrl = "http://khm" + servernum.ToString() + ".google.com/kh/v=49&x=";
//string url = baseUrl + col.ToString() + "&y=" + row.ToString() + "&z=" + level.ToString() + sec2;
//return url;
}

2009年11月8日星期日

地理信息的另一种表达方式--Cartogram地图

        先来看一则旧闻:
英科学家绘制新世界人口地图 中印两国最突出
        下面是几张新闻里的地图:


        第一张图中可以看出,目前时间上人口最多的中国和印度被表达的很夸张,但这种图形上的夸张恰恰很好的表达了两国人口与其他国家人口数量的相对关系。这种地图被称为Cartogram:
The geometry or space of the map is distorted in order to convey the information of this alternate variable.

        为了要强烈表达地图中某种属性信息,而将图形进行一些扭曲,而扭曲的重要原则就是不改变原图形的拓扑关系。
        那么在ArcGIS Desktop中如何做出这种地图呢?请到ArcScripts网站下载这个免费的工具,安装好后它会出现在ToolBox中。它由密歇根大学的 Mark Newman和Michael Gastner开发完成。压缩包中已经包含了详细的使用说明和实例数据,下面是自带数据做出的一张2007年世界各国GDP总量地图:

        再次提醒,当你想突出地图上的某个属性信息而制作一张令人印象深刻的专题图时,记得试试这个工具。别忘了它适用矢量、栅格两种数据,而且可以做出经过两个或多个属性变量影响的cartogram地图。
        利用ArcGIS Desktop和这个工具,我们不是也作出了英国科学家才做出的地图吗:)

2009年11月3日星期二

ArcGIS中的线性参考/动态分段技术(一):Linear Referencing背景

Linear Referencing背景
        定位:介绍Linear Referencing背景;在ArcMap中关于Linear Referencing的结构和功能;以及ArcGIS Server中几个应用场景的实现。
        注:有关更详细的操作可查看在线帮助,或搜索论坛。
什么是Linear Referencing
        Linear Referencing(下文引用为LR)翻译过来是线性参考,在公路,管网等行业的GIS应用中时常提到。LR是一种利用沿着可测量的线要素的相对方位来存储地理位置的方法。比如下图中:

        下面线的长度一次标为0,10,20,30,40……,而沿着这条线,我们看到上面有:
  • 一个位于坐标12处的点;
  • 一个位于坐标10东侧4个坐标的点;
  • 一段起始坐标分别为18和26的线段;
  • 一段起始坐标为28,长度为12的线段。

        为什么要用到LR技术?主要有两个原因:1、很多事件,像上边的例子一样,是通过沿着(曲)线的相对位置来记录的;2、要显示一条线上的多个属性集合时,由于各个属性在(曲)线上所对应的位置不同,同一数据源如果不做处理,很难达到要求。使用LR技术可解决此问题。
        以公路方面的一个应用场景为例说明。我们要显示一条公路的4种不同属性:道路管辖情况、路面材料、路段限速情况和路况,假设该公路长100公里:

1、前40公里为交警2大队管辖,后60公里为交警4大队管辖;
2、30至70公里为水泥路面,其余为沥青路面;
3、0-20公里的路段限速45km/h,20-40公里的路段限速35km/h,40-70公里路段限速45km/h,70-100公里路段限速55km/h;
4、0-20公里路况一般,20-40公里路况很好,40-60公里路况很差,60-100公里路况很好。
        属于同一数据源对应多个属性(且属沿线分布)的情况。如果不使用LR技术,那么需要4个公路图层,每个图层的公路根据属性分成长短不同的段落(Feature),才能够将这些属性展示出来;而是用了LR技术后,只需要一个公路数据(Feature数量不限),和四个事件表即可在不改变实际公路数据的情况下,按要求显示上述四种属性。
        Dynamic Segmentation:动态分段,属于LR采用的一种技术(一般应称之为线性参考问题中的动态分段技术)。是根据属性表中存储的相对位置信息,以及相应的线性数据,动态计算出线性数据上相对位置所对应的实际地理坐标的过程。动态分段正是因为表达不同属性时,不用去分割实际的地理数据,而是动态计算出该属性对应的地理位置而得名。
ArcGIS中Linear Referencing的实现原理
        ArcGIS中实现Linear Referencing主要通过以下两种数据结构:
1、Route FeatureClass
2、Event Table
        通过Dynamic Segmentation技术,Event Table中不同位置的Event就定位到了Route FeatureClass下对应的Line Feature上。
Route FeatureClass
        实际上是拥有两个特殊字段的Polyline FeatureClass:
1、必须包含有M(Measure)值的Shape字段。拥有M值的Shape字段,不但能存储x,y(,z)坐标,还能够多存储一个M数值;
2、必须包含有一个标识线段ID的字段,可以是Number或者Text类型。
        除了上述两个字段要求,还可以有其他字段。

        Route FeatureClass不同于普通的Polyline FeatureClass,是因为它具有一个测量系统,而这个测量系统的原理就是,通过存储在Feature的Vertice中的M值以及该Feature实际的ShapeLength,来动态插值出线上每一点的相对位置。比如一条公路数字化时,有两个节点(Vertice),分别表示该公路的起始桩号0公里和结束桩号100公里,该Feature存储在WGS1984坐标系中,ShapeLength为2.00,那么该公路上40公里处的位置,就应该位于图上该Feature的40%的位置,也就是ShapeLength为0.80的位置。
        而ArcGIS中,不要求每个节点都必须有M值。对于没有M值的节点其M值会标记为NaN(not a number):

        此外在不违反逻辑错误的情况下,M值可以随意设置。比如上图左边的图形,0-10段的实际ShapeLength看起来比10-20段的ShapeLength明显要长,也可以将上述四个节点的M值随意地设置为0,3,7,30。但是如果设置为0,10,5,30的话就产生了逻辑错误(route measure anomalies),ArcMap中会将其突出显示,提醒用户使用工具修改。
Event Table
        实际上是拥有2-3个特殊字段的表(ArcGIS支持的表均可,甚至可以是有特定格式的text文件):
1、类似Route FeatureClass中RouteID的一个字段。用来存储与Route FeatureClass中哪个线Feature对应。可以是Number或Text类型;
2、根据Event类型不同而必须的1-2个字段:
  • Point Event:比如108国道1900公里处发生了交通事故这个Event,需要一个Number类型的字段来记录1900这个相对位置;
  • Line Event:比如108国道1850到1950公里段的路况很差这个Event,需要两个Number类型的字段来分别记录1850、1950这两个起止位置。

        除了上述两个字段要求,还可以有其他字段。
        Event Table中一条记录就对应了需要在线上定位的一个点或一段距离,可以用来标识事件或属性等。下图描述了Dynamic Segmentation技术利用Route FeatureClass和Event Table产生的结果:

ArcGIS桌面中对Linear Referencing的实现
        ArcGIS桌面中不仅提供了专门的Linear Referencing Toolbox,对于产生的结果图层,也能像普通图层一样进行各种操作,而针对Linear Referencing的方方面面也提供了非常细粒度的操作供用户调整。
  • 对Route FeatureClass的创建与修改。包括:通过Catalog或Tool或向导创建RouteFeatureClass;利用Tool从已有的Polyline FeatureClass创建Route FeatureClass;通过Tool或向导利用已有的Point FeatureClass来校准Route FeatureClass的M值(注:通过对RouteID字段建立索引,可提高Dynamic Segmentation的效率); 利用Route Editing Toolbar对其进行修改;
  • 将Route FeatureClass作为图层显示,并对其进行查询。包括:对Route进行Identify。查询出线上任意点的M值(Identify Route Locations工具需从Customize中调出);查找某条线上指定M值的位置(包括Point和Line两种),通过Find工具实现;自定义符号显示M值的异常。包括逻辑错误等,可通过Route图层的属性对话框实现;在地图上像刻度尺一样任意显示Route的M值(Hatch)。通过将定义Hatch Definition(可多个),将其组织在Hatch Class(可多个)下,并附加SQL Query和Range Scale操作,基本实现任意复杂的“道路标尺”,而“标尺”的Label也可进行Script的高级控制,最终还能将“标尺”转换为Graphics,或将“标尺”风格另存为Style。在Route图层的属性对话框中实现;
  • 通过Tool和Attribute Table,对Event Table进行创建和修改;
  • 通过Tool,利用Dynamic Segmentation技术将Event Table中的Event显示在Route上(可显示点、线、面),其结果作为一个图层添加到TOC中,可进行显示、查询和分析等操作;
  • 通过Tool或向导,对Route Event进行Overlay,Aggregate,Transform等操作。

        以上所有具体操作可参考桌面帮助中的内容,如果安装了ArcTutor,还会有Linear Referencing Tutorial的PDF可供学习。

2009年9月16日星期三

抢先看:细数ArcMap 9.4中的九大亮点

        介绍:esri 09用户大会上的视频,其中详细介绍了于明年二季度即将发布的ArcGIS 9.4产品中,ArcMap 9.4的9大亮点。
        视频地址在这里:ArcGIS 9.4:Desktop Usability
flv格式(体积更小)
wmv格式(更清晰)

        在这里拣重点的东西翻译一下:
        题外话1:Jack说,过去的三年时间里,我们都致力于9.4版本的开发,有时候我们也称它为version 10,但最后我们还是将版本定为了9.4。(看来ArcGIS 10是呼之欲出了);
        题外话2:9.4版本将可以和9.3.1版本同时安装在一台机器上。
        下面进入特性倒数,由Jack非常赏识的一位名叫John Coken的年轻人演讲:
9、新的用户界面(主要是dockable windows):
可停靠的toc。与visual stuidio的诸多可停靠面板一样,使用最多的table of contents面板将可以停靠。隐藏toc后,屏幕可以显示更多的地图内容:


并且,当toc从自动隐藏或从自动隐藏中恢复时,地图内容不需要刷新。
集成到的arcmap中的catalog管理界面(可以将其他的地图数据从此界面中直接拖入,以实现add data的功能,此功能将会greatly improve your productivity):

并且也可以进行停靠:


8、新的Attribute Table界面:
图层的属性表也实现了停靠,默认是在窗口正下方:

可同时打开多个图层属性表。虽然现在版本中也可以实现,但实际中打开两个或以上属性表后,程序的可操作性大大下降,不得不在多个属性表中来回切换。现在可以将他们作为多个标签页,同时放在可停靠窗口中。除此之外,还可以在可停靠窗口中并排显示多个属性表内容,便于进行内容比对:


7、强大而实用的即时搜索功能:
使用这个搜索面板,可以轻易搜索出多方面的内容:

比如,需要额外的地图数据,像google那样在这里进行搜索,从列出的结果列表中,将图层拖拽到地图上即可实现添加地图数据。可以看出,搜索是在ArcGIS Online上进行的,随着以后ArcGIS Online的不断强大,会有越来越多的用户将自己可以共享的数据发布到AGOL上面,使得AGOL逐渐成为一个强大的“云端”,相比于自己购买的成本或为者获取数据的难度,既方便又快捷,何乐而不为呢?虽然AGOL从理论上的强大到实际中的可用,还有很长的路要走,但不可否认这是一个新颖而正确的趋势,所以不熟悉新版AGOL的朋友,赶紧熟悉一下吧。(推荐flyingis大侠的一片博文,另外参见9.3.1中的LayerPackage)
除此之外,还可以对GP工具(arctoolbox里的内容)进行搜索(搜索本地的内容,带有auto completion的功能),快速定位到需要使用的工具,在结果列表中点击即可打开:


6、新的报表功能:
通过向导式的创建方式,可以轻易的从现有数据创建出复杂的报表(样子比较像DevExpress控件开发出来的报表),包括可选的样式模板。



从最后一幅图可看出,创建完成后还可以对报表的模板进行编辑,随时插入或删除需要补充和多余的内容。

5、更强大的ModelBuilder和Geoprocessing:
Geoprocesssing,是GIS的核心。在ArcGIS的桌面产品中提供了源远流长的ModelBuilder和Python Scritps。 ModelBuilder可以快速,直观,方便的为自己的问题定制科学的解决办法,与编程处理方式是相得益彰。94版本中的ModelBuilder,当把鼠标移动到一个tool或parameter上时,可以不通过右键,直接以tooltip的方式查看到它的所有属性:

还有一个比较令人兴奋的地方就是ModelBuilder中终于加入了Undo和Redo的功能(上图中红圈的部分包括对Auto Layout和误删除的恢复),经常因为手快而误操作的朋友可以宽心了。
此外,还允许在customize的过程中,将自己常用的tool或者model直接拖拽的任何一个toolbar上,以实现更快捷的访问。
再此外,对于任何一个tool,在执行的时候,新的Geoprocess options里面有一个background Geoprocess选项,可以使得此工具的每次执行都在后台进行,在执行的过程中,除了有右下角的进度条,用户仍可在前台对ArcMap进行任何操作,结果出来后会以气泡的方式进行提示。对于耗时的工具来说,这是个令人兴奋的功能。

4、TOC中新的Layers标签页:
演讲者将其称为smart legend。现在的TOC中有Display,Source和Selection三个标签页,最后这个更是少用。这个新的Layers标签页,会根据当前范围内的,可见的地图内容来显示图例,不在当前范围,或者不可见的内容,都不会进行显示;而移动和地图范围或者改变了图层的可见性(可在Layers标签页中直接更改图层可见性和可选择设定)后,面板中的图例会动态发生变化,仍然只显示当前范围内的可见图层的图例。
点击某个图例后,使用该图例的所有feature会以动画的方式在地图上进行闪烁,非常直观的定位出所有使用该图例的feature。


3、可以搜索的Symbol Selector:
目前版本的ArcMap,若想改变一个图层的符号,单击该符号后,在Symbol Selector中只能凭肉眼去从近2000个符号(默认情况下)里寻找想要的符号,94中,如下图,有了搜索工具条,可以直接输入想要的符号名称,即可快速定位到该符号。比如直升机符号输入helicopter即可:


2、ArcMap变得更加Time-Aware:
每个图层属性对话框中将有一个新的Time标签页,类似92版本推出的Animation功能,可以更容易和快速的展示时间有关的地图数据,比如10年的火场历史等。

提示:视频中这个特性讲完后,小伙子会展示特有的美式肢体语言,来博得现场的掌声,也是我们演讲过程中所应该学习的内容:)

1、Fast Basemaps:
首先看下图:

现阶段非常别扭的一个用户体验就是,当移动地图后,仍然按住鼠标左键,会看到地图新范围上并没有内容,而是大片的空白,释放鼠标左键后,此区域的内容才会重绘。
94版本中,可在data frame中通过右键新建一个basemap layer,实际上是一个特殊类型的group layer,之后,可以再toc中,把想要作为底图的所有图层添加到这个basemap layer下。之后,移动地图,神奇的事情发生了:不论怎样快速移动,basemap layer下的几个图层都会始终呈现(实际上是快速重绘),再也看不到任何的空白了……bravo!
(现阶段:ArcGIS Engine中,使用Dynamic Display技术的地图也会有类似的体验;ArcGIS Server中,如果是做过缓存的map service,而且缓存获取的速度足够快(比如在本机上,不受带宽的影响),也会有类似的体验。)

2009年9月13日星期日

从arcgisscripting到arcpy——Geoprocessing在前进

        仔细查看9.3.1中本地的Desktop帮助会发现,没有任何先兆的情况下,An overview of writing geoprocessing scripts主题介绍了Arcpy模块,与在线帮助中该主题的内容完全不一样。而这个Arcpy就是9.4中arcgisscripting的升级版。文档编写人员在本地帮助中为9.4打了一个广告:)
        从win32com到arcgisscripting,geoprocessor实现了跨平台;从gp.create()到gp.create(9.3),脚本中许多对象得到了质的升级。而arcpy正是arcgisscripting的继承者,它将为我们带来包括数据分析,数据转换,数据管理,及工作自动化在内的更加智能化的编程体验。在ESRI 2009 UC的视频中也能看到,ArcGIS Desktop 9.4中将Python环境更紧密的结合到了ArcMap中来。这也再次说明了Python作为scientific programming language for GIS的重要性。
        Geoprocessing是ArcGIS产品的三大核心(Geodatabase,Geovisualization,Geoprocessing)理念之一,也是AGS中gp服务的基石。Desktop之所以强大,在很大程度上取决于Geoprocessing Framework的支撑。若要深入掌握Geoprocessing,除了反复操练ArcToolbox,还得写的一手好的Python Scripts才行。