DotSpatial:将多边形要素转换为System.Drawing.Region

时间:2013-12-03 22:07:30

标签: gis polygon point-in-polygon dotspatial

我想用颜色绘制多边形区域。

我知道我可以使用Symbolizer来执行此操作,但我希望该区域闪烁(在计时器中更改它的颜色)并且使用symbolizer似乎很慢。

我已经使用Map.OnPaint事件来绘制点的彩色图像(在PointLayer中)。

那么如何将多边形要素(在PolygonLayer中)转换为System.Drawing.Region,以便我可以使用Graphics类中的方法绘制该区域?

提前致谢。

1 个答案:

答案 0 :(得分:1)

这是一个演示。这是特定于多边形的,但应该让您了解如何将多边形转换为GraphicsPath,然后您可以使用它在图形对象上使用您选择的画笔/笔进行填充或绘制。这只是在一个相对简单的形状上测试,但它使用与MapPolygonLayer基本相同的绘图代码,所以它应该非常准确。如果您处于编辑模式,您可能希望直接从该功能获取顶点,而不是我获得它们的方式。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DotSpatial.Controls;
using DotSpatial.Data;
using DotSpatial.Symbology;

namespace WindowsFormsApplication3
{
    public partial class Form1 : Form
    {
        /// <summary>
        /// Timer for controlling flashing
        /// </summary>
        Timer timer1;

        /// <summary>
        /// True if the timer is actively flashing
        /// </summary>
        private bool timerEnabled;

        /// <summary>
        /// True if the 0 index shape should be colored yellow
        /// </summary>
        private bool highlighted;

        /// <summary>
        /// The layer with the polygon you wish to show flashing
        /// </summary>
        IMapFeatureLayer layer;

        /// <summary>
        /// Form constructor, initialize timer and paint event handler
        /// </summary>
        public Form1()
        {
            InitializeComponent();
            map1.Paint += map1_Paint;
            timer1 = new Timer();
            timer1.Interval = 1000;
            timer1.Tick += timer1_Tick;
        }

        /// <summary>
        /// Occurs when the timer ticks.  This changes the highlighting and forces the map to refresh itself.  This will not
        /// redraw all the other features, since those are cached.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void timer1_Tick(object sender, EventArgs e)
        {
            highlighted = !highlighted;
            map1.Invalidate();
        }

        /// <summary>
        /// Occurs when the map is painting.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void map1_Paint(object sender, PaintEventArgs e)
        {
            MapPolygonLayer pg = layer as MapPolygonLayer;

            // If the shape is highlighted, draw it here.
            if (pg != null && highlighted)
            {
                System.Drawing.Drawing2D.GraphicsPath borderPath = PolygonToGraphicsPath(e, pg, 0);
                e.Graphics.FillPath(Brushes.Yellow, borderPath);
                e.Graphics.DrawPath(Pens.Cyan, borderPath);
            }
        }

        /// <summary>
        /// Converts the polygon at index into a new shape.
        /// </summary>
        /// <param name="e">The paint event arguments from the paint event.</param>
        /// <param name="pg">The polygon layer</param>
        /// <param name="index">The integer zero based index of the shape to get</param>
        /// <returns></returns>
        private System.Drawing.Drawing2D.GraphicsPath PolygonToGraphicsPath(PaintEventArgs e, MapPolygonLayer pg, int index)
        {
            System.Drawing.Drawing2D.GraphicsPath borderPath = new System.Drawing.Drawing2D.GraphicsPath();

            // This controls the relationship between pixel and map coordinates
            MapArgs args = new MapArgs(map1.ClientRectangle, map1.PixelToProj(map1.ClientRectangle), e.Graphics);

            // These variables help define the offsets necessary for drawing from the args.
            double minX = args.MinX;
            double maxY = args.MaxY;
            double dx = args.Dx;
            double dy = args.Dy;

            // SoutherlandHodgman clipping is about preventing exceptions from points outside the bounds, while still keeping
            // the geometry the same inside the bounds.
            SoutherlandHodgman shClip = new SoutherlandHodgman(map1.ClientRectangle);
            ShapeRange shpx = pg.DataSet.ShapeIndices[index];

            // interleaved x/y values of all the shapes on the layer.
            double[] vertices = pg.DataSet.Vertex;
            for (int prt = 0; prt < shpx.Parts.Count; prt++)
            {
                PartRange prtx = shpx.Parts[prt];
                int start = prtx.StartIndex;
                int end = prtx.EndIndex;
                List<double[]> points = new List<double[]>();

                for (int i = start; i <= end; i++)
                {
                    double[] pt = new double[2];
                    pt[0] = (vertices[i * 2] - minX) * dx;
                    pt[1] = (maxY - vertices[i * 2 + 1]) * dy;
                    points.Add(pt);
                }
                // Actually do the SoutherlandHodgman clipping
                if (shClip != null)
                {
                    points = shClip.Clip(points);
                }
                // Prevent a lot of unnecessary drawing of duplicate pixels when zoomed out.
                List<Point> intPoints = DuplicationPreventer.Clean(points);
                if (intPoints.Count < 2)
                {
                    continue;
                }

                borderPath.StartFigure();
                Point[] pointArray = intPoints.ToArray();
                borderPath.AddLines(pointArray);
            }
            return borderPath;
        }

        /// <summary>
        /// When the first button is clicked, this will prompt the user to open a shapefile, and add it to the map.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            layer = map1.AddFeatureLayer();

        }

        /// <summary>
        /// when the second button is clicked the feature should start flashing.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            if (timerEnabled)
            {
                timer1.Stop();
                timerEnabled = false;
            }
            else
            {
                timer1.Start();
                timerEnabled = true;
            }

        }
    }
}