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

原创 2006年06月08日 22:40:00

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

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

 

 

相关文章推荐

[Win32]画刷、矩形、不规则区域和剪裁

1. 画刷简介:     1) Windows就是使用画刷来实现抖动色彩技术的(即

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Cohen-Sutherland线段裁剪算法

通过一个矩形的裁剪区域将整个屏幕分成9个部分,并为每一个部分赋予相应的区域码,然后根据端点的位置确定这个端点的区域码。 先判断能否完全接受或者完全排除一条线段,若以上2个判断无法直接得出,则逐步裁剪...

Win32 绘图基础 -- 绘制直线、边框、贝塞尔曲线、填充、裁剪

分类: Win32 SDK 2012-11-10 00:37 3990人阅读 评论(2) 收藏 举报 Win32填充区直线绘图 目录(?)[+] 注:以下内容为学习...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Win32下绘图程序(一)画线、画矩形、画椭圆

1、 2、 3、
  • wwkaven
  • wwkaven
  • 2014年08月05日 20:16
  • 1401

C++ 从一幅图片上裁取需要的区域

1、Mat Mat src, image_src; //原图 Mat imageROI; //ROI区域 Mat TempImg; //裁取出的区域存储为Mat int ...

Win32 SDK中窗口全屏处理 用window api实现程序全屏显示

http://www.cnblogs.com/phinecos/archive/2008/02/14/1069117.html    首先是考虑全屏处理的时机,是在创建窗口时还是显示窗口...
  • chla
  • chla
  • 2015年01月19日 16:00
  • 498

SDK学习笔记2-一个Win32窗口程序实现过程

Win32程序实现的步骤: WinMain函数的定义 创建一个窗口 1. 设计一个窗口类 2. 注册窗口类 3. 创建窗口 4. 显示及刷新窗口进行消息循环 完成回调函数 //WinMain...
  • nvcgkk
  • nvcgkk
  • 2016年12月03日 21:33
  • 322

提取VS的Win32SDk用C/C++编译器 (续)——使用方法

上一篇博文(地址:http://blog.csdn.net/zuishikonghuan/article/details/46359933)中,我介绍了如何从VS中提取Win32SDK用的C/C++编...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:二维线段裁剪程序的C/SDK WIN32实现
举报原因:
原因补充:

(最多只允许输入30个字)