计算机图形学(五)线段的中点分割裁剪算法讲解与源代码
因为****现在上传不上去资源,所以使用了百度云。
源码下载:点我下载
基本思想:
对于每条线段P1P2分为三种情况处理:
(1) 若P1P2完全在窗口内,则显示该线段P1P2简称“取”之。
(2) 若P1P2明显在窗口外,则丢弃该线段,简称“弃”之。
(3) 若线段不满足“取”或“弃”
的条件,则在交点处把线段分为两段。其中一段完全在窗口外,可弃之。然后对另一段重复上述处理。
为快速判断,采用如下编码方法:每个区域赋予4位编码CtCbCrCl。
定义:
本算法与Cohen-Sutherland算法一样首先对线段端点进行编码,并把线段与窗口的关系分为三种情况:全在、完全不在和线段和窗口有交。
对前两种情况,进行一样的处理。对于第三种情况,用中点分割的方法求出线段与窗口的交点。
描述算法:
求线段与窗口的交点,A、B分别为距P0、P1最近的可见点,Pm为P0、P1中点。
AB之间的连线即为线段P0、P1的可见部分。
从P0出发找最近可见点A的方法先求出P0、 P1的中点Pm ,若P0、Pm不是显然不可见的,并且P0 、P1在窗口中有可见部分,则距P0最近的可见点一定落在 P0 Pm上,所以用P0 Pm代替P0 P1;否则取PmP1代替P0 P1 再对新的P0 P1求中点Pm。
重复上述过程,直到PmP1长度小于给定的控制常数为止,此时Pm收敛于交点。
从P1出发找最近可见点B采用上面类似方法。
下面给出设置编码:
-
# define MAX 1000
-
# define LEFT 1
-
# define RIGHT 2
-
# define BOTTOM 4
-
# define TOP 8
-
int XL;
-
int XR;
-
int YB;
-
int YT;
-
CClipingView::CClipingView()
-
{
-
Draw=false;
-
XL=120;
-
XR=800;
-
YB=400;
-
YT=100;
-
}
-
int CClipingView::EnCode(CPoint p)
-
{
-
int code=0;
-
if(p.x<XL) code|=LEFT;
-
if(p.x>XR) code|=RIGHT;
-
if(p.y<YT) code|=TOP;
-
if(p.y>YB) code|=BOTTOM;
-
return code;
-
}
核心代码:
-
void CClipingView::OnMove()
-
{
-
CDC *pDC;
-
pDC=GetDC();
-
CString str;
-
CBrush bru;
-
bru.CreateSolidBrush(RGB(255,0,0));
-
CBrush *oldbru=pDC->SelectObject(&bru);
-
CPoint temp,p;
-
bool Y=true;
-
while(1)
-
{
-
Y=true;
-
CPen pen1(0,3,RGB(255,255,0));
-
CPen *oldpen=pDC->SelectObject(&pen1);
-
pDC->MoveTo(p1);
-
pDC->LineTo(p2);
-
pDC->SelectObject(oldpen);
-
pDC->SelectObject(&bru);
-
Invalidate();
-
//this->
-
Sleep(700);
-
if(EnCode(p1)==EnCode(p2)&&EnCode(p2)==0)
-
{
-
Sleep(700);
-
Invalidate();
-
return;
-
}
-
else if((EnCode(p1)&EnCode(p2))!=0)
-
{
-
Yn=false;
-
Sleep(700);
-
Invalidate();
-
return;
-
}
-
else
-
{
-
int i=0;
-
while(1)
-
{
-
if(p1.x-p2.x<=1&&p1.x-p2.x>=-1)
-
{
-
p2=p;
-
p1=temp;
-
Sleep(700);
-
break;
-
}
-
if(EnCode(p1)==0)
-
{
-
ExChange(p1,p2);
-
pDC->TextOut(50,500,"交换P1和P2! ");
-
pDC->TextOut(p1.x,p1.y+8,"P1");
-
pDC->TextOut(p2.x,p2.y+8,"P2");
-
Sleep(700);
-
}
-
if(Y)
-
temp=p2;
-
p.x=(p1.x+p2.x)/2;
-
p.y=(p1.y+p2.y)/2;
-
pDC->TextOut(50,500,"求出中点坐标P! ");
-
pDC->TextOut(p.x,p.y+8,"P");
-
pDC->Ellipse(p.x-4,p.y+4,p.x+4,p.y-4);
-
Sleep(700);
-
if((EnCode(p1)&EnCode(p))!=0)
-
{
-
CPen pen(0,4,RGB(255,255,255));
-
CPen *oldpen=pDC->SelectObject(&pen);
-
pDC->MoveTo(p1);
-
pDC->LineTo(p);
-
pDC->SelectObject(oldpen);
-
pDC->SelectObject(&bru);
-
Sleep(700);
-
p1=p;
-
pDC->TextOut(50,500,"P1赋值为P! ");
-
pDC->TextOut(p1.x,p1.y+8,"P1");
-
pDC->Ellipse(p1.x-4,p1.y+4,p1.x+4,p1.y-4);
-
Sleep(700);
-
}
-
else
-
{
-
CPen pen(0,4,RGB(255,255,255));
-
CPen *oldpen=pDC->SelectObject(&pen);
-
pDC->MoveTo(p2);
-
pDC->LineTo(p);
-
pDC->SelectObject(oldpen);
-
pDC->SelectObject(&bru);
-
Sleep(700);
-
p2=p;
-
pDC->TextOut(50,500,"P2赋值为P! ");
-
pDC->TextOut(p2.x,p2.y+8,"P2");
-
pDC->Ellipse(p2.x-4,p2.y+4,p2.x+4,p2.y-4);
-
Sleep(700);
-
}
-
Y=false;
-
}
-
}
-
}
-
}
-
void CClipingView::ExChange(CPoint &p1, CPoint &p2)
-
{
-
p1.x=p1.x^p2.x;
-
p2.x=p1.x^p2.x;
-
p1.x=p1.x^p2.x;
-
p1.y=p1.y^p2.y;
-
p2.y=p1.y^p2.y;
-
p1.y=p1.y^p2.y;
-
}
代码中我输出了一些算法运算时的过程在界面上。
说一下源码使用的过程:
1.一开始进来就是直线分割,可已选择在正常情况下,也可以选择在网格情况下。如果在网格情况下,请先设置网格大小。
2.可以点击“Draw”来画一个窗口。
3.画一条直线。
4.点击第一个“开”来运非网格下的直线分割。点击第3个开运行网格下的直线分割算法。
如果有什么问题,还望大家多多指教。一起学习,一起进步。