二维线段裁剪程序的C/SDK WIN32实现

前些天在做打乒乓程序,一连做了好几个,但做到多线程的版本的时候一直有问题,又加上临近考试了,所以那个先放一放,把图形学的课程设计题目先做一下,于是就做了下面这个程序:(不过那个多线程的版本打乒乓我以后一定补做它)

  一:问题描述
   在二维情况下,线段的裁剪就是说有一个线段,有一个矩形,我们要判断这个线段哪一部分是属于矩形内部的,然后只保留内部的那部分,而舍弃矩形外的部分,图形学中目前流行的考裁剪算法有:求解联立方程组的线段裁剪法, Cohen-Sutherland 算法,以及参数化的线段裁剪算法等等。本程序采用了 Cohen-Sutherland 算法,以 WIN32 下调用 GDI API 函数实现,实现平台为 WINDOWS XP +Visual C++6.0
二:解题算法
Cohen-Sutherland 算法:
1 :编码:
我们按线段的端点相对裁剪矩形的位置对将要判断的线段端点进行编码,编码算法如下:
第一位为 1 ,表示端点在 yT 上方;
第二位为 1 ,表示端点在 yB 上方;
第三为为 1 ,表示端点在 xR 右方;
第四位为 1 ,表示端点在 xL 左方;
否则,相应位置零 0
相应的编码如图所示:

2:当线段的两个端点的4位编码全为0,则此线段全部在窗口内,可直接接受;

3:如果对线段的两个端点的4位编码进行逻辑与运算,结果为非零,则此线段在窗口之外可以直接舍弃;

4:这一线断既不能直接舍弃也不能直接接受,它可能与窗口相交。

当发生情况4时,我们需要对线段进行再分割,即找到与窗口一个边框的交点。根据交点的位置,赋予其四位编码,然后检查分割后的线段,对其进行接受、舍弃、分割。重复以上过程,直至不出现第4种情况为止。

三:程序说明及运行结果

   启动2D LineClippping.exe,默认先画直线,你可以画不止一条直线,最后它们都将被裁剪,画完直线,点 DrawRectangle 按钮,开始画裁剪矩形,矩形只能画一个,画完矩形,点Clipping按钮,程序就完成了裁剪操作并且将结果显示在了客户区,如果你画线或者画矩形的中间对已画的图形不满意,可以按Restet 按钮随时清除所有已画图形,重新来过。最后完毕时,点右上角的关闭按钮即可退出程序。

1:开始画直线

2:画矩形:

3:裁剪后

四:程序源码

/Powered by alex 2006.6.6 曰完成//

#include<windows.h>     

 

#define DRAWRECT 0          //for Button ID

#define CLIPPING 1

#define RESET    2

 

typedef struct line          //store two vertex of every lines

{

    int xStart,yStart;                    

    int xEnd,yEnd;                               

}LINE,*PLINE;

 

LINE lines[100];            //maximun lines can deal with is 100

LINE line;

int j=0;

 

POINT rectLH,rectRL;

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

 

void CSLineClip(PLINE,int,int,int,int); //This is the Code Fuction

 

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE prevInstance,PSTR szCmdLine,int iCmdShow)

{

    static TCHAR szAppName[]="2D Line Clipping"; 

    HWND hwnd;                               

    MSG  msg;                                

    WNDCLASS wndclass;

    for(int i=0;i<100;i++){

       lines[i].xStart=0;

       lines[i].yStart=0;

       lines[i].xEnd=0;

       lines[i].yEnd=0;

    }

 

    wndclass.style=CS_HREDRAW | CS_VREDRAW |CS_DBLCLKS;        

    wndclass.lpfnWndProc=WndProc;                

    wndclass.cbClsExtra=0;                       

    wndclass.cbWndExtra=0;                       

    wndclass.hInstance=hInstance;                

    wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);  

    wndclass.hCursor=LoadCursor(NULL,IDC_CROSS); 

    wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

    wndclass.lpszMenuName=NULL;                  

    wndclass.lpszClassName=szAppName;            

 

    RegisterClass(&wndclass);                    

    hwnd=CreateWindow(szAppName,"2D Line Clipping",WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,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;                           

}

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

    HWND hButtonRect;

    HWND hButtonClipping;

    HWND hButtonReset;

 

    int cxChar,cyChar;

    static PLINE head=lines;

    int i=0;

    enum Shape{Line,Rect};

    static Shape WhatShape=Line;

                           

    HDC hdc;                              

    PAINTSTRUCT ps;  

    RECT clientrect;

 

    switch(message)                              

    {

    case WM_CREATE:

       cxChar=LOWORD(GetDialogBaseUnits());

       cyChar=HIWORD(GetDialogBaseUnits());

       hButtonRect   =CreateWindow(TEXT("BUTTON"),"DrawRectangle",WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,10*cxChar,28*cyChar,20*cxChar,7*cyChar/4,hwnd,(HMENU)DRAWRECT,((LPCREATESTRUCT)lParam)->hInstance,NULL);

       hButtonClipping=CreateWindow(TEXT("BUTTON"),"Clipping",     WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,40*cxChar,28*cyChar,20*cxChar,7*cyChar/4,hwnd,(HMENU)CLIPPING,((LPCREATESTRUCT)lParam)->hInstance,NULL);

       hButtonReset   =CreateWindow(TEXT("BUTTON"),"Reset",        WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,70*cxChar,28*cyChar,20*cxChar,7*cyChar/4,hwnd,(HMENU)RESET,   ((LPCREATESTRUCT)lParam)->hInstance,NULL);

       return 0;

    case WM_LBUTTONDOWN:

       if(WhatShape==Line)

{

           line.xStart=(int)LOWORD(lParam);

           line.yStart=(int)HIWORD(lParam);

       }

       else{

           if(rectLH.x!=0 && rectLH.y!=0)

{

              MessageBox(hwnd,"You can only draw one rectangle !","Error",MB_OK);

              return 0;

           }

           rectLH.x=(int)LOWORD(lParam);

           rectLH.y=(int)HIWORD(lParam);

       }

       return 0;

    case WM_MOUSEMOVE:

       if(wParam & MK_LBUTTON)

{

           hdc=GetDC(hwnd);

           SelectObject(hdc,GetStockObject(WHITE_PEN));

           if(WhatShape==Line)

{

              MoveToEx(hdc,line.xStart,line.yStart,NULL);

              LineTo(hdc,line.xEnd,line.yEnd);

           }

           else

{

              if(rectRL.x!=0 && rectRL.y!=0){

              Rectangle(hdc,rectLH.x,rectLH.y,rectRL.x,rectRL.y);

              }

           }

           if(WhatShape==Line)

{

              line.xEnd=(int)LOWORD(lParam);

              line.yEnd=(int)HIWORD(lParam);

           }

           else{

              rectRL.x=(int)LOWORD(lParam);

              rectRL.y=(int)HIWORD(lParam);

           }

           SelectObject(hdc,GetStockObject(BLACK_PEN));

           if(WhatShape==Line)

{

               MoveToEx(hdc,line.xStart,line.yStart,NULL);

              LineTo(hdc,line.xEnd,line.yEnd);

           }

           else{

              Rectangle(hdc,rectLH.x,rectLH.y,rectRL.x,rectRL.y);

           }

           ReleaseDC(hwnd,hdc);

           InvalidateRect(hwnd,NULL,FALSE);

       }

       return 0;

    case WM_LBUTTONUP:

       if(WhatShape==Line){

           line.xEnd=LOWORD(lParam);

           line.yEnd=HIWORD(lParam);

           lines[j].xStart=line.xStart;

           lines[j].yStart=line.yStart;

           lines[j].xEnd=line.xEnd;

           lines[j].yEnd=line.yEnd;

           j++;

       }

       else{

           rectRL.x=(int)LOWORD(lParam);

           rectRL.y=(int)HIWORD(lParam);

       }

       return 0;

    case WM_COMMAND:

       switch(LOWORD(wParam)){

       case DRAWRECT:

           if(lines[0].xStart==0 && lines[0].yStart==0){

              MessageBox(hwnd,"You can only draw rectangle after you draw some lines !","Error",MB_OK);

              break;

           }

           WhatShape=Rect;

           break;

       case CLIPPING:

           if(lines[0].xStart==0 && lines[0].yStart==0){

              MessageBox(hwnd,"Please draw at least one line to complete clipping !","Error",MB_OK);

              break;

           }

           if(rectRL.x==0 && rectRL.y==0){

              MessageBox(hwnd,"You haven't draw your clipping rectangle !","Error",MB_OK);

              break;

           }

           for(head=lines;head->xStart!=0 && head->yStart!=0;head++)

           {

           CSLineClip(head,rectLH.x,rectRL.x,rectLH.y,rectRL.y);

           }

           head=lines;

           hdc=GetDC(hwnd);

           GetClientRect(hwnd,&clientrect);

           Rectangle(hdc,clientrect.left-5,clientrect.top-5,clientrect.right+5,clientrect.bottom+5);

           ReleaseDC(hwnd,hdc);

           InvalidateRect(hwnd,NULL,FALSE);

           break;

       case RESET:

           j=0;

           WhatShape=Line;

           head=lines;

           for(int i=0;i<100;i++){

              lines[i].xStart=0;

              lines[i].yStart=0;

              lines[i].xEnd=0;

              lines[i].yEnd=0;

           }

           rectLH.x=0;

           rectLH.y=0;

           rectRL.x=0;

           rectRL.y=0;

           hdc=GetDC(hwnd);

           GetClientRect(hwnd,&clientrect);

           Rectangle(hdc,clientrect.left-5,clientrect.top-5,clientrect.right+5,clientrect.bottom+5);

           ReleaseDC(hwnd,hdc);

           InvalidateRect(hwnd,NULL,FALSE);

           break;

       }

       return 0;

    case WM_PAINT:

       hdc=BeginPaint(hwnd,&ps);

       if(rectRL.x!=0 && rectRL.y!=0){

           Rectangle(hdc,rectLH.x,rectLH.y,rectRL.x,rectRL.y);

       }

 

       for(head=lines;head->xStart!=0 && head->yStart!=0;head++)

       {

           if(head->xStart!=-1 && head->yStart!=-1){

              MoveToEx(hdc,head->xStart,head->yStart,NULL);

              LineTo(hdc,head->xEnd,head->yEnd);

           }

       }

       head=lines;

       EndPaint(hwnd,&ps);

       return 0;

    case WM_DESTROY:

       PostQuitMessage(0);

       return 0;

    }

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

}  

 

