Nicholl-Lee-Nicholl二维线段裁剪算法相对于Cohen-Sutherland和Liang-Barsky算法来说,在求交点之前进行了线段端点相对于几个区域的判断,可以确切的知道要求交点的边的信息。

  此方法只在二维空间裁剪时使用,C-S和L-B裁剪方法则可应用到三维空间。

算法步骤:

1   先使用C-S裁剪算法的区域码判断方法,去除一部分在裁剪区域外面的线段、显示在完全在裁剪区域内的线段。其他不能判断的情况,采用NLN算法进行裁剪。

2   p1和p2若有一点在区域内,必要时交换端点以确保p1在区域内。

   分别计算p1到裁剪区域四个顶点斜率m1-m4(从左下端点顺时针的4个顶点),判断线段斜率m与m1-m4的关系,决定计算哪条边与线段的交点。交点值赋给p2.

3   p1和p2有一个点在区域0001(左侧),必要时交换端点以确保p1在0001内。

   因为p2在区域内的情况被步骤2覆盖,因此p1为线段与左边界的交点。

   分别计算m1-m4,判断线段斜率m与m1-m4的关系,决定计算哪条边与线段的交点。此交点赋值给p2.

4   p1和p2有一个点在区域1001(左上角),必要时交换端点以确保p1在1001内。

   同样p2在区域内的情况被步骤2覆盖。

   分别计算m1-m4,判断线段斜率m与m1-m4的关系(注意此处需要判断m2与m4的大小,决定计算哪条边与线段的交点)。分别计算p1和p2。

5   对于其他6种情况,分别判断p1和p2的位置,在不同的区域,将线段和裁剪区域旋转相应的角度,重复步骤2-4进行裁剪。裁剪完成后再将线段旋转回原来的位置。

 #include <GLUT/GLUT.h>
