【问题标题】:c++ Bresenham's line algorithm draw arc and rotatec++ Bresenham的线算法画弧和旋转
【发布时间】:2021-08-31 14:55:23
【问题描述】:

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

【问题讨论】:

  • 多年前,我根据 Bresenham 文档实现了几个弧形算法,为 Allegro 游戏库做出了贡献(当我联系他以获取更多信息时,我还亲自收到了他的一封私人信件!) .你可以在这里找到完整的来源:liballeg.org

标签: c++ geometry geometric-arc bresenham


【解决方案1】:

要获得 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);
    }
}

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

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

按照现状,这不是一项简单的任务。可能只是更容易使用浮点例程。数学更直接,处理器现在往往比制作这些整数例程时更好地处理它们。

【讨论】:

  • 谢谢,我认为我们应该改变方程式,但我的版本不起作用。你能举个例子吗?它不是来自迈克尔·阿布拉什的黑皮书。
  • 唉,这是从图形编程书中的一章中的黑皮书未收录。我记得阅读并假设它会在编译版本中。现在在网上搜索它......
  • 谢谢,但我更喜欢使用 Bresenham 的算法。
【解决方案2】:

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

AFAIK 共有三种方法:
A) 像 Bresenham 一样的增量
B) 细分方法如this
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 倍)。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-15
    • 1970-01-01
    • 2015-06-10
    • 2014-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多