a working non-recursive floodfill algorithm written in C?

后端 未结 12 2226
日久生厌
日久生厌 2020-12-02 23:39

I\'ve been trying to find a working floodfill algorithm. Of the many algorithms I\'ve tried only the \'recursive line fill\' one behaves exactly as it should with the major

12条回答
  •  失恋的感觉
    2020-12-03 00:27

    I found this fill by Paul Heckbert to be the simplest non-recursive C implementation:

    /*
     * A Seed Fill Algorithm
     * by Paul Heckbert
     * from "Graphics Gems", Academic Press, 1990
     *
     * user provides pixelread() and pixelwrite() routines
     */
    
    /*
     * fill.c : simple seed fill program
     * Calls pixelread() to read pixels, pixelwrite() to write pixels.
     *
     * Paul Heckbert    13 Sept 1982, 28 Jan 1987
     */
    
    typedef struct {        /* window: a discrete 2-D rectangle */
        int x0, y0;         /* xmin and ymin */
        int x1, y1;         /* xmax and ymax (inclusive) */
    } Window;
    
    typedef int Pixel;      /* 1-channel frame buffer assumed */
    
    Pixel pixelread(int x, int y);
    void pixelwrite(int x, int y, Pixel p);
    
    typedef struct {short y, xl, xr, dy;} Segment;
    /*
     * Filled horizontal segment of scanline y for xl<=x<=xr.
     * Parent segment was on line y-dy.  dy=1 or -1
     */
    
    #define MAX 10000       /* max depth of stack */
    
    #define PUSH(Y, XL, XR, DY) /* push new segment on stack */ \
        if (sp=win->y0 && Y+(DY)<=win->y1) \
        {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
    
    #define POP(Y, XL, XR, DY)  /* pop segment off stack */ \
        {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
    
    /*
     * fill: set the pixel at (x,y) and all of its 4-connected neighbors
     * with the same pixel value to the new pixel value nv.
     * A 4-connected neighbor is a pixel above, below, left, or right of a pixel.
     */
    
    void fill(x, y, win, nv)
    int x, y;   /* seed point */
    Window *win;    /* screen window */
    Pixel nv;   /* new pixel value */
    {
        int l, x1, x2, dy;
        Pixel ov;   /* old pixel value */
        Segment stack[MAX], *sp = stack;    /* stack of filled segments */
    
        ov = pixelread(x, y);       /* read pv at seed point */
        if (ov==nv || xx0 || x>win->x1 || yy0 || y>win->y1) return;
        PUSH(y, x, x, 1);           /* needed in some cases */
        PUSH(y+1, x, x, -1);        /* seed segment (popped 1st) */
    
        while (sp>stack) {
        /* pop segment off stack and fill a neighboring scan line */
        POP(y, x1, x2, dy);
        /*
         * segment of scan line y-dy for x1<=x<=x2 was previously filled,
         * now explore adjacent pixels in scan line y
         */
        for (x=x1; x>=win->x0 && pixelread(x, y)==ov; x--)
            pixelwrite(x, y, nv);
        if (x>=x1) goto skip;
        l = x+1;
        if (lx1 && pixelread(x, y)==ov; x++)
            pixelwrite(x, y, nv);
            PUSH(y, l, x-1, dy);
            if (x>x2+1) PUSH(y, x2+1, x-1, -dy);    /* leak on right? */
    skip:       for (x++; x<=x2 && pixelread(x, y)!=ov; x++);
            l = x;
        } while (x<=x2);
        }
    }
    

    source: https://github.com/erich666/GraphicsGems/blob/master/gems/SeedFill.c

提交回复
热议问题