#include <iostream>
#include <math.h>
#include "lineNLN.h"
#include "linebres.h" GLfloat m1, m2, m3, m4; const GLint winLeftBitCode = 0x1; // 直接为1也没问题
const GLint winRightBitCode = 0x2;
const GLint winBottomBitCode = 0x4;
const GLint winTopBitCode = 0x8; typedef GLfloat Matrix3x3 [][];
Matrix3x3 matRotate;
Matrix3x3 matComposite;
const GLdouble pi = 3.14159;
GLfloat delta;
wcPt2D center; inline GLint inside (GLint code)
{
return GLint (!(code));
}
inline GLint reject (GLint code1, GLint code2)
{
return GLint (code1 & code2);
}
inline GLint accept (GLint code1, GLint code2)
{
return GLint (!(code1 | code2));
} GLubyte encode (wcPt2D pt, wcPt2D winMin, wcPt2D winMax)
{
GLubyte code = 0x00; if(pt.getx() < winMin.getx())
code = code | winLeftBitCode;
if(pt.getx() > winMax.getx())
code = code | winRightBitCode;
if(pt.gety() < winMin.gety())
code = code | winBottomBitCode;
if(pt.gety() > winMax.gety())
code = code | winTopBitCode; return code;
} void swapPts (wcPt2D * p1, wcPt2D * p2) // TODO 为什么要用指针?
{
wcPt2D tmp;
tmp = * p1; * p1 = * p2; * p2 = tmp;
} void swapCode (GLubyte * c1, GLubyte * c2)
{
GLubyte tmp;
tmp = * c1; * c1 = * c2; * c2 = tmp;
} void renewWinVertexes (wcPt2D * winMin, wcPt2D * winMax)
{
wcPt2D tmp1, tmp2;
tmp1.setCoords(fmin(winMin->getx(), winMax->getx()), fmin(winMin->gety(), winMax->gety()));
tmp2.setCoords(fmax(winMin->getx(), winMax->getx()), fmax(winMin->gety(), winMax->gety()));
* winMin = tmp1;
* winMax = tmp2;
} void matrix3x3SetIdentity (Matrix3x3 matIden3x3)
{
GLint row, col;
for(row = ; row < ; row++)
{
for(col = ; col < ; col++)
{
matIden3x3[row][col] = (row == col);
}
}
} void matrix3x3Premultiply (Matrix3x3 m1, Matrix3x3 m2)
{
GLint row, col;
Matrix3x3 matTemp; for(row = ; row < ; row++)
{
for(col = ; col < ; col++)
{
matTemp[row][col] = m1[row][] * m2 [][col] + m1[row][] * m2 [][col] + m1[row][] * m2 [][col];
}
} for(row = ; row < ; row++)
{
for(col = ; col < ; col++)
{
m2[row][col] = matTemp[row][col];
}
}
} void rotate2D (wcPt2D pivotPt, GLfloat theta)
{
matrix3x3SetIdentity(matRotate); matRotate[][] = cos(theta);
matRotate[][] = -sin(theta);
matRotate[][] = pivotPt.getx() * ( - cos(theta)) + pivotPt.gety() * sin(theta);
matRotate[][] = sin(theta);
matRotate[][] = cos(theta);
matRotate[][] = pivotPt.gety() * ( - cos(theta)) + pivotPt.getx() * sin(theta);
} void transformVerts2D (wcPt2D * verts)
{
GLfloat tempx, tempy; tempx = matRotate[][] * verts->getx() + matRotate[][] * verts->gety() + matRotate[][];
tempy = matRotate[][] * verts->getx() + matRotate[][] * verts->gety() + matRotate[][]; verts->setCoords(tempx, tempy);
} void slopeWith4Vertexes (wcPt2D winMin, wcPt2D winMax, wcPt2D p1)
{
m1 = (p1.gety() - winMin.gety()) / (p1.getx() - winMin.getx());
m2 = (p1.gety() - winMax.gety()) / (p1.getx() - winMin.getx());
m3 = (p1.gety() - winMax.gety()) / (p1.getx() - winMax.getx());
m4 = (p1.gety() - winMin.gety()) / (p1.getx() - winMax.getx()); // std::cout << "slope : m1 : " << m1 << " m2 : " << m2 << " m3 : " << m3 << " m4 : " << m4 << std::endl;
} void lineClipNLN (wcPt2D winMin, wcPt2D winMax, wcPt2D p1, wcPt2D p2)
{
GLubyte code1, code2;
GLint plotLine = false, done = false;
GLfloat m = 0.0; while (!done)
{
code1 = encode(p1, winMin, winMax);
code2 = encode(p2, winMin, winMax);
if(accept(code1, code2))
{
plotLine = true;
done = true;
}
else
{
if(reject(code1, code2))
{
std::cout << "1 rejected line!" << std::endl;
done = true;
}
else
{
// 有一个点在裁剪区域内
if(inside(code1) || inside(code2))
{
plotLine = true;
done = true;
if(!inside(code1))
{
swapPts(&p1, &p2);
swapCode(&code1, &code2);
}
wcPt2D topLeft, bottomRight;
topLeft.setCoords(winMin.getx(), winMax.gety());
bottomRight.setCoords(winMax.getx(), winMin.gety());
if(p1.equals(winMin) || p1.equals(winMax) || p1.equals(topLeft) || p1.equals(bottomRight))
{
p2.setCoords(p1.getx(), p1.gety());
}
else
{
slopeWith4Vertexes(winMin, winMax, p1); if(p1.getx() != p2.getx())
{
m = (p2.gety() - p1.gety()) / (p2.getx() - p1.getx()); if(m <= m1 && m >= m2 && (code2 & winLeftBitCode))
{//L
p2.setCoords(winMin.getx(), p1.gety() + m * (winMin.getx() - p1.getx()));
}
else if(m <= m3 && m >= m4 && (code2 & winRightBitCode))
{//R
p2.setCoords(winMax.getx(), p1.gety() + m * (winMax.getx() - p1.getx()));
}
else if((m > m3 || m < m2) && (code2 & winTopBitCode))
{//T
p2.setCoords(p1.getx() + (winMax.gety() - p1.gety())/m, winMax.gety());
}
else if((m > m1 || m < m4) && (code2 & winBottomBitCode))
{//B
p2.setCoords(p1.getx() + (winMin.gety() - p1.gety())/m, winMin.gety());
}
}
else
{
if(p2.gety() > winMax.gety())
{
p2.setCoords(p2.getx(), winMax.gety());
}
else
{
p2.setCoords(p2.getx(), winMin.gety());
}
}
}
}
else
{
if(code1 == 0x01 || code2 == 0x01)
// 有一个点的区域码是0001,即在裁剪区域正左侧,L的情况在上一个if中包含,这里只会有LT,LR,LB和rejected的情况
{
if(code1 != 0x01)
{
swapPts(&p1, &p2);
swapCode(&code1, &code2);
}
slopeWith4Vertexes(winMin, winMax, p1);
if(p1.getx() != p2.getx())
{
m = (p2.gety() - p1.gety()) / (p2.getx() - p1.getx());
}
if(m < m1 || m > m2)
{
std::cout << "2 rejected line!" << std::endl;
done = true;
}
else
{
p1.setCoords(winMin.getx(), p1.gety() + m * (winMin.getx() - p1.getx()));
if((m <= m2 && m >= m3) && (code2 & winTopBitCode))
{//LT
p2.setCoords(p1.getx() + (winMax.gety() - p1.gety())/m, winMax.gety());
}
else if((m < m3 && m >= m4) && (code2 & winRightBitCode))
{//LR
p2.setCoords(winMax.getx(), p1.gety() + m * (winMax.getx() - p1.getx()));
}
else if((m < m4 && m >= m1) && (code2 & winBottomBitCode))
{//LB
p2.setCoords(p1.getx() + (winMin.gety() - p1.gety())/m, winMin.gety());
}
plotLine = true;
done = true;
}
}
else if(code1 == (winLeftBitCode | winTopBitCode) || code2 == (winLeftBitCode | winTopBitCode))
// 有一个点在裁剪区域外左上角的情况,这里的L、T情况已经在第一个if里包含
{
if(code1 != (winLeftBitCode | winTopBitCode))
{
swapPts(&p1, &p2);
swapCode(&code1, &code2);
} slopeWith4Vertexes(winMin, winMax, p1);
if(p1.getx() != p2.getx())
{
m = (p2.gety() - p1.gety()) / (p2.getx() - p1.getx());
}
if(m > m3 || m < m1)
{
std::cout << "3 rejected line!" << std::endl;
done = true;
}
else
{
plotLine = true;
done = true;
if(m <= m3 && m >= m4)
{
p2.setCoords(winMax.getx(), p1.gety() + m * (winMax.getx() - p1.getx()));
if(m2 > m4 && m <= m2)
{//LR
p1.setCoords(winMin.getx(), p1.gety() + m * (winMin.getx() - p1.getx()));
}
else
{//TR
p1.setCoords(p1.getx() + (winMax.gety() - p1.gety())/m, winMax.gety());
}
}
else if(m < m4 && m >= m1)
{
p2.setCoords(p1.getx() + (winMin.gety() - p1.gety())/m, winMin.gety());
if(m2 < m4 && m >= m2)
{//TB
p1.setCoords(p1.getx() + (winMax.gety() - p1.gety())/m, winMax.gety());
}
else
{//LB
p1.setCoords(winMin.getx(), p1.gety() + m * (winMin.getx() - p1.getx()));
}
}
}
}
else
{
center.setCoords((winMin.getx() + winMax.getx())/, (winMin.gety() + winMax.gety())/); if(code1 == (winLeftBitCode | winBottomBitCode) || code2 == (winLeftBitCode | winBottomBitCode))
{//LB
delta = -pi/;
}
else if(code1 == winBottomBitCode || code2 == winBottomBitCode)
{//B
delta = -pi/;
}
else if(code1 == (winBottomBitCode | winRightBitCode) || code2 == (winBottomBitCode | winRightBitCode))
{//BR
delta = pi;
}
else if(code1 == winRightBitCode || code2 == winRightBitCode)
{//R
delta = pi;
}
else if(code1 == (winRightBitCode | winTopBitCode) || code2 == (winRightBitCode | winTopBitCode))
{//TR
delta = pi/;
}
else if(code1 == winTopBitCode || code2 == winTopBitCode)
{//T
delta = pi/;
}
rotate2D(center, delta);
transformVerts2D(&p1);
transformVerts2D(&p2);
transformVerts2D(&winMin);
transformVerts2D(&winMax);
renewWinVertexes(&winMin, &winMax);
}
}
}
}
} if(plotLine)
{
if(delta != )
{
rotate2D(center, -delta);
transformVerts2D(&p1);
transformVerts2D(&p2);
}
lineBres(round(p1.getx()), round(p1.gety()), round(p2.getx()), round(p2.gety()));
}
delta = ;
}

