【问题标题】:Drawing a triangle with rounded corners绘制圆角三角形
【发布时间】:2014-12-10 15:00:19
【问题描述】:

这是我绘制三角形的代码:

Graphics y = CreateGraphics();
Pen yy = new Pen(Color.Red);
pictureBox1.Refresh();

Point x = new Point(Convert.ToInt32(textBox1.Text)*10, Convert.ToInt32(textBox2.Text)*10);
Point xx = new Point(Convert.ToInt32(textBox3.Text)*10, Convert.ToInt32(textBox4.Text)*10);
Point xxx = new Point(Convert.ToInt32(textBox5.Text)*10, Convert.ToInt32(textBox6.Text)*10);

Point[] u = { x, xx, xxx };
y = pictureBox1.CreateGraphics();
y.DrawPolygon(yy, u);

有什么办法可以解决这个问题吗?我在谷歌上读到了它,似乎只有一种圆矩形的方法,而不是三角形。

是否有任何命令可以为我执行此操作,或者我必须手动执行此操作?

感谢回复:)

【问题讨论】:

标签: c#


【解决方案1】:

不可能开箱即用。

您可以像这样创建圆角多边形:

  • 通过缩短(两端)您选择的像素数来更改每条线,现在 AB 线是 A1B1 线..
  • 创建一个GraphicsPath,它由这些线组成,并且在每对线之间有一条连接这些新端点的曲线
  • 为了更好地控制曲线,在原始角和新端点的连接之间添加一个点会有所帮助

对于三角形ABC,这意味着

  • 创建 A1、A2、B1、B2、C1、C2
  • 然后计算中间点A3、B3、C3
  • 最后添加到 GraphicsPath:
    • 线 A1B1、曲线 B1B3B2、线 B2C1、曲线 C1C3C2、线 C2A2 和曲线 A2A3A1。

下面是一段使用这种方法的代码:

要在 Paint 事件中使用的 GraphicsPaths:

GraphicsPath GP = null;

一种带有点列表的测试方法,组成一个三角形 - (*) 我们通过两个点过度绘制以使事情变得更容易;可以通过添加几行代码来添加最终的线条和曲线..

private void TestButton_Click(object sender, EventArgs e)
{
    Point A = new Point(5, 50);
    Point B = new Point(250, 100);
    Point C = new Point(50, 250);

    List<Point> points = new List<Point>();
    points.Add(A);
    points.Add(B);
    points.Add(C);
    points.Add(A);  // *
    points.Add(B);  // *

    GP = roundedPolygon(points.ToArray(), 20);

    panel1.Invalidate();
}

private void panel1_Paint(object sender, PaintEventArgs e)
{
   if (GP == null) return;
   using (Pen pen = new Pen(Brushes.BlueViolet, 3f))
          e.Graphics.DrawPath(pen, GP);
}


GraphicsPath roundedPolygon(Point[] points, int rounding)
{
    GraphicsPath GP = new GraphicsPath();
    List<Line> lines = new List<Line>();
    for (int p = 0; p < points.Length - 1; p++)
        lines.Add( shortenLine(new Line(points[p], points[p+1]), rounding) );
    for (int l = 0; l < lines.Count - 1; l++)
    {
        GP.AddLine(lines[l].P1, lines[l].P2);
        GP.AddCurve(new Point[] { lines[l].P2, 
                                  supPoint(lines[l].P2,points[l+1], lines[l+1].P1), 
                                  lines[l+1].P1 });

    }
    return GP;
}

// a simple structure
struct Line
{
    public Point P1; public Point P2;
    public Line(Point p1, Point p2){P1 = p1; P2 = p2;}
}

// routine to make a line shorter on both ends
Line shortenLine(Line line, int byPixels)
{
    float len = (float)Math.Sqrt(Math.Pow(line.P1.X - line.P2.X, 2)
                               + Math.Pow(line.P1.Y - line.P2.Y, 2));
    float prop = (len - byPixels) / len;
    Point p2 = pointBetween(line.P1, line.P2, prop);
    Point p1 = pointBetween(line.P1, line.P2, 1 - prop);
    return new Line(p1,p2);
}

