代码之家  ›  专栏  ›  技术社区  ›  Thomas O

寻找一种快速轮廓线绘制算法

  •  2
  • Thomas O  · 技术社区  · 14 年前

    我在找一个快速算法来画一条轮廓线。对于此应用程序,轮廓仅需要1像素宽。如果两条线共享一个公共点,那么无论是默认的还是通过一个选项,都应该可以使它们无缝地连接在一起。

    请原谅ASCII艺术,但这可能是最好的方式来演示它。

    正常线路:

     ##
       ##
         ##
           ##
             ##
               ##
    

    “概述”行:

     **
    *##**
     **##**
       **##**
         **##**
           **##**
             **##*
               **
    

    我在做一个dsPIC33FJ128GP802。它是一个小型的微控制器/数字信号处理器,能处理40mips(每秒百万条指令)。它只能进行整数运算(加法、减法和乘法:它可以进行除法运算,但需要大约19个周期)。它被用来同时处理OSD层,只有3-4mips的处理时间可用于计算,所以速度是关键。像素占据三种状态:黑色、白色和透明;视频场为192x128像素。这是为一个开源项目Super OSD准备的: http://code.google.com/p/super-osd/

    我想到的第一个解决方案是绘制3x3矩形,第一个过程中使用轮廓像素,第二个过程中使用普通像素,但这可能会很慢,因为每个像素至少有3个像素被覆盖,绘制它们的时间被浪费。所以我在找一个更快的方法。每个像素大约需要30个周期。目标是画一条100像素长的线需要50000个周期。

    2 回复  |  直到 9 年前
        1
  •  1
  •   Edgar Bonet    14 年前

    我建议这样做(C/伪代码混合):

    void draw_outline(int x1, int y1, int x2, int y2)
    {
        int x, y;
        double slope;
    
        if (abs(x2-x1) >= abs(y2-y1)) {
            // line closer to horizontal than vertical
            if (x2 < x1) swap_points(1, 2);
            // now x1 <= x2
            slope = 1.0*(y2-y1)/(x2-x1);
            draw_pixel(x1-1, y1, '*');
            for (x = x1; x <= x2; x++) {
                y = y1 + round(slope*(x-x1));
                draw_pixel(x, y-1, '*');
                draw_pixel(x, y+1, '*');
                // here draw_line() does draw_pixel(x, y, '#');
            }
            draw_pixel(x2+1, y2, '*');
        }
        else {
            // same as above, but swap x and y
        }
    }
    

    编辑 :如果您想让连续的线路无缝连接,我 你真的必须在第一遍画出所有的轮廓,而且 draw_line() draw_pixel(x, y, '#'); 而不是四个 draw_pixel(..., ..., '*'); 然后你就:

    void draw_polyline(point p[], int n)
    {
        int i;
    
        for (i = 0; i < n-1; i++)
            draw_outline(p[i].x, p[i].y, p[i+1].x, p[i+1].y);
        for (i = 0; i < n-1; i++)
            draw_line(p[i].x, p[i].y, p[i+1].x, p[i+1].y);
    }
    
        2
  •  0
  •   Franz D.    9 年前

    我的方法是用布雷森汉姆画多条线。看看你的ASCII艺术,你会注意到轮廓线和Bresenham线是一样的,只是上下移动了1个像素——加上第一个点左边和最后一个点右边的一个像素。

    对于一般版本,您需要确定行是平的还是陡的——即 abs(y1 - y0) <= abs(x1 - x0)

    通过一次为每一行像素绘制一条线和两个轮廓像素,这可能是值得优化的。然而,如果需要无缝的轮廓,最简单的解决方案是先画出所有的轮廓,然后再画线本身——这不适用于“三像素Bresenham”优化。