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( 0 0 ),  new  Point( 0 300 ),  new  Point( 500 300 ),  new  Point( 500 0 ) };
    
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,  0 512 new  Point( 0 0 ), 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( 50 50 300 300 ));
    gp.AddLines(
new  Point[] {  new  Point( 100 100 ),  new  Point( 500 100 ),  new  Point( 200 300 ) });
    gp.SetMarkers();
    gp.AddCurve(
new  Point[] {  new  Point( 100 100 ),  new  Point( 60 200 ),  new  Point( 200 360 ) });
    gp.CloseFigure();
    gp.AddEllipse(
new  Rectangle( 0 0 100 100 ));
    gp.SetMarkers();
    gp.AddLine(
new  Point( 90 100 ),  new  Point( 300 270 ));
    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++,不过原理都一样。

 

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

 

你可能感兴趣的:(Path)