14-边界表示的种子填充算法

参考:https://www.bilibili.com/video/BV1L24y1Z7Sz/

原理

完成代码:

// 13-边界表示的种子填充算法
// 参考 https://www.bilibili.com/video/BV1L24y1Z7Sz

#define UNICODE
#include <Windows.h>
#include <Windowsx.h>
#define WINDOW_TEXT L"13-边界表示的种子填充算法"
#define ROUND(d) int(d+0.5)  // 四舍五入

struct Point2  // 二维点
{
    Point2() :x(0), y(0) {}
    Point2(int x, int y) :x(x), y(y) {}
    int    x;
    int    y;

};

struct Stack  // 栈
{
    Stack* pTop;  // 节点指针
    Stack* pNext; // 指针域
    Point2 Pixel; // 数据域

    Stack() 
    {
        pTop  = NULL;
        pNext = NULL;
        Pixel = Point2(0, 0);
    };
    ~Stack() {};

    void Push(Point2 point) // 入栈
    {
        pTop = new Stack;
        pTop->Pixel = point;
        pTop->pNext = this->pNext;
        this->pNext = pTop;
    }

    Point2 Pop()            // 出栈
    {
        Point2 point;
        if (this->pNext!=NULL)
        {
            pTop = this->pNext;
            this->pNext = pTop->pNext;
            point = pTop->Pixel;
            delete pTop;
        }
        return point;
    }
};


class Fill
{
public:
    Stack*   _pHead;     // 头 
    Stack*   _pTop;      // 顶
    Point2   _P[7];      // 顶点表
    Point2   _seed;      // 种子像素
    COLORREF _seedClr; // 种子像素颜色
public:
    Fill()
    {      
        _P[0] = Point2(50, 70);
        _P[1] = Point2(-150, 270);
        _P[2] = Point2(-250, 20);
        _P[3] = Point2(-150, -280);
        _P[4] = Point2(0, -80);
        _P[5] = Point2(100, -280);
        _P[6] = Point2(300, 120);
        _seed = Point2(0, 0);
        _pHead = NULL;
        _pTop  = NULL;
        _seedClr = RGB(0,0,255);

    };
    ~Fill() {};

    // 绘制线框
    void DrawObject(HDC hdc)
    {      
        Point2 pTemp;
        for (int i = 0; i < 7; i++)
        {
            if (0 == i)
            {
                MoveToEx(hdc, _P[i].x, _P[i].y, NULL);
                pTemp = _P[i];
            }
            else
            {
                LineTo(hdc, _P[i].x, _P[i].y);
            }
        }

        LineTo(hdc, pTemp.x, pTemp.y);  // 闭合线框    
    }

