c ++ Bresenham的线算法绘制弧和旋转

时间:2011-12-09 15:23:42

标签: c++ geometry geometric-arc bresenham

我正在寻找用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;
        }
}

2 个答案:

答案 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 ++测试并报告。