基于.NET 2.0 的 GIS 开源项目 SharpMap 分析手记(一)
SharpMap 介绍: SharpMap 是一个“小巧可爱”的基于.net 2.0 使用
C#开发的 Map 渲染类库,可以渲染各类 GIS 数据(目前支持 ESRI Shape 和
PostGIS 格式),可应用于桌面和 Web 程序。
其网址为:http://sharpmap.iter.dk/ 和
http://www.codeplex.com/SharpMap
SharpMap 的发布许可(License)为 GNU General Public License,
开发者为 Morten Nielsen(http://www.iter.dk/)。目前的稳定版本为
0.8(9.0beta 已发布),代码行数近 10000 行,实现了以下功能:
①支持的数据格式:
PostGreSQL/PostGIS,ESRI Shapefile
支持 WMS layers
支持 ECW 和 JPEG2000 栅格数据格式
②Windows Forms 控件,可以移动和缩放
③通过 HttpHandler 支持 ASP.net 程序
④点、线、多边形、多点、多线和多多边形等几何类型和几何集合
(GeometryCollections)等 OpenGIS Simple Features
Specification
⑤可通过 Data Providers(增加数据类型支持)、Layer Types(增
加层类型)和 Geometry Types 等扩展
⑥图形使用 GDI+渲染,支持 anti-aliased 等
⑦专题图
上面这段话是根据马兄的 BLOG 整理的,如果不希望我引用请马兄告知我删
除。
下面就是实用的 STEP BY STEP。
(1)下载 VS .NET 2005
由于 SharpMap 基于.NET 2.0,为了分析 SharpMap,首先要作的就是
下载一个 VS .NET 2005,这个比较大,估计有 1.6G,所以建议找个速度快点
的网站或者…
(2)安装 VS .NET 2005
还算比较好装,我装的时候没碰到什么问题,一次成功;
(3)设置 IIS ASP.NET 为 2.0
这点必须注意,因为默认的 IIS ASP.NET 为 1.1(我安装操作系统的是
Windows Server 2003);
做法是打开 IIS 信息服务管理器,在“默认网站”上单击右键选择“属性”,
弹出如下对话框,在 ASP.NET 页设置 ASP.NET 的版本为 2.0.50727;
(4)下载 SharpMap
到 http://www.codeplex.com/SharpMap 去下载一个 SharpMap,我
下载的是 0.9 版;
(5)解压和试运行
解压后可以看到一个 demo 文件夹,在 VS 2005 中打开 Simple.aspx,
在 VS 2005 中单击右键,选择“在浏览器中查看
基于.NET 2.0 的 GIS 开源项目 SharpMap 分析手记(二):源代码
解压下载的 0.9 版源代码,有两个文件夹:SharpMap 和 SharpMap.UI。
其中 SharpMap.UI 是用户界面相关命名空间,如窗体 Forms、Ajax 等。SharpMap
工程是主体,包括数据转换、坐标、数据、几何体、图层等命名空间,下面分别介绍:
SharpMap 命名空间,包括 Map 类,通过创建 Map 对象的实例来生成地图。Map 对象
由包含 Layer 对象组成 Layers 集合,通过 GetMap 方法来 Render 地图。
Converts 命名空间,提供数据转换服务。
CoordinateSystems 命名空间,提供坐标系统及其投影和转换。
Data 命名空间,提供对各种数据支持,现在包括 MSSQL 和 ShapeFile 支持。
Providers 名称空间,包括了 IProvider 接口和 Shape 文件、PostGIS 数据的读
取实现。该名称空间为 SharpMap 提供数据读(写)支持,通过面向接口的设计,可以比
较容易的增加各类数据格式。
Geometries 命名空间,包括了 SharpMap 要使用到的各种几何类及其接口类,例 如
点、线、面等类。是 SharpMap 的基础之一,所有几何对象都继承自 Geometry 这个抽象
类,其中定义了几何对象应该具备的公共操作,例如大小、 ID、外接矩阵、几何运算等等。
Layers 命名空间,提供各种图层支持,包括注记层、矢量层等。Layer 是一个抽象
类,实现了 ILayer 接口,Layer 目前有 3 个子类,分别是 VectorLayer、LabelLayer
和 WmsLayer,分别代 3 种不同数据类型的图层。
Rendering 命名空间,目前包括矢量渲染器类和几个专题图渲染器类,该类可以将几
何对象根据其 Style 设置渲染为一个 System.Drawing.Graphics 对象。
Styles 命名空间,该命名空间主要提供了图层的样式设置类,例如线样式、点样式、
填充样式等。
Utilities 名称空间包括 Algorithms 类(目前仅实现了一个方法);Providers
类,是 Provider 的一个 Helper,应用了反射机制;Surrogates 主要用于系统的 Pen
和 Brush 的序列化;Transform 提供了从图片坐标到地理坐标的互相变换,也即桌面 GIS
的二次开发中经常使用的屏幕坐标和地理坐标的转换,主要用于地图的渲染、交互操作等。
Utilities.SpatialIndexing 用于对象的空间索引。
Web 名称空间实现了 HttpHandler 和 Caching 类,用于网络环境。
Web 命名空间,包括对网络支持如 HTTP 等,Web.Wms 提供对 WMS 的支持。
SharpMap.UI 工程包括:
Forms 名称空间,包含 MapImage 控件,一个简单的 User Control(用户控件),
封装了 Map 类,用于 Windows Form 编程。
Web.UI.Ajax 提供对 Ajax 支持。
基于.NET 2.0 的 GIS 开源项目 SharpMap 分析手记(三):地图渲染分析
1 运行过程
我们通过实例来讲述 SharpMap 的运行过程和渲染(绘制)机制。首先打开
Simple.aspx,可知此页面有一组单选框(3 个,分别是放大、缩小和漫游)和一个图像
按钮,用于显示地图。它的代码在 Simple.aspx.cs 中。
打开 Simple.aspx.cs,在 Page_Load 函数中是页面初始化代码。可知地图生成分
两步:
1.1 初始化地图
myMap = MapHelper.InitializeMap(new
System.Drawing.Size((int)imgMap.Width.Value,(int)imgMap.Hei
ght.Value));
我们找到 MapHelper.InitializeMap 函数,发现地图的初始化分为以下几步:
(1)创建地图,创建图层
//Initialize a new map of size 'imagesize'
SharpMap.Map map = new SharpMap.Map(size);
//Set up the countries layer
SharpMap.Layers.VectorLayer layCountries = new
SharpMap.Layers.VectorLayer("Countries");
//Set the datasource to a shapefile in the App_data folder
layCountries.DataSource = new
SharpMap.Data.Providers.ShapeFile(HttpContext.Current.Serve
r.MapPath(@"~\App_data\countries.shp"), true);
(2)基本的图层显示设置
//Set fill-style to green
layCountries.Style.Fill = new SolidBrush(Color.Green);
//Set the polygons to have a black outline
layCountries.Style.Outline = System.Drawing.Pens.Black;
layCountries.Style.EnableOutline = true;
layCountries.SRID = 4326;
(3)加入图层到地图
//Add the layers to the map object.
//The order we add them in are the order they are drawn, so we add
the rivers last to put them on top
map.Layers.Add(layCountries);
map.Layers.Add(layRivers);
map.Layers.Add(layCities);
map.Layers.Add(layLabel);
map.Layers.Add(layCityLabel);
(4)地图放缩、背景、中心等设置
//limit the zoom to 360 degrees width
map.MaximumZoom = 360;
map.BackColor = Color.LightBlue;
map.Zoom = 360;
map.Center = new SharpMap.Geometries.Point(0,0);
1.2 绘制并生成地图
我们回到 Simple.aspx.cs 的 Page_Load 函数,发现下一步调用 GenerateMap();
//This is the initial view of the map. Zoom to the extents of the
map:
//myMap.ZoomToExtents();
//or center on 0,0 and zoom to full earth (360 degrees)
//myMap.Center = new SharpMap.Geometries.Point(0,0);
//myMap.Zoom = 360;
//Create the map
GenerateMap();
在同一文件中,GenerateMap()包含以下两步:
(1)保存当前地图状态
//Save the current mapcenter and zoom in the viewstate
ViewState.Add("mapCenter", myMap.Center);
ViewState.Add("mapZoom", myMap.Zoom);
(2)渲染地图
//Render map
System.Drawing.Image img = myMap.GetMap();
string imgID = SharpMap.Web.Caching.InsertIntoCache(1, img);
imgMap.ImageUrl = "getmap.aspx?ID=" +
HttpUtility.UrlEncode(imgID);
它的核心就是通过 myMap.GetMap()创建了一个地图图片。我们来看看这个 GetMap()
函数。
在 Map.cs 文件中找到 GetMap()函数,它分为以下几步:
①创建图像,得到图像绘制环境参数
System.Drawing.Image img = new
System.Drawing.Bitmap(this.Size.Width, this.Size.Height);
System.Drawing.Graphics g =
System.Drawing.Graphics.FromImage(img);
g.Transform = this.MapTransform;
g.Clear(this.BackColor);
g.PageUnit = System.Drawing.GraphicsUnit.Pixel;
②绘制图层
int SRID = (Layers.Count > 0 ? Layers[0].SRID : -1); //Get the SRID
of the first layer
for (int i = 0; i < _Layers.Count; i++)
{
if (_Layers.Enabled && _Layers.MaxVisible >= this.Zoom &&
_Layers.MinVisible < this.Zoom)
_Layers.Render(g, this);
}
关键在于_Layers.Render(g, this),它是ILayer 接口的一个函数,我们找
VectorLayer 的实现来看看,它分为两种,一种是专题地图,一种是非专题地图绘制。
对于专题地图,它针对 SharpMap.Data.FeatureDataTable 的每一 个 feature
进行绘制,先绘制其外框,再绘制内部几何体。对于非专题地图,它针对
this.DataSource.GetGeometriesInView(envelope)得到的几何体进行绘制,也是
先绘制其外框,再绘制内部几何体。最后的绘制工作都调用
SharpMap.Rendering.VectorRenderer 类的函数完成。
SharpMap.Rendering.VectorRenderer 类包含绘制注记、线串、多线串、多点、多
多边形、点、多边形等。
绘制好图层后将激发 LayerRendered 事件:
if(LayerRendered!=null) LayerRendered(this, g); //Fire event
绘制好地图后将激发 Map 类的 MapRendered 事件:
if (MapRendered != null) MapRendered(g); //Fire render event
2SharpMap.Rendering.VectorRenderer 的各个函数具体分析现在我们对渲染地
图的全过程已经有了个总体概念和初步理解,下面来具体看一下
SharpMap.Rendering.VectorRenderer 的各个函数:
2.1 DrawLabel
///
/// Renders a label to the map.
///
///
Graphics reference
///
Label placement
///
Offset of label in screen
coordinates
///
Font used for rendering
///
Font forecolor ///
Background color
///
Color of halo
///
Text rotation in
degrees
///
Text to render
///
Map reference
public static void DrawLabel(System.Drawing.Graphics g,
System.Drawing.PointF LabelPoint, System.Drawing.PointF Offset,
System.Drawing.Font font, System.Drawing.Color forecolor,
System.Drawing.Brush backcolor, System.Drawing.Pen halo, float
rotation, string text, SharpMap.Map map)
这里面要注意的是这是绘制使用的函数是 DrawPath 和 FillPath,而且是作者从
DrawString 改进的,可能是为了绘制过程的统一,因为其它几何体的具体绘制也使用
DrawPath。
if (halo != null)
g.DrawPath(halo, path);
g.FillPath(new System.Drawing.SolidBrush(forecolor), path);
//g.DrawString(text, font, new
System.Drawing.SolidBrush(forecolor), LabelPoint.X, LabelPoint.Y);
2.2 DrawLineString
///
/// Renders a LineString to the map.
///
///
Graphics reference
///
LineString to render
///
Pen style used for rendering
///
Map reference
public static void DrawLineString(System.Drawing.Graphics g,
Geometries.LineString line, System.Drawing.Pen pen, SharpMap.Map
map)
这个函数很简单,也是采用 DrawPath 进行具体绘制。
2.3 DrawMultiLineString
///
/// Renders a MultiLineString to the map.
///
///
Graphics reference
///
MultiLineString to be rendered
///
Pen style used for rendering
///
Map reference
public static void DrawMultiLineString(System.Drawing.Graphics
g,Geometries.MultiLineString lines, System.Drawing.Pen
pen,SharpMap.Map map)
它通过循环调用 DrawLineString 来进行绘制。
2.4 DrawMultiPoint
///
/// Renders a to the
map.
///
///
Graphics reference
///
MultiPoint to render
///
Symbol to place over point
///
The amount that the symbol should
be scaled. A scale of '1' equals to no scaling
///
Symbol offset af scale=1
///
Symbol rotation in degrees
///
Map reference
public static void DrawMultiPoint(System.Drawing.Graphics g,
Geometries.MultiPoint points, System.Drawing.Bitmap symbol, float
symbolscale, System.Drawing.PointF offset, float rotation,
SharpMap.Map map)
它通过循环调用 DrawPoint 来进行绘制。
2.5 DrawMultiPolygon
///
/// Renders a multipolygon byt rendering each polygon in the
collection by calling DrawPolygon.
///
///
Graphics reference
///
MultiPolygon to render
///
Brush used for filling (null or transparent
for no filling)
///
Outline pen style (null if no
outline)
///
Specifies whether polygon clipping should
be applied
///
Map reference
public static void DrawMultiPolygon(System.Drawing.Graphics g,
Geometries.MultiPolygon pols, System.Drawing.Brush brush,
System.Drawing.Pen pen, bool clip, SharpMap.Map map)
它通过循环调用 DrawPolygon 来进行绘制。
2.6 DrawPoint
///
/// Renders a point to the map.
///
///
Graphics reference
///
Point to render
///
Symbol to place over point
///
The amount that the symbol should
be scaled. A scale of '1' equals to no scaling
///
Symbol offset af scale=1
///
Symbol rotation in degrees
///
Map reference
public static void DrawPoint(System.Drawing.Graphics g,
SharpMap.Geometries.Point point, System.Drawing.Bitmap symbol, float
symbolscale, System.Drawing.PointF offset, float rotation,
SharpMap.Map map)
其中,symbol 参数为一个位图,代表点的符号,这说明 SharpMap 暂时只支持位图
符号,不支持矢量符号绘制。最终绘制调用 DrawImage。
2.7 DrawPolygon
///
/// Renders a polygon to the map.
///
///
Graphics reference
///
Polygon to render
///
Brush used for filling (null or transparent
for no filling)
///
Outline pen style (null if no
outline)