2009年5月29日星期五

Silverlight API中的行军箭头和渐变符号

        模仿老牛一把。不像Flex有BitmapData类,由于sl中不支持GDI+,也就不能用System.Drawing中的类来动态画图,从而不能用PictureMarkerSymbol的source来实现。这里用了MarkerSymbol,自定义了ControlTemplate。

2009年5月22日星期五

恍如隔年

又是一年答辩时。即使去年答辩那天没有地震,其他情景也都历历在目,偷吃着给专家评委准备的水果,忙着打拨不通的电话,和老魏小崔走过育才路的转角,zw宣布他荣登大师兄宝座,晚上唱歌拿了把伞……一年的时间一晃就过去了,想想发生过的事情,仿佛都在昨天一样。
其实很佩服和羡慕小李他爸。为了自己精神上的追求,只身一人云游四方,与陌生人交谈,与自己的思想沟通,路途中会有无数经历,主要是思想境界的升华。也不用和这个主任那个领导打交道,虽然没有路虎开,但远胜过那些呼风唤雨,拍板拿事的人。有时候也在想,面朝大海春暖花开。但没有经历过,即使在背靠大海,有小桥流水绿树青草的山间,过着天天耕地喝酒的日子也会觉得烦。努力工作,换来好的生活,是一件再也正常不过的事情。但最后的追求到底是什么?金钱?荣誉?幸福?想起一句歌词:阿拉善突然来了沙尘暴,把所有白领吹成黑领了……前一阵子李文华老先生去世,感动之余留给我印象最深的是为人低调,淡泊名利这八个字。
If you really want it, push the past pain, use it, control it, feed everything to your fire, pains, failures, critics, glories...if you really want it.我的fire大概已经在错误的追求中熄灭了吧。
5:30,下雨的清晨,湿漉的街道,没有行人。扫扫记忆,像歌中唱的那样:出发啦,不要问那路在哪,迎风向前,是唯一的方法……


2009年5月19日星期二

China mobile

        昨晚打10086,里面说现在是23点以后,您确定要使用紧急服务吗?紧急服务只能停开机云云,难道他们赚的比以前少了,把值夜班的人都撤了?害的今天占用23点以前的宝贵时间继续打10086,就问个关于机器呼叫转移设置的问题,说了半天都不清楚,给人感觉打10086只能单向办理收费业务,就是只能办理,不能退办。果然,我说要取消短信业务,结果被告知只能拿身份证去营业厅办……办的时候怎么那么痛快啊,电话,网上,短信一不小心就办成功了,退的时候就只能去营业厅……我半年才给你们打一次电话,这点要求都不能满足,哎!
        移动去年营业额800亿人民币。前阵子3G的广告是挺好,但是和人一样啊,不能光穿衣服漂亮,主要还得心灵美。不得不让我觉得它跟学校网络中心一样恶心,就是只收钱不办该办的事。

2009年5月17日星期日

Bright Star

        金棕榈奖唯一的女得主Jane Campion(获奖作品是反映女性细腻心理的《钢琴课》,是部好电影),携19世纪诗人John Keats的爱情诗《Bright Star》的同名电影又去戛纳了……还没看过电影,到是对这首诗比较感兴趣。
        写作背景就是电影情节,关键是作者只有25岁不到的年龄(就去世了)。找到了一个比较完整的注释版本,也有明喻暗喻之类的分析,估计是外国语文课上的内容。从深蓝夜空中的星星,到宗教隐士洗礼的流水,还有柔软飘落的新雾,山顶上的白雪,爱人的tender breath,仿佛一次优美的时空旅行……但最后还是没能避开永远的话题:永恒和死亡。

Bright star,would I were stedfast as thou art—
Not in love splendor hung aloft the night,
And watching,with eternal lids apart,
Like nature's patient,sleepless eremite,

The moving waters at their priestlike task
Of pure ablution round earth's human shores,
Or gazing on the new soft-fallen mask
Of snow upon the mountains and the moors;

No—yet still stedfast,still unchangeable,
Pillow'd upon my fair love's ripening breast,
To feel for ever its soft swell and fall,
Awake for ever in a sweet unrest,

