我正在努力处理一个情况,我想用GDI +绘制一个圆圈并在其上绘制一些点(绘制为较小的圆圈),但圆圈似乎是非圆形的。通过实现缩放和零点移动,我可以放大点和圆,并找到不完全位于圆上的点。
当我添加'离散'如果使用了足够的段,则使用线段绘制的圆圈非常适合点。由于数学是相同的,我认为我的代码中的舍入误差不能成为圆偏差的原因(尽管可能在DrawEllipse的实现中)。
事实上,在45/135/225/315度的偏差最大。
我制作了一个小项目,用稍微不同的设置再现效果:我绘制了多个圆圈,它们的原点位于另一个圆上,其中心位于表格中心,半径相同。如果一切顺利,所有圈子都应该触摸表格的中心。但是像100和39这样的大半径,它们不再通过中心了,但是它可以通过大约15像素的距离来错过它。
要重现这种情况,请创建一个新的c#项目,放在form1 button1上,并从中调用Draw()函数:
private void Draw()
{
Graphics g = this.CreateGraphics();
g.Clear(this.BackColor );
double hw = this.Width / 2;
double hh = this.Height / 2;
double scale = 100000;
double R = 1;
for (int i = 0; i < 12; i++)
{
double angle = i * 30;
double cx = R * Math.Cos(angle * Math.PI / 180);
double cy = R * Math.Sin(angle * Math.PI / 180);
g.DrawEllipse(new Pen(Color.Blue, 1f), (float)(hw - scale * (cx + R)), (float)(hh + scale * (cy - R)), (float)(2 * R * scale), (float)(2 * R * scale));
g.DrawLine(Pens.Black, new Point(0, (int)hh), new Point(this.Width, (int)hh));
g.DrawLine(Pens.Black, new Point((int)hw, 0), new Point((int)hw, this.Height));
double r = 3;
g.DrawEllipse(new Pen(Color.Green, 1f), (float)(hw - r), (float)(hh - r), (float)(2 * r), (float)(2 * r));
//Pen magpen = new Pen(Color.Magenta, 1);
//double n = 360d / 1000;
//for (double j = 0; j < 360; j += n)
//{
// double p1x = R * Math.Cos(j * Math.PI / 180) + cx;
// double p1y = R * Math.Sin(j * Math.PI / 180) + cy;
// double p2x = R * Math.Cos((j + n) * Math.PI / 180) + cx;
// double p2y = R * Math.Sin((j + n) * Math.PI / 180) + cy;
// g.DrawLine(magpen, (float)(hw - scale * p1x), (float)(hh + scale * p1y), (float)(hw - scale * p2x), (float)(hh + scale * p2y));
//}
}
}
使用100到100&000; 000之间的变量刻度来查看效果:圆圈不再触碰原点,但在它周围摆动。如果您取消注释您可以看到的注释行,那么洋红色的“离散”线条就会消失。圈子表现得更好。
使用&#39;离散&#39;圆圈和圆弧是性能杀手,我正在寻找一种用GDI +绘制更好圆圈的方法。
任何想法,建议?
答案 0 :(得分:1)
GDI+(至少在其原生版本中)不绘制椭圆:它使用三次贝塞尔近似,如 here 和 here 所述。
即代替
c = cos(angle);
s = sin(angle);
x = c * radius;
y = s * radius;
或者,对于椭圆(a & b 以某种顺序作为长半轴和半短轴)
x = c * a;
y = s * b;
使用
K = (sqrt(2) - 1) * 4.0 / 3;
t = angle * 0.5 / pi;
u = 1 - t;
c = (u * u * u) * 1 + (3 * u * u * t) * 1 + (3 * u * t * t) * K + (t * t * t) * 0;
s = (u * u * u) * 0 + (3 * u * u * t) * K + (3 * u * t * t) * 1 + (t * t * t) * 1;
(对于 [0, pi/2] 范围内的角度:其他象限可以通过对称计算)。
答案 1 :(得分:0)
g.DrawArc(new Pen(Color.Blue, 1f), (float)((hw) - R * scale), -(float)((2 * R * scale) - hh), (float)(2 * R * scale), (float)(2 * R * scale), 0, 360);
我用这种方法得到了一些精确的结果。但这只是一个样本。