// with a proportion of 0.5 the point sits in the middle
Point pointBetween(Point p1, Point p2, float prop)
{
    return new Point((int)(p1.X + (p2.X - p1.X) * prop), 
                     (int)(p1.Y + (p2.Y - p1.Y) * prop));
}

// a supporting point, change the second prop (**) to change the rounding shape! 
Point supPoint(Point p1, Point p2, Point p0)
{
    Point p12 = pointBetween(p1, p2, 0.5f);
    return pointBetween(p12, p0, 0.5f);       // **
}

例子:

【讨论】:

    【解决方案2】:

    我认为如果你适当地调整你的坐标并为你的Pen指定一个大于1的Width并将LineJoin属性设置为Rounded,你应该得到一个带圆角的三角形。

    【讨论】:

      【解决方案3】:

      我与数学斗争了一会儿,然后我有了一个想法……重叠的形状。

            <Canvas >
           <Polyline Margin="-1 0 0 0"
              Fill="{StaticResource Yellow}" 
              Points="3,14.5 17,14.5 10,2 3,14.5" 
              StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round"
              Stroke="Black" 
              StrokeThickness="4"/>
           <Polyline Margin="-1 0 0 0"
              Fill="{StaticResource Yellow}" 
              Stroke="{StaticResource Yellow}"
              Points="3,14.5 17,14.5 10,2 3,14.5"   
              StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round"
              StrokeThickness="3"/>
        </Canvas>
      

      【讨论】:

        【解决方案4】:
        public GraphicsPath DrawRoundedTriangle(RectangleF Rect, PointF point_A, PointF point_B, PointF point_C, float Radius)
            {
                Radius = (Rect.Height / 9f) * (Radius * 0.2f);
                float Diameter = Radius * 2f;
                float arcSize = (float)((Diameter / 2f) * Math.Sqrt(3.0));
                GraphicsPath path = new GraphicsPath();
                float sweep_angle = 120f; //Angle of Arc in the corners
                if (Radius == 0f)
                {
                    //Drawing of triangle without a rounded corner
                    path.AddLine(point_A, point_B);
                    path.AddLine(point_B, point_C);
                    path.AddLine(point_C, point_A);
                }
                else
                {
                    PointF[] array = new PointF[6];
        
                    array[0] = new PointF(point_A.X + Radius, point_A.Y - arcSize);  //Left Vertex point
                    array[1] = new PointF(point_B.X - Radius, point_B.Y + arcSize); //Top Vertex point
                    array[2] = new PointF(point_B.X + Radius, point_B.Y + arcSize); //Top Vertex point
                    array[3] = new PointF(point_C.X - Radius, point_C.Y - arcSize); //Right Vertex point
                    array[4] = new PointF(point_C.X - arcSize, point_C.Y);        //Right Vertex point
                    array[5] = new PointF(point_A.X + arcSize, point_C.Y);       //Left Vertex point
        
                    //Path Creation for Drawing
                    path.AddArc( (array[5].X - Radius), (array[5].Y - Diameter), Diameter, Diameter, 90f, sweep_angle);                 //Left Vertex
                    path.AddLine(array[0], array[1]);                                                                                   //Left Side Line
                    path.AddArc(array[1].X, ((array[1].Y - arcSize) + Radius), Diameter, Diameter, 210f, sweep_angle);                  //Top Vertex
                    path.AddLine(array[2], array[3]);                                                                                   //Right Side Line
                    path.AddArc((array[3].X - arcSize), (array[3].Y - (Diameter - arcSize)), Diameter, Diameter, 330f, sweep_angle);    //Right Vertex
                    path.AddLine(array[4], array[5]);                                                                                   //Bottom Line
                }
                path.CloseFigure();
                return path;
            }
        

        【讨论】: