关闭

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

2225人阅读 评论(1) 收藏 举报

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

 一:问题描述
  在二维情况下,线段的裁剪就是说有一个线段,有一个矩形,我们要判断这个线段哪一部分是属于矩形内部的,然后只保留内部的那部分,而舍弃矩形外的部分,图形学中目前流行的考裁剪算法有:求解联立方程组的线段裁剪法,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
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:282187次
    • 积分:4220
    • 等级:
    • 排名:第7512名
    • 原创:117篇
    • 转载:4篇
    • 译文:1篇
    • 评论:279条
    文章分类
    最新评论