PathPointType浅析(C#)

 

GraphicsPath构造函数
        //
        
// 摘要:
        
//     使用指定的 System.Drawing.Drawing2D.PathPointType 和 System.Drawing.Point 数组初始化
        
//     System.Drawing.Drawing2D.GraphicsPath 类的新实例。
        
//
        
// 参数:
        
//   pts:
        
//     System.Drawing.Point 结构的数组,它定义组成此 System.Drawing.Drawing2D.GraphicsPath 的点的坐标。
        
//
        
//   types:
        
//     System.Drawing.Drawing2D.PathPointType 枚举元素的数组,它指定 pts 数组中各相应点的类型。
        public GraphicsPath(Point[] pts, byte[] types);

这是GraphicsPath的构造函数,其中types就是PathPointType类型的数组,那么PathPointType到底有什么秘密呢? 

PathPointType定义
    // 摘要:
    
//     指定 System.Drawing.Drawing2D.GraphicsPath 对象中点的类型。
    public enum PathPointType
    {
        
// 摘要:
        
//     System.Drawing.Drawing2D.GraphicsPath 对象的起始点。
        Start = 0,
        
//
        
// 摘要:
        
//     连线线段。
        Line = 1,
        
//
        
// 摘要:
        
//     立体贝塞尔曲线。
        Bezier3 = 3,
        
//
        
// 摘要:
        
//     默认贝塞尔曲线。
        Bezier = 3,
        
//
        
// 摘要:
        
//     遮盖点。
        PathTypeMask = 7,
        
//
        
// 摘要:
        
//     对应线段为虚线。
        DashMode = 16,
        
//
        
// 摘要:
        
//     路径标记。
        PathMarker = 32,
        
//
        
// 摘要:
        
//     子路径的终结点。
        CloseSubpath = 128,
    }

 1、PathPointType.Start

子路径的起始点。任何GraphicsPath中的点数组的第一个点的类型都为PathPointType.Start,即使你把它赋值为PathPointType.Line或PathPointType.Bezier也会被改为PathPointType.Start。

先给出一段测试函数,以后代码要用到:

测试GraphicsPath代码
//别忘记添加引用:
//using System.Drawing;
//using System.Drawing.Drawing2D;
private void Draw(GraphicsPath gp)
{
    GraphicsPath g 
= this.CreateGraphics();
    g.DrawPath(Pens.Red, gp);
    
int pl = gp.PathData.Points.Length;
    
for (int i = 0; i < pl; i++)
    {
        g.DrawString(gp.PathData.Types[i].ToString(), 
this.Font, Brushes.Blue, gp.PathData.Points[i]);
    }
}

 在按钮事件中引用下面的测试函数:  

代码
private void TestPathPointTypeStart()
{
    Point[] ps 
= new Point[] { new Point(00), new Point(0300), new Point(500300), new Point(5000) };
    
byte[] ts = new byte[] { (byte)PathPointType.Line, (byte)PathPointType.Bezier, (byte)PathPointType.Bezier, (byte)PathPointType.Bezier };
    GraphicsPath gp 
= new GraphicsPath(ps, ts);
    Draw(gp);
}

 运行后你会发现第一个点的类型不是1而是0,而第一个点最终作为Bezier曲线的端点渲染,这是有第二个点的类型决定的。

2、PathPointType.Line

不需要多解释,标记该点为直线的端点。

3、PathPointType.Bezier

标记该点为Bezier曲线的端点或控制点。一段Bezier曲线有4个点,如果描述多段Bezier曲线需要3N+1个点。如果连续的类型标记为PathPointType.Bezier的点的个数不为3N+1的话是无法建立GraphicsPath的!

前三种类型是用来定义路径的,路径的形状是由前三种类型决定的,每个点的类型必须是这三种之一!

后面几种则是用来标记的,他们不会影响路径的形状。

4、PathPointType.PathTypeMask

遮盖点。该值不应该用来定义GraphicsPath,它其实是个掩码,对于任何一个PathPointType类型的变量,将它与PathPointType.PathTypeMask进行"&"操作得到的就是该点形状属性(PathPointType.Start、PathPointType.Line或PathPointType.Bezier)。

看一下这段测试代码:

测试PathTypeMask
private void TestPathPointTypePathTypeMask()
{
    GraphicsPath gp 
= new GraphicsPath();
    gp.AddString(
""this.Font.FontFamily, 0512new Point(00), StringFormat.GenericDefault);
    Draw(gp);
    
string s = "";
    
foreach (byte b in gp.PathTypes)
    {
        s 
+= b & (byte)PathPointType.PathTypeMask;
        s 
+= ",";
    }
    MessageBox.Show(s);
}

 窗体上显示的是点的实际类型值,你可以发现有131这样的值,它是PathPointType.Bezier与PathPointType.CloseSubpath的和,表示该点是Bezier曲线而且还是子路径的结束点。而弹出的对话框上显示的是进行"&"操作后得到的。

5、PathPointType.DashMode

标记对应线段为虚线。必须和前三个类型一起使用,如PathPointType.Bezier|PathPointType.DashMode;如果单独使用PathPointType.DashMode运行将不会有结果。但在实际使用时,GDI+并不会将对应线段渲染为虚线,我觉得该标记只是个摆设,建议大家忽视。

6、PathPointType.PathMarker

路径标记点。同样必须和前三个类型一起使用。使用GraphicsPathIterator类的NextMarker方法可以抽取任意两个标记间的路径。看一下例子:

PathMarker示例
private void TestGraphicsPathIterator()
{
    GraphicsPath gp 
= new GraphicsPath();
    gp.AddRectangle(
new Rectangle(5050300300));
    gp.AddLines(
new Point[] { new Point(100100), new Point(500100), new Point(200300) });
    gp.SetMarkers();
    gp.AddCurve(
new Point[] { new Point(100100), new Point(60200), new Point(200360) });
    gp.CloseFigure();
    gp.AddEllipse(
new Rectangle(00100100));
    gp.SetMarkers();
    gp.AddLine(
new Point(90100), new Point(300270));
    Draw(gp);
    
//GraphicsPathIterator gpi = new GraphicsPathIterator(gp);
    
//int start = 0;
    
//int end = 0;
    
//int count = 0;
    
//count = gpi.NextMarker(out start, out end);//这行代码就是识别PathMarker的,抽取当前PathMarker到下一个PathMarker之间的路径。执行一次表示抽取第一个点到首次用PathMarker标识的点之间的路径。你可以在执行一次试试!
    
//PointF[] points = new PointF[count];
    
//byte[] types = new byte[count];
    
//gpi.CopyData(ref points, ref types, start, end);
    
//GraphicsPath gp2 = new GraphicsPath(points, types);
    
//this.CreateGraphics().Clear(this.BackColor);
    
//Draw(gp2);
}

 首先,运行后显示所有的路径。

然后把注释去掉,执行所有的语句,运行后显示一部分路径。

最后把count = gpi.NextMarker(out start, out end);执行两次(复制一行就行!),运行后显示另一部分路径。

解释一下上述代码:

添加一个矩形—>添加一组线段—>设置标记点—>添加一段曲线—>封闭曲线—>添加一个椭圆—>设置标记点—>添加一直线

这是完整的建立Path的过程,Path会认为把第一个点是标记点,所以执行一次NextMarker方法,将抽取矩形和一组线段,再执行一次NextMarker方法,将抽取封闭曲线和椭圆。

7、PathPointType.CloseSubpath

前面已经提过,标记子路径的结束点。如果一个路径有多个子路径,每个子路径的最后一点要用CloseSubpath标识,当然它也必须和前三种类型一起使用。使用GraphicsPathIterator类的NextSubpath方法可以抽取任意一个子路径,使用方法类似NextMarker,这里不再给出代码了。

 

本文就当入门,相信大家已经对PathPointType有了一定的了解,其实GraphicsPathIterator是一个很有用的类,它封装了很多对PathPointType处理的方法,建议大家花时间研究一下!

推荐参考书籍《精通GDI+编程》,示例代码是C++,不过原理都一样。

 

不小心在哪点了隐藏,害得文章有一段不能显示,搞了半天,郁闷。睡觉!

 

posted @ 2010-02-23 23:05  火必烈  阅读(1655)  评论(0编辑  收藏  举报