天天看點

DotSpatial空間測量圖層支援元素識别

轉載請注明來源:http://blog.csdn.net/caoshiying

以前寫的兩篇文章:

  距離測量:http://blog.csdn.net/caoshiying/article/details/51820983

  面積測量:http://blog.csdn.net/caoshiying/article/details/51860026

分别講解基于DotSpatial如何實作距離測量和面積測量,都沒有說明暗中存在的問題:不支援元素識别。以資料驅動的方式實作的空間測量圖層都屬于要素圖層。元素識别的時候會對空間測量圖層進行元素識别。這兩篇文章講解的空間測量圖層的實作方法都沒有為要素增加屬性資訊,元素識别會報錯。要解決這個問題,其實也很簡單——加上屬性資訊就可以了。

首先,給要素圖層命名并定義屬性資料結構,代碼如下:

LegendText = "面積測量圖層";
            DataSet.DataTable.Columns.Add("編号",typeof(int));
            DataSet.DataTable.Columns.Add("面積", typeof(string));
           

然後把面積計算方法從DrawMeasureInformation方法中提取出來,代碼如下:

public string GetMeasureString(IFeature feature)
        {
            var length = Math.Abs(CgAlgorithms.SignedArea(feature.Coordinates));
            var unit = "平方米";
            if (length > 1000000)
            {
                length /= 1000000;
                unit = "平方公裡";
            }
            var draws = length.ToString("F2") + unit;
            return draws;
        }
           

修改測量圖層對應的地圖函數,在添加空間要素的資訊的位置(在OnMouseDoubleClick方法中)把代碼改成如下所示:

coordinates.Add(coordinates.First());
            var coords = new List<Coordinate>();
            coords.AddRange(coordinates);
            var feature = new Feature(new Polygon(coords));
            measureAreaLayer.DataSet.AddFeature(feature);
            feature.ParentFeatureSet = measureAreaLayer.FeatureSet;
            var rows = measureAreaLayer.DataSet.DataTable.Rows;
            rows[rows.Count - 1].SetField<string>(1, measureAreaLayer.GetMeasureString(feature));
            rows[rows.Count - 1].SetField<int>(0, rows.Count);
            feature.UpdateEnvelope();
           

至此,空間測量實作了支援元素識别,效果如下所示:

DotSpatial空間測量圖層支援元素識别

空間測量的地圖函數完整 代碼如下:

using DotSpatial.Controls;
using DotSpatial.Data;
using DotSpatial.Topology;
using System;
using System.Data;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CustomLayer
{
    class MeasureAreaFunction : MapFunction
    {
        private MeasureAreaLayer measureAreaLayer;
        private List<Coordinate> coordinates;
        private Bitmap backBufferImage = null;
        private bool bMouseDown = false;
        private bool bDoubleClicked = false;
        private bool bMeasuring = false;

        internal MeasureAreaFunction(IMap mapCtrl, MeasureAreaLayer measureAreaLayer) :
            base(mapCtrl)
        {
            this.measureAreaLayer = measureAreaLayer;
            coordinates = new List<Coordinate>();
        }

        protected override void OnActivate()
        {
            base.OnActivate();
            coordinates.Clear();
            backBufferImage = new Bitmap(Map.ClientRectangle.Width, Map.ClientRectangle.Height, PixelFormat.Format32bppArgb);
            Map.MapFrame.SaveLayersToBitmap(new List<Extent>() { Map.ViewExtents }, backBufferImage, measureAreaLayer);
            bMouseDown = false;
            bDoubleClicked = false;
        }
        protected override void OnMouseDown(GeoMouseArgs e)
        {
            base.OnMouseDown(e);
            bMouseDown = true;
            bMeasuring = true;
        }

        protected override void OnMouseDoubleClick(GeoMouseArgs e)
        {
            base.OnMouseDoubleClick(e);
            if (coordinates.Count < 3)
                return;
            coordinates.Add(coordinates.First());
            var coords = new List<Coordinate>();
            coords.AddRange(coordinates);
            var feature = new Feature(new Polygon(coords));
            measureAreaLayer.DataSet.AddFeature(feature);
            feature.ParentFeatureSet = measureAreaLayer.FeatureSet;
            var rows = measureAreaLayer.DataSet.DataTable.Rows;
            rows[rows.Count - 1].SetField<string>(1, measureAreaLayer.GetMeasureString(feature));
            rows[rows.Count - 1].SetField<int>(0, rows.Count);
            feature.UpdateEnvelope();
            measureAreaLayer.DataSet.InitializeVertices();
            measureAreaLayer.Invalidate();
            backBufferImage.Dispose();
            backBufferImage = new Bitmap(Map.ClientRectangle.Width, Map.ClientRectangle.Height, PixelFormat.Format32bppArgb);
            Map.MapFrame.SaveLayersToBitmap(new List<Extent>() { Map.ViewExtents }, backBufferImage, measureAreaLayer);
            coordinates.Clear();
            bDoubleClicked = true;
            bMeasuring = false;
        }

        protected override void OnMouseUp(GeoMouseArgs e)
        {
            base.OnMouseUp(e);
            if (bDoubleClicked == false)
                coordinates.Add(e.GeographicLocation);
            bDoubleClicked = false;
            bMouseDown = false;
        }

        protected override void OnMouseMove(GeoMouseArgs e)
        {
            base.OnMouseMove(e);
            if (bMouseDown)
                return;
            if (!bMeasuring)
                return;
            var cs = new List<Coordinate>();
            var img1 = new Bitmap(Map.ClientRectangle.Width, Map.ClientRectangle.Height, PixelFormat.Format32bppArgb);
            var img2 = new Bitmap(Map.ClientRectangle.Width, Map.ClientRectangle.Height, PixelFormat.Format32bppArgb);
            cs.AddRange(coordinates);
            cs.Add(e.GeographicLocation);
            measureAreaLayer.SaveToBitmap(img1, Map.ClientRectangle, Map.ViewExtents, cs);
            var g2 = Graphics.FromImage(img2);
            g2.DrawImage(backBufferImage, 0, 0);
            g2.DrawImage(img1, 0, 0);
            var g = (Map as DotSpatial.Controls.Map).CreateGraphics();
            g.DrawImage(img2, 0, 0);
            g2.Dispose();
            g.Dispose();
            img1.Dispose();
            img2.Dispose();
        }


        protected override void OnDeactivate()
        {
            base.OnDeactivate();
            if (backBufferImage != null)
                backBufferImage.Dispose();
            coordinates.Clear();
            bMeasuring = false;
            bMouseDown = false;
            bDoubleClicked = false;
        }
    }
}
           