    // 4联通填充算法
    void BoundaryFill4(HWND hwnd,HDC hdc)
    {
        COLORREF boundaryClr = RGB(0, 0, 0);//边界颜色
        COLORREF color;// 当前像素颜色;
        int x; // 种子与图形位置
        int y;       

        RECT rect;
        GetClientRect(hwnd, &rect);
        int nClientLeft   = -rect.right / 2;
        int nClientRight  = rect.right / 2;
        int nClientTop    = rect.bottom / 2;
        int nClientbottom = -rect.bottom / 2;

        x = _seed.x - 1;
        while (boundaryClr != GetPixel(hdc, x, _seed.y) && _seedClr != GetPixel(hdc, x, _seed.y)) // 是否位于多边形左侧
        {
            x--;
            if (x < nClientLeft) // 到达客户区左段
            {
                MessageBox(NULL, L"种子不在客户区域图形内", L"提示", MB_OK);
                return;

            }
        }

        x = _seed.x + 1;
        while (boundaryClr != GetPixel(hdc, x, _seed.y) && _seedClr != GetPixel(hdc, x, _seed.y)) // 是否位于多边形左侧
        {
            x++;
            if (x >= nClientRight) // 到达客户区右侧
            {
                MessageBox(NULL, L"种子不在客户区域图形内", L"提示", MB_OK);
                return;

            }
        }

        y = _seed.y + 1;
        while (boundaryClr != GetPixel(hdc, _seed.x, y) && _seedClr != GetPixel(hdc, _seed.x, y))
        {
            y++;
            if (y >= nClientTop) // 上方
            {
                MessageBox(NULL, L"种子不在客户区域图形内", L"提示", MB_OK);
                return;
            }
        }

        y = _seed.y - 1;
        while (boundaryClr != GetPixel(hdc, _seed.x, y) && _seedClr != GetPixel(hdc, _seed.x, y))
        {
            y--;
            if (y <= nClientbottom) // 下方
            {
                MessageBox(NULL, L"种子不在客户区域图形内", L"提示", MB_OK);
                return;
            }
        }

        // 位于多边形内

        _pHead = new Stack; // 建立栈头节点

        _pHead->pNext = NULL;

        Point2 left, top, right, bottom;// 种子四个邻节点
       
        _pHead->Push(_seed);// 种子像素入栈

        while (NULL != _pHead->pNext) // 栈不为空
        {
            Point2 popPoint = _pHead->Pop();

            if (_seedClr == GetPixel(hdc, popPoint.x, popPoint.y))
            {
                continue;// 加速
            }

            SetPixel(hdc,popPoint.x,popPoint.y,_seedClr); // 设置种子点处颜色

            left.x = popPoint.x - 1, left.y = popPoint.y; // 搜索临近点左方像素点。
            color = GetPixel(hdc, left.x, left.y);
            if (boundaryClr!=color&&_seedClr!=color)
            {
                _pHead->Push(left); // 左侧像素入栈
            }

            right.x = popPoint.x + 1, right.y = popPoint.y;  // 搜索临近点右方像素点。
            color = GetPixel(hdc, right.x, right.y);
            if (boundaryClr != color && _seedClr != color)
            {
                _pHead->Push(right); // 右侧像素入栈
            }


            top.x = popPoint.x, top.y = popPoint.y+1;  // 搜索临近点上方像素点。
            color = GetPixel(hdc, top.x, top.y);
            if (boundaryClr != color && _seedClr != color)
            {
                _pHead->Push(top); // 上侧像素入栈
            }


            bottom.x = popPoint.x, bottom.y = popPoint.y - 1;  // 搜索临近点下方像素点。
            color = GetPixel(hdc, bottom.x, bottom.y);
            if (boundaryClr != color && _seedClr != color)
            {
                _pHead->Push(bottom); // 下侧像素入栈
            }

        }
       
        TextOut(hdc, nClientLeft+5,nClientTop-10,L"填充完成",lstrlenW(L"填充完成"));
        delete _pHead;
        _pHead = NULL;
    }
};


Fill g_Fill; // 填充

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rc;
    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_LBUTTONDOWN: // 点击左键填充多边形

        hdc = GetDC(hwnd);

        GetClientRect(hwnd, &rc);
        SetMapMode(hdc, MM_ANISOTROPIC);
        SetWindowExtEx(hdc, rc.right, rc.bottom, NULL);
        SetViewportExtEx(hdc, rc.right, -rc.bottom, NULL);
        SetViewportOrgEx(hdc, rc.right / 2, rc.bottom / 2, NULL);

        g_Fill._seed.x =   GET_X_LPARAM(lParam)- rc.right / 2;
        g_Fill._seed.y = -(GET_Y_LPARAM(lParam) - rc.bottom / 2);

        g_Fill.BoundaryFill4(hwnd, hdc);

        ReleaseDC(hwnd,hdc);
        return 0;

    case WM_PAINT:
    {
        hdc = BeginPaint(hwnd, &ps);

        GetClientRect(hwnd, &rc);
        SetMapMode(hdc, MM_ANISOTROPIC);
        SetWindowExtEx(hdc, rc.right, rc.bottom, NULL);
        SetViewportExtEx(hdc, rc.right, -rc.bottom, NULL);
        SetViewportOrgEx(hdc, rc.right / 2, rc.bottom / 2, NULL);

        g_Fill.DrawObject(hdc);   // 绘制多边形线框  

        EndPaint(hwnd, &ps);
    }
    return 0;

    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    // Register the window class.
    const wchar_t CLASS_NAME[] = L"CAG";
    WNDCLASS wc = { };

    wc.style = CS_HREDRAW | CS_VREDRAW; // 重新绘制整个工作区
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(
        0,                              // Optional window styles.
        CLASS_NAME,                     // Window class
        WINDOW_TEXT,                    // Window text
        WS_OVERLAPPEDWINDOW,            // Window style

        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

        NULL,       // Parent window    
        NULL,       // Menu
        hInstance,  // Instance handle
        NULL        // Additional application data
    );

    if (hwnd == NULL)
    {
        return 0;
    }
    ShowWindow(hwnd, nCmdShow);


    MSG msg = { };
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值