绘制贝塞尔样条曲线

一条二维贝塞尔曲线样条曲线使用四个点定义:两个端点和两个控点。两个端点表示曲线的起点和终点。控点就好像 “磁铁” 一样把曲线从两个端点的直线处吸弯。两个端点是固定的,两个控点可以改变,按住鼠标左键并拖动鼠标就可以改变第一个控点,按住右键并拖动鼠标就可以改变第二个控点。

下面是MSDN中贝塞尔样条曲线的定义:

PolyBezier

The PolyBezier function draws one or more Bézier curves.

BOOL PolyBezier(
  HDC hdc,            // handle to device context
  CONST POINT *lppt,  // endpoints and control points
  DWORD cPoints       // count of endpoints and control points
);

Parameters

hdc
[in] Handle to a device context.
lppt
[in] Pointer to an array of POINT structures that contain the endpoints and control points of the curve(s).
cPoints
[in] Specifies the number of points in the lppt array. This value must be one more than three times the number of curves to be drawn, because each Bézier curve requires two control points and an endpoint, and the initial curve requires an additional starting point.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. 


示例代码:

#include
 
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;


int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("Bezier") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;
     
     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("Program requires Windows NT!"), 
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName, TEXT ("Bezier Splines"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
     
     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}


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)
{
     static POINT apt[4] ;
     HDC          hdc ;
     int          cxClient, cyClient ;
     PAINTSTRUCT  ps ;
     
     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 / 2 ;
          apt[1].y = cyClient / 4 ;
          
          apt[2].x =     cxClient / 2 ;
          apt[2].y = 3 * cyClient / 4 ;
          
          apt[3].x = 3 * cxClient / 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 (WHITE_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 (BLACK_PEN)) ;
               DrawBezier (hdc, apt) ;
               ReleaseDC (hwnd, hdc) ;
          }
          return 0 ;
          
     case WM_PAINT:
          InvalidateRect (hwnd, NULL, TRUE) ;
          
          hdc = BeginPaint (hwnd, &ps) ;
          
          DrawBezier (hdc, apt) ;
          
          EndPaint (hwnd, &ps) ;
          return 0 ;
          
     case WM_DESTROY:
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}


   



         贝塞尔曲线的直线和曲线总是相切的。从20世纪60年代起,二维的贝塞尔曲线就被认为是在计算机图形学中最有用的曲线之一(仅次于直线和椭圆),只要稍加练习,通常就可以只有操纵曲线,画出与预期形状非常接近的曲线。

        在32位的Windows版本出现之前,必须使用 Polyline 函数来建立贝塞尔样条曲线。同时还需要知道下面的贝塞尔样条曲线的参数方程。(x0,  y0) 是起点,(x3, y3) 是终点, (x1, y1) 和 (x2, y2) 是两个控点。t 值的取值是从 0 到 1 ,改变 t 的值可以获得不同的曲线:

                 

          

在 windows98 中,不需要知道这些公式。为了绘制一条或多条连接的贝塞尔样条曲线,只需简单的调用:

    PolyBezier ( hdc, apt, icount );

或          

  PolyBezierTo ( hdc, apt, icount) ;  


关于这两个函数的解释详见MSDN。


你可能感兴趣的:(windows编程)