#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下的消息处理方式:先用白色的画笔画曲线,再用黑色的画笔画曲线,这样就做出了皮筋一样的效果:第一条曲线实际上是随着鼠标运动而产生的轨迹,不是我们想要的结果,我们想要的是最后移动到位置时的曲线,所以最后才用我们自定义的笔(这里定义为红色,虚线)画图。