• 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++,不过原理都一样。

     

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

  • 相关阅读:
    洛谷P2334
    线性基
    6.28 模拟赛解题报告
    左偏树
    哈夫曼树 Huffman
    CSP/NOIP 之前还需要学/复习的东西
    CF718C
    6.13 模拟赛结题报告
    关于模拟退火
    『笔记』网络流
  • 原文地址:https://www.cnblogs.com/huobilie/p/1672160.html
Copyright © 2020-2023  润新知