• SharpMap介绍及源码分析


    本文发表于《3sNews新闻周刊》第一期,有删改,请勿转载。

    SharpMap是一个基于.net 2.0使用C#开发的Map渲染类库,可以渲染各类GIS数据(目前支持ESRI Shape和PostGIS格式),可应用于桌面和Web程序。

    其网址为:http://sharpmap.iter.dk/

    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等
    专题图

    可以看出,SharpMap目前可以算是一个实现了最基本功能的GIS系统,但一些很重要的功能,例如投影,比例尺,空间分析,图形的属性信息,查询检索等等,还没有或者还在开发中。一个好消息是,作者在SharpMap的网站写到:Diego Guidi(NetTopologySuite的开发者)已经创建了一个SharpMap和NTS之间的一个连接,这样,就可以在SharpMap中使用NTS的空间变换、缓冲区等功能。

    笔者之所以在这里分析ShrapMap,出于以下原因:

          SharpMap足够小(小于10000行),且具备了一个GIS软件的基本功能,容易下手;
          基于.net和C#开发;
          开放源码(不开放就没有办法分析,废话);
          SharpMap还在开发中,可以通过跟踪其源码学习提高。

    一项技术或者一个工具,知其然和知其所以然,对于应用的深度和熟练程度还是具有很大的影响,特别是程序开发。分析SharpMap,不一定是要使用SharpMap,是希望通过分析SharpMap,可以了解一个GIS系统的纵剖面,从而可以更好的进行GIS的应用和开发。

    源码结构

    以下是SharpMap在VS 2005下的Class视图和Solution视图,可以看出SharpMap由SharpMap和其他14个次级名称空间组成,其中SharpMap名称空间下的Map类为这个系统的核心所在。



    Map类,位于SharpMap命名空间下,通过创建Map对象的实例来生成地图。Map对象由包含Layer对象组成Layers集合,通过GetMap方法来Render地图。

    Converts名称空间,提供数据转换服务。

    Forms名称空间,包含MapImage控件,一个简单的User Control(用户控件),封装了Map类,用于Windows Form编程。

    Geometries名称空间,包括了SharpMap要使用到的各种几何类及其接口类,例如点、线、面等类。

    是SharpMap的基础之一,所有几何对象都继承自Geometry这个抽象类,其中定义了几何对象应该具备的公共操作,例如大小、ID、外接矩阵、几何运算等等。
     
    Layers名称空间,包括了ILayer接口,Layer集合类等,代表地图的图层。
     
    Layer是一个抽象类,实现了ILayer接口,Layer目前有3个子类,分别是VectorLayer、LabelLayer和WmsLayer,分别代3种不同数据类型的图层。

    Providers名称空间,包括了IProvider接口和Shape文件、PostGIS数据的读取实现。该名称空间为SharpMap提供数据读(写)支持,通过面向接口的设计,可以比较容易的增加各类数据格式。

    Rendering名称空间,目前包括矢量渲染器类和几个专题图渲染器类,该类可以将几何对象根据其Style设置渲染为一个System.Drawing.Graphics对象。

    Styles名称空间,该名称空间主要提供了图层的样式设置类,例如线样式、点样式、填充样式等.
     
    Utilities名称空间包括Algorithms类(目前仅实现了一个方法);Providers类,是Provider的一个Helper,应用了反射机制;Surrogates主要用于系统的Pen和Brush的序列化;Transform提供了从图片坐标到地理坐标的互相变换,也即桌面GIS的二次开发中经常使用的屏幕坐标和地理坐标的转换,主要用于地图的渲染、交互操作等。

    Utilities.SpatialIndexing用于对象的空间索引,我们后面还会继续介绍,Web名称空间实现了HttpHandler和Caching类,用于网络环境。

    运行机制

    通过剖析其名称空间,我们对SharpMap源码的结构和组成有了大概的了解,下来我们通过上面的应用实例来剖析其运行机制。

    SharpMap.Map myMap = new SharpMap.Map(picMap.Size);

    这句代码创建了一个新的Map的对象,Map对象包括了中点、大小、缩放比例、图层等字段,Layers集合对象包括了地图的各个图层,可以通过Layers.Add方法增加新的图层,通过GetLayerByName方法返回某个图层。缩放等方法是通过Center和Zoom属性来控制的。当地图图层修改和地图渲染后会触发相应的事件。

    接着就需要新建不同的Layer对象,设置其属性和数据源以及样式。例如:

    SharpMap.Layers.VectorLayer myLayer = new SharpMap.Layers.VectorLayer("My layer");
    string ConnStr = "Server=127.0.0.1;Port=5432;User Id=postgres;Password=password;Database=myGisDb;";
    //创建图层的数据源
    myLayer.DataSource = new SharpMap.Providers.PostGIS(ConnStr, "myTable", "the_geom", 32632);

    不同的Providers对象,例如PostGIS或者Shape对象负责打开相应的空间数据集,读取数据,返回部分或者全部的空间对象。

    接着就需要设置Layer的样式,例如填充、线形等属性。目前,Style对象只是简单的封装了System.Drawing.Pen、System.Drawing.Brush、System.Drawing.Bitmap等对象。并增加图层到Map的Layers集合:

    myMap.Layers.Add(myLayer);

    我们可以通过设置Map的Center、Zoom、Size等属性来进行Map操作,例如缩放、平移等操作,例如封装Map对象为一个User Control控件,主要的动作就是操作Map的各个属性。

    最后,我们就可以通过GetMap对象返回一个System.Drawing.Image对象,代表目前的地图,用于显示或输出:

    System.Drawing.Image imgMap = myMap.GetMap(); //Renders the map

    GetMap是整个SharpMap的核心之一,我们来一步步剖析其流程。

    System.Drawing.Image img = new System.Drawing.Bitmap();
    System.Drawing.Graphics g 
    = System.Drawing.Graphics.FromImage(img);
    g.Clear(
    this.BackColor);
    foreach (SharpMap.ILayer layer in this.Layers)
    {    
    if(layer.Enabled && layer.MaxVisible>=this.Zoom &&
        layer.MinVisible
    <this.Zoom)
            layer.Render(g,
    this);
    }

    if (MapRendered != null) MapRendered(g); //Fire render event
    g.Dispose();
    return img;

    以上代码就是GetMap的全部代码,首先创建一个System.Drawing.Image对象,然后为其创建一个System.Drawing.Graphics对象,通过这个对象来渲染地图到这个Image对象,最后返回这个对象。

    其核心在于循环所有图层,如果其在显示范围之内,则调用Layer对象的Render方法,渲染这个图层。

    抽象类Layer中的Render方法为:

    if(LayerRendered!=null) LayerRendered(this, g);

    VectorLayer子类的Render方法为:

    g.SmoothingMode = this.SmoothingMode;
     
    List
    <SharpMap.Geometries.Geometry> features = this.DataSource.GetFeaturesInView(map.Envelope);
    //Linestring outlines is drawn by drawing the layer once with a thicker line
    //before drawing the "inline" on top.
    if (this.Style.EnableOutline)
    {
        
    foreach (SharpMap.Geometries.Geometry feature in features)
        
    {
            
    //首先绘制所有图形对象的线轮廓
            
        }

    }

     
    //double i = 0;
    foreach (Geometries.Geometry feature in features)
    {
        
    switch (feature.GeometryType)
        
    {
            
    //根据不同的图形绘制其
            
        }

    }

    base.Render(g,map);

    这段代码首先根据地图的显示范围,获取范围内的所有对象:GetFeaturesInView,然后逐次绘制不同这些对象。绘制对象时,调用了SharpMap.Rendering对象的不同方法。在SharpMap.Rendering对象中,不同几何对象的绘制方法最终调用了.net的System.Drawing中的GDI+的绘制方法,完成地图的绘制。

    需要说明的是不同的数据源的GetFeaturesInView方法实现方法是不同的,目前版本的Shape数据源的Provider是使用了空间索引算法,PostGIS数据源则通过PostGIS的空间索引接口来获取需要的数据。

    系统效率的好坏,基本上就在于这里,一个是如何获取视图内的空间对象,关键在于空间索引;一个是渲染机制,例如使用DirectX加快渲染。

    这样,我们就基本完成了对SharpMap的剖析。SharpMap是一个刚刚启动不久的项目,开发者到目前为止只有一人,所以,实现的功能有限,有些设计也不是很成熟,例如缺乏空间分析和检索功能,但完全可以作为一个非常好的教学系统来使用。

    从作者Morten Nielsen了解到,该项目是从2005年夏天开始的,目的是:

    It was a good case for learning some of the new .NET 2.0 features and for getting "under the hood" of many of the GIS-related algorithms needed, like spatial indexing, spatial translations and topology rules.
    通过项目,可以学习.net 2.0的一些新的特性,而且可以了解GIS相关的一些底层算法,例如空间索引、空间变换、拓扑规则等。

    从中我们是否可以看到对技术的一种不同的态度,少一些空谈,多一些务实,这是笔者个人的感受。


    后续文章:
    SharpMap深度分析:地图渲染、坐标和比例尺
    SharpMap深度分析:地图数据Provider

  • 相关阅读:
    STL学习笔记数值算法
    FreeTextBox使用
    IOS 通过ObjectiveC读取、解析Excel
    在C#中使用访问者(Visitor)模式对组合(Composite)对象进行验证
    监测ASP.NET应用程序性能最简单的方法
    Web开发常见的几个漏洞解决方法
    FTP文件操作之下载文件
    你所需要知道的一些git 的使用命令:历史
    C#中Hashtable、Dictionary详解以及写入和读取对比
    日志组件:log4j、logback、commonlogging
  • 原文地址:https://www.cnblogs.com/maweifeng/p/337181.html
Copyright © 2020-2023  润新知