琐事 9

首先是一段技术贴,不写java的可以安全跳过。

我打工的项目需要写一个工具,用于把收到的机载GPS数据实时plot出来,具体来说就是在一张地图上给每架飞机画一个标志,后面跟几个点标明之前的航迹,前面引一条线标出其航向和航速。其他的都好办,主要是这个地图一开始把我难住了。一开始我试图找一些开源的GIS库,未果,大部分GIS库都要求特别格式的地图,而这些地图很难找,大部分时候只能找到国界线图。后来又尝试着找业余航空爱好者用的导航图,可是那些图的规模又多半非常小,因为通常是给滑翔机之类的东西用。我一直觉得,地图应该是某种文本格式,给出一系列经纬度,我把这些经纬度用简易圆柱投影转换为笛卡尔坐标,然后画到屏幕上。但是找了两三天之后我终于失去了耐心,符合要求的地图几乎不存在,即便存在也是要买的。此时让我撞到一个网站,唤作OpenStreetMap。这个站点也算以一种wiki模式运作,就是每个人都可以使用自己的GPS去测量街道,然后绘制到这个网站上供别人使用,使用CC by-sa授权,有一个类似google maps的界面。我一开始的想法很天真,就是既然这个网站上可以导出地图为PNG,那我就写个脚本把比例合适的地图批量导出欧洲部分来,然后嵌入程序里使用。但是我在试着写python脚本导出地图的时候发现了一个问题,就是地图投影。具体来说,同样南北跨越两纬度,东西跨越两经度的地图,在赤道上是方形的,越靠近两极却会在纵向上越变越长。Wikepedia一番后,我才意识到我忽略了一个非常noob的事实,即,在我们常见的地图上,比如天津市地图,乃至某些世界地图上,采用的都是麦卡托投影。麦卡托投影的原理不比简易圆柱投影复杂多少:想象用一张白纸卷成圆柱形,裹住一个透明的地球仪,使纸筒的轴心与地球自转轴重合,而透明地球仪的球面上刻有不透明的国界线,然后在透明地球仪的球心放一个光源,那么此刻白纸上的投影就差不多是麦卡托投影。你在这张地图上看不到南北两极,且格陵兰的尺寸和非洲差不多。网上的地图,包括google maps的街道图,微软maps和yahoo maps,都是采用这种投影的,OpenStreetMap也是。这种投影的优点是可以明确地看出两点之间的位置关系,缺点是,嗯,它扭曲了事实。

既然OpenSteetMap采用了麦卡托投影,也就意味着我之前写的简易圆柱投影不再适用了。投影算法倒是有现成的库,一一张张计算导出的地图应该在哪里拼接,似乎也不是个很大的问题。但我忽然想到,每次在google maps上zoom in的时候,地图都是一块一块显示出来的,而且每块的大小貌似是一样的。那么google是怎样计算出每一张地图需要哪些小块的呢?Firebugs给了我答案。

google map - tile url

原来每张OpenStreetMap和Google Maps上的地图小块都是256 x 256的PNG,以形如http://mt3.google.com/mt?n=404&v=w2.75&hl=en&x=X&y=Y&zoom=Z&s=,或http://b.tile.openstreetmap.org/Z/X/Y.png的url给出来。X、Y和Z都是正整数,指定了它在Z的zoom level时,是一张麦卡托投影的地图上横向和纵向的第几张切片。至于那个w2.75,是指街道图的版本号,地形图则是w2p.71。Zoomlevel和图片之间的关系很简单,当zoom level是17的时候,整个地球(确切的说,是南北正负85度之间的地区)包含在一张边长为256px的正方形图片上,而zoom level是16的时候,就将这张图切分为四等份,分别放在4张边长为256px的正方形图片上,以此类推。由此可知,zoom level 0应该有417=17,179,869,184张图片,每张图片都跨越0.00274658203经度,跨越的纬度则随着维度的升高而增加。当然,google maps实际上在zoom level 17的时候并不会准备所有这些图片,南极洲之类的地方就会简单地显示We are sorry but we have no maps for this region。

