我想用颜色绘制多边形区域。
我知道我可以使用Symbolizer
来执行此操作,但我希望该区域闪烁(在计时器中更改它的颜色)并且使用symbolizer
似乎很慢。
我已经使用Map.OnPaint
事件来绘制点的彩色图像(在PointLayer
中)。
那么如何将多边形要素(在PolygonLayer
中)转换为System.Drawing.Region
,以便我可以使用Graphics类中的方法绘制该区域?
提前致谢。
答案 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;
}
}
}
}