Still,still to hear her tender-taken breath,
And so live ever-or else swoon to death.

注释:
stedfast:永恒的,不变的
aloft:高高在上的,夜空中的
lids:眼皮
Eremite:有宗教背景的隐士
pure ablution:洗礼

        想起一首同样想象空间极大的情诗,作者是木子。《我纷纷的情欲》:

尤其静夜
我的情欲大
纷纷飘下
缀满树枝窗棂
唇涡,胸埠,股壑
平原远山,路和路
都覆盖我的情欲
因为第二天
又纷纷飘下
更静,更大
我的情欲

2009年5月6日星期三

ArcGIS API for Silverlight开发入门(8):在程序中使用Virtual Earth的服务

        Silverlight API中还包括了一个ESRI.ArcGIS.VirtualEarth.dll类库,让我们可以方便的访问到老东家的VirtualEarth服务。目前Silverlight API中提供的VirtualEarth服务有三种:Map,Geocode和Routing,不过一看就知道后两种服务对于国内的数据来说又无缘了。
        直接看如何使用它的Map服务获取地图数据吧。同前,新建一个Silverlight工程,添加ESRI.ArcGIS.dll和ESRI.ArcGIS.VirtualEarth.dll的引用,引入xml命名空间,在xaml里面这样写:
<esri:Map x:Name="Map1" Loaded="Map1_Loaded">
<esri:Map.Layers>
<esriVE:TileLayer ID="VELayer" LayerStyle="AerialWithLabels" ServerType="Staging"/>
</esri:Map.Layers>
</esri:Map>

        可以看出,和添加其他图层基本是一样的。SIlverlight API中针对VE地图的图层类型是TileLayer,LayerStyle有三种:Road,Aerial和AerialWithLabels,分别对应矢量图,影像图和带街道标注的影像图。ServerType就比较特殊了,有两种:Staging和Production,分别对应访问VE服务的账户类别,前者是免费的,后者是收费的。如果你此时运行程序的话,那是看不到地图的,因为TileLayer还有个关键的token属性没有设置。
        VE的服务那是相当安全,每次访问VE的服务,都要提供一个token(一个加密字符串)来进行身份验证,而这个token又是根据TokenService自动生成的,要通过TokenService生成一个token,又需要一个合法的Microsoft Virtual Earth Platform developer account……明白了这个过程,就来做我们的工作吧。
        首先,去申请一个Microsoft Virtual Earth Platform developer account,当然之前你还得有一个Windows Live账号。申请的这个账号是Evaluation版的,所以决定了以后我们只能使用Staging的服务,如果要把它变成Production版本,可以通过邮件联系微软,然后缴费;
        之后到注册时所填的邮箱去激活申请的Microsoft Virtual Earth Platform developer account账号,然后为其设置密码(必须是8-14为之间,包括大、小写字母,数字,且还要有非字母数字的字符,和windows server 2008是一样的),我们平常肯定不会这样设置密码,为了以防万一,建议赶紧把设置好的密码记录下来,
没准哪天就忘了。现在就可以用这个账户和密码来访问TokenService,通过它生成token,交给TileLayer的token属性。
        为了安全目的考虑,token是不建议也不能直接在Silverlight程序中进行设置的。那么怎么办呢?这样办:1、通过装载Silverlight的aspx页面的Page_Load方法,来申请我们的token,并把它添加到Silverlight的初始参数中,2、然后当Silverlight插件载入的时候,把token读出来,3、在Map_Loaded事件中,赋给TileLayer。
1、通过TokenService申请token:
在web app中add web reference,url用https://staging.common.virtualearth.net/find-30/common.asmx?wsdl,起个名字叫VirtualEarthService.TokenService。
<script language="C#" runat="Server">
private string VEAccountID = "你的ID(注意只是AccountID)";
private string VEAccountPassword="你的密码";