至于google 的卫星图,和微软的virtual earth图,其url是类似http://kh2.google.com/kh?n=404&v=28&hl=en&t=trtqtrstrtqstss这样,采用的是另一种图片编号方法。最大的地图仍旧会被4等分,每一个等份分别标为 q r s t(为什么?),然后每个等份再4等分,再分别标为 q r s t,以此类推,这样每一个地图小片都可以用一串唯一的序列标识出来,序列的长度也就等同于zoom level。

弄清楚了这些,我有种感觉,就是肯定已经有什么人想过把这些图片挪为他用了,但是google到的结果还是以web application居多,我开始以为没有人想过怎样将这一套东西移植到一个java桌面程序里。事实上我错了,世界上总会有人不屈不挠地把为一种环境开发的资源移植到另一种环境中去。因缘际会地,我找到了这样一块金子:Building Maps into Your Swing Application with the JXMapViewerJXMapViewer的伟大之处在于,它可以当作Swing的JPanel来用,不同之处是它内建了对OpenStreetMap的支持,可以把那些小图片都down下来替你拼接好,并且可以自动将一个绝对的地理坐标转换为当前屏幕上相对的像素坐标,以便你在地图上画些别的东西。接下来的问题就迎刃而解了:写一个提供google maps的map provider,就可以让它支持google maps。写一个aircraft plotter扩展其固有的painter类型,就可以把飞机标在上面。实现的效果如下:

Screenshot of TIS-B data plotting java app using google map

经过几个小时的观察,感觉法兰克福机场果然是非常的繁忙;飞向巴黎的飞机很多;阿尔卑斯山和黑森林挡住了很多本应收到的信号。

对了,前面说了,OpenStreetMap的授权是CC by-sa,所以用它是没有问题的。但是GoogleMaps是受版权保护的,所以只能做测试用。另外,这个实现方案有很明显的缺点,比如不能在南极使用,也必须和WWW有通讯。

漫画

WoW欧服Moonglade服务器曾有一个公会叫做The Order of the Stick,翻成「条棍骑士团」听起来不错。我于是去Google这个名字,果然找到了有趣的东西。这是一则漫画连载,讲的是一群人跑团的故事。对于ADnD,和许多我其他叶公好龙的爱好一样,我只是一个noob,不过这则漫画倒不要求读者有多专业,只要略知ADnD的一二,就可以读得很高兴了。

The order of the stick - gary gygax

Wikipedia是个好东西,无论学习还是娱乐,它都能帮你。在wiki上有一个词条叫做Webcomic,我顺着The Order of the Stick找到了它,又从这里找到了很多其他的漫画连载,从此步入了网上追漫画的不归路。在此推荐几个:

Piled Higher and Deeper

简称PHD,讲的是nerd们读学位的生活。

PHD comic - your life ambition-what happend??

0xBABAF000L

法国linux爱好者的漫画,更新缓慢,不过很有趣。

0xBABAF000L comic - vi vs emacs

Dilbert

我居然还推荐这个……这漫画有点家喻户晓吧。Anyway,如果你还不知道的话。

dilbert - psyco

xkcd

A webcomic of romance, sarcasm, math, and language. 非常Geek。大爱。

Some say the world will end in fire; some say in segfaults.

HH

如其名,是非常H的漫画,倒不是说它画得有多H,而是它的思想非常地H……18x内容,请确定身边没有家长。它有中文翻译,而且翻译得很棒。

hh 014

又,离我最近规模最大的亚超在斯特拉斯堡,所以每个月总要去上一次。那里有一家购物中心,名叫Palace des Halles。它的底层有一家漫画店,满是漫画和模型。模型方面,丁丁历险记和星球大战的模型是永恒的主题,其余则根据潮流更新。模型有大有小,有一米多长的千年鹰号,也有10公分大小的Q版钢铁人。至于漫画,很明显地分为欧美系和日系。欧美系的我自然不懂,日系的只认得一些知名之作,比如EVA、犬夜叉之类,当然都是法语的。这两类漫画从画风到装帧上泾渭分明:日系一般是软皮包装,比较厚,封面和封底是彩页,内页黑白,开本通常是32开,角色都是大眼睛,很少超过六头身,女性一般都胸围傲人。欧美系则一般是硬皮包装,比较薄,通常是全彩,8开或16开。人物画风多种多样,有非常写实的,也有非常写意的,但是写实的就非常写实,写意的就非常写意。

doubanclaimd8b58f4c7e1195a8