CGA裁剪算法之线段裁剪算法
常用的线段裁剪算法有三种:【1】Cohen_SutherLand裁剪算法,【2】中点分割裁剪算法,【3】参数化方法。
1. Cohen_SutherLand裁剪算法
为了能快速的判断一条直线与矩形窗口属于何种位置关系,Cohen_SutherLand裁剪算法采用如下的编码方案,因此又称为“编码裁剪算法”。
在编码裁剪算法中采用了如下图所示的空间划分和编码方案:
编码的[上, 下, 右, 左], 即上: 1000, 下:0100,右:0010, 左:0001,分别对应的十进制数: 上:8, 下:4, 右:2, 左:1。所以在矩形窗口(包含四个边的边界)左上,左下,右上,右下编码如下图。
裁剪一条线段时,先求出两端点所在的区号code1和code2,有如下情况:
(1)若code1 = 0且code2 = 0,则说明线段的两个端点均在窗口内,那么整条线段必在窗口内,应取之,直线可以直接显示;
(2)若code1和code2经按位与运算的结果不为0,则说明两个端点同在窗口的上 方、下方、左方或右方。这种情况下,对线段的处理是弃之,直线不进行显示。
(3)如果上述两种条件都不成立,则按第三种情况处理。求出线段与窗口某边的交点,在交点处把线段一分 为二,其中必有一段完全在窗口外,可弃之,对另一段则重复上述处理,如线段P1P2, 则最终得到的显示线段为P3P4,即为裁剪后的线段,然后进行显示。
算法分析:
因为需要对窗口的不同防线进行编码,所以只适合方形的窗口,不适合圆形的窗口裁剪处理。
程序如下:
1 ////裁剪算法 2 #define TOP_EDGE 8 3 #define BOTTOM_EDGE 4 4 #define RIGHT_EDGE 2 5 #define LEFT_EDGE 1 6 7 class CBassClip 8 { 9 public: 10 11 public: 12 bool isInited; 13 14 }; 15 16 class CCohenSutherLandClip:public CBassClip 17 { 18 public: 19 CCohenSutherLandClip() 20 { 21 isInited = false; 22 } 23 bool cohen_SutherLandClip(Point &p_startPos, Point &p_endPos, Point &p_startResult, Point &p_endResult); 24 void readClipInformation(Point &p_winRU, Point &p_winLB); 25 private: 26 //声明出编码获取说明 27 unsigned char getCompPointCode(Point &p_Point); 28 private: 29 Point m_winLB, m_winRU; 30 31 }; 32 33 //初始化裁剪信息 34 inline void CCohenSutherLandClip::readClipInformation(Point &p_winRU, Point &p_winLB) 35 { 36 this->m_winLB = p_winLB; 37 this->m_winRU = p_winRU; 38 39 this->isInited = true; 40 } 41 //获取指定点的窗口位置编码 42 inline unsigned char CCohenSutherLandClip::getCompPointCode(Point &p_Point) 43 { 44 assert(isInited); 45 unsigned char code = 0x00; 46 //边界位置算窗口内 47 if (p_Point.y > m_winRU.y ) 48 code |= 8; 49 if (p_Point.y < m_winLB.y ) 50 code |= 4; 51 if (p_Point.x > m_winRU.x ) 52 code |= 2; 53 if (p_Point.x < m_winLB.x ) 54 code |= 1; 55 return code; 56 } 57 //编码裁剪算法实现 58 inline bool CCohenSutherLandClip::cohen_SutherLandClip(Point &p_startPos, Point &p_endPos, Point &p_startResult, Point &p_endResult) 59 { 60 assert(isInited); 61 bool accept, done; 62 63 float x,y; 64 accept = false; 65 done = false; 66 67 unsigned char code0,code1, codeout; 68 code0 = getCompPointCode(p_startPos); 69 code1 = getCompPointCode(p_endPos); 70 do{ 71 if(!(code0 | code1))//窗口内部 72 { 73 accept = true ; 74 done = true; 75 } 76 else if(code0 & code1)//窗口外部 77 done = true; 78 else//不确定 79 { 80 if(code0 != 0) 81 codeout = code0; 82 else 83 codeout = code1; 84 85 if(codeout & LEFT_EDGE) 86 { 87 y = p_startPos.y + (p_endPos.y-p_startPos.y)*(m_winLB.x-p_startPos.x)/(p_endPos.x-p_startPos.x); 88 x = m_winLB.x; 89 } 90 else if(codeout & RIGHT_EDGE){ 91 y = p_startPos.y + (p_endPos.y-p_startPos.y)*(m_winRU.x-p_startPos.x)/(p_endPos.x-p_startPos.x); 92 x = m_winRU.x; 93 } 94 else if(codeout & BOTTOM_EDGE){ 95 x = p_startPos.x + (p_endPos.x-p_startPos.x)*(m_winLB.y-p_startPos.y)/(p_endPos.y-p_startPos.y); 96 y = m_winLB.y; 97 } 98 else if(codeout & TOP_EDGE){ 99 x = p_startPos.x + (p_endPos.x-p_startPos.x)*(m_winRU.y-p_startPos.y)/(p_endPos.y-p_startPos.y); 100 y = m_winRU.y; 101 } 102 103 if(codeout == code0)//开始顶点处理完毕 104 { 105 p_startResult.x = x; 106 p_startResult.y = y; 107 code0 = getCompPointCode(p_startResult); 108 } 109 else 110 { 111 p_endResult.x = x; 112 p_endResult.y = y; 113 code1 = getCompPointCode(p_endResult); 114 } 115 } 116 }while(!done); 117 return accept; 118 }