第26周-window程序设计(基础篇)-第5章(图形基础)-贝塞尔曲线BEZIER.C

来源:互联网 发布:mac 退出dashboard 编辑:程序博客网 时间:2024/06/04 14:23

1、贝塞尔曲线BEZIER.C:

/*贝塞尔曲线:一条二维的贝塞尔曲线由四个点定义-两个端点和两个控制点。曲线的端点在两个端点上,控制点就好像「磁石」一样把曲线从两个端点间的直线处拉走。这一点可以由底下的BEZIER互动交谈程序做出最好的展示。BEZIER.C——Bezier Splines(样条函数) Demo.*/#include<windows.h>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) ;     wndclasswndclass.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) ;   } /*1、在这个程序中,两个顶点设定在显示区域的上下居中、左右位于1/4和3/4处的位置;两个控制点可以改变,按住鼠标左键或右键并拖动鼠标可以分别改动两个控制点之一。2、,贝塞尔曲线总是受限于一个四边形(叫做「凸包」),这个四边形由端点和控制点连接而成。3、曲线总是与第一个控制点到起点的直线相切,并保持同一方向;同时,也与第二个控制点到终点的直线相切,并保持同一方向。这是用于推导贝塞尔公式时所做的另外两个假设。*//*32位系统前后操作贝塞尔曲线对比*/前:x(t) = (1 - t)3 x0 + 3t (1 - t)2 x1 + 3t2 (1 - t) x2 + t3 x3y(t) = (1 - t)3 y0 + 3t (1 - t)2 y1 + 3t2 (1 - t) y2 + t3 y3后:PolyBezier (hdc, apt, iCount) ;PolyBezierTo (hdc, apt, iCount) ;/*apt都是POINT结构的数组。对PolyBezier,前四个点(按照顺序)给出贝塞尔曲线的起点、第一个控制点、第二个控制点和终点。此后的每一条贝塞尔曲线只需给出三个点,因为后一条贝塞尔曲线的起点就是前一条贝塞尔曲线的终点,所以,iCount参数等于1加上您所绘制的这些首尾相接曲线条数的三倍。*//*注意:在画一系列相连的贝塞尔曲线时,只有当第一条贝塞尔曲线的第二个控制点、第一条贝塞尔曲线的终点(也就是第二条曲线的起点)和第二条贝塞尔曲线的第一个控制点线性相关时,也就是说这三个点在同一条直线上时,曲线在连接点处才是光滑的。*/

可编译代码:

#if defined(UNICODE) && !defined(_UNICODE)    #define _UNICODE#elif defined(_UNICODE) && !defined(UNICODE)    #define UNICODE#endif#include <tchar.h>#include <windows.h>/*  Declare Windows procedure  */LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);/*  Make the class name into a global variable  */TCHAR szClassName[ ] = _T("Bezier");int WINAPI WinMain (HINSTANCE hThisInstance,                     HINSTANCE hPrevInstance,                     LPSTR lpszArgument,                     int nCmdShow){    HWND hwnd;               /* This is the handle for our window */    MSG messages;            /* Here messages to the application are saved */    WNDCLASSEX wincl;        /* Data structure for the windowclass */    /* The Window structure */    wincl.hInstance = hThisInstance;    wincl.lpszClassName = szClassName;    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */    wincl.cbSize = sizeof (WNDCLASSEX);    /* Use default icon and mouse-pointer */    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);    wincl.lpszMenuName = NULL;                 /* No menu */    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */    wincl.cbWndExtra = 0;                      /* structure or the window instance */    /* Use Windows's default colour as the background of the window */    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;    /* Register the window class, and if it fails quit the program */    if (!RegisterClassEx (&wincl))        return 0;    /* The class is registered, let's create the program*/    hwnd = CreateWindowEx (           0,                   /* Extended possibilites for variation */           szClassName,         /* Classname */           _T("Bezier"),       /* Title Text */           WS_OVERLAPPEDWINDOW, /* default window */           CW_USEDEFAULT,       /* Windows decides the position */           CW_USEDEFAULT,       /* where the window ends up on the screen */           544,                 /* The programs width */           375,                 /* and height in pixels */           HWND_DESKTOP,        /* The window is a child-window to desktop */           NULL,                /* No menu */           hThisInstance,       /* Program Instance handler */           NULL                 /* No Window Creation data */           );    /* Make the window visible on the screen */    ShowWindow (hwnd, nCmdShow);    /* Run the message loop. It will run until GetMessage() returns 0 */    while (GetMessage (&messages, NULL, 0, 0))    {        /* Translate virtual-key messages into character messages */        TranslateMessage(&messages);        /* Send message to WindowProcedure */        DispatchMessage(&messages);    }    /* The program return-value is 0 - The value that PostQuitMessage() gave */    return messages.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) ;     }/*  This function is called by the Windows function DispatchMessage()  */LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){  static POINT apt[4];  HDC hdc ;  int cxClient,cyClient;  PAINTSTRUCT ps ;    switch (message)                  /* handle the messages */    {         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);       /* send a WM_QUIT to the message queue */            break;        default:                      /* for messages that we don't deal with */            return DefWindowProc (hwnd, message, wParam, lParam);    }    return 0;}

0 0