面積測量圖層完整代碼如下所示:

using DotSpatial.Controls;
using DotSpatial.Data;
using DotSpatial.Symbology;
using DotSpatial.Topology;
using DotSpatial.Topology.Algorithm;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CustomLayer
{
    class MeasureAreaLayer : MapPolygonLayer
    {
        private Font font = new Font("微軟雅黑", 14);
        public MeasureAreaLayer()
        {
            LegendText = "面積測量圖層";
            DataSet.DataTable.Columns.Add("編号",typeof(int));
            DataSet.DataTable.Columns.Add("面積", typeof(string));
        }

        public override void DrawRegions(MapArgs args, List<Extent> regions)
        {
            base.DrawRegions(args, regions);
            DrawMeasureInformation(FeatureSet.Features, args);
        }

        public void SaveToBitmap(Image img, Rectangle rc, Extent ext, List<Coordinate> coordinates)
        {
            var g = Graphics.FromImage(img);
            var a = new MapArgs(rc, ext, g);
            var p = new MapPointLayer() { Projection = MapFrame.Projection };
            var l = new MapLineLayer() { Projection = MapFrame.Projection };
            var n = new MapPolygonLayer() { Projection = MapFrame.Projection };
            var e = new List<Extent>() { ext };

            n.Symbolizer = Symbolizer;
            p.Symbolizer = new PointSymbolizer(Color.Blue, DotSpatial.Symbology.PointShape.Ellipse, 4);
            l.Symbolizer = new LineSymbolizer(Color.Blue, 1);
            if (coordinates.Count > 2)
                n.FeatureSet.Features.Add(new Feature(FeatureType.Polygon, coordinates));
            else if (coordinates.Count == 1)
                p.FeatureSet.AddFeature(new Feature(FeatureType.Point, coordinates));
            else if (coordinates.Count == 2)
                l.FeatureSet.AddFeature(new Feature(FeatureType.Line, coordinates));
            n.DrawRegions(a, e);
            p.DrawRegions(a, e);
            l.DrawRegions(a, e);
            if (coordinates.Count > 2)
                DrawMeasureInformation(n.FeatureSet.Features, a);
            n.Dispose();
            p.Dispose();
            l.Dispose();
            g.Dispose();
        }

        private void DrawMeasureInformation(IFeatureList features, MapArgs args)
        {
            if (double.IsInfinity(args.Dx) || double.IsInfinity(args.Dy) || double.IsInfinity(args.MinX) || double.IsInfinity(args.MaxY))
                return;

            foreach (var feature in features)
            {
                var original = args.Device.Transform;
                var shift = original.Clone();
                var tool = new CentroidArea();
                tool.Add(feature.Coordinates.ToArray());
                var coord = tool.Centroid;
                var pt = new PointF((float)((coord.X - args.MinX) * args.Dx), (float)((args.MaxY - coord.Y) * args.Dy));
                if (double.IsNaN(coord.X) || double.IsInfinity(coord.X))
                {
                    Console.WriteLine("已跳過一行。");
                    continue;
                }
                shift.Translate(pt.X, pt.Y);
                args.Device.Transform = shift;
                var draws = GetMeasureString(feature);
                args.Device.DrawString(draws, font, Brushes.Red, new PointF(-args.Device.MeasureString(draws, font).Width / 2, 0));
                args.Device.Transform = original;
                shift.Dispose();
            }
        }

        public string GetMeasureString(IFeature feature)
        {
            var length = Math.Abs(CgAlgorithms.SignedArea(feature.Coordinates));
            var unit = "平方米";
            if (length > 1000000)
            {
                length /= 1000000;
                unit = "平方公裡";
            }
            var draws = length.ToString("F2") + unit;
            return draws;
        }
    }
}