最近公司想在一个产品上加一个电子地图的功能,让我有机会接触到GIS领域。这几年国内的GIS技术也发展的很快,但是相关的技术文档还是很缺乏,都是英文的。我的文笔不好,写的东西也很浅显,但是希望能给看文章的一点点帮助,我就心满意足了。

  我用的 SharpMap是一个开源的Gis项目,功能还可以,最大的特点就是简单易用,适合刚刚接触GIS技术的朋友。同时还使用了MapWindow GIS来帮助画地图,使用NetTopologySuite来完善一些sharpmap没有提供或者功能不全的地方。MapWindow GIS使用起来不是很方便,熟悉了就容易了。关于软件的使用我就不再赘述,大家有问题可以跟帖,我会及时回复。

  这次我们根据demo先了解一下如何show一个地图。这是最基本的步骤,也比较简单,希望能对刚入门的同学有所帮助。

  我们使用SharpMap.UI.dll中的ajax控件 

 <smap:AjaxMapControl width="1600px" Height="600px" id="ajaxMap" runat="server"
 OnClickEvent="MapClicked" onmouseout="toolTip();"; OnViewChange="ViewChanged" CssClass="Ly"    UseCache="false"
                        OnViewChanging="ViewChanging" ZoomSpeed="1" />

  来展示地图,主要代码分析如下:

  首先,初始化地图

  Initialize Map    

    public static SharpMap.Map InitializeMap(System.Drawing.Size size)
        {
            HttpContext.Current.Trace.Write("Initializing map");

            //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.Server.MapPath(@"~App_datacountries.shp"), true);

            //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;

            //Set up a river layer
            SharpMap.Layers.VectorLayer layRivers = new SharpMap.Layers.VectorLayer("Rivers");
            //Set the datasource to a shapefile in the App_data folder
            layRivers.DataSource = new SharpMap.Data.Providers.ShapeFile(HttpContext.Current.Server.MapPath(@"~App_datarivers.shp"), true);
            //Define a blue 1px wide pen
            layRivers.Style.Line = new Pen(Color.Blue, 1);
            layRivers.SRID = 4326;

            //Set up a river layer
            SharpMap.Layers.VectorLayer layCities = new SharpMap.Layers.VectorLayer("Cities");
            //Set the datasource to a shapefile in the App_data folder
            layCities.DataSource = new SharpMap.Data.Providers.ShapeFile(HttpContext.Current.Server.MapPath(@"~App_datacities.shp"), true);
            //Define a blue 1px wide pen
            //layCities.Style.Symbol = new Bitmap(HttpContext.Current.Server.MapPath(@"~App_dataicon.png"));
            layCities.Style.SymbolScale = 0.8f;
            layCities.MaxVisible = 40;
            layCities.SRID = 4326;

            //Set up a country label layer
            SharpMap.Layers.LabelLayer layLabel = new SharpMap.Layers.LabelLayer("Country labels");
            layLabel.DataSource = layCountries.DataSource;
            layLabel.Enabled = true;
            layLabel.LabelColumn = "Name";
            layLabel.Style = new SharpMap.Styles.LabelStyle();
            layLabel.Style.ForeColor = Color.White;
            layLabel.Style.Font = new Font(FontFamily.GenericSerif, 12);
            layLabel.Style.BackColor = new System.Drawing.SolidBrush(Color.FromArgb(128, 255, 0, 0));
            layLabel.MaxVisible = 90;
            layLabel.MinVisible = 30;
            layLabel.Style.HorizontalAlignment = SharpMap.Styles.LabelStyle.HorizontalAlignmentEnum.Center;
            layLabel.SRID = 4326;
            layLabel.MultipartGeometryBehaviour = SharpMap.Layers.LabelLayer.MultipartGeometryBehaviourEnum.Largest;

            //Set up a city label layer
            SharpMap.Layers.LabelLayer layCityLabel = new SharpMap.Layers.LabelLayer("City labels");
            layCityLabel.DataSource = layCities.DataSource;
            layCityLabel.Enabled = true;
            layCityLabel.LabelColumn = "Name";
            layCityLabel.Style = new SharpMap.Styles.LabelStyle();
            layCityLabel.Style.ForeColor = Color.Black;
            layCityLabel.Style.Font = new Font(FontFamily.GenericSerif, 11);
            layCityLabel.MaxVisible = layLabel.MinVisible;
            layCityLabel.Style.HorizontalAlignment = SharpMap.Styles.LabelStyle.HorizontalAlignmentEnum.Left;
            layCityLabel.Style.VerticalAlignment = SharpMap.Styles.LabelStyle.VerticalAlignmentEnum.Bottom;
            layCityLabel.Style.Offset = new PointF(3, 3);
            layCityLabel.Style.Halo = new Pen(Color.Yellow, 2);
            layCityLabel.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
            layCityLabel.SmoothingMode = SmoothingMode.AntiAlias;
            layCityLabel.SRID = 4326;
            layCityLabel.LabelFilter = SharpMap.Rendering.LabelCollisionDetection.ThoroughCollisionDetection;
            layCityLabel.Style.CollisionDetection = true;

            //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);


            //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);

            HttpContext.Current.Trace.Write("Map initialized");
            return map;
        }

