我正在寻找用Bresenham的线算法制作弧线的方法。这个算法绘制了完美的圆形,但如果我需要绘制弧线(从0到Pi)并将其旋转30度(例如),该怎么办?
void DrawCircle(HDC hdc,int x0, int y0, int radius)
{
int x = 0;
int y = radius;
int delta = 2 - 2 * radius;
int error = 0;
while(y >= 0) {
//SetPixel(hdc,x0 + x, y0 + y,pencol);
SetPixel(hdc,x0 + x, y0 - y,pencol);
//SetPixel(hdc,x0 - x, y0 + y,pencol);
SetPixel(hdc,x0 - x, y0 - y,pencol);
error = 2 * (delta + y) - 1;
if(delta < 0 && error <= 0) {
++x;
delta += 2 * x + 1;
continue;
}
error = 2 * (delta - x) - 1;
if(delta > 0 && error > 0) {
--y;
delta += 1 - 2 * y;
continue;
}
++x;
delta += 2 * (x - y);
--y;
}
}
答案 0 :(得分:3)
要获得1/2个圆圈(到pi),只需调用一个SetPixel例程。要使弧度旋转30度,需要一些触发。您可以让上面的循环运行,直到您的x / y比率等于tan(30度),然后开始实际绘制,直到您的比率达到您想要停止的值。不是最有效的方式,但它会起作用。为了更好地完成它,您需要预先计算起始4 var值。您可以从上面的运行中获取值并将它们作为起始值插入,这将非常有效。
您是否从Michael Abrash's Black Book内容中获得了上述算法?如果没有,我会谷歌将其作为快速圆弧/圆弧绘制的第二个参考点。
唉,扯掉章节的椭圆不包含在那里。以下是我在网上发现的声称来自Abrash的内容:
/* One of Abrash's ellipse algorithms */
void draw_ellipse(int x, int y, int a, int b, int color)
{
int wx, wy;
int thresh;
int asq = a * a;
int bsq = b * b;
int xa, ya;
draw_pixel(x, y+b, color);
draw_pixel(x, y-b, color);
wx = 0;
wy = b;
xa = 0;
ya = asq * 2 * b;
thresh = asq / 4 - asq * b;
for (;;) {
thresh += xa + bsq;
if (thresh >= 0) {
ya -= asq * 2;
thresh -= ya;
wy--;
}
xa += bsq * 2;
wx++;
if (xa >= ya)
break;
draw_pixel(x+wx, y-wy, color);
draw_pixel(x-wx, y-wy, color);
draw_pixel(x+wx, y+wy, color);
draw_pixel(x-wx, y+wy, color);
}
draw_pixel(x+a, y, color);
draw_pixel(x-a, y, color);
wx = a;
wy = 0;
xa = bsq * 2 * a;
ya = 0;
thresh = bsq / 4 - bsq * a;
for (;;) {
thresh += ya + asq;
if (thresh >= 0) {
xa -= bsq * 2;
thresh = thresh - xa;
wx--;
}
ya += asq * 2;
wy++;
if (ya > xa)
break;
draw_pixel(x+wx, y-wy, color);
draw_pixel(x-wx, y-wy, color);
draw_pixel(x+wx, y+wy, color);
draw_pixel(x-wx, y+wy, color);
}
}
你的想法是你在x4时刻绘制圆圈的第8个,然后翻转以获得其他8个圆圈。尽管如此,仍然没有直接回答你的问题。正在努力......
同样,上面的代码应该可以工作,你只需要仔细控制开始和结束条件。 y> = 0需要成为完成“弧”长度时的y,并且需要计算起始值作为弧的起点。
这不是一件简单明了的事情。可能只是更容易使用浮点例程。数学更直接,处理器现在比处理这些整数例程时更好地处理它们。
答案 1 :(得分:2)
如果您不需要确定Bresenham,有一个快速的步骤方法介绍了 in this SO post ,您可以在其中设置中心点,起点和弧角。它不需要停止标准,因为它已经包含在算法中(通过弧角)。使其快速的是预测切向和径向运动因子,实际循环没有触发函数调用,只有乘法,加法和减法。
AFAIK有三种方法:
A)像Bresenham一样增量
B)像this这样的细分方法
C)步骤(或段)方法
我将采用步骤方法的慢速示例(如果速度很重要,请不要使用此方法):
// I know the question is tagged c++, but the idea comes clear in javascript
var start_angle = 0.5, end_angle = 1.1, r = 30;
for(var i = start_angle; i < end_angle; i = i + 0.05)
{
drawpixel(x: 50 + Math.cos(i) * r, y: 100 + Math.sin(i) * r); // center point is (x = 50, y = 100)
}
缓慢来自cos和sin,它们在循环中重复(不必要)。这可以通过预先计算cos和sin来解决,如上面提到的SO帖子中所述。这意味着巨大的加速(在top5 javascript引擎中平均为12倍)。
我制作了一个非完全可比的speedtest各种圆弧绘制算法。 Bresenham速度很快,但需要添加启动和停止标准逻辑,这会慢慢减慢算法。如果你真的需要Bresenham和arc,我还没有现成的解决方案,但还没有找到。肯定是可能的。顺便说一句,与Bresenham(至少在javascript中)相比,使用预先计算的触发的步骤方法的性能并不差。请用c ++测试并报告。