圆弧图形质量
Arc graphic quality
回到这里。有什么方法可以提高Arc的质量吗?
我正在使用 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);
}
提前致谢。
编辑:
我已经按照 LarsTech 的建议做了,现在质量是完美的,但我没有我需要的数字:
- OuterRectangle: 是ClientRectangle区域,我正在操纵它使Width和Height长度相同;
- InnerRectangle:是 ClientRectangle 面积的 2/3,因此,是 OuterRectangle;
Properties.Origin:是圆弧开始的角度。我在枚举器中将其作为基点,其中北为 270,东为 0,
所以。如上图,为西南,135度;
Properties.GaugeType:是另一个枚举器,如果是 Complete = 360,Half = 180,Quarter = 90,那么我可以确定扫掠角。如果图形是 ThreeQuarter,270 度。
问题:
当裁剪当前 Graphics 的一个区域时(Graphics.SetClip 方法),生成的图形会丢失质量,因为 Graphics.SmoothingMode = SmoothingMode.AntiAlias
生成的抗锯齿效果丢失。
一个可能的解决方案是避免剪裁由用于设计圆弧的GraphicsPath
定义的区域(GraphicsPath.AddPie方法);然而,这会使饼图的线条可见,从而影响形状。
另一个解决方案是使用 Canvas 的背景颜色在圆弧的中心绘制一个省略号。由于弧线是使用两个矩形绘制的,我们可以使用内部矩形,根据需要对其进行膨胀(Rectangle.Inflate 方法)(通常是用于线的 Pen 大小的一小部分 - Pen.Width / 2
)。
这允许删除由 GraphicsPath
形状生成的伪影并在形状的中心绘制一些其他图形内容。
例如,使用不同的笔刷:
LinearGradientBrush HatchBrush TextureBrush
当然还有其他方法可以达到同样的效果。我们可以使用 GraphicsPath.AddArc method, extract or calculate the first and last points of the Arcs and use them to draw two lines (GraphicsPath.AddLine) 绘制圆弧,这将关闭图形。
但是,由于我们要在圆弧的中心绘制不同的图形对象,这些对象无论如何都会覆盖中心区域。
如何使用此代码:
- 在一个Form中,添加一个TrackBar(此处命名为
tbarSpeed
)
- 添加图片框(名称为
Canvas
),大小为(200, 200)
.
- 连接 TrackBar
tbarSpeed_Scroll
事件和面板 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)
{
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();
}
回到这里。有什么方法可以提高Arc的质量吗?
我正在使用 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);
}
提前致谢。
编辑:
我已经按照 LarsTech 的建议做了,现在质量是完美的,但我没有我需要的数字:
- OuterRectangle: 是ClientRectangle区域,我正在操纵它使Width和Height长度相同;
- InnerRectangle:是 ClientRectangle 面积的 2/3,因此,是 OuterRectangle;
Properties.Origin:是圆弧开始的角度。我在枚举器中将其作为基点,其中北为 270,东为 0,
所以。如上图,为西南,135度;Properties.GaugeType:是另一个枚举器,如果是 Complete = 360,Half = 180,Quarter = 90,那么我可以确定扫掠角。如果图形是 ThreeQuarter,270 度。
问题:
当裁剪当前 Graphics 的一个区域时(Graphics.SetClip 方法),生成的图形会丢失质量,因为 Graphics.SmoothingMode = SmoothingMode.AntiAlias
生成的抗锯齿效果丢失。
一个可能的解决方案是避免剪裁由用于设计圆弧的GraphicsPath
定义的区域(GraphicsPath.AddPie方法);然而,这会使饼图的线条可见,从而影响形状。
另一个解决方案是使用 Canvas 的背景颜色在圆弧的中心绘制一个省略号。由于弧线是使用两个矩形绘制的,我们可以使用内部矩形,根据需要对其进行膨胀(Rectangle.Inflate 方法)(通常是用于线的 Pen 大小的一小部分 - Pen.Width / 2
)。
这允许删除由 GraphicsPath
形状生成的伪影并在形状的中心绘制一些其他图形内容。
例如,使用不同的笔刷:
LinearGradientBrush HatchBrush TextureBrush
当然还有其他方法可以达到同样的效果。我们可以使用 GraphicsPath.AddArc method, extract or calculate the first and last points of the Arcs and use them to draw two lines (GraphicsPath.AddLine) 绘制圆弧,这将关闭图形。
但是,由于我们要在圆弧的中心绘制不同的图形对象,这些对象无论如何都会覆盖中心区域。
如何使用此代码:
- 在一个Form中,添加一个TrackBar(此处命名为
tbarSpeed
) - 添加图片框(名称为
Canvas
),大小为(200, 200)
. - 连接 TrackBar
tbarSpeed_Scroll
事件和面板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)
{
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();
}