在这段代码中,

   SharpMap.Layers.VectorLayer layCountries = new SharpMap.Layers.VectorLayer("Countries");
   layCountries.DataSource = new SharpMap.Data.Providers.ShapeFile(HttpContext.Current.Server.MapPath(@"~App_datacountries.shp"), true);

  这两句话定义并初始化了一个map的一个层。一个map可能包含多个层,我们对map进行操作,其实就是对map的各个层进行操作,比如说道路层,建筑层等等。根据业务的复杂程度,可能有很多个层。一般来说,每个层都有各自的抽象特征(一类对象),可以进行一样的操作。各个层组合起来,就是一个map.

  好,接着说初始化。这里为VectorLayer的构造函数提供了一个层的名称,然受设置了数据源。一个层的Datasource是一个IProvider类型的数据,而ShapeFile类正是实现了Iprovider接口的类。(这点很重要,以后有很多机会需要把一个datasource转换成ShapeFile)。

  接下来是对这个层进行着色,呵呵 就是这个层上的对象如何填充颜色。这里因为是刚刚开始,我们就用最简单的办法,设置了一个

layCountries.Style.Fill = new SolidBrush(Color.Green);

  这样,就把层上的对象都填充成了绿色。在以后的讲解中,我们会让大家了解到如何自定义theme,这样我们能根据实现设置的对象的类型填充不同的颜色,以实现自定义的样式,让地图多彩多姿。

  然后我们看到label层。每一个map的layer都有自己的label层。

   SharpMap.Layers.LabelLayer layLabel = new SharpMap.Layers.LabelLayer("Country labels");
   layLabel.DataSource = layCountries.DataSource;
   layLabel.Enabled = true;
   layLabel.LabelColumn = "Name";

  这里我们首先定义了一个label层,然后把countries层的datasource直接赋给label层的datasource就OK了。这样,这个新定义的label层就属于countries层了。然后我们给它制定一个labelColumn,这个是必须指定的。它表示countries层的每个对象应该显示什么内容。这个内容在ShapeFile(我们在MapWindow GIS中建立的shapefile文件)的attribute中进行增加和更新。

  我想有必要说一下地图的对象。

  地图上有很多点,线和多边形。这些都是对象。我们都可以对他们进行操作。每个对象有相应的属性,这些属性我们也可以添加,修改和删除。而上述的label的LabelColumn就是这些属性中的一个。我们在这里可以指定一个,也可以通过LabelStringDelegate来委托一个方法返回一个字符串(这个将在以后进行详细讲解)。

  OK,在设置了label的字体颜色,大小和背景色之后,有两个个属性是特别值得我们注意的。

  layLabel.MaxVisible = 90;
  ayLabel.MinVisible = 30;

  这两个值说明了我们在多大/多小的比例尺下可以看到这个label层。我就经常会忽略这个问题,以至于在放大或缩小比例尺的时候看不到label,也找不到原因。

  在初始化的最后,我们把所有的层都加到地图中来,在设置一下最大的比例尺,背景色和中心点,就可以了

   map.Layers.Add(layCountries);
   map.Layers.Add(layRivers);
   map.Layers.Add(layCities);
   map.Layers.Add(layLabel);
   map.Layers.Add(layCityLabel);
   
 
   //limit the zoom to 360 degrees width
   map.MaximumZoom = 360;
   map.BackColor = Color.LightBlue;

 

  最后,我们通过一个maphandler(ashx)把地图输出到页面上。

  System.Drawing.Bitmap img = (System.Drawing.Bitmap)map.GetMap();
  context.Response.ContentType = "image/png";
  System.IO.MemoryStream MS = new System.IO.MemoryStream();
  img.Save(MS, System.Drawing.Imaging.ImageFormat.Png);
  // tidy up 
  img.Dispose();
  byte[] buffer = MS.ToArray();
  context.Response.OutputStream.Write(buffer, 0, buffer.Length);

  这样,简单的地图就出来了。怎么样,有成就感吗?呵呵 

  这里的代码都来自www.codeplex.com/sharpmap的demo,我只是对其中一些代码进行了说明,有需要的可以去下载

  下次我们将自己做一些更好玩的东西,当我们点击地图上某个对象,显示出这个对象的若干信息,怎么样,酷吧?

posted on 2012-12-18 16:27  骑牛射雕  阅读(361)  评论(0编辑  收藏  举报