GDI Bezier 样条曲线(7)

Bezier 样条曲线

Bezier 样条曲线使用四个点来定义:两个端点(起点和终点)和两个控点(用于使其不同程度地弯曲)。

绘制 Bezier 样条曲线

使用 PolyBezier 函数和 PolyBezierTo 函数可以绘制 Bezier 样条曲线:

BOOL PolyBezier(
    HDC hdc,            // 设备环境句柄
    CONST POINT* lppt,  // 端点和控制点(顺序是开始点、第一控点、第二控点、终点)
    DWORD cPoints       // 端点和控点的总数量
);
BOOL PolyBezierTo(
    HDC hdc,            // 设备环境句柄
    CONST POINT *lppt,  // 端点和控制点(顺序是第一控点、第二控点、终点)
    DWORD cCount        // 端点和控点的总数量
);

注:PolyBezierTo 函数把当前位置当做开始点,所以只需要给定其他三个点,函数返回时,当前位置将被设置为终点。

BEZIER 示例程序

#include <windows.h>

void DrawBezier(HDC hdc, POINT apt[]) {
    PolyBezier(hdc, apt, 4);

    MoveToEx(hdc, apt[0].x, apt[0].y, NULL);
    LineTo(hdc, apt[1].x, apt[1].y);

    MoveToEx(hdc, apt[2].x, apt[2].y, NULL);
    LineTo(hdc, apt[3].x, apt[3].y);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {

    HDC hdc;
    PAINTSTRUCT ps;
    static int cxClient, cyClient;
    static POINT apt[4];

    switch (message) {
    case WM_SIZE:

        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);

        apt[0].x = cxClient / 4;
        apt[0].y = cyClient / 2;

        apt[1].x = cxClient * 4 / 8;
        apt[1].y = cyClient / 4;

        apt[2].x = cxClient * 4 / 8;
        apt[2].y = cyClient * 3 / 4;

        apt[3].x = cxClient * 3 / 4;
        apt[3].y = cyClient / 2;

        return 0;

    case WM_LBUTTONDOWN:
    case WM_RBUTTONDOWN:
    case WM_MOUSEMOVE:
        if (wParam & MK_LBUTTON || wParam & MK_RBUTTON) {
            hdc = GetDC(hwnd);

            SelectObject(hdc, GetStockObject(BLACK_PEN));
            DrawBezier(hdc, apt);

            if (wParam & MK_LBUTTON) {
                apt[1].x = LOWORD(lParam);
                apt[1].y = HIWORD(lParam);
             }

            if (wParam & MK_RBUTTON) {
                apt[2].x = LOWORD(lParam);
                apt[2].y = HIWORD(lParam);
            }

            SelectObject(hdc, GetStockObject(WHITE_PEN));
            DrawBezier(hdc, apt);

            ReleaseDC(hwnd, hdc);
        }

        return 0;

    case WM_PAINT:
        InvalidateRect(hwnd, NULL, TRUE);
        hdc = BeginPaint(hwnd, &ps);

        SelectObject(hdc, GetStockObject(WHITE_PEN));
        DrawBezier(hdc, apt);

        EndPaint(hwnd, &ps);
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

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

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    
    LPCTSTR lpszClassName = TEXT("BezierDemo");
    LPCTSTR lpszWindowName = TEXT("Bezier Demo");
    WNDCLASS wndclass;
    HWND hwnd;
    MSG msg;

    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hInstance = hInstance;
    wndclass.lpfnWndProc = WndProc;
    wndclass.lpszClassName = lpszClassName;
    wndclass.lpszMenuName = lpszWindowName;
    wndclass.style = CS_HREDRAW | CS_VREDRAW;

    if (!RegisterClass(&wndclass)) {
        MessageBox(NULL, TEXT("This program requires Windows NT!"), lpszWindowName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(
        lpszClassName,
        lpszWindowName,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        hInstance,
        NULL
    );


    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

猜你喜欢

转载自www.cnblogs.com/yenyuloong/p/9121522.html