Качество графики дуги - PullRequest
       35

Качество графики дуги

0 голосов
/ 09 января 2019

Вернуться сюда. Есть ли способ улучшить качество дуги?
Я использую e.Graphics.SmoothingMode = SmoothingMode.AntiAlias

Это фрагмент кода, который создает дугу:

using (GraphicsPath gp = new GraphicsPath())
{
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    gp.Reset();
    gp.AddPie(_OuterRectangle, (float)_Properties.Origin, (float)_Properties.GaugeType);
    gp.Reverse();

    gp.AddPie(_InnerRectangle, (float)_Properties.Origin, (float)_Properties.GaugeType);
    gp.Reverse();
    pArea.SetClip(gp);

    using (Pen oPen = new Pen(this.ForeColor, 2f))
    {
       e.Graphics.DrawPath(oPen, gp);
    }
    e.Graphics.SetClip(ClientRectangle);
}

enter image description here

Заранее спасибо.

EDIT:
Я сделал то, что предложил LarsTech, и теперь качество отличное, но у меня нет нужной фигуры:

enter image description here

  • OuterRectangle : это область ClientRectangle, которой я манипулирую, чтобы сделать ширину и высоту одинаковой длины;
  • InnerRectangle : составляет 2/3 от площади ClientRectangle, ergo, от OuterRectangle;
  • Properties.Origin : угол, где начинается дуга. У меня это в счетчике в виде кардинальных точек, где север 270, восток 0,
    так что. В случае фигуры, это Юго-Запад, 135 градусов;

  • Properties.GaugeType : еще один перечислитель, который говорит, что если Complete = 360, Half = 180, Quarter = 90, то есть с помощью этого я могу определить угол развертки. В случае фигуры это ThreeQuarter, 270 градусов.

1 Ответ

0 голосов
/ 11 января 2019

Проблема :
При обрезке области текущей графики ( Graphics.SetClip метод) результирующий чертеж теряет качество, поскольку эффект сглаживания, генерируемый Graphics.SmoothingMode = SmoothingMode.AntiAlias, теряется.

Возможное решение состоит в том, чтобы избежать ограничения области, определенной GraphicsPath, используемой для проектирования дуг (метод GraphicsPath.AddPie ); это, однако, оставляет линии пирога видимыми, ставя под угрозу форму.

Другое решение - нарисовать многоточие в центре дуг, используя фоновый цвет холста. Поскольку дуги нарисованы с использованием двух прямоугольников, мы можем использовать внутренний прямоугольник, раздувая его (метод Rectangle.Inflate ) по мере необходимости (часть - Pen.Width / 2 - размера пера, используемого для контура, обычно ).

Rectangle inflate

Это позволяет удалить артефакты, сгенерированные формами GraphicsPath, и нарисовать некоторый другой графический контент в центре фигур.

Например, используя разные кисти:

LinearGradienBrush - HatchBrush - TextureBrush

  LinearGradientBrush           HatchBrush               TextureBrush

Конечно, есть и другие методы для достижения того же результата. Мы могли бы нарисовать дуги, используя метод GraphicsPath.AddArc , извлечь или рассчитать первую и последнюю точки дуг и использовать их для рисования двух линий ( GraphicsPath.AddLine ), которые закроются фигуры.

Но, поскольку мы хотим рисовать различные графические объекты в центре дуг, эти объекты в любом случае будут покрывать центральную область.

Как использовать этот код :

  • В форме добавьте TrackBar (здесь он называется tbarSpeed)
  • Добавьте панель (называемую Canvas), с размером (200, 200). Используйте предоставленный здесь элемент управления Custom Panel, который добавляет немного ControlStyles в свой конструктор. Это позволит избежать мерцания и артефактов
  • Подключите трекбар tbarSpeed_Scroll и событие Panel 1066 *Canvas_Paint.

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)
{
    Control canvas = sender as Control;
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    Rectangle outerRectangle = new Rectangle(10, 10, 180, 180);
    Rectangle innerRectangle = new Rectangle(30, 30, 140, 140);
    Rectangle blendRectangle = new Rectangle(10, 10, 180, 160);
    PointF innerCenter = new PointF(outerRectangle.Left + (outerRectangle.Width / 2),
                                    outerRectangle.Top + (outerRectangle.Height / 2));
    float gaugeLength = (outerRectangle.Width / 2) - 2;

    using (GraphicsPath path = new GraphicsPath())
    {
        path.AddPie(outerRectangle, GaugeStartAngle, GaugeSweepAngle);
        path.AddPie(innerRectangle, GaugeStartAngle, GaugeSweepAngle);
        innerRectangle.Inflate(-1, -1);

        using (Pen pen = new Pen(Color.White, 3f))
        using (SolidBrush backgroundbrush = new SolidBrush(canvas.BackColor))
        using (LinearGradientBrush gradientBrush = new LinearGradientBrush(blendRectangle,
               Color.Green, Color.Red, LinearGradientMode.ForwardDiagonal))
        {
            Blend 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 (StringFormat 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 (Matrix matrix = new Matrix())
            {
                matrix.RotateAt(GaugeStartAngle + 90 + (GaugeValue * (GaugeSweepAngle / 100)), innerCenter);
                e.Graphics.Transform = matrix;
                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();
}

Настраиваемая панель управления :

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();
    }
}

Gauge control

Пример кода на PasteBin

...