Arc graphic quality

前端 未结 1 463
悲哀的现实
悲哀的现实 2020-12-04 03:08

Back here. Is there any way to improve the quality of the Arc?
I\'m using e.Graphics.SmoothingMode = SmoothingMode.AntiAlias

This is the piece of

相关标签:
1条回答
  • 2020-12-04 04:06

    The problem:
    When clipping a region of the current Graphics (Graphics.SetClip method), the resulting drawing loses quality, because the antialiasing effect generated by Graphics.SmoothingMode = SmoothingMode.AntiAlias is lost.

    A possible solution is to avoid clipping the region defined by the GraphicsPath used to design the arcs (GraphicsPath.AddPie method); this, however, leaves the lines of the Pie visible, compromising the shape.

    Another solution is to draw an ellipsis in the center of the arcs using the background color of the Canvas. Since the arcs are drawn using two rectangles, we can use the inner rectagle, inflate it (Rectangle.Inflate method) as needed (a fraction - Pen.Width / 2 - of the Pen size used for the ouline, usually).

    This allows to delete the artifacts generated by the GraphicsPath shapes and to draw some other graphics content in the center of the shapes.

    For example, using different Brushes:

      LinearGradientBrush           HatchBrush               TextureBrush
    

    Of course there are other methods to achieve the same result. We could draw the Arcs using the GraphicsPath.AddArc method, extract or calculate the first and last points of the Arcs and use them to draw two lines (GraphicsPath.AddLine) that will close the figures.

    But, since we want to draw different graphics objects in the center of the arcs, these objects will cover the center area anyway.

    How to use this code:

    • In a Form, add a TrackBar (called tbarSpeed, here)
    • Add a Panel (called Canvas), with Size (200, 200). Use the Custom Panel control provided here, which adds some ControlStyles in its costructor. This will avoid flickering and artifacts
    • Wire up the TrackBar tbarSpeed_Scroll event and the Panel Canvas_Paint event.

    using System.Drawing;
    using System.Drawing.Drawing2D;
    
    
    float GaugeValue = 88.0f;
    float GaugeSweepAngle = 270.0f;
    float GaugeStartAngle = 135.0F;
    
    private void Canvas_Paint(object sender, PaintEventArgs e)
    {
        var canvas = sender as Control;
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        var outerRectangle = new Rectangle(10, 10, 180, 180);
        var innerRectangle = new Rectangle(30, 30, 140, 140);
        var blendRectangle = new Rectangle(10, 10, 180, 160);
        var innerCenter = new PointF(outerRectangle.Left + (outerRectangle.Width / 2),
                                        outerRectangle.Top + (outerRectangle.Height / 2));
        float gaugeLength = (outerRectangle.Width / 2) - 2;
    
        using (var path = new GraphicsPath())
        {
            path.AddPie(outerRectangle, GaugeStartAngle, GaugeSweepAngle);
            path.AddPie(innerRectangle, GaugeStartAngle, GaugeSweepAngle);
            innerRectangle.Inflate(-1, -1);
    
            using (var pen = new Pen(Color.White, 3f))
            using (var backgroundbrush = new SolidBrush(canvas.BackColor))
            using (var gradientBrush = new LinearGradientBrush(blendRectangle,
                   Color.Green, Color.Red, LinearGradientMode.ForwardDiagonal))
            {
                var blend = new Blend()
                {
                    Factors = new[] { 0.0f, 0.0f, 0.1f, 0.3f, 0.7f, 1.0f },
                    Positions = new[] { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f }
                };
    
                gradientBrush.Blend = blend;
                e.Graphics.FillPath(gradientBrush, path);
                e.Graphics.DrawPath(pen, path);
    
                e.Graphics.FillEllipse(backgroundbrush, innerRectangle);
    
                using (var format = new StringFormat())
                {
                    format.Alignment = StringAlignment.Center;
                    format.LineAlignment = StringAlignment.Center;
                    innerRectangle.Location = new Point(innerRectangle.X, innerRectangle.Y + canvas.Font.Height);
                    e.Graphics.DrawString(GaugeValue.ToString() + "%", canvas.Font, Brushes.White, innerRectangle, format);
                }
    
                using (var mx = new Matrix())
                {
                    mx.RotateAt(GaugeStartAngle + 90 + (GaugeValue * (GaugeSweepAngle / 100)), innerCenter);
                    e.Graphics.Transform = mx;
                    e.Graphics.DrawLine(pen, innerCenter, new PointF(innerCenter.X, innerCenter.Y - gaugeLength));
                    e.Graphics.ResetTransform();
                }
            }
        }
    }
    
    private void tbarSpeed_Scroll(object sender, EventArgs e)
    {
        GaugeValue = tbarSpeed.Value;
        Canvas.Invalidate();
    }
    

    Custom Panel control:

    using System.ComponentModel;
    using System.Windows.Forms;
    
    [DesignerCategory("code")]
    public class DrawingPanel : Panel
    {
        public DrawingPanel()
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint |
                          ControlStyles.UserPaint |
                          ControlStyles.OptimizedDoubleBuffer, true);
            this.UpdateStyles();
        }
    }
    

    Sample code on PasteBin

    0 讨论(0)
提交回复
热议问题