7

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

2 回答 2

4

要获得 1/2 个圆(到 pi),只需调用其中一个 SetPixel 例程。让你的弧线旋转 30 度需要一些触发。您可以让上述循环运行,直到您的 x/y 比率等于 tan(30 度),然后开始实际绘制,直到您的比率达到您想要停止的值。不是最有效的方法,但它会起作用。为了让它更好,你需要预先计算你的起始 4 var 值。您可以从上述运行中获取值并将它们作为起始值插入,这将非常有效。

您是否从Michael Abrash 的黑皮书资料中获得了上述算法?如果没有,我会在谷歌上搜索它作为快速圆/弧绘图的第二个参考点。

好吧,唉,撕开章节的省略号不包括在里面。这是我在网上找到的声称来自 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);
    }
}

这个想法是您一次绘制 8 个圆 x4,然后翻转以绘制其他 8 个圆。虽然仍然没有直接回答你的问题。正在努力...

同样,您上面的代码应该可以工作,您只需要仔细控制开始和结束条件。y >= 0 需要成为 y 在完成“弧”长度后的任何值,并且需要计算起始值作为弧的开始。

就目前的情况而言,这将不是一项直接的任务。可能只是更容易使用浮点例程。数学更直接,处理器现在往往比这些整数例程被制作时更好地处理它们。

于 2011-12-09T16:01:17.420 回答
4

如果你不需要确定 Bresenham,这个 SO post中介绍了一种快速步进方法,您可以在其中设置中心点、起点和弧角。它不需要停止标准,因为它已经包含在算法中(按弧角)。使其快速的是切向和径向运动因子的预先计算,实际循环没有三角函数调用,只有乘法、加法和减法。

AFAIK 有三种类型的方法:
A)像 Bresenham 这样的增量B)像这样
的 细分方法 C)步进(或分段)方法

我将举一个缓慢的 step 方法示例(如果速度很重要,请不要使用它):

// 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 倍)。

我对各种圆和圆弧绘制算法进行了非完全可比的速度测试。Bresenham 速度很快,但需要添加启动和停止标准逻辑,这会稍微减慢算法速度。如果你真的需要 Bresenham 和 arc,我没有现成的解决方案,也没有找到这样的解决方案。这肯定是可能的。顺便说一句,与 Bresenham 相比,使用预先计算的 trigs 的 step 方法在性能上并没有那么差(至少在 javascript 中)。请用 C++ 测试并报告。

于 2013-02-10T00:17:43.120 回答