Cohen-Sutherland裁剪算法

贴上示例程序。注释随便写了点。Cohen-Sutherland裁剪算法的推导?这个看代码就清楚了,没什么推导。

  1. /* 2008/8/29 */
  2. #define WIN32_LEAN_AND_MEAN   //不使用MFC
  3. #define INITGUID      //使用GUID
  4. #include <windows.h>
  5. #include <windowsx.h>
  6. #include <mmsystem.h> //多媒体API
  7. #include <iostream.h>
  8. #include <conio.h>    //控制台IO支持
  9. #include <stdlib.h>   //声明定义的一些常用标准函数库
  10. #include <malloc.h>   //声明或定义一些内存的函数
  11. #include <memory.h>   //提供了内存操作相关的一些函数及声明
  12. #include <string.h>   //字符串的一些功能
  13. #include <stdarg.h>   //defines ANSI-style macros for variable argument functions
  14. #include <stdio.h>    //efinitions/declarations for standard I/O routines
  15. #include <math.h>     //一些数学方法
  16. #include <io.h>       //declarations for low-level file handling and I/O functions
  17. #include <fcntl.h>    //file control options used by open()
  18. #include <ddraw.h>
  19. //windows类名
  20. #define  WINDOW_CLASS_NAME "WINCLASS1"
  21. //宽,高,色深(像素)
  22. #define  SCREEN_WIDTH   640
  23. #define  SCREEN_HEIGHT   480
  24. #define  SCREEN_BPP     8
  25. //#define  BITMAP_ID            0x4D42
  26. #define  MAX_COLORS_PALETTE   256
  27. typedef unsigned short USHORT;
  28. typedef unsigned short WORD;
  29. typedef unsigned char UCHAR;
  30. typedef unsigned char BYTE;
  31. //填充表面
  32. int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color);
  33. //画线
  34. int Draw_Line(int x0,int y0,int x1,int y1,UCHAR color,UCHAR* vb_start,int lpitch);
  35. //裁剪直线
  36. int Clip_Line(int &x1,int &y1,int &x2,int &y2);
  37. //画剪切区域内的线
  38. int Draw_Clip_Line(int x0,int y0,int x1,int y1,UCHAR color,UCHAR* dest_buffer,int lpitch);
  39. //键盘按键宏
  40. #define  KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code)&0x8000)?1:0)
  41. #define  KEYUP(vk_code)   ((GetAsyncKeyState(vk_code)&0x8000)?0:1)
  42. //初始化结构体
  43. #define  DDRAW_INIT_STRUCT(ddstruct) { memset(&ddstruct,0,sizeof(ddstruct));ddstruct.dwSize=sizeof(ddstruct); }
  44. HWND main_window_handle =NULL;
  45. int  window_closed =0;
  46. HINSTANCE hinstance_app =NULL;
  47. LPDIRECTDRAW7 lpdd =NULL;
  48. LPDIRECTDRAWSURFACE7 lpddsprimary =NULL;  //主缓存
  49. LPDIRECTDRAWSURFACE7 lpddsback =NULL;     //后备缓冲
  50. LPDIRECTDRAWPALETTE  lpddpal =NULL;       //调色板接口
  51. LPDIRECTDRAWCLIPPER  lpddclipper =NULL;   //裁剪器
  52. PALETTEENTRY         palette[256];        //调色板
  53. DDSURFACEDESC2       ddsd;
  54. DDBLTFX              ddbltfx;
  55. DDSCAPS2             ddscaps;
  56. /*裁剪区域*/
  57. int min_clip_x = ((SCREEN_WIDTH/2)-100),
  58.     max_clip_x = ((SCREEN_WIDTH/2)+100),
  59.     min_clip_y = ((SCREEN_HEIGHT/2)-100),
  60.     max_clip_y = ((SCREEN_HEIGHT/2)+100);
  61. char buffer[80];
  62. int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color)
  63. {
  64.   DDRAW_INIT_STRUCT(ddbltfx);
  65.   ddbltfx.dwFillColor=color;
  66.   lpdds->Blt(NULL,
  67.              NULL,
  68.              NULL,
  69.              DDBLT_COLORFILL|DDBLT_WAIT,
  70.              &ddbltfx);
  71.   return(1);
  72. }
  73. Draw_Clip_Line(int x0,int y0,int x1,int y1,UCHAR color,UCHAR* dest_buffer,int lpitch)
  74. {
  75.   int cxs,cys,cxe,cye;
  76.   cxs=x0;
  77.   cys=y0;
  78.   cxe=x1;
  79.   cye=y1;
  80.   if(Clip_Line(cxs,cys,cxe,cye))
  81.     Draw_Line(cxs,cys,cxe,cye,color,dest_buffer,lpitch);
  82.   return(1);
  83. }
  84. Clip_Line(int &x1,int &y1,int &x2,int &y2)
  85. {/*Cohen-Sutherland裁剪算法*/
  86.   #define CLIP_CODE_C 0x0000
  87.   #define CLIP_CODE_N 0x0008
  88.   #define CLIP_CODE_S 0x0004
  89.   #define CLIP_CODE_E 0x0002
  90.   #define CLIP_CODE_W 0x0001
  91.   #define CLIP_CODE_NE 0x000a
  92.   #define CLIP_CODE_SE 0x0006
  93.   #define CLIP_CODE_NW 0x0009
  94.   #define CLIP_CODE_SW 0x0005
  95.   int xc1=x1,
  96.       yc1=y1,
  97.       xc2=x2,
  98.       yc2=y2;
  99.   
  100.   int p1_code=0,
  101.       p2_code=0;
  102.   if(y1<min_clip_y)
  103.     p1_code|=CLIP_CODE_N;
  104.   else
  105.   if(y1>max_clip_y)
  106.     p1_code|=CLIP_CODE_S;
  107.   if(x1<min_clip_x)
  108.     p1_code|=CLIP_CODE_W;
  109.   else
  110.   if(x1>max_clip_x)
  111.     p1_code|=CLIP_CODE_E;
  112.   if(y2<min_clip_y)
  113.     p2_code|=CLIP_CODE_N;
  114.   else
  115.   if(y2>max_clip_y)
  116.     p2_code|=CLIP_CODE_S;
  117.   if(x2<min_clip_x)
  118.     p2_code|=CLIP_CODE_W;
  119.   else
  120.   if(x2>max_clip_x)
  121.     p2_code|=CLIP_CODE_E;
  122.   //若两点在剪切区域外且在同一方向
  123.   if((p1_code&p2_code))
  124.     return(0);
  125.   //若两点都在剪切区域内
  126.   if(p1_code==0&&p2_code==0)
  127.     return(1);
  128.   switch(p1_code)
  129.   {
  130.   case CLIP_CODE_C: break;
  131.   case CLIP_CODE_N:
  132.     {
  133.       yc1=min_clip_y;
  134.       xc1=x1+(min_clip_y-y1)*(x2-x1)/(y2-y1);
  135.     }break;
  136.   case CLIP_CODE_S:
  137.     {
  138.       yc1=max_clip_y;
  139.       xc1=x1+(max_clip_y-y1)*(x2-x1)/(y2-y1);
  140.     }break;
  141.   case CLIP_CODE_W:
  142.     {
  143.       xc1=min_clip_x;
  144.       yc1=y1+(min_clip_x-x1)*(y2-y1)/(x2-x1);
  145.     }break;
  146.   case CLIP_CODE_E:
  147.     {
  148.       xc1=max_clip_x;
  149.       yc1=y1+(max_clip_x-x1)*(y2-y1)/(x2-x1);
  150.     }break;
  151.   case CLIP_CODE_NE:
  152.     {
  153.       yc1=min_clip_y;
  154.       xc1=x1+(min_clip_y-y1)*(x2-x1)/(y2-y1);
  155.       if(xc1<min_clip_x||xc1>max_clip_x)
  156.       {
  157.         xc1=max_clip_x;
  158.         yc1=y1+(max_clip_x-x1)*(y2-y1)/(x2-x1);
  159.       }
  160.     }break;
  161.   case CLIP_CODE_SE:
  162.     {
  163.       yc1=max_clip_y;
  164.       xc1=x1+(max_clip_y-y1)*(x2-x1)/(y2-y1);
  165.       if(xc1<min_clip_x||xc1>max_clip_x)
  166.       {
  167.         xc1=max_clip_x;
  168.         yc1=y1+(max_clip_x-x1)*(y2-y1)/(x2-x1);
  169.       }
  170.     }break;
  171.   case CLIP_CODE_NW:
  172.     {
  173.       yc1=min_clip_y;
  174.       xc1=x1+(min_clip_y-y1)*(x2-x1)/(y2-y1);
  175.       if(xc1<min_clip_x||xc1>max_clip_x)
  176.       {
  177.         xc1=min_clip_x;
  178.         yc1=y1+(min_clip_x-x1)*(y2-y1)/(x2-x1);
  179.       }
  180.     }break;
  181.   case CLIP_CODE_SW:
  182.     {
  183.       yc1=max_clip_y;
  184.       xc1=x1+(max_clip_y-y1)*(x2-x1)/(y2-y1);
  185.       if(xc1<min_clip_x||xc2>max_clip_x)
  186.       {
  187.         xc1=min_clip_x;
  188.         yc1=y1+(min_clip_x-x1)*(y2-y1)/(x2-x1);
  189.       }
  190.     }break;
  191.     
  192.   default:break;
  193.     
  194.   }
  195.   switch(p2_code)
  196.   {
  197.   case CLIP_CODE_C: break;
  198.   case CLIP_CODE_N:
  199.     {
  200.       yc2=min_clip_y;
  201.       xc2=x2+(min_clip_y-y2)*(x2-x1)/(y2-y1);
  202.     }break;
  203.   case CLIP_CODE_S:
  204.     {
  205.       yc2=max_clip_y;
  206.       xc2=x2+(max_clip_y-y2)*(x2-x1)/(y2-y1);
  207.     }break;
  208.   case CLIP_CODE_W:
  209.     {
  210.       xc2=min_clip_x;
  211.       yc2=y2+(min_clip_x-x2)*(y2-y1)/(x2-x1);
  212.     }break;
  213.   case CLIP_CODE_E:
  214.     {
  215.       xc2=max_clip_x;
  216.       yc2=y2+(max_clip_x-x2)*(y2-y1)/(x2-x1);
  217.     }break;
  218.   case CLIP_CODE_NE:
  219.     {
  220.       yc2=min_clip_y;
  221.       xc2=x2+(min_clip_y-y2)*(x2-x1)/(y2-y1);
  222.       if(xc2<min_clip_x||xc2>max_clip_x)
  223.       {
  224.         xc2=max_clip_x;
  225.         yc2=y2+(max_clip_x-x2)*(y2-y1)/(x2-x1);
  226.       }
  227.     }break;
  228.   case CLIP_CODE_SE:
  229.     {
  230.       yc2=max_clip_y;
  231.       xc2=x2+(max_clip_y-y2)*(x2-x1)/(y2-y1);
  232.       if(xc2<min_clip_x||xc2>max_clip_x)
  233.       {
  234.         xc2=max_clip_x;
  235.         yc2=y2+(max_clip_x-x2)*(y2-y1)/(x2-x1);
  236.       }
  237.     }break;
  238.   case CLIP_CODE_NW:
  239.     {
  240.       yc2=min_clip_y;
  241.       xc2=x2+(min_clip_y-y2)*(x2-x1)/(y2-y1);
  242.       if(xc2<min_clip_x||xc2>max_clip_x)
  243.       {
  244.         xc2=min_clip_x;
  245.         yc2=y2+(min_clip_x-x2)*(y2-y1)/(x2-x1);
  246.       }
  247.     }break;
  248.   case CLIP_CODE_SW:
  249.     {
  250.       yc2=max_clip_y;
  251.       xc2=x2+(max_clip_y-y2)*(x2-x1)/(y2-y1);
  252.       if(xc2<min_clip_x||xc2>max_clip_x)
  253.       {
  254.         xc2=min_clip_x;
  255.         yc2=y2+(min_clip_x-x2)*(y2-y1)/(x2-x1);
  256.       }
  257.     }break;
  258.     
  259.   default:break;    
  260.   }
  261.   if( (xc1<min_clip_x)||(xc1>max_clip_x)||
  262.     (yc1<min_clip_y)||(yc1>max_clip_y)||
  263.     (xc2<min_clip_x)||(xc2>max_clip_x)||
  264.     (yc2<min_clip_y)||(yc2>max_clip_y) )
  265.   {/*若经过裁剪仍有点在剪切区域外,
  266.     则剪切区域内不存在要画的直线*/
  267.     return (0);
  268.   }
  269.   /*否则修改直线的两个端点坐标*/
  270.   x1=xc1;
  271.   y1=yc1;
  272.   x2=xc2;
  273.   y2=yc2;
  274.   return (1);
  275. }
  276. int Draw_Line(int x0,int y0,int x1,int y1,UCHAR color,UCHAR* vb_start,int lpitch)
  277. {/*Bresenham算法画线*/
  278.   int dx,
  279.       dy,
  280.       dx2,
  281.       dy2,
  282.       x_inc,
  283.       y_inc,
  284.       error,
  285.       index;
  286.   vb_start=vb_start+x0+y0*lpitch;
  287.   dx=x1-x0;
  288.   dy=y1-y0;
  289.   if(dx>=0)
  290.     x_inc=1;
  291.   else
  292.   {
  293.     x_inc=-1;
  294.     dx=-dx;
  295.   }
  296.   
  297.   if(dy>=0)
  298.     y_inc=lpitch;
  299.   else
  300.   {
  301.     y_inc=-lpitch;
  302.     dy=-dy;
  303.   }
  304.   dx2=dx<<1;
  305.   dy2=dy<<1;
  306.   if(dx>dy)
  307.   {/*斜率<1的情况*/
  308.     error=dy2-dx;
  309.     for(index=0;index<=dx;index++)
  310.     {
  311.       *vb_start=color;
  312.       if(error>=0)
  313.       {
  314.         error-=dx2;
  315.         vb_start+=y_inc;  
  316.       }
  317.         error+=dy2;
  318.         vb_start+=x_inc;
  319.     }
  320.   }
  321.   else
  322.   {/*斜率>1的情况*/
  323.     error=dx2-dy;
  324.     for(index=0;index<=dy;index++)
  325.     {
  326.       *vb_start=color;
  327.       if(error>=0)
  328.       {
  329.         error-=dy2;
  330.         vb_start+=x_inc;
  331.       }
  332.       error+=dx2;
  333.       vb_start+=y_inc;
  334.     }
  335.   }
  336.   
  337.   return(1);
  338. }
  339. LRESULT CALLBACK WindowProc(HWND hwnd,
  340.                             UINT msg,
  341.                             WPARAM wparam,
  342.                             LPARAM lparam)
  343. {
  344. PAINTSTRUCT     ps;     
  345. HDC             hdc;    
  346.        
  347. switch(msg)
  348.     {   
  349.     case WM_CREATE: 
  350.         {
  351.         return(0);
  352.         } break;
  353.    
  354.     case WM_PAINT: 
  355.         {
  356.         hdc = BeginPaint(hwnd,&ps);  
  357.         
  358.         EndPaint(hwnd,&ps);
  359.         return(0);
  360.         } break;
  361.     case WM_DESTROY: 
  362.         {
  363.         PostQuitMessage(0);
  364.         return(0);
  365.         } break;
  366.     default:break;
  367.     }
  368. return (DefWindowProc(hwnd, msg, wparam, lparam));
  369. }
  370. int Game_Init(void *parms=NULL,int num_parms=0)
  371. {
  372.   if(FAILED(DirectDrawCreateEx(NULL,(void **)&lpdd,IID_IDirectDraw7,NULL)))
  373.     return(0);
  374.   if(FAILED(lpdd->SetCooperativeLevel(main_window_handle,
  375.                                       DDSCL_FULLSCREEN|DDSCL_ALLOWMODEX|
  376.                                       DDSCL_EXCLUSIVE|DDSCL_ALLOWREBOOT)))
  377.     return(0);
  378.   if(FAILED(lpdd->SetDisplayMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,0,0)))
  379.     return(0);
  380.   DDRAW_INIT_STRUCT(ddsd);
  381.   ddsd.dwFlags=DDSD_CAPS;
  382.   ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE;
  383.   
  384.   if(FAILED(lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL)))
  385.     return(0);
  386.   for (int color=1; color < 255; color++)
  387.     {
  388.     palette[color].peRed   = rand()%256;
  389.     palette[color].peGreen = rand()%256;
  390.     palette[color].peBlue  = rand()%256;
  391.     palette[color].peFlags = PC_NOCOLLAPSE;
  392.     } 
  393. palette[0].peRed     = 0;
  394. palette[0].peGreen   = 0;
  395. palette[0].peBlue    = 0;
  396. palette[0].peFlags   = PC_NOCOLLAPSE;
  397. palette[255].peRed   = 255;
  398. palette[255].peGreen = 255;
  399. palette[255].peBlue  = 255;
  400. palette[255].peFlags = PC_NOCOLLAPSE;
  401. if(FAILED(lpdd->CreatePalette(DDPCAPS_8BIT|DDPCAPS_ALLOW256|
  402.                               DDPCAPS_INITIALIZE,palette,&lpddpal,NULL)))
  403.     return(0);
  404. if(FAILED(lpddsprimary->SetPalette(lpddpal)))
  405.     return(0);
  406. DDraw_Fill_Surface(lpddsprimary,0);
  407. return(1);  
  408. }
  409. int Game_Main(void *parms = NULL, int num_parms = 0)
  410. {
  411.   if(window_closed)
  412.     return(0);
  413.   if(KEYDOWN(VK_ESCAPE))
  414.   {
  415.     PostMessage(main_window_handle,WM_CLOSE,0,0);
  416.     window_closed=1;
  417.   }
  418.   DDRAW_INIT_STRUCT(ddsd);
  419.   if(FAILED(lpddsprimary->Lock(NULL,&ddsd,DDLOCK_WAIT|DDLOCK_SURFACEMEMORYPTR,NULL)))
  420.     return(0);
  421.   for (int index=0; index < 1000; index++)
  422.     {
  423.     Draw_Clip_Line(rand()%SCREEN_WIDTH, rand()%SCREEN_HEIGHT,
  424.               rand()%SCREEN_WIDTH, rand()%SCREEN_HEIGHT,
  425.               rand()%256,
  426.               (UCHAR *)ddsd.lpSurface, ddsd.lPitch);
  427.     } 
  428. if (FAILED(lpddsprimary->Unlock(NULL)))
  429.    return(0);
  430. Sleep(33);
  431. return(1);
  432. }
  433. int Game_Shutdown(void *parms = NULL, int num_parms = 0)
  434. {/*清除资源*/
  435. if (lpddpal)
  436.    {
  437.    lpddpal->Release();
  438.    lpddpal = NULL;
  439.    }
  440. if (lpddsprimary)
  441.    {
  442.    lpddsprimary->Release();
  443.    lpddsprimary = NULL;
  444.    } 
  445. if (lpdd)
  446.    {
  447.    lpdd->Release();
  448.    lpdd = NULL;
  449.    } 
  450. return(1);
  451. }
  452. int WINAPI WinMain( HINSTANCE hinstance,
  453.                     HINSTANCE hprevinstance,
  454.                     LPSTR lpcmdline,
  455.                     int ncmdshow)
  456. {
  457. WNDCLASSEX winclass; 
  458. HWND       hwnd;    
  459. MSG        msg;      
  460. HDC        hdc;    
  461. winclass.cbSize         = sizeof(WNDCLASSEX);
  462. winclass.style          = CS_DBLCLKS | CS_OWNDC | 
  463.                           CS_HREDRAW | CS_VREDRAW;
  464. winclass.lpfnWndProc    = WindowProc;
  465. winclass.cbClsExtra     = 0;
  466. winclass.cbWndExtra     = 0;
  467. winclass.hInstance      = hinstance;
  468. winclass.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
  469. winclass.hCursor        = LoadCursor(NULL, IDC_ARROW); 
  470. winclass.hbrBackground  = (HBRUSH)GetStockObject(BLACK_BRUSH);
  471. winclass.lpszMenuName   = NULL;
  472. winclass.lpszClassName  = WINDOW_CLASS_NAME;
  473. winclass.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);
  474. hinstance_app = hinstance;
  475. if (!RegisterClassEx(&winclass))
  476.     return(0);
  477. if (!(hwnd = CreateWindowEx(NULL,                  
  478.                             WINDOW_CLASS_NAME,    
  479.                             "DirectDraw 8-Bit Line Drawing Demo"
  480.                             WS_POPUP | WS_VISIBLE,
  481.                             0,0,    
  482.                             SCREEN_WIDTH,SCREEN_HEIGHT,  
  483.                             NULL,     
  484.                             NULL,  
  485.                             hinstance,
  486.                             NULL))) 
  487. return(0);
  488. main_window_handle = hwnd;
  489. Game_Init();
  490. while(TRUE)
  491.     {
  492.   
  493.     if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  494.        { 
  495.        if (msg.message == WM_QUIT)
  496.            break;
  497.     
  498.        TranslateMessage(&msg);
  499.        DispatchMessage(&msg);
  500.        }
  501.      Game_Main();
  502.        
  503.     } 
  504. Game_Shutdown();
  505. return(msg.wParam);
  506. }

必要的优化:在Cohen-Sutherland裁剪直线算法中,由一个点的X(Y)坐标推算这个点Y(X)坐标时可以把推算的坐标+0.5,以减小误差。因为坐标在由浮点型转换为整型时会造成信息丢失。比如12.6它会转化int时为12,若加上0.5再转换则为13,自然是后者误差更小。

有关Bresenham画线算法的推导,可以参见http://www.cnblogs.com/soroman/archive/2006/07/27/509602.html 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值