在本学期的所学的裁剪算法中,有一个叫做Nicholl-Lee-Nicholl的算法。
在实践中,我遇到了一个小问题,因为教程中所讲的只有起点在剪裁框内、左侧和左上的情况,并说其余情况均可以通过点的平移或旋转变换等方式变换到上述3个区域内。
但考虑到裁剪框并不都是正方形,所以上方区域和左侧区域也不都是完全映射的,所以并不能简单的旋转平移点,而是整个屏幕都旋转,这样的话还不如为上方区域单独做算法。
最终实现代码如下:
1 /* Nicholl-Lee-Nicholl Line Clipping Algorithm */ 2 void NichollLeeNichollClip() 3 { 4 // 变量 5 clipped_line_num = 0; 6 float m, k; 7 float mLT, mLB, mRB, mRT; // 生成起点到四个剪裁窗口顶点的斜率 8 // 针对每条线 9 for (int i = 0; i < line_num; i++) 10 { 11 // 生成剪裁线 12 line clip_line = l[i]; 13 // 区域码赋值 14 getRegionCode(clip_line.original); 15 getRegionCode(clip_line.terminal); 16 // 判断框内线条(两端点区域码都为00000) 17 if ((clip_line.original.code | clip_line.terminal.code) == 0x0) 18 { 19 clipped_l[clipped_line_num] = clip_line; 20 clipped_line_num++; 21 continue; 22 } 23 // 判断框外线条(两端点区域码按为与为真) 24 if (clip_line.original.code & clip_line.terminal.code) 25 { 26 continue; 27 } 28 // 判断起点是否在已有算法区域的对称区域 29 int before_code; // 变换之前的区域码 30 before_code = clip_line.original.code; 31 // 右侧变换 32 if (clip_line.original.code == winRightBitCode) 33 { 34 clip_line.original.x = clip_left + clip_right - clip_line.original.x; 35 clip_line.terminal.x = clip_left + clip_right - clip_line.terminal.x; 36 } 37 // 右上侧变换 38 if (clip_line.original.code == ( winRightBitCode | winTopBitCode ) ) 39 { 40 clip_line.original.x = clip_left + clip_right - clip_line.original.x; 41 clip_line.terminal.x = clip_left + clip_right - clip_line.terminal.x; 42 } 43 // 左下侧变换 44 if (clip_line.original.code == ( winLeftBitCode | winBottomBitCode ) ) 45 { 46 clip_line.original.y = clip_top + clip_bottom - clip_line.original.y; 47 clip_line.terminal.y = clip_top + clip_bottom - clip_line.terminal.y; 48 } 49 // 右下侧变换 50 if (clip_line.original.code == ( winRightBitCode | winBottomBitCode ) ) 51 { 52 clip_line.original.x = clip_left + clip_right - clip_line.original.x; 53 clip_line.terminal.x = clip_left + clip_right - clip_line.terminal.x; 54 clip_line.original.y = clip_top + clip_bottom - clip_line.original.y; 55 clip_line.terminal.y = clip_top + clip_bottom - clip_line.terminal.y; 56 } 57 // 下侧变换 58 if (clip_line.original.code == winBottomBitCode) 59 { 60 clip_line.original.y = clip_top + clip_bottom - clip_line.original.y; 61 clip_line.terminal.y = clip_top + clip_bottom - clip_line.terminal.y; 62 } 63 // 重新加载区域码 64 getRegionCode(clip_line.original); 65 getRegionCode(clip_line.terminal); 66 // 以下情况均要用到斜率 67 mLT=(float)(clip_top-clip_line.original.y)/(clip_left-clip_line.original.x); 68 mLB=(float)(clip_bottom-clip_line.original.y)/(clip_left-clip_line.original.x); 69 mRB=(float)(clip_bottom-clip_line.original.y)/(clip_right-clip_line.original.x); 70 mRT=(float)(clip_top-clip_line.original.y)/(clip_right-clip_line.original.x); 71 m=(float)(clip_line.terminal.y-clip_line.original.y)/(clip_line.terminal.x-clip_line.original.x); 72 k = 1 / m; 73 74 // 判断起点位置 75 // 情况一:在框内 76 if (clip_line.original.code == 0x0) 77 { 78 // left 79 if ((mLT <= m && m < mLB) && clip_line.terminal.code & winLeftBitCode) 80 { 81 clip_line.terminal.y = clip_line.terminal.y + round(m * (clip_left - clip_line.terminal.x)); 82 clip_line.terminal.x = clip_left; 83 } 84 // bottom 85 if ((m >= mLB || m < mRB) && clip_line.terminal.code & winBottomBitCode) 86 { 87 clip_line.terminal.x = clip_line.terminal.x + round(k * (clip_bottom - clip_line.terminal.y)); 88 clip_line.terminal.y = clip_bottom; 89 } 90 // right 91 if ((mRB <= m && m < mRT) && clip_line.terminal.code & winRightBitCode) 92 { 93 clip_line.terminal.y = clip_line.terminal.y + round(m * (clip_right - clip_line.terminal.x)); 94 clip_line.terminal.x = clip_right; 95 } 96 // top 97 if ((m >= mRT || m < mLT) && clip_line.terminal.code & winTopBitCode) 98 { 99 clip_line.terminal.x = clip_line.terminal.x + round(k * (clip_top - clip_line.terminal.y)); 100 clip_line.terminal.y = clip_top; 101 } 102 } 103 // 情况二:在框左侧 104 elseif (clip_line.original.code == winLeftBitCode) 105 { 106 if (m < mLB || m >= mLT) // 区域外 107 continue; 108 else 109 { 110 // 起点剪裁 L 111 clip_line.original.y = clip_line.original.y + round(m * (clip_left - clip_line.original.x); 112 clip_line.original.x = clip_left; 113 if (clip_line.terminal.code != 0x0) 114 { 115 if (mLB <= m && m < mRB) // LB 116 { 117 clip_line.terminal.x = clip_line.terminal.x + round(k * (clip_bottom - clip_line.terminal.y)); 118 clip_line.terminal.y = clip_bottom; 119 } 120 elseif (mRB <= m && m < mRT) // LR 121 { 122 clip_line.terminal.y = clip_line.terminal.y + round(m * (clip_right - clip_line.terminal.x)); 123 clip_line.terminal.x = clip_right; 124 } 125 elseif (mRT <= m && m < mLT) // LT 126 { 127 clip_line.terminal.x = clip_line.terminal.x + round(k * (clip_top - clip_line.terminal.y)); 128 clip_line.terminal.y = clip_top; 129 } 130 } 131 } 132 } 133 // 情况三:在框左上侧 134 elseif (clip_line.original.code == ( winLeftBitCode | winTopBitCode ) ) 135 { 136 if (m < mLB || m >= mRT) // 区域外 137 continue; 138 else 139 { 140 // 起点靠近左裁剪线 141 if (clip_left - clip_line.original.x < clip_line.original.y - clip_top) 142 { 143 if (mLB <= m && m < mLT) 144 { 145 // L 146 clip_line.original.y = clip_line.original.y + round(m * (clip_left - clip_line.original.x)); 147 clip_line.original.x = clip_left; 148 if (clip_line.terminal.code != 0x0) // LB 149 { 150 clip_line.terminal.x = clip_line.terminal.x + round(k * (clip_bottom - clip_line.terminal.y)); 151 clip_line.terminal.y = clip_bottom; 152 } 153 } 154 elseif (mLT <= m && m < mRB) 155 { 156 // T 157 clip_line.original.x = clip_line.original.x + round(k * (clip_top - clip_line.original.y)); 158 clip_line.original.y = clip_top; 159 if (clip_line.terminal.code != 0x0) // TB 160 { 161 clip_line.terminal.x = clip_line.terminal.x + round(k * (clip_bottom - clip_line.terminal.y)); 162 clip_line.terminal.y = clip_bottom; 163 } 164 } 165 elseif (mRB <= m && m < mRT) 166 { 167 // T 168 clip_line.original.x = clip_line.original.x + round(k * (clip_top - clip_line.original.y)); 169 clip_line.original.y = clip_top; 170 if (clip_line.terminal.code != 0x0) // TR 171 { 172 clip_line.terminal.y = clip_line.terminal.y + round(m * (clip_right - clip_line.terminal.x)); 173 clip_line.terminal.x = clip_right; 174 } 175 } 176 } 177 // 起点靠近上裁剪线 178 else 179 { 180 if (mLB <= m && m < mRB) 181 { 182 // L 183 clip_line.original.y = clip_line.original.y + round(m * (clip_left - clip_line.original.x)); 184 clip_line.original.x = clip_left; 185 if (clip_line.terminal.code != 0x0) // LB 186 { 187 clip_line.terminal.x = clip_line.terminal.x + round(k * (clip_bottom - clip_line.terminal.y)); 188 clip_line.terminal.y = clip_bottom; 189 } 190 } 191 elseif (mRB <= m && m < mLT) 192 { 193 // L 194 clip_line.original.y = clip_line.original.y + round(m * (clip_left - clip_line.original.x)); 195 clip_line.original.x = clip_left; 196 if (clip_line.terminal.code != 0x0) // LR 197 { 198 clip_line.terminal.y = clip_line.terminal.y + round(m * (clip_right - clip_line.terminal.x)); 199 clip_line.terminal.x = clip_right; 200 } 201 } 202 elseif (mLT <= m && m < mRT) 203 { 204 // T 205 clip_line.original.x = clip_line.original.x + round(k * (clip_top - clip_line.original.y)); 206 clip_line.original.y = clip_top; 207 if (clip_line.terminal.code != 0x0) // TR 208 { 209 clip_line.terminal.y = clip_line.terminal.y + round(m * (clip_right - clip_line.terminal.x)); 210 clip_line.terminal.x = clip_right; 211 } 212 } 213 } 214 } 215 216 } 217 // 情况四:在框上侧 218 elseif (clip_line.original.code == winTopBitCode) 219 { 220 if ((m > 0 && m < mLT) || (m < 0 && m >= mRT)) // 区域外 221 continue; 222 else 223 { 224 // T 225 clip_line.original.x = clip_line.original.x + round(k * (clip_top - clip_line.original.y)); 226 clip_line.original.y = clip_top; 227 if (clip_line.terminal.code != 0x0) 228 { 229 if (mLT <= m && m < mLB) // TL 230 { 231 clip_line.terminal.y = clip_line.terminal.y + round(m * (clip_left - clip_line.terminal.x)); 232 clip_line.terminal.x = clip_left; 233 } 234 elseif (m >= mLB || m <= mRB) // TB 235 { 236 clip_line.terminal.x = clip_line.terminal.x + round(k * (clip_bottom - clip_line.terminal.y)); 237 clip_line.terminal.y = clip_bottom; 238 } 239 elseif (mRB <= m && m < mRT) // TR 240 { 241 clip_line.terminal.y = clip_line.terminal.y + round(m * (clip_right - clip_line.terminal.x)); 242 clip_line.terminal.x = clip_right; 243 } 244 } 245 } 246 } 247 // 恢复对称区域的变化 248 // 右侧变换 249 if (before_code == winRightBitCode) 250 { 251 clip_line.original.x = clip_left + clip_right - clip_line.original.x; 252 clip_line.terminal.x = clip_left + clip_right - clip_line.terminal.x; 253 } 254 // 右上侧变换 255 if (before_code == ( winRightBitCode | winTopBitCode ) ) 256 { 257 clip_line.original.x = clip_left + clip_right - clip_line.original.x; 258 clip_line.terminal.x = clip_left + clip_right - clip_line.terminal.x; 259 } 260 // 左下侧变换 261 if (before_code == ( winLeftBitCode | winBottomBitCode ) ) 262 { 263 clip_line.original.y = clip_top + clip_bottom - clip_line.original.y; 264 clip_line.terminal.y = clip_top + clip_bottom - clip_line.terminal.y; 265 } 266 // 右下侧变换 267 if (before_code == ( winRightBitCode | winBottomBitCode ) ) 268 { 269 clip_line.original.x = clip_left + clip_right - clip_line.original.x; 270 clip_line.terminal.x = clip_left + clip_right - clip_line.terminal.x; 271 clip_line.original.y = clip_top + clip_bottom - clip_line.original.y; 272 clip_line.terminal.y = clip_top + clip_bottom - clip_line.terminal.y; 273 } 274 // 下侧变换 275 if (before_code == winBottomBitCode) 276 { 277 clip_line.original.y = clip_top + clip_bottom - clip_line.original.y; 278 clip_line.terminal.y = clip_top + clip_bottom - clip_line.terminal.y; 279 } 280 // 将剪裁好的直线存入数组 281 clipped_l[clipped_line_num] = clip_line; 282 clipped_line_num++; 283 } 284 }
时间: 2024-10-25 21:28:44