【问题标题】:How can I draw a "line" in a 2-D array (simulacrum for a screen)如何在二维数组中绘制“线”(屏幕模拟)
【发布时间】:2009-10-01 06:33:25
【问题描述】:

我正在处理一个将打印到位图的项目(更具体地说是 RAW,但这对问题并不重要),但我正在处理程序中的二维数组。

我希望能够为 a、b、x 和 y 的任意值绘制一条从点 (a,b) 到点 (x,y) 的线。我不需要像抗锯齿这样的花哨的东西;在这一点上最近的邻居很好。例如,假设我有一个 5x5 2d 数组,如下所示:

00,10,20,30,40
01,11,21,31,41
02,12,22,32,42
03,13,23,33,43
04,14,24,34,44

现在,假设我想在 04 和 42 之间画一条线。我想要一种可靠的方法,如下所示:

0,0,0,0,0
0,0,0,0,0
0,0,0,1,1
0,1,1,1,0
1,1,0,0,0

我确定有人在想“哎呀,这家伙是智障吗?他在这里失败了吗?”,但请幽默!

我正在使用 C++,但这应该是实际问题的次要问题。

【问题讨论】:

  • 让我想起了 ACM 编程竞赛题。

标签: c++ multidimensional-array


【解决方案1】:

Bresenham's line algorithm 是你需要的:


Bresenham 线算法的结果说明。

【讨论】:

  • 是的,布雷森纳姆几十年来一直是标准。有替代品,但不多,也不常见。
【解决方案2】:

就像 Simucal 所说,布雷森纳姆是正确的选择。这是一个幼稚的实现。

不是完美的 C 代码,如果你想要线段的粗细,你必须做一些魔法。此外,您应该沿着 x 遍历,而不是像我在这里所做的那样遍历 y。它对缓存更友好。如果要抗锯齿,请搜索“Wu-lines”。使用来自位置的分数作为渐变是一个聪明的技巧。

线条粗细的提示: 如果顶点按逆时针顺序计算 v1 - v0 的归一化向量 V(-y,x),如果顶点按顺时针顺序计算 V(y,-x)。然后你有四个点定义为:v0、v0 + V * 线宽、v1 和 v1 + V * 线宽。通过沿边缘插值来栅格化该四边形。但如果你已经想走那么远,你可能会编写一个三角形光栅化器来代替。

typedef struct Point 
{
    int x, y;
} Point;

typedef struct Color {
    unsigned char r,g,b;
} Color;

#define RGB(x) (x->r << 16) | (x->g << 8) | (x->b)

int DrawLinestrip(int width, int height, unsigned int* buffer,
    Color* color, Point* verts, int count)
{
    int i, x,y,xbegin, xdelta, ydelta, xdiff, ydiff, accum, sign;
    Point *p1, *p2;
    if(!verts || count < 2)
        return -1;

    for(i=1; i<count; ++i){
        if(verts[i].y > verts[i-1].y){ /* sort by y */
            p1 = &verts[i-1];
            p2 = &verts[i];
        } else {
            p1 = &verts[i];
            p2 = &verts[i-1];
        }

        xdelta = p2->x - p1->x;
        ydelta = p2->y - p1->y;
        accum = 0;
        sign = 0;

        if(!xdelta && !ydelta)
            continue;
        else if(!xdelta && ydelta){ /* Special case: straight vertical line */
            x = p1->x;
            for(y=p1->y; y<(p1->y + ydelta); ++y){
                buffer[x + y*width] = RGB(color);
            }
        }
        else if(xdelta && !ydelta){ /* Special case: straight horisontal line */
            y = p1->y;
            xbegin = (p1->x < p2->x ? p1->x : p2->x);
            for(x=xbegin; x<=xbegin+abs(xdelta); ++x){
                buffer[x + y*width] = RGB(color);
            }
        }
        else {
            xdiff = (xdelta << 16) / ydelta;
            ydiff = (ydelta << 16) / xdelta;

            if( abs(xdiff) > abs(ydiff) ){ /* horizontal-major */
                y = p1->y;
                if(xdelta < 0){ /* traversing negative x */
                    for(x=p1->x; x >= p2->x; --x){
                        buffer[x + y*width] = RGB(color);
                        accum += abs(ydiff);
                        while(accum >= (1<<16)){
                            ++y;
                            accum -= (1<<16);
                        }
                    }
                } else { /* traversing positive x */
                    for(x=p1->x; x <= p2->x; ++x){
                        buffer[x + y*width] = RGB(color);
                        accum += abs(ydiff);
                        while(accum >= (1<<16)){
                            ++y;
                            accum -= (1<<16);
                        }
                    }
                }
            } else if( abs(ydiff) > abs(xdiff) ){ /* vertical major */
                sign = (xdelta > 0 ? 1 : -1);
                x = p1->x;
                for(y=p1->y; y <= p2->y; ++y){
                    buffer[x + y*width] = RGB(color);
                    accum += abs(xdiff);
                    while(accum >= (1<<16)){
                        x += sign;
                        accum -= (1<<16);
                    }
                }            
            } else if( abs(ydiff) == abs(xdiff) ){ /* 45 degrees */
                sign = (xdelta > 0 ? 1 : -1);
                x = p1->x;
                for(y=p1->y; y <= p2->y; ++y){
                    buffer[x + y*width] = RGB(color);
                    x+= sign;
                }
            }
        }
    }
    return 0;
}

【讨论】:

    猜你喜欢
    • 2017-08-26
    • 2018-09-04
    • 1970-01-01
    • 1970-01-01
    • 2012-10-28
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多