【Asp.net精品源码栏目提醒】:文章导读:在新的一年中,各位网友都进入紧张的学习或是工作阶段。
网学会员整理了Asp.net精品源码-【精品】SharpMap - 大学课件的相关内容供大家参考,祝大家在新的一年里工作和学习顺利!
本文使用 Sharpmap 0.9。
Sharpmap 作为优秀的基于 vs2005 的 GIS 解决方案,大家也对其了解甚多,我就不多说了。
在实际使用中,特别是 web 控件,作者并没有暴露很多编程方法,本文基于此进行讨论。
在项目开发中,我们希望在鼠标拖拽时起码要实现几个功能:平移、拉框缩放、拉框选择。
通过更改 Sharpmap.UI.dll 的方式修改,可以实现。
首先,增加鼠标拖拽选择模式属性 MouseMode,并增加 enum,代码形如: public enum eMouseMode Pan Zoom Select private eMouseMode _MouseMode ///// ltsummarygt /// Set Mouse downup move event to pan or zoom mode /// lt/summarygt CategoryquotBehaviorquot DefaultValue0 Descriptionquot设置鼠标拖拽方式:即设置 MousedownMousemoveMouseup 事件的处理方式。
默认值为 Pan。
quot public eMouseMode MouseMode get return _MouseMode set _MouseMode value 其次,将属性暴露给 JS,让客户端可以调用。
通过修改 GenerateClientScripts 函数,增加 setvarsScript 变量定义。
拉框需要有 html 控件,我这里使用 div。
首先,在 GenerateMapBox 函数中生成控件,使用 Controls.add 方法增加进来。
其次,在 JS 中注册。
通过修改 JS 文件的 SharpMap_Init 函数和 CS 文件的 GenerateClientScripts 函数,将增加的控件暴露给 JS 使用。
至此我们在前后台均可以使用新增加的控件和方法。
然后,就可以在 SharpMap_MouseDownUp Over函数里面写代码了。
SharpMap 深度分析:地图数据 Provider Provider 或者 Provider 模式对于很多人应该都不陌生,在 DNN 和
Asp.net 2.0 中都大量应用了 Provider 模式。
目前主流的 GIS 平台的数据提供也应该基本上都是基于 Provider 这样的模式,大家比较熟悉的应该是 SuperMap 提出的多源空间数据引擎的概念。
在 SharpMap 里,数据 Provider 是这样使用的: string ConnStr quotServer127.0.0.1Port5432UserIdpostgresPasswordpasswor dDatabasemyGisDbquot myLayer.DataSource new SharpMap.Providers.PostGISConnStr quotmyTablequot quotthe_g eomquot 32632 而实际上,在 Layer 类里,DataSource 定义为: public SharpMap.Data.Providers.IProvider DataSource ... 也就是说,这里的 Provider 是针对 IProvider 接口的,这样,对于不同的层,你可以指定不同的数据源(使用不同的数据 Provider,而支持不同的数据格式)。
下面是 Provider接口的类图,定义了接口的属性和操作: 个人认为,Provider 的核心思想在于面向接口编程,也就是说通过接口定义需要的服务,至于服务的实现,可以通过具体的方式来实现。
就 GIS 数据引擎来说,就是定义对空间数据需要的操作,例如打开、关闭、读取某个范围内的数据、检索、分析等等这些接口,然后通过继承这个接口来实现对不同的数据的操作。
例如对 Shape 文件的操作和对 PostGIS 文件的操作是完全不同的,但其接口一致。
而在系统内部,对数据的操作,例如放大缩小、变换、显示,只需要针对接口编程,就可以实现支持不同的数据源。
这里的实现和 DNN 等的不同在于,DNN 是通过配置文件和反射机制,来实现不同的 Provider 的更换,而无须更改代码实现,而 SharpMap 或其他 GIS 的类似实现是需要在开发时指定使用的 Provider。
Provider 的实现还有一个比较重要的问题就是要操作的数据的定义,因为具体的 Provider 的实现最终要将数据转换为系统内部的数据类型和结构,然后返回。
对于具体的 Geometry 的结构,基本上是在 OGC 的规范的基础上实现,对于这部分内容,很多非 GIS 的面向对象的书也喜欢用这个来讲述类、对象、继承等概念,大家都很熟悉,这里就不多说了。
对 OGC 的 Simple Feature 实现比较好的一个.net 类库是 NTS(JTS 的.net 移植版本),目前正在看他的
源码,后面会写一些自己的笔记。
SharpMap 的一些代码,看注释也是在 NTS 的基础上实现的。
SharpMap 的 Provider 没有定义数据的修改、编辑,从理论上讲,完全可以实现任意数据的读取、修改,但实际上,数据的读取显示一般来说,实现难度不是很大,因为大家都是点线面及其组合这样的对象;但由于内部结构,拓扑关系,修改就比较困难了。
例如 SuperMap 的产品也只是可以只读读取一些其他格式的数据(如 MicroStation DGN,AutoCAD 数据),而没有修改功能。
SharpMap 深度分析:地图渲染、坐标和比例尺地图都有一个单位(Unit)、比例尺(Zoom)的概念,还有投影的问题。
对于 Unit,一般使用 Km、m 或者经纬度来表示。
一幅地图,在其所有数据的 Unit 和投影都一致的情况下,在绘制这些对象到地图时,就要根据比例尺进行坐标转换;同时,在进行地图的缩放、移动、拾取等操作的时候,鼠标的坐标是桌面的坐标系统,也要转换到地图坐标系统(一般称为World Coordinates System,简称 WCS)。
首先来看比例(Zoom)在 Map 类里的定义: private double _Zoom public double Zoom get return _Zoom set if value lt _MinimumZoom _Zoom _MinimumZoom else if value gt _MaximumZoom _Zoom _MaximumZoom else _Zoom value if MapViewOnChange null MapViewOnChange 这个 Zoom 表示使用地图 Unit 表示的地图宽度。
例如地图单位是 Km,那么如果目前地图的宽度是 500Km,Zoom 就是 500。
这个和 Mapinfo 中 Zoom 的概念是一致的。
那么在渲染的时候,就要对所有对象进行坐标转换,转换为要渲染的图片的坐标系统,然后调用 GDI进行渲染。
对于对象的渲染,定义在 Layer 的名称空间里,在 VectorLayer 类的 Render 方法里,根据 Geometry 对象的层次依次遍历各个对象,然后调用 Rendering 名称空间的 VectorRenderer 的各个方法来渲染不同的点、线、面等对象。
在渲染具体对象时,我们看到这些方法都调用了一个 TransformToImage 的方法,而这个方法定义在不同的 Geometry 名称空间的不同类里,目的是由空间对象经过坐标变换后返回一个.net 的绘图对象。
我们把这个流程整理如下: Map 对象 GetMap 方法→GetMap 方法遍历其 Layer,调用 Layer 的 Render 方法→各个 Layer 开始渲染自己,对于栅格和 WMS 层,返回范围内的图片即可,主要是 VectorLayer 的渲染→VectorLayer 调用自己 DataSource Provider 的 GetFeaturesInView 方法,返回范围内的对象到一个列表→依次遍历列表的各个对象,调用 Rendering 名称空间的 VectorRenderer 的各个方法来渲染不同的点、线、面等对象→渲染这些对象前,调用几何对象的TransformToImage 方法,返回一个.net 的绘图对象→GDI根据 Style 渲染 在最后一步,各个对象调用的 TransformToImage 方法其实是逐次转换这个对象的各个点。
而点的坐标转换定义在 Utilities.Transform 下,有 2 个方法: public static System.Drawing.PointF WorldtoMapSharpMap.Geometries.Point p Shar pMap.Map map 和 public static SharpMap.Geometries.Point MapToWorldSystem.Drawing.PointF p Shar pMap.Map map 分别转换 WCS 坐标到 Image 坐标和转换 Image 坐标到 WCS 坐标。
这是转换代码: System.Drawing.PointF result new System.Drawing.Point double Height map.Zoom map.Size.Height / map.Size.Width double left map.Center.X - map.Zoom/2 double top map.Center.Y Height/2 double pxSize map.Zoom / map.Size.Width result.X floatMath.Roundp.X - left / pxSize 0 result.Y floatMath.Roundtop - p.Y / pxSize 0 return result left 和 top 表示当前地图的左上角坐标,Height 是高度,需要通过 Zoom 和 Height 来换算一下,也许写作 map.Zoom map.Size.Height / map.Size.Width更好理解一点。
pxSize 相当于在最终的图片上的一个单位相当于 WCS 的多少单位,这样,p.X - left / pxSize 就是横坐标,纵坐标由于图片 y 轴相反,因此是top - p.Y / pxSize。
有过 Dos 或者Windows 图形编程经验的人对于这样的代码应该是非常熟悉。
这段代码的计算 left、height、top、pxSize 这些参数的语句其实应该在 Map 每次更改Zoom 时计算比较好,因为这个函数会被调用非常多次(每个点都要转换坐标),不过这些都是优化的话了,可以放在系统稳定以后。
不同的地图单位和投影下的地图渲染操作 SharpMap 目前还没有 Unit 的问题,在 Map 和 Layer 里也没有定义 Unit,投影在新版0.90 的 beta 里有部分代码。
象 ArcGIS 和 Mapinfo 都支持动态投影,也就是对 Map 定义一个 Unit 和投影,对不同的 Layer 定义一个投影和 Unit,他可以自动的转换这些 Layer 的 Unit 到地图,然后叠加显示。
这样的话,在显示(渲染)时,就需要对所有对象都要进行投影和尺度变换。
虽然似乎在打开数据的时候进行转换,但是由于对于空间数据库,一次打开所有数据已经越来越不可能,而且对数据作分析的时候,如果数据打开时转换了数据的 Unit,那么分析结果也会出现问题。
因此,这类实现应该是在地图渲染时进行投影和变换。
SharpMap 学习(3)我写的东西内容浅显,希望能给初学者一些帮助。
至于深入研究 sharpmap 和 GIS 技术的大牛,请不吝赐教,给我们这些菜鸟多一些指导。
今天我们接着来聊 sharpmap 的基本使用技巧,根据 attribute 来填充地图对象的颜色,让用户更清晰的看到重点的业务对象对应在地图上的表示以及如何自定义 label 层的显示内容,字体的大小等。
所以,今天的主题主要是自定义:自定义 theme,自定义 label 以及label 字体。
首先,我们要为地图填充上不同的色彩,让他们看起来五颜六色,容易分辨。
比如河流和湖泊要填成蓝色,草地要填充上绿色,房子要填充上白色,道路要填充上青色等等。
怎么做呢?很简单,先看下代码: SharpMap.Rendering.Thematics.CustomTheme iTheme new SharpMap.Rendering. Thematics.CustomThemeGetMyStyle 在初始化 Map 的时候,加上上面的一行代码。
它定义了一个自定义的 Theme 对象,这个对象的构造函数需要传入一个我们自己写的方法(委托),这个方法里面具体说明了这个 theme 是如何定义的,方法代码如下: private static SharpMap.Styles.VectorStyle GetMyStyleSharpMap.Data.FeatureD ataRow row SharpMap.Styles.VectorStyle style new SharpMap.Style s.VectorStyle switch rowquotStatusquot.ToString.ToLower case quotavailablequot: //If status is interred fill it with yellow style.Fill Brushes.Yellow return style default: style.Fill Brushes.Green return style 这段简单代码大家都看得懂,这个委托定义需要传入一个 FeatureDataRow它的作用就是在初始化地图的过程中,每处理一个对象,都要到这个方法中来考察一下 feature 的值是多少以决定具体要填充哪些颜色。
在这里,当 status 为 available 时,就填充黄色,否则就填充绿色。
定义的 VectorStyle 用来返回给地图。
是不是很简单呢? 地图填充完了,我们要在上面显示出到底他们是什么。
在第一篇中,我们已经可以把对象的一个属性显示出来,但是当地图扩大到一定比例时,仅仅显示名字这一种信息已经不足以满足用户的需要了。
比如说一栋房子,在很远处看它时,我们只需要看到他的颜色就行了。
但是当我们离的很近的时候,难道看到的是全白色吗?显然不是,我们还可以看到门牌号,窗户上的贴纸以及其它详细信息。
地图也一样,当比例尺改变以后,应该有更详细的信息被列出来。
老规矩,先贴代码: SharpMap.Layers.LabelLayer myLabel new SharpMap.Layers.LabelLayerquotlabels quot myLabel .DataSource myLayer.DataSource myLabel.LabelStringDelegate new SharpMap.Layers.LabelLayer.GetLabelMethod GetLabelString 在这里,首先定义了一个 label就像在初始化地图里一样,或者就在初始化地图里做),然后把你所要显示的图层的数据源赋值给这个 label 的数据源,接着为 label 层的 LabelStringDelegate 指定一个方法(这个方法传入一个 FeatureDataRow返回一个字符串),最后去实现这个方法,代码如下: public static string GetLabelStringFeatureDataRow dr string field1 string.Empty string field2 string.Empty string field13 string.Empty if drquotHouseNumberquot null field1 drquotHouseNumberquot.ToString if drquotHostNamequot null field2 drquotHostNamequot.ToString if drquotMemoquot null field3 drquotMemoquot.ToString StringBuilder sb new StringBuilder sb.Appendfield1 sb.Appendquot: quot sb.Appendfield2 sb.Appendquotrnquot field3 return sb.ToString 代码简单的要死,不再详述,值得注意的是:如果要换行,请使用“rn” 这里不支持 html 拼的字符串。
哈,又解决一个问题。
爽吧?然后,新的问题又来了,字体一直都是那么大,或者一直都是那么小,这可怎么办呢?看起来也相当不舒服啊。
如果字体能随着比例尺的变化而变化就好了。
这个没问题,我们马上就搞定它。
看代码: public void ChangeFontSizedouble Zoom SharpMap.Layers.ILayer iLayer SharpMap.Layers.LabelLayer labelLayer SharpMap.Layers.LabelLayeriLayer if Zoom lt 800 ampamp Zoom gt 400 SharpMap.Layers.LabelLayerlabelLayer.Style.Font new System.Drawing.FontSystem.Drawing.FontFamily.GenericSerif 6 else if Zoom lt 400 ampamp Zoom gt 140 SharpMap.Layers.LabelLayerlabelLayer.Style.Font new System.Drawing.FontSystem.Drawing.FontFamily.GenericSerif 8 else if Zoom lt 140.00 ampamp Zoom gt 20 SharpMap.Layers.LabelLayerlabelLayer.Style.Font new System.Drawing.FontSystem.Drawing.FontFamily.GenericSerif 16 else if Zoom lt 20.00 SharpMap.Layers.LabelLayerlabelLayer.Style.Font new System.Drawing.FontSystem.Drawing.FontFamily.GenericSerif 48 else SharpMap.Layers.LabelLayerlabelLayer.Style.Font new System.Drawing.FontSystem.Drawing.FontFamily.GenericSerif 70 这个方法传入了一个 Zoom 值和一个 ILayer,没有返回值,直接修改 ILayer 就可以了。
相信大家都看得懂吧?值得注意的问题是:AjaxMap 上面的 map 对象有个属性叫做 zoomAmount,这是个 javascript 的属性需要在前台指定,它说明了地图放大或缩小的比例尺倍数。
Demo 中是在 RadioButtonList 的 ListItem 中指定的。
这个过程是这样的:当点击Zoom In 这个 button,自动执行了一段 javascript: ajaxMapObj.disableClickEvent ajaxMapObj.zoomAmount 3 然后当我们点击地图,click 事件已经被禁止,系统刷新地图,此时在 handler 里接受到了地图的新的参数(zoom 等),然后重新绘制了地图。
所以,我们在 handler 里取得 zoom 参数,并且使用 GetLayerByName(“”)方法来取得 label 层 ChangeFontSizeZoom map.GetLayerByNamequotmylabelsquot 这样,就实现了字体随着比例尺变化儿变化。
有同学可能问:那如何让 label 的内容随着比例尺变化而变化呢?只需要把刚才那句话 myLabel.LabelStringDelegate new SharpMap.Layers.LabelLayer.GetLabelMethodGet LabelString 放到相应的 if。
。
else 语句里就行了。
简单吧? SharpMap 学习(2)在经过第一篇的简单学习之后,我们开始了解一些稍微有点儿意思的东西,进一步掌握和学习利用 sharpmap 进行开发的技巧。
这次,我们主要是跟大家一起学习一下如何根据地图上的一个点,来查询这个点所在的对象的信息,并显示到点击的位置。
这非常有用,比如说一个想把一个房子显示在地图上,我们用鼠标一点,便知道这个房子里住的什么人,干什么的,以及其它相关信息。
同样的,我们还是使用 sharpmap 提供的 ajax 控件,环境和第一篇一模一样。
但是这里,我们要引用一个叫做 NetTopologySuite 的类库。
它经常和 SharpMap 一起使用,这次我们只使用其中的一个小部分,废话不多说,开始做。
这里我们使用
asp.net ajax 1.0,首先引用了 dll,并且拖上 scripmanager 并设置为 EnablePageMethodstrue,这样我们就可以在页面中写静态方法来实现 AJAX。
在 MapClicked 方法(AjaxMapControl 控件提供的方法,直接写在 js 中即可,表示单击的时候发生一些事情)中,我们调用我们写的 js,根据两个点来返回一个字符串。
这个字符串就是拼好的 html,直接显示出来。
function MapClickedeventobj var mousePos SharpMap_GetRelativePositionevent.clientXevent.clie ntYobj.container var pnt SharpMap_PixelToMapmousePos.xmousePos.yobj var field document.getElementByIddataContents //field.innerHTML quotYou clicked map at: quot pnt.x quotquot pnt.y GetDatapnt.x pnt.y 这个方法里面的 SharpMap_GetRelatiovePosition 和 SharpMap_PixelToMap 方法根据鼠标在屏幕上的坐标计算出鼠标点在地图上的坐标,再调用我们自己写的 GetData 方法即可。
在 GetData .