#include <windows.h>
#include <math.h>
#define NUM 1000
#define TWOPI (2*3.14159)
LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, //目前執行個體句柄
HINSTANCE hPrevInstance, //先前執行個體句柄
LPSTR lpCmdLine, //指令行
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))
{
return -1;
}
//建立視窗
hwnd = CreateWindow(szAppName, //視窗類的名稱,必須是已經注冊的
TEXT("貝塞爾函數"), //視窗标題
WS_OVERLAPPEDWINDOW, //視窗風格
CW_USEDEFAULT, //X坐标
CW_USEDEFAULT, //Y坐标
CW_USEDEFAULT, //寬度
CW_USEDEFAULT, //高度
NULL, //父視窗句柄
NULL, //菜單視窗句柄
hInstance, //進階版本的windos忽略
NULL);
//顯示視窗
//ShowWindow(hwnd,SW_SHOWNA);
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)
{
HDC hdc;
PAINTSTRUCT ps;
int i,j;
static int cxClient,cyClient;
static POINT apt[4] ;
switch(message)
{
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
//4個點分别是起點,第一控制點,第二控制點。終點
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_RBUTTONUP:
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, CreatePen (PS_DASH, 0, RGB (255, 0, 0))) ;
//畫曲線
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);
}
在windows中,使用PolyBezier函數繪制貝塞爾曲線。
程式中要注意的是:WM_MOUSEMOVE下的消息處理方式:先用白色的畫筆畫曲線,再用黑色的畫筆畫曲線,這樣就做出了皮筋一樣的效果:第一條曲線實際上是随着滑鼠運動而産生的軌迹,不是我們想要的結果,我們想要的是最後移動到位置時的曲線,是以最後才用我們自定義的筆(這裡定義為紅色,虛線)畫圖。