NLN二维线段裁剪算法

完整代码路径:https://github.com/p0e0o0p0l0e0/Computer_Graphics/tree/f9a7ad1987586445d780de2461d423af0dd9ba6a

[图形学] 习题8.12 NLN二维线段裁剪算法实现的更多相关文章

  1. poj 1195:Mobile phones(二维线段树,矩阵求和)

    Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14391   Accepted: 6685 De ...

  2. codeforces 677D D. Vanya and Treasure(二维线段树)

    题目链接: D. Vanya and Treasure time limit per test 1.5 seconds memory limit per test 256 megabytes inpu ...

  3. tyvj P1716 - 上帝造题的七分钟 二维树状数组区间查询及修改 二维线段树

    P1716 - 上帝造题的七分钟 From Riatre    Normal (OI)总时限:50s    内存限制:128MB    代码长度限制:64KB 背景 Background 裸体就意味着 ...

  4. bzoj4785:[ZJOI2017]树状数组:二维线段树

    分析: "如果你对树状数组比较熟悉,不难发现可怜求的是后缀和" 设数列为\(A\),那么可怜求的就是\(A_{l-1}\)到\(A_{r-1}\)的和(即\(l-1\)的后缀减\( ...

  5. 「ZJOI2017」树状数组(二维线段树)

    「ZJOI2017」树状数组(二维线段树) 吉老师的题目真是难想... 代码中求的是 \(\sum_{i=l-1}^{r-1}a_i\),而实际求的是 \(\sum_{i=l}^{r}a_i\),所以 ...

  6. [BZOJ4785][ZJOI2017]树状数组(概率+二维线段树)

    4785: [Zjoi2017]树状数组 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 297  Solved: 195[Submit][Status ...

  7. 【BZOJ1513】[POI2006]Tet-Tetris 3D 二维线段树

    [BZOJ1513][POI2006]Tet-Tetris 3D Description Task: Tetris 3D "Tetris" 游戏的作者决定做一个新的游戏, 一个三维 ...

  8. 【BZOJ4785】[Zjoi2017]树状数组 树套树(二维线段树)

    [BZOJ4785][Zjoi2017]树状数组 Description 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道基础的树状数组题.给出一 ...

  9. POJ2029 二维线段树

    Get Many Persimmon Trees POJ - 2029 Seiji Hayashi had been a professor of the Nisshinkan Samurai Sch ...

随机推荐

  1. VHDL乘除法及转换

    首先鄙视一下这个不智能的语言 1.要进行乘法与除法,数据类型必须是signed 2.两个16位的数相乘,结果必须是32位的 3.乘以2的n次幂的数可以直接乘,之后截位也比较方便,(其实直接移位就可以) ...

  2. Linux中重定向

    转:http://blog.csdn.net/songyang516/article/details/6758256 1重定向 1.1      重定向符号 >               输出 ...

  3. 多线程编程-- part 3 多线程同步->synchronized关键字

    多线程同时访问一个资源,可以会产生不可预料的结果,所以为这个资源加锁,访问资源的第一个线程为其加锁后,其他线程便不能在使用那个资源,直到锁被解除. 举个例子: 存款1000元,能取出800的时候我就取 ...

  4. JQuery中参数e,event

    与Flex类似,JavaScript中的事件也同样存在,捕获--触发--冒泡 三个节点.比较常见的情况是,在子DIV触发事件时,如果父DIV也监听同类事件,那么也会一起触发,并向上冒泡 jQuery对 ...

  5. R语言 模糊c均值(FCM)算法程序(转)

    FCM <- function(x, K, mybeta = 2, nstart = 1, iter_max = 100, eps = 1e-06) { ## FCM ## INPUTS ## ...

  6. JVM学习笔记三:垃圾收集器与内存分配策略

    内存回收与分配重点关注的是堆内存和方法区内存(程序计数器占用小,虚拟机栈和本地方法栈随线程有相同的生命周期). 一.判断对象是否存活? 1. 引用计数算法 优势:实现简单,效率高. 致命缺陷:无法解决 ...

  7. linux新学篇

    [学会使用快捷键] Ctrl + C:这个是用来终止当前命令的快捷键,当然你也可以输入一大串字符,不想让它运行直接Ctrl + C,光标就会跳入下一行. Tab: 这个键是最有用的键了,也是笔者敲击概 ...

  8. ReactNative学习之Html基本标签使用

    前言: 前面简单学习了html简单标签的使用,今天学习一下其他的标签的使用. HTML的超链接 1.)创建一个超链接 <div> <p> <a href="ht ...

  9. Nginx上部署HTTPS

    Nginx上部署HTTPS依赖OpenSSL库和包含文件,即须先安装好libssl-dev,且ln -s /usr/lib/x86_64-linux-gnu/libssl.so  /usr/lib/, ...

  10. 请教 C# 异步 async await 问题

    各位园友,之前对C#异步只是肤浅了解,请教一个具体问题. 需求: 前台会发送一个Array,这个数组都是 id的集合,比较大.分两步,首先保存这些id,然后去调用异步方法. 可以正常返回json,也可 ...