图形学算法之Nicholl-Lee-Nicholl算法

在本学期的所学的裁剪算法中,有一个叫做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

图形学算法之Nicholl-Lee-Nicholl算法的相关文章

算法导论——lec 13 贪心算法与图上算法

之前我们介绍了用动态规划的方法来解决一些最优化的问题.但对于有些最优化问题来说,用动态规划就是"高射炮打蚊子",采用一些更加简单有效的方法就可以解决.贪心算法就是其中之一.贪心算法是使所做的选择看起来是当前最佳的,期望通过所做的局部最优选择来产生一个全局最优解. 一. 活动选择问题 [问题]对几个互相竞争的活动进行调度:活动集合S = {a1, a2, ..., an},它们都要求以独占的方式使用某一公共资源(如教室),每个活动ai有一个开始时间si和结束时间fi ,且0 ≤ si &

基本算法研究1-冒泡排序算法测试

基本算法研究1-冒泡排序算法测试 1.经典冒泡排序法基本原理 先看一个动态图,感觉比较形象: 冒泡排序(Bubble Sort)是一种简单的排序算法.默认是从小到大排序,即把最大的数据排在最后,相当于每次把最大数据像气泡一样浮到水面一样.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换. 基本步骤: 1.比较相邻的元素.如果第一个比第二个大,就交换他们两个.        2.对每一对相邻元素作同样的工作,从开始第一对

【机器学习算法-python实现】采样算法的简单实现

1.背景 采样算法是机器学习中比较常用,也比较容易实现的(出去分层采样).常用的采样算法有以下几种(来自百度知道): 一.单纯随机抽样(simple random sampling) 将调查总体全部观察单位编号,再用抽签法或随机数字表随机抽取部分观察单位组成样本. 优点:操作简单,均数.率及相应的标准误计算简单. 缺点:总体较大时,难以一一编号. 二.系统抽样(systematic sampling) 又称机械抽样.等距抽样,即先将总体的观察单位按某一顺序号分成n个部分,再从第一部分随机抽取第k

【JavaScript】【算法】JavaScript版排序算法

JavaScript版排序算法:冒泡排序.快速排序.插入排序.希尔排序(小数据时,希尔排序会比快排快哦) 1 //排序算法 2 window.onload = function(){ 3 var array = [0,1,2,44,4, 4 324,5,65,6,6, 5 34,4,5,6,2, 6 43,5,6,62,43, 7 5,1,4,51,56, 8 76,7,7,2,1, 9 45,4,6,7,8]; 10 //var array = [4,2,5,1,0,3]; 11 array

图灵算法群《啊哈算法》领读

--图灵算法群阅读计划(第一期) 领读人:Zoctopus·Lian 本书特色 一本充满智慧和趣味的算法入门书.没有枯燥的描述,没有难懂的公式,一切以实际应用为出发点. 书中涉及到的数据结构有栈.队列.链表.树.并查集.堆和图等:涉及到的算法有排序.枚举.深度和广度优先搜索.图的遍历,当然还有图论中不可以缺少的四种最短路径算法.两种最小生成树算法.割点与割边算法.二分图的最大匹配算法等. 书中通过幽默的语言配以可爱的插图来讲解算法,使用C语言实现. 适合读者 适合算法零基础入门和喜爱编程的朋友(

《算法之道》精华 算法设计部分

<算法之道>精华 算法设计部分 本书作者邹恒明,作者另有一本书<数据结构之弦>,以及<操作系统之哲学原理>都是非常好的书 这本书能够算得上是深入浅出.文笔非常好,作者加入了非常多自己的思考 本文仅包含算法设计部分,算法分析略去,并没有严格依照章节顺序来记录 附录 算法随想 有人喜欢遍历,希望踏遍千山万水,人生丰富多彩:有人一生贪婪,眼界不宽,及时行乐:有人注定穷搜,辛辛苦苦,收获有限:有人善用时空均衡,用最少的时间办最多的事情.十分精明:有人会分治,再难的问题也能解决.

图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用

图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 B(G).其中 T(G)是遍历图时所经过的边的集合,B(G) 是遍历图时未经过的边的集合.显然,G1(V, T) 是图 G 的极小连通子图,即子图G1 是连通图 G 的生成树. 深度优先生成森林   右边的是深度优先生成森林: 连通图的生成树不一定是唯一的,不同的遍历图的方法得到不同的生成树;从不

【数据分析/挖掘底层算法】原创实现二项分布算法以及应用

7.2 二项分布算法 作者 白宁超 2015年8月15日22:51:38 摘要:本文继统计学几何分布.二项分布.泊松分布研究的深入,基于各种分布基础概念和核心知识介绍之后.就各种分布的实现和真实环境下应用方是目的.在进行一系列相互独立实验,每次既有成功,又有失败的可能,且单次实验成功概率相等.在一系列试验中求成功的次数.这种情况下适用于本算法.本算法中在n次伯努利试验中:试验n次得到r次成功的概率.二项分布的期望.二项分布方差的具体实现. 目录 统计学之离散概率分布的运用 统计学之几何分布.二项

CBA算法---基于关联规则进行分类的算法

更多数据挖掘算法:https://github.com/linyiqun/DataMiningAlgorithm 介绍 CBA算法全称是Classification base of Association,就是基于关联规则进行分类的算法,说到关联规则,我们就会想到Apriori和FP-Tree算法都是关联规则挖掘算法,而CBA算法正是利用了Apriori挖掘出的关联规则,然后做分类判断,所以在某种程度上说,CBA算法也可以说是一种集成挖掘算法. 算法原理 CBA算法作为分类算法,他的分类情况也就

java文本相似度计算(Levenshtein Distance算法(中文翻译:编辑距离算法))----代码和详解

算法代码实现: package com.util; public class SimFeatureUtil { private static int min(int one, int two, int three) { int min = one; if (two < min) { min = two; } if (three < min) { min = three; } return min; } public static int ld(String str1, String str2)