图形学算法之NichollLeeNicholl算法

在本学期的所学的裁剪算法中,有一个叫做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 }
原文地址:https://www.cnblogs.com/bjut13070019/p/5601388.html