protected void Page_Load(object sender,EventArgs e)
{
_08_virtual_earth.Web.VirtualEarthService.TokenService.CommonService commenservice = new _08_virtual_earth.Web.VirtualEarthService.TokenService.CommonService();

commenservice.Credentials = new System.Net.NetworkCredential(VEAccountID, VEAccountPassword);

_08_virtual_earth.Web.VirtualEarthService.TokenService.TokenSpecification tokenSpec=new _08_virtual_earth.Web.VirtualEarthService.TokenService.TokenSpecification();
tokenSpec.TokenValidityDurationMinutes=480;
if (HttpContext.Current!=null && !HttpContext.Current.Request.IsLocal)
{
tokenSpec.ClientIPAddress=HttpContext.Current.Request.UserHostAddress;
}
else
{
tokenSpec.ClientIPAddress="127.0.0.1";
}

string token = "";
token = commenservice.GetClientToken(tokenSpec);

Xaml1.InitParameters = string.Format("token={0}", token);
}
</script>

其中Xaml1是Silverlight插件的ID:<asp:Silverlight ID="Xaml1" runat="server"...
2、Silverlight插件载入时读出这个token。在App.xaml.cs中:
private void Application_Startup(object sender, StartupEventArgs e)
{
VEtoken = e.InitParams["token"];
this.RootVisual = new Page();
}

3、最后在加载地图控件后,交付token:
private void Map1_Loaded(object sender, RoutedEventArgs e)
{
foreach (Layer layer in Map1.Layers)
if (layer is TileLayer)
(layer as TileLayer).Token = (Application.Current as App).VEtoken;
}

        终于能看见VE的图了。当然,我们的开发账户是免费的,所以地图上有很多“Staging”麻点(每个tile一个):


        至此,ArcGIS API for Silverlight的开发入门已经讲完了,我和大家一样也是边学边写的,刚好这两天SIlverlight API又升级了第二个Beta版。其实Silverlight和Flex一样,能使传统的WebGIS散发出全新的魅力,从而使我们的程序在RIA的道路上大踏步前进,能够做出什么样的效果也基本只受想象力的制约了。随着Silverlight 3的推出,我们也有理由相信Silverlight的明天会更好。

2009年5月5日星期二

Last Chance Harvey

        《哈维最后的机会》,看着看着我就觉得像是老年温馨版的《日出之前》,最后的结局又比《幸福终点站》来的要舒服。

        Harvey Shine,笑容就和他的last name一样,辛勤工作的他为了去伦敦参加女儿的婚礼,丢了工作,到了伦敦后先被前妻数落一番,后被女儿告知决定让继父代替他参加婚礼……事实证明,不是老哈维人不好,只是别人比他更适合那个家庭。Kate Walker伤心哭诉的时候,老哈维也没有去给一个可靠男人的拥抱,还是让她自己做出了决定。
        “我能把这当做是还有希望吗?
        如果是的话,给我个明确的微笑。”
        musicman说,青春还没有掏出手枪我们就倒下了,永远的倒下。但这不也是在生活之路上的重生吗?没有了青春,但我们的生命还在继续。
        和《日出》《日落》一样,这种片子好像只适合在欧洲拍摄,不管是欧洲小镇还是大城,阳光总是显得特别充足,即使是在一天中最冷的日出前后,也感觉不到一点寒意。整个城市都非常干净,路边的落叶也只会让画面显得更加清新,看了就让人直想去哪里呆一段时间。
        另插一句,在L world里头也看见人家老外掏钱上作文课。我觉得一个小孩,要是不要让他在中小学写12年的作文,把娃一直憋着,等他长大了,抛开他掏钱去上writing class不说,肯定会写一篇丰富感情自然流露的好文章出来,为啥?憋的慌么,就跟那啥道理是一样的,至少也会保有对写作这一美好事物的兴趣。
        其实看到这个片子的介绍是去年冬天一个早晨,最近发现它的时候才想起来还有这么一茬事,又让我想起了当时的情景,挺有意思。

ArcGIS API for Silverlight updated

        Silverlight API升级了,但还在继续它的beta之旅(Build 209,之前是Build 160),看来要修正的地方真不少。
        除了新出一个OverviewMap的widget,改进了Magnifier widget(减轻使用时的服务器负担),还允许在Map控件初始化的时候根据Extent来动态投影地图,这与Flex API是一样了……具体的变化请看这里

2009年5月2日星期六

