logo资料库

sharpmap教程.doc

第1页 / 共20页
第2页 / 共20页
第3页 / 共20页
第4页 / 共20页
第5页 / 共20页
第6页 / 共20页
第7页 / 共20页
第8页 / 共20页
资料共20页,剩余部分请下载后查看
SharpMap深度分析:地图渲染、坐标和比例尺
SharpMap学习(3)
SharpMap学习(1)
本文使用 Sharpmap 0.9。 Sharpmap 作为优秀的基于 vs2005 的 GIS 解决方案,大家也对其了解甚多,我就不 多说了。在实际使用中,特别是 web 控件,作者并没有暴露很多编程方法,本文基于此进 行讨论。 在项目开发中,我们希望在鼠标拖拽时起码要实现几个功能:平移、拉框缩放、拉框选 择。通过更改 Sharpmap.UI.dll 的方式修改,可以实现。 首先,增加鼠标拖拽选择模式属性 MouseMode,并增加 enum,代码形如: public enum eMouseMode { } Pan, Zoom, Select private eMouseMode _MouseMode; /**//// /// Set Mouse down,up, move event to pan or zoom mode /// [Category("Behavior")] [DefaultValue(0)] [Description("设置鼠标拖拽方式:即设置 Mousedown,Mousemove,Mouseup 事件 的处理方式。默认值为 Pan。")] 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_MouseDown(Up, Over)函数里面写代码了。 SharpMap 深度分析:地图数据 Provider Provider 或者 Provider 模式对于很多人应该都不陌生,在 DNN 和 Asp.net 2.0 中都大量 应用了 Provider 模式。目前主流的 GIS 平台的数据提供也应该基本上都是基于 Provider 这 样的模式,大家比较熟悉的应该是 SuperMap 提出的多源空间数据引擎的概念。 在 SharpMap 里,数据 Provider 是这样使用的: string ConnStr = "Server=127.0.0.1;Port=5432;UserId=postgres;Password=password;D atabase=myGisDb;"; myLayer.DataSource = new SharpMap.Providers.PostGIS(ConnStr, "myTable", "the_geo m", 32632); 而实际上,在 Layer 类里,DataSource 定义为:
public SharpMap.Data.Providers.IProvider DataSource { } ... 也就是说,这里的 Provider 是针对 IProvider 接口的,这样,对于不同的层,你可以指 定不同的数据源(使用不同的数据 Provider,而支持不同的数据格式)。下面是 Provider 接口的类图,定义了接口的属性和操作: 个人认为,Provider 的核心思想在于面向接口编程,也就是说通过接口定义需要的服务, 至于服务的实现,可以通过具体的方式来实现。就 GIS 数据引擎来说,就是定义对空间数 据需要的操作,例如打开、关闭、读取某个范围内的数据、检索、分析等等这些接口,然后 通过继承这个接口来实现对不同的数据的操作。例如对 Shape 文件的操作和对 PostGIS 文 件的操作是完全不同的,但其接口一致。而在系统内部,对数据的操作,例如放大缩小、变 换、显示,只需要针对接口编程,就可以实现支持不同的数据源。
这里的实现和 DNN 等的不同在于,DNN 是通过配置文件和反射机制,来实现不同的 P rovider 的更换,而无须更改代码实现,而 SharpMap 或其他 GIS 的类似实现是需要在开发 时指定使用的 Provider。 Provider 的实现还有一个比较重要的问题就是要操作的数据的定义,因为具体的 Provi der 的实现最终要将数据转换为系统内部的数据类型和结构,然后返回。 对于具体的 Geometry 的结构,基本上是在 OGC 的规范的基础上实现,对于这部分内 容,很多非 GIS 的面向对象的书也喜欢用这个来讲述类、对象、继承等概念,大家都很熟 悉,这里就不多说了。对 OGC 的 Simple Feature 实现比较好的一个.net 类库是 NTS(JT S 的.net 移植版本),目前正在看他的源码,后面会写一些自己的笔记。SharpMap 的一些 代码,看注释也是在 NTS 的基础上实现的。 SharpMap 的 Provider 没有定义数据的修改、编辑,从理论上讲,完全可以实现任意 数据的读取、修改,但实际上,数据的读取显示一般来说,实现难度不是很大,因为大家都 是点线面及其组合这样的对象;但由于内部结构,拓扑关系,修改就比较困难了。例如 Su perMap 的产品也只是可以只读读取一些其他格式的数据(如 MicroStation DGN,AutoCA D 数据),而没有修改功能。 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 < _MinimumZoom) _Zoom = _MinimumZoom; else if (value > _MaximumZoom) _Zoom = _MaximumZoom; else _Zoom = value; if (MapViewOnChange != null) MapViewOnChange(); } } 这个 Zoom 表示使用地图 Unit 表示的地图宽度。例如地图单位是 Km,那么如果目前 地图的宽度是 500Km,Zoom 就是 500。这个和 Mapinfo 中 Zoom 的概念是一致的。 那么在渲染的时候,就要对所有对象进行坐标转换,转换为要渲染的图片的坐标系统, 然后调用 GDI+进行渲染。 对于对象的渲染,定义在 Layer 的名称空间里,在 VectorLayer 类的 Render 方法里, 根据 Geometry 对象的层次依次遍历各个对象,然后调用 Rendering 名称空间的 VectorRe nderer 的各个方法来渲染不同的点、线、面等对象。 在渲染具体对象时,我们看到这些方法都调用了一个 TransformToImage 的方法,而这 个方法定义在不同的 Geometry 名称空间的不同类里,目的是由空间对象经过坐标变换后返 回一个.net 的绘图对象。 我们把这个流程整理如下:
Map 对象 GetMap 方法→GetMap 方法遍历其 Layer,调用 Layer 的 Render 方法→各 个 Layer 开始渲染自己,对于栅格和 WMS 层,返回范围内的图片即可,主要是 VectorLay er 的渲染→VectorLayer 调用自己 DataSource Provider 的 GetFeaturesInView 方法,返回 范围内的对象到一个列表→依次遍历列表的各个对象,调用 Rendering 名称空间的 Vector Renderer 的各个方法来渲染不同的点、线、面等对象→渲染这些对象前,调用几何对象的 TransformToImage 方法,返回一个.net 的绘图对象→GDI+根据 Style 渲染 在最后一步,各个对象调用的 TransformToImage 方法其实是逐次转换这个对象的各个 点。而点的坐标转换定义在 Utilities.Transform 下,有 2 个方法: public static System.Drawing.PointF WorldtoMap(SharpMap.Geometries.Point p, SharpMa p.Map map) 和 public static SharpMap.Geometries.Point MapToWorld(System.Drawing.PointF p, SharpMa p.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 = (float)Math.Round(((p.X - left) / pxSize), 0); result.Y = (float)Math.Round(((top - p.Y) / pxSize), 0); return result;
left 和 top 表示当前地图的左上角坐标,Height 是高度,需要通过 Zoom 和 Height 来 换算一下,也许写作 map.Zoom * (map.Size.Height / map.Size.Width)更好理解一点。px Size 相当于在最终的图片上的一个单位相当于 WCS 的多少单位,这样,(p.X - left) / px Size 就是横坐标,纵坐标由于图片 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 的 Un it 到地图,然后叠加显示。 这样的话,在显示(渲染)时,就需要对所有对象都要进行投影和尺度变换。虽然似乎 在打开数据的时候进行转换,但是由于对于空间数据库,一次打开所有数据已经越来越不可 能,而且对数据作分析的时候,如果数据打开时转换了数据的 Unit,那么分析结果也会出现 问题。因此,这类实现应该是在地图渲染时进行投影和变换。 SharpMap 学习(3) 我写的东西内容浅显,希望能给初学者一些帮助。至于深入研究 sharpmap 和 GIS 技术的 大牛,请不吝赐教,给我们这些菜鸟多一些指导。 今天我们接着来聊 sharpmap 的基本使用技巧,根据 attribute 来填充地图对象的颜色, 让用户更清晰的看到重点的业务对象对应在地图上的表示,以及如何自定义 label 层的显示 内容,字体的大小等。所以,今天的主题主要是自定义:自定义 theme,自定义 label 以及 label 字体。
首先,我们要为地图填充上不同的色彩,让他们看起来五颜六色,容易分辨。比如河流 和湖泊要填成蓝色,草地要填充上绿色,房子要填充上白色,道路要填充上青色等等。怎么 做呢?很简单,先看下代码: SharpMap.Rendering.Thematics.CustomTheme iTheme = new SharpMap.Rendering.The matics.CustomTheme(GetMyStyle); 在初始化 Map 的时候,加上上面的一行代码。它定义了一个自定义的 Theme 对象, 这个对象的构造函数需要传入一个我们自己写的方法(委托),这个方法里面具体说明了这 个 theme 是如何定义的,方法代码如下: private static SharpMap.Styles.VectorStyle GetMyStyle(SharpMap.Data.FeatureData Row row) ctorStyle(); yellow { } SharpMap.Styles.VectorStyle style = new SharpMap.Styles.Ve switch (row["Status"].ToString().ToLower()) { } case "available": //If status is interred, fill it with style.Fill = Brushes.Yellow; return style; default: style.Fill = Brushes.Green; return style; 这段简单代码大家都看得懂,这个委托定义需要传入一个 FeatureDataRow,它的作用就是 在初始化地图的过程中,每处理一个对象,都要到这个方法中来考察一下 feature 的值是多
分享到:
收藏