typedef unsigned int outcode;

 

enum {TOP=0X8,BOTTOM=0X4,RIGHT=0X2,LEFT=0X1};

 

outcode CompOutCode(int x,int y,int xmin,int xmax,int ymin,int ymax)

{

    outcode code=0;

    if(y>ymax){

       code |=BOTTOM;

    }

    else if(y<ymin){

       code |=TOP;

    }

    if(x>xmax){

       code |=RIGHT;

    }

    else if(x<xmin){

       code |=LEFT;

    }

    return code;

}

void CSLineClip(PLINE current,int xmin,int xmax,int ymin,int ymax)

{

    outcode outcode0,outcode1,outcodeOut;

    bool accept=FALSE,done=FALSE;

    int x0=current->xStart;

    int y0=current->yStart;

    int x1=current->xEnd;

    int y1=current->yEnd;

    outcode0=CompOutCode(x0,y0,xmin,xmax,ymin,ymax);

    outcode1=CompOutCode(x1,y1,xmin,xmax,ymin,ymax);

    int x,y;

    while(outcode0 !=0 || outcode1 !=0)

{

       if(outcode0 & outcode1)            //Reject Directly!

       {

           current->xStart=-1;

           current->yStart=-1;

           current->xEnd=-1;

           current->yEnd=-1;

           break;

       }

       outcodeOut=outcode0?outcode0:outcode1;

       if(outcodeOut & LEFT)

{

           x=xmin;

           y=y0+(int)(float(y1 - y0)*float(xmin-x0)/float(x1 - x0));

       }

       else if(outcodeOut & RIGHT)

{

           x=xmax;

           y=y0+int(float(y1-y0)*float(xmax-x0)/float(x1-x0));

       }

       else if(outcodeOut & BOTTOM)

{

           y=ymax;

           x=x0+int(float(x1-x0)*float(ymax-y0)/float(y1-y0));

       }

       else if(outcodeOut & TOP)

{

           y=ymin;

           x=x0+int(float(x1-x0)*float(ymin-y0)/float(y1-y0));

       }

       if(outcodeOut==outcode0)

{

           current->xStart=x;

           current->yStart=y;

           outcode0=CompOutCode(x,y,xmin,xmax,ymin,ymax);

       }

       else

       {

           current->xEnd=x;

           current->yEnd=y;

           outcode1=CompOutCode(x,y,xmin,xmax,ymin,ymax);

       }

    }

}

END//

 

 
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值