ArcGIS API for Silverlight开发入门(7):使用非AGS数据源的图层

        通过上一节学习,可以看出在Silverlight API中不仅可以轻松使用ArcGIS Server 9.3发布的地图服务,也可以通过继承相应的图层,引入其他的数据源,比如ArcGIS Server 9.2发布的地图服务,WMS服务,或者其他免费的数据。本节就通过一个实例,来看看如何将Google Map作为底图数据。
        Google Map是经过缓存的数据,所以需要继承的是TiledMapServiceLayer。那么在扩展这个图层的时候需要做哪些工作呢?首先就要明白地图缓存的原理。可以看出我们继承的这个图层,需要收集到以下几个信息:
1、Tiling Scheme Origin;
2、切图的范围,也就是FullExtent;
3、SpatialReference;
4、TileInfo,包括切图的大小,级数,以及每级的Resolution;
5、最后就是重写GetTileUrl方法。
        这是为什么呢?可以想象,当地图控件的范围改变时,能够获取到当前范围的信息,那么只要把左上角和右下角之间的Tile全部按顺序显示出来就行了。由前面的文章可以看出,当图层获取了1、2、3、4四个信息后,图层完全可以自动计算出所需的Tile,最后根据GetTileUrl方法取回这些Tile显示出来即可。
        那么对于Google Map的前4个参数,如何取得呢?记得在Catalog中做缓存时,有一个Load Tiling Scheme from Google Map吗?按照这个Tiling Scheme将一个地图服务做缓存,然后查看它的conf.xml和Service Directory,便完全可以取得这几个参数了。另外关于如何获取Google Map的缓存,网上已经有非常多方法,这里就不再讨论了。



        代码如下:
public class GoogleMap:TiledMapServiceLayer
{
public override void Initialize()
{
this.FullExtent = new ESRI.ArcGIS.Geometry.Envelope(-20037508.342787,-20037508.342787,20037508.342787,20037508.342787);//(-180, -85.0511287798066,180, 85.0511287798066)
{
SpatialReference = new ESRI.ArcGIS.Geometry.SpatialReference(102113);
};
this.SpatialReference = new ESRI.ArcGIS.Geometry.SpatialReference(102113);
//this.InitialExtent = this.FullExtent;
this.TileInfo = new TileInfo()
{
Height = 256,
Width = 256,
Origin = new ESRI.ArcGIS.Geometry.MapPoint(-20037508.342787, 20037508.342787)//Origin = new ESRI.ArcGIS.Geometry.MapPoint(-180, 90)
{
SpatialReference = new ESRI.ArcGIS.Geometry.SpatialReference(102113)
},
Lods = new Lod[20]
};

double resolution = 156543.033928;
for (int i = 0; i < TileInfo.Lods.Length; i++)
{
TileInfo.Lods[i] = new Lod() { Resolution = resolution };
resolution /= 2;
}

base.Initialize();
}

public override string GetTileUrl(int level, int row, int col)
{
//google maps map
//string baseUrl = "http://mt0.google.com/mt/v=ap.92&hl=zh-CN&x=";
//string url = baseUrl + col.ToString() + "&y=" + row.ToString() + "&z=" + level.ToString() + "&s=";
//return url;

////google maps satallite
string baseUrl = "http://khm2.google.com/kh/v=38&hl=zh-CN&x=";
string url = baseUrl + col.ToString() + "&y=" + row.ToString() + "&z=" + level.ToString() + "&s=";
return url;
}

}

        需要注意一点,Google Map采用的是WGS 1984 Web Mercator投影,这个投影的wkid在REST API中查不到,但在Service Direcotry中可以找到,是102113。另外,重写DynamicMapServiceLayer也是基本相同的。
        之后也可以按照这个Tiling Scheme对自己的服务作缓存,自己的数据和Google Map便可以叠加在一起了。但是这样子使用Google Map的数据不仅担心会被封IP,而且更重要的是版权问题,毕竟不像JS API(有ArcGIS JavaScript Extension for the Google Maps API )或者Flex API(有Google Map API for Flex)。别忘了MS有自己的Virtual Earth,下一节中就来看看如何在我们的程序中名正言顺的使用VE的数据吧。

2009年5月1日星期五

一幅漫画

rt