计算机图形学_实验报告三_图形裁剪算法
- 格式:doc
- 大小:130.00 KB
- 文档页数:9
实验报告Experimentation Report of Taiyuan teachers College系部计算机系年级三年级课程图形学姓名同组者日期项目直线段的裁剪算法一、实验目的:1.熟悉图形裁剪的基本知识2.掌握Cohen-Sutherland 直线裁剪算法二、实验内容:在矩形窗口的裁剪算法中,考虑到构成图形的基本元素就是线段,曲线可看成是有很多小线段逼近而成的,因此,讨论线段的裁剪算法更为实用,即Cohen-Sutherland裁剪算法。
Cohen-Sutherland裁剪算法具体思路如下。
任意平面线段和矩形窗口的位置关系只会有如下3种:(1)完全落在窗口内。
(2)完全落在窗口外。
(3)部分落在窗口内,部分落在窗口外。
要想判断线段和窗口的位置关系,只要找到线段的两端点相对于矩形窗口的位置即可,线段的两端点相对于矩形窗口的位置可能会有如下几种情况:(1)线段的两个端点均在窗口内,这时线段全部落在窗口内,完全可见,应予以保留。
(2)线段的两个端点均在窗口边界线外同侧,这时线段全部落在窗口外,完全不可见,应予以舍弃。
(3)线段的一个端点在窗口内,另一个端点在窗口外,这时线段部分可见,应求出线段与窗口边界线的交点,从而得到线段在窗口内的可见部分。
(4)线段的两个端点均不在窗口内,但不处于窗口边界线外同侧,这时有可能线段是部分可见的,也可能是完全不可见的。
Cohen-Sutherland裁剪算法就是按照上述思路来对线段进行裁剪的,只是在线段的两端点相对于矩形窗口的位置上,巧妙地运用了编码的思想。
首先,延长窗口的四条边界线,将平面划分成9个区域,然后,用四位二进制数C3C2C1C0对这9个区域进行编码,编码规则如下:第0位C0:当线段的端点在窗口的左边界之左时,该位编码为1,否则,该位编码为0。
第1位C1:当线段的端点在窗口的右边界之右时,该位编码为1,否则,该位编码为0。
第2位C2:当线段的端点在窗口的下边界之下时,该位编码为1,否则,该位编码为0。
计算机图形学课程实验报告信息与计算科学(三)上机实验3:裁剪算法班级:姓名:学号:上机实验(3)的题目和要求一、实验目的掌握图形裁剪算法的基本思想,并能上机编程实现相应的算法。
二、实验要求(Direction)1.每个学生单独完成。
2.开发语言规定为C语言。
3.请在自己的实验报告上写明姓名、学号、班级。
4.每次交的实验报告内容包括:试验目的和意义、题目、程序制作步骤、主程序(包括源代码注释)。
三、实验题目实验题1:上机编一程序实现直线的中点裁剪算法。
具体要求如下说明:1 该程序能实现窗口屏幕上任意一条直线的裁剪;2 直线段要求可以随机输入;运行结果图:裁剪之前裁剪之后#define LE 2#define RI 4#define BO 6#define TO 10#define XLEFT 150#define XRIGHT 350#define YBOTTOM 150#define YTOP 300#include "math.h"#include "stdio.h"#include "graphics.h"void main(){int x1,y1,x2,y2,xx,yy,xxx,yyy;int graphdriver=DETECT,graphmode;initgraph(&graphdriver,&graphmode," ");setcolor(6);line(XLEFT,YTOP,XRIGHT,YTOP);line(XLEFT,YBOTTOM,XRIGHT,YBOTTOM);line(XLEFT,YTOP,XLEFT,YBOTTOM);line(XRIGHT,YTOP,XRIGHT,YBOTTOM);x1=50;y1=200;x2=400;y2=300;setcolor(1);line(x1,y1,x2,y2);xx=0;yy=0;xxx=0;yyy=0;draw_ett(x1,y1,x2,y2,&xx,&yy);draw_ett(x2,y2,xx,yy,&xxx,&yyy);setcolor(4);line(xx,yy,xxx,yyy);getch();closegraph();}int encode (int x, int y, int *code){ int c=0;if (x<XLEFT) c=c|LE;else if (x>XRIGHT) c=c|RI;if (y<YBOTTOM) c=c|BO;else if (y>YTOP) c=c|TO;*code=c;return code;}draw_ett(int x1, int y1, int x2, int y2, int *x, int *y) { int code1,code2,code;int xx,yy;float d,d1,d2;encode(x1,y1,&code1);encode(x2,y2,&code2);if (code2==0) { xx=x2;yy=y2; *x=xx; * y=yy;return;}if ((code1&code2)!=0) return;L1: xx=(x1+x2)/2;yy=(y1+y2)/2;encode(xx, yy, &code);d1=(yy-y1)*(yy-y1);d2=(xx-x1)*(xx-x1);d=sqrt(d1+d2);if (d<=1) { *x=xx;*y=yy; return;}if ((code&code1)!=0){ x1=xx; y1=yy; }else { x2=xx; y2=yy;}goto L1;}实验题2:实现Sutherland-Hodgeman多边形裁剪算法。
太原工业学院实验报告GetClientRect(&rect);//获得客户区的大小pDC->SetMapMode(MM_ANISOTROPIC);//pDC自定义坐标系pDC->SetWindowExt(rect.Width(),rect.Height());//设置窗口范围pDC->SetViewportExt(rect.Width(),-rect.Height());//设置视区范围,x轴水平向右,y轴垂直向上pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);//客户区中心为原点CDC memDC;//内存DCCBitmap NewBitmap,*pOldBitmap;//内存中承载的临时位图memDC.CreateCompatibleDC(pDC);//创建一个与显示pDC兼容的内存memDCNewBitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());//创建兼容位图pOldBitmap=memDC.SelectObject(&NewBitmap);//将兼容位图选入memDCmemDC.FillSolidRect(rect,pDC->GetBkColor());//按原来背景填充客户区,否则是黑色memDC.SetMapMode(MM_ANISOTROPIC);//memDC自定义坐标系memDC.SetWindowExt(rect.Width(),rect.Height());memDC.SetViewportExt(rect.Width(),-rect.Height());memDC.SetViewportOrg(rect.Width()/2,rect.Height()/2);rect.OffsetRect(-rect.Width()/2,-rect.Height()/2);DrawWindowRect(&memDC);//绘制窗口if(PtCount>=1){memDC.MoveTo(Round(P[0].x),Round(P[0].y));memDC.LineTo(Round(P[1].x),Round(P[1].y));}pDC->BitBlt(rect.left,rect.top,rect.Width(),rect.Height(),&memDC,-rect.Width()/2,-rect.Height()/2,SRCCOPY);//将内存memDC中的位图拷贝到显示pDC中memDC.SelectObject(pOldBitmap);//恢复位图NewBitmap.DeleteObject();//删除位图}(2)绘制裁剪窗口void CTestView::DrawWindowRect(CDC* pDC)//绘制裁剪窗口{// TODO: Add your message handler code here and/or call defaultpDC->SetTextColor(RGB(128,0,255));pDC->TextOut(-10,Wyt+20,CString("窗口"));CPen NewPen3,*pOldPen3;//定义3个像素宽度的画笔NewPen3.CreatePen(PS_SOLID,3,RGB(255,128,0));pOldPen3=pDC->SelectObject(&NewPen3);pDC->Rectangle(Wxl,Wyt,Wxr,Wyb);pDC->SelectObject(pOldPen3);NewPen3.DeleteObject();}(3)Cohen-Sutherland算法void CTestView::Cohen()//Cohen-Sutherland算法{CP2 p;//交点坐标EnCode(P[0]);//起点编码EnCode(P[1]);//终点编码while(P[0].rc!=0 || P[1].rc!=0)//处理至少一个顶点在窗口之外的情况{if((P[0].rc & P[1].rc)!=0)//简弃之{PtCount=0;return;}if(0==P[0].rc)//确保P[0]位于窗口之外{CP2 Temp;Temp=P[0];P[0]=P[1];P[1]=Temp;}UINT RC=P[0].rc;double k=(P[1].y-P[0].y)/(P[1].x-P[0].x);//直线段的斜率//窗口边界按左、右、下、上的顺序裁剪直线段if(RC & LEFT)//P[0]点位于窗口的左侧{p.x=Wxl;//计算交点y坐标p.y=k*(p.x-P[0].x)+P[0].y;}else if(RC & RIGHT)//P[0]点位于窗口的右侧{p.x=Wxr;//计算交点y坐标p.y=k*(p.x-P[0].x)+P[0].y;}else if(RC & BOTTOM)//P[0]点位于窗口的下侧{p.y=Wyb;//计算交点x坐标p.x=(p.y-P[0].y)/k+P[0].x;}else if(RC & TOP)//P[0]点位于窗口的上侧{p.y=Wyt;//计算交点x坐标p.x=(p.y-P[0].y)/k+P[0].x;}EnCode(p);P[0]=p;}}void CTestView::EnCode(CP2 &pt)//端点编码函数{pt.rc=0;if(pt.x<Wxl)pt.rc=pt.rc|LEFT;else if(pt.x>Wxr)pt.rc=pt.rc|RIGHT;if(pt.y<Wyb)pt.rc=pt.rc|BOTTOM;else if(pt.y>Wyt)pt.rc=pt.rc|TOP;}(4)人机交互void CTestView::OnDrawpic(){// TODO: Add your command handler code herePtCount=0;bDrawLine=TRUE;MessageBox(CString("鼠标画线,剪刀裁剪"),CString("提示"),MB_OKCANCEL);Invalidate(FALSE);}运行结果:实验拓展:在屏幕上显示一个直线构成的图案,使用鼠标选择两点绘制矩形代表窗口对图案矩形裁剪。
图形裁剪算法1.实验目的:理解地区编码设计直线裁剪算法编程实现直线裁剪算法2.实验描绘:设置裁剪窗口坐标为:wxl=250;wxr=850;wyb=250;wyt=450;裁剪前以下列图所示:裁剪后结果为:3.算法设计:直线裁剪算法:假定裁剪窗口是标准矩形,由上(y=wyt )、下( y=wyb )、左( x=wxl )、右( x=wxr )四条边构成,以下列图所示。
延伸窗口四条边形成9 个地区。
依据被裁剪直线的任一端点P(x, y)所处的窗口地区地点,能够给予一组 4 位二进制地区码C4C3C2C1 。
编码定义规则:第一位 C1:若端点位于窗口之左边,即第二位 C2:若端点位于窗口之右边,即第三位 C3:若端点位于窗口之下侧,即第四位 C4:若端点位于窗口之上侧,即X<WxlX>WxrY<WybY>Wyt,则,则,则,则C1=1 ,不然C2=1 ,不然C3=1 ,不然C4=1 ,不然C1=0。
C2=0。
C3=0 。
C4=0。
裁剪步骤:1.若直线的两个端点的地区编码都为0,即 RC1|RC2=0 (两者按位相或的结果为 0,即2.若直线的两个端点的地区编码都不为0,即 RC1&RC2 ≠ 0(两者按位相与的结果不为0,即 RC1≠0 且 RC2≠ 0,即直线位于窗外的同一侧,说明直线的两个端点都在窗口外,应“ 简弃”。
3.若直线既不知足“ 简取” 也不知足“ 简弃” 的条件,直线段必定与窗口订交,需要计算直线与窗口界限的交点。
交点将直线分为两段,此中一段完整位于窗口外,可“ 简弃”。
对另一段给予交点处的地区编码,再次测试,再次求交,直至确立完整位于窗口内的直线段为止。
4.实现时,一般按固定次序左( x=wxl )、右( x=wxr )、下( y=wyb )、上( y=wyt )求解窗口与直线的交点。
4.源程序:class CTestView : public CView{.protected:double Pointx[2],Pointy[2];//用户绘制的直线int wxl,wxr,wyb,wyt;//左上与右下CDC Picture;// 内存 (预存 )DC, 防备屏幕闪耀char m_i; // 第一个点仍是第二个点BOOL m_Attatch;BOOL m_Draw;unsigned int RC,RC0,RC1;..}CTestView::CTestView(){//窗口地点坐标wxl=250;wxr=850;wyb=250;wyt=450;m_Attatch=FALSE;m_i=0;m_Draw=FALSE;RC0=0;RC1=0;}void CTestView::OnDraw(CDC* pDC){CTestDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);//装载位图CRect Rect;GetClientRect(&Rect);// 获取客户区的大小CBitmap Bitmap,*pBitmap;Bitmap.LoadBitmap(IDB_BITMAP);CDC MemDC;MemDC.CreateCompatibleDC(GetDC());pBitmap=MemDC.SelectObject(&Bitmap);MemDC.BitBlt(0,0,Rect.Width(),Rect.Height(),&Picture,0,0,SRCCOPY);MemDC.TextOut((wxl+wxr)/2,wyb-20,"窗口");//窗口标题//绘制窗口和直线CPen Pen3,*pOldPen3;// 定义 3 个像素宽度的画笔Pen3.CreatePen(PS_SOLID,3,RGB(0,0,0));pOldPen3=MemDC.SelectObject(&Pen3);MemDC.MoveTo(wxl,wyt);MemDC.LineTo(wxr,wyt);MemDC.LineTo(wxr,wyb);MemDC.LineTo(wxl,wyb);MemDC.LineTo(wxl,wyt);MemDC.SelectObject(pOldPen3);Pen3.DeleteObject();CPen Pen1,*pOldPen1;// 定义 1 个像素宽度的画笔Pen1.CreatePen(PS_SOLID,1,RGB(0,0,255));pOldPen1=MemDC.SelectObject(&Pen1);if(m_i>=1){MemDC.MoveTo(ROUND(Pointx[0]),ROUND(Pointy[0]));MemDC.LineTo(ROUND(Pointx[1]),ROUND(Pointy[1]));}MemDC.SelectObject(pOldPen1);Pen1.DeleteObject();CDC *dc=GetDC();dc->BitBlt(0,0,Rect.Width(),Rect.Height(),&MemDC,0,0,SRCCOPY);MemDC.SelectObject(pBitmap);}void CTestView::OnMENUClip()//裁剪菜单函数{Cohen();Invalidate(FALSE);}unsigned int CTestView::EnCode(double LinePx,double LinePy)//端点编码函数{// 次序左右下上RC=0;if(LinePx<wxl){RC=RC | LEFT;}if(LinePx>wxr){RC=RC | RIGHT;}if(LinePy<wyb){RC=RC | BOTTOM;}if(LinePy>wyt){RC=RC | TOP;}return RC;}void CTestView::OnMENUDrawLine()//绘制直线菜单函数{//TODO: Add your command handler codehere if(FALSE==m_Attatch){Picture.CreateCompatibleDC(GetDC());CBitmap *Bitmap,*pBitmap;Bitmap=new CBitmap;Bitmap->LoadBitmap(IDB_BITMAP);pBitmap=Picture.SelectObject(Bitmap);m_Attatch=TRUE;}m_Draw=TRUE;m_i=0;Invalidate(FALSE);AfxGetMainWnd()->SetWindowText("事例10:Cohen-Sutherland直线裁剪算法");// 显示标题MessageBox(" 请使用鼠标在屏幕上绘制直线,而后点击裁剪按钮进行裁剪"," 提示",MB_OKCANCEL);}void CTestView::OnLButtonDown(UINT nFlags, CPoint point)//单击鼠标左键函数{//TODO: Add your message handler code here and/or call defaultif(TRUE==m_Draw){if(m_i<2){Pointx[m_i]=point.x;Pointy[m_i]=point.y;m_i++;}}CView::OnLButtonDown(nFlags, point);}void CTestView::OnMouseMove(UINT nFlags, CPoint point) //鼠标挪动函数{//TODO: Add your message handler code here and/or call defaultif(TRUE==m_Draw){if(m_i<2){Pointx[m_i]=point.x;Pointy[m_i]=point.y;Invalidate(FALSE);}}CView::OnMouseMove(nFlags, point);}void CTestView::Cohen()//Cohen - Sutherland 算法{BOOL Change;double x,y;RC0=EnCode(Pointx[0],Pointy[0]);RC1=EnCode(Pointx[1],Pointy[1]);while(TRUE){Change=FALSE;if(0 == (RC0|RC1)){// 简取之return;}else if(0!=(RC0 & RC1)){// 简弃之return;}else{if(0==RC0)// 假如P0 点在窗口内,互换P0 和P1,保证p0 点在窗口外{//互换点的坐标值double TPointx,TPointy;TPointx=Pointx[0];TPointy=Pointy[0];Pointx[0]=Pointx[1];Pointy[0]=Pointy[1];Pointx[1]=TPointx;Pointy[1]=TPointy;//互换点的编码值unsigned int TRC;TRC=RC0;RC0=RC1;RC1=TRC;}//按左、右、下、上的次序裁剪if(RC0 & LEFT )//P0点位于窗口的左边{x=wxl;// 求交点 yy=Pointy[0]+(Pointy[1]-Pointy[0])*(x-Pointx[0])/(Pointx[1]-Pointx[0]);Pointx[0]=x;Pointy[0]=y;Change=TRUE;RC0=EnCode(Pointx[0],Pointy[0]);RC1=EnCode(Pointx[1],Pointy[1]);}if(RC0 & RIGHT )//P0点位于窗口的右边{x=wxr;// 求交点 yy=Pointy[0]+(Pointy[1]-Pointy[0])*(x-Pointx[0])/(Pointx[1]-Pointx[0]);Pointx[0]=x;Pointy[0]=y;Change=TRUE;RC0=EnCode(Pointx[0],Pointy[0]);RC1=EnCode(Pointx[1],Pointy[1]);}if(RC0 & BOTTOM )//P0点位于窗口的下侧{y=wyb;// 求交点 xx=Pointx[0]+(Pointx[1]-Pointx[0])*(y-Pointy[0])/(Pointy[1]-Pointy[0]);Pointx[0]=x;Pointy[0]=y;Change=TRUE;RC0=EnCode(Pointx[0],Pointy[0]);RC1=EnCode(Pointx[1],Pointy[1]);}if(RC0 & TOP )//P0点位于窗口的上侧{y=wyt;// 求交点 xx=Pointx[0]+(Pointx[1]-Pointx[0])*(y-Pointy[0])/(Pointy[1]-Pointy[0]);Pointx[0]=x;Pointy[0]=y;Change=TRUE;RC0=EnCode(Pointx[0],Pointy[0]);RC1=EnCode(Pointx[1],Pointy[1]);}if(FALSE==Change){return;}}}}5.运转结果:。
一、实验目标1.了解Cohen-SutherLand线段裁剪算法、Liang-Barsky线段裁剪算法、SutherLand-Hodgeman多边形裁剪算法的基本思想;2.掌握Cohen-SutherLand线段裁剪算法、Liang-Barsky线段裁剪算法、SutherLand-Hodgeman多边形裁剪算法的算法实现;二、实验内容本次实验主要是实现Cohen-SutherLand线段裁剪算法、Liang-Barsky线段裁剪算法、SutherLand-Hodgeman多边形裁剪算法。
Cohen-sutherland线段裁剪算法思想:该算法也称为编码算法,首先对线段的两个端点按所在的区域进行分区编码,根据编码可以迅速地判明全部在窗口内的线段和全部在某边界外侧的线段。
只有不属于这两种情况的线段,才需要求出线段与窗口边界的交点,求出交点后,舍去窗外部分。
对剩余部分,把它作为新的线段看待,又从头开始考虑。
两遍循环之后,就能确定该线段是部分截留下来,还是全部舍弃。
Cohen-sutherland线段裁剪算法步骤:1、分区编码延长裁剪边框将二维平面分成九个区域,每个区域各用一个四位二进制代码标识。
各区代码值如图中所示。
四位二进制代码的编码规则是:(1)第一位置1:区域在左边界外侧(2)第二位置1:区域在右边界外侧(3)第三位置1:区域在下边界外侧(4)第四位置1:区域在上边界外侧裁剪窗口内(包括边界上)的区域,四位二进制代码均为0。
设线段的两个端点为P1(x1,y1)和P2(x2,y2),根据上述规则,可以求出P1和P2所在区域的分区代码C1和C2。
2、判别根据C1和C2的具体值,可以有三种情况:(1)C1=C2=0,表明两端点全在窗口内,因而整个线段也在窗内,应予保留。
(2)C1&C2≠0(两端点代码按位作逻辑乘不为0),即C1和C2至少有某一位同时为1,表明两端点必定处于某一边界的同一外侧,因而整个线段全在窗外,应予舍弃。
一、实验目的:直线段的裁剪:编码裁剪算法,中点分割裁剪算法。
二、实验内容://BasicGraph.cpp//请将下列裁剪程序补充完整,并用注释说明是何种裁剪算法void Encode (int x,int y,int *code,int XL,int XR,int YB,int YT) {//请将此程序补充完整int c=0;if(x<XL) c=c|LEFT;else if(x>XR) c=c|RIGHT;if(y<YB) c=c|BOTTOM;else if(y>YT) c=c|TOP;(*code)=c;}//编码裁剪算法:void C_S_Line(POINT &p1,POINT &p2,int XL,int XR,int YB,int YT) {//请将此程序补充完整int x1,x2,y1,y2,x,y,code1,code2,code;x1=p1.x; x2=p2.x; y1=p1.y; y2=p2.y;Encode(x1,y1,&code1,XL,XR,YB,YT);Encode(x2,y2,&code2,XL,XR,YB,YT);while(code1!=0||code2!=0){if((code1&code2)!=0) return;code=code1;if(code1==0) code=code2;if((LEFT&code)!=0){x=XL;y=y1+(y2-y1)*(XL-x1)/(x2-x1);}else if((RIGHT&code)!=0){x=XR;y=y1+(y2-y1)*(XR-x1)/(x2-x1);}if((BOTTOM&code)!=0){y=YB;x=x1+(x2-x1)*(YB-y1)/(y2-y1);}else if((TOP&code)!=0){y=YT;x=x1+(x2-x1)*(YT-y1)/(y2-y1);}if(code==code1){x1=x;y1=y;Encode(x,y,&code1,XL,XR,YB,YT);}else{x2=x;y2=y;Encode(x,y,&code2,XL,XR,YB,YT);}}p1.x=x1;p1.y=y1;p2.x=x2;p2.y=y2;}int IsInArea(POINT point,int XL,int XR,int YB,int YT){//请将此程序补充完整if(point.x>=XL && point.x<=XR && point.y>YB && point.y<YT) return 1;else return 0;}int NotIntersect(POINT begin,POINT end,int XL,int XR,int YB,int YT) {//请将此程序补充完整int maxx,maxy,minx,miny;maxx=(begin.x>end.x)?begin.x:end.x;minx=(begin.x<end.x)?begin.x:end.x;maxy=(begin.y>end.y)?begin.y:end.y;miny=(begin.y<end.y)?begin.y:end.y;if(maxx<XL|| minx>XR||maxy<YB||miny>YT) return 1;else return 0;}//中点裁剪算法:POINT ClipMid(POINT begin,POINT end,int XL,int XR,int YB,int YT){//请将此程序补充完整POINT mid,temp;if(IsInArea(begin,XL,XR,YB,YT)) temp=begin;else if(NotIntersect(begin,end,XL,XR,YB,YT)) temp=begin;else{mid.x=(begin.x+end.x)/2;mid.y=(begin.y+end.y)/2;if(abs(mid.x-end.x)<=1&& abs(mid.y-end.y)<=1) temp=mid;else{if(NotIntersect(begin,mid,XL,XR,YB,YT))temp=ClipMid(mid,end,XL,XR,YB,YT);elsetemp=ClipMid(begin,mid,XL,XR,YB,YT);}}return temp;}//Liang-Barsky直线裁剪算法:void ClipParameter(POINT &p1,POINT &p2,int XL,int XR,int YB,int YT) {float u1=0.0,u2=1.0;float dx=p2.x-p1.x,dy=p2.y-p1.y;if(clipTest(-dx,p1.x-XL,&u1,&u2))if(clipTest(dx,XR-p1.x,&u1,&u2))if(clipTest(-dy,p1.y-YB,&u1,&u2))if(clipTest(dy,YT-p1.y,&u1,&u2)){if(u2<1.0){p2.x=p1.x+u2*dx;p2.y=p1.y+u2*dy;}if(u1>0.0){p1.x=p1.x+u1*dx;p1.y=p1.y+u1*dy;}}}int clipTest(float p,float q,float *u1,float *u2){float r;int remainFlag=1;if(p<0.0){r=q/p;if(r>*u2) remainFlag=0;else if(r>*u1) *u1=r;}else if(p>0.0){r=q/p;if(r<*u1) remainFlag=0;else if(r<*u2) *u2=r;}else //*p=0if(q<0.0) remainFlag=0;return remainFlag;}//逐边裁剪算法://typedef struct tRes { int yes,isIn; POINT pout;} Res;Res TestIntersect(int edge,int type,POINT p1,POINT p2){//判断p2是否在所裁剪的窗边edge的内侧,是否与p1点分别在窗边edge的异侧float dx,dy,m;Res res;int isIn=0,yes=0;POINT pout;dy=p2.y-p1.y;dx=p2.x-p1.x;m=dy/dx;switch(type){case 1: /*right*/if(p2.x<=edge){isIn=1;if(p1.x>edge)yes=1;}else if(p1.x<=edge)yes=1;break;case 2: /*bottom*/if(p2.y>=edge){isIn=1;if(p1.y<edge)yes=1;}else if(p1.y>=edge)yes=1;break;case 3: /*left*/if(p2.x>=edge){isIn=1;if(p1.x<edge)yes=1;}else if(p1.x>=edge)yes=1;break;case 4: /*top*/if(p2.y<=edge){isIn=1;if(p1.y>edge)yes=1;}else if(p1.y<=edge)yes=1;default: break;}if(yes){if((type==1) || (type==3)){ pout.x=edge;pout.y=p1.y+m*(pout.x-p1.x);}if((type==2) || (type==4)){ pout.y=edge;pout.x=p1.x+(pout.y-p1.y)/m;}}res.isIn=isIn;res.yes=yes;res.pout=pout;return res;}int clipSingleEdge(int edge,int type,int nin,POINT pin[50],POINT pout[50])/*对多边形pin与窗边edge进行裁剪,返回裁剪后的多边形pout及点数*/ {int i,k=0;POINT p;Res res;p.x=pin[nin-1].x;p.y=pin[nin-1].y;for(i=0;i<nin;i++){res=TestIntersect(edge,type,p,pin[i]);if(res.yes){ pout[k].x=res.pout.x;pout[k].y=res.pout.y;k++;} if(res.isIn){ pout[k].x=pin[i].x;pout[k].y=pin[i].y;k++;}p.x=pin[i].x;p.y=pin[i].y;}return k;}void ClipEdgePolygon(POINT ps[50],int &n,int XL,int XR,int YB,int YT) { /*对多边形ps进行逐边裁剪*/int n1=0,n2=0;POINT pt[50];n1=clipSingleEdge(XR,1,n,ps,pt);n2=clipSingleEdge(YB,2,n1,pt,ps);n1=clipSingleEdge(XL,3,n2,ps,pt);n2=clipSingleEdge(YT,4,n1,pt,ps);n=n2;}//多边形编码裁剪算法:void ClipEncodePolygon(POINT ps[50],int &n,int XL,int XR,int YB,int YT) {POINT tp[50];int k=0,m;int code1,code2,code;int x,y;for(int i=0;i<n-1;i++){Encode(ps[i].x,ps[i].y,&code1,XL,XR,YB,YT);Encode(ps[i+1].x,ps[i+1].y,&code2,XL,XR,YB,YT);code=code1;m=i;for(int j=0;j<2;j++){if((code1 & code2)!=0) //线段两端都在窗口外的同一侧{switch(code){case 1:x=XL;y=ps[m].y;break;case 2:x=XR;y=ps[m].y;break;case 4:x=ps[m].x;y=YB;break;case 5:x=XL;y=YB;break;case 6:x=XR;y=YB;break;case 8:x=ps[m].x;y=YT;break;case 9:x=XL;y=YT;break;case 10:x=XR;y=YT;break;}tp[k].x=x;tp[k].y=y;k++;}else if((code1 & code2)==0) //线段两端不在窗口的同一侧{if(code==0){tp[k]=ps[m];k++;}else if ((LEFT & code) !=0) //线段与左边界相交 {x=XL;y=ps[i].y+(ps[i+1].y-ps[i].y)*(XL-ps[i].x)/(ps[i+1].x-ps[i].x);if(y>YB && y<YT){tp[k].x=x;tp[k].y=y;k++;}}else if((TOP & code)!=0) //线段与上边界相交{y=YT;x=ps[i].x+(ps[i+1].x-ps[i].x)*(YT-ps[i].y)/(ps[i+1].y-ps[i].y);if(x>XL && x<XR){tp[k].x=x;tp[k].y=y;k++;}}else if((RIGHT & code)!=0) //线段与右边界相交 {x=XR;y=ps[i].y+(ps[i+1].y-ps[i].y)*(XR-ps[i].x)/(ps[i+1].x-ps[i].x);if(y>YB && y<YT){tp[k].x=x;tp[k].y=y;k++;}}else if((BOTTOM & code) != 0) //线段与下边界相交 {y=YB;x=ps[i].x+(ps[i+1].x-ps[i].x)*(YB-ps[i].y)/(ps[i+1].y-ps[i].y);if(x>XL && x<XR){tp[k].x=x;tp[k].y=y;k++;}}}code=code2;m++;}//for(j)}//for(i)for(i=0;i<k;i++)ps[i]=tp[i];n=k;}//函数的调用,裁剪窗口的调整//DrawView.cpp文件//裁剪窗口的调整CDrawView::CDrawView(){/************请在此函数中将裁剪窗口大小调整为长度100单位像素,宽度50单位像素的矩形********/// TODO: add construction code here//m_pWidth=1;m_pStyle=PEN_STYLE_SOLID;m_pColor=RGB(0,0,0);m_FFlag=0;m_FColor=RGB(0,0,0);m_HFlag=0;CurrentDraw=DRAW_VCLINE;m_Num=0;m_Drag=0;m_HCursor=AfxGetApp()->LoadStandardCursor(IDC_CROSS);//DrawType=0;ClipFlag=0;ClipType=-1;XL=200;XR=300;YB=150;YT=200;//XL=200;XR=500;YB=150;YT=400;ClipWindowColor=RGB(192,192,50);}void CDrawView::OnDraw(CDC* pDC){CDrawDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereif(ClipFlag){CPen NewPen,*pOldPen;NewPen.CreatePen(PS_DASH,1,ClipWindowColor);pOldPen=pDC->SelectObject(&NewPen);pDC->MoveTo(XL,YB);pDC->LineTo(XR,YB);pDC->LineTo(XR,YT);pDC->LineTo(XL,YT);pDC->LineTo(XL,YB);}int index;index=pDoc->GetShapeNumber();for(int i=0;i<index;i++)pDoc->GetShape(i)->Drawing(pDC);}void CDrawView::OnInitialUpdate(){CSize sizeTotal;sizeTotal.cx = 640; sizeTotal.cy = 480;SetScrollSizes(MM_TEXT, sizeTotal);// TODO: Add your specialized code here and/or call the base class }void CDrawView::OnLButtonDown(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultCClientDC dc(this);OnPrepareDC(&dc);dc.DPtoLP(&point);m_pPrev=point;m_pOrigin=point; //点击鼠标左键作为拖动绘图的第一点m_Drag=1;SetCapture();RECT rect;GetClientRect(&rect);ClientToScreen(&rect);ClipCursor(&rect);CScrollView::OnLButtonDown(nFlags, point);}//函数调用处void CDrawView::OnLButtonUp(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultif(m_Drag){m_Drag=0;ReleaseCapture();ClipCursor(NULL);CDrawDoc *pDoc=GetDocument();CShape *pShape;POINT p1,p2;if(CurrentDraw==DRAW_VCLINE || CurrentDraw==DRAW_DDALINE ||CurrentDraw==DRAW_MIDLINE || CurrentDraw==DRAW_BSHLINE){if(ClipFlag){switch(ClipType){/****************编码裁剪函数调用处*************/case CLIP_ENCODE:C_S_Line(m_pOrigin,m_pPrev,XL,XR,YB,YT); break; /****************中点分割裁剪函数调用处************/case CLIP_MIDPOINT: ClipMid(m_pPrev,m_pOrigin,XL,XR,YB,YT);p1=ClipMid(m_pPrev,m_pOrigin,XL,XR,YB,YT);p2=ClipMid(m_pOrigin,m_pPrev,XL,XR,YB,YT);m_pOrigin=p1;m_pPrev=p2;break;case CLIP_PARAMETER:ClipParameter(m_pOrigin,m_pPrev,XL,XR,YB,YT);break;}}pShape=newCLine(m_pOrigin,m_pPrev,m_pWidth,m_pStyle,m_pColor,DrawType);pDoc->AddShape(pShape);}if(CurrentDraw==DRAW_RECTANGLE){if(ClipType==CLIP_WINDOW){XL=m_pOrigin.x;XR=m_pPrev.x;YB=m_pOrigin.y;YT=m_pPrev.y;}else{pShape=newCRectangle(m_pOrigin,m_pPrev,m_pWidth,m_pStyle,m_pColor,m_FFlag,m_FColor,m_HFlag,m_Hatch);pDoc->AddShape(pShape);}}if( CurrentDraw==DRAW_VCCIRCLE || CurrentDraw==DRAW_MIDCIRCLE || CurrentDraw==DRAW_BSHCIRCLE){pShape=newCCircle(m_pOrigin,m_pPrev,m_pWidth,m_pStyle,m_pColor,m_FFlag,m_FColor,m_HFlag,m_Hatch,DrawType);pDoc->AddShape(pShape);}if(CurrentDraw==DRAW_VCELLIPSE || CurrentDraw==DRAW_MIDELLIPSE) {pShape=newCEllipse(m_pOrigin,m_pPrev,m_pWidth,m_pStyle,m_pColor,m_FFlag,m_FColor,m_HFlag,m_Hatch,DrawType);pDoc->AddShape(pShape);}pDoc->UpdateAllViews(NULL);}CScrollView::OnLButtonUp(nFlags, point);}三实验结果:四、实验总结通过这次试验使我了解到如何运用计算机程序对窗口进行剪裁,了解到编码剪裁算法直观方便,速度较快,中点分割剪裁算法不用进行乘除运算,剪裁效率高,Liang-Barsky直线裁剪算法更快。
第1篇一、实验目的本次实验旨在深入理解并掌握裁剪算法的基本原理,通过编程实现Cohen-Sutherland算法和Liang-Barsky算法,对图形进行窗口裁剪,从而提高图形处理效率,优化显示效果。
二、实验环境1. 开发环境:Visual Studio 20192. 编程语言:C++3. 图形库:OpenGL三、实验内容1. 理解裁剪算法的基本原理;2. 实现Cohen-Sutherland算法;3. 实现Liang-Barsky算法;4. 对图形进行窗口裁剪,并展示裁剪效果。
四、实验过程1. 理解裁剪算法的基本原理裁剪算法是计算机图形学中的一个重要技术,用于将一个图形或图像中不需要的部分去除,只保留需要的部分。
常见的裁剪算法有Cohen-Sutherland算法、Liang-Barsky算法等。
Cohen-Sutherland算法是一种编码线段裁剪算法,通过将线段端点相对于窗口的位置进行编码,判断线段是否与窗口相交,从而实现裁剪。
Liang-Barsky算法是一种参数化线段裁剪算法,通过计算线段参数,判断线段是否与窗口相交,从而实现裁剪。
2. 实现Cohen-Sutherland算法(1)定义窗口边界首先,定义窗口边界,包括左边界、右边界、上边界和下边界。
(2)编码线段端点将线段端点相对于窗口的位置进行编码,编码规则如下:- 如果端点在窗口内,则编码为0;- 如果端点在窗口左侧,则编码为1;- 如果端点在窗口右侧,则编码为2;- 如果端点在窗口上方,则编码为4;- 如果端点在窗口下方,则编码为8。
(3)判断线段是否与窗口相交将线段两端点的编码进行异或运算,如果结果为0,则线段与窗口相交;否则,线段与窗口不相交。
(4)裁剪线段如果线段与窗口相交,则根据端点编码,将线段分为两部分,分别进行裁剪。
3. 实现Liang-Barsky算法(1)定义窗口边界首先,定义窗口边界,包括左边界、右边界、上边界和下边界。
图像裁剪的实验报告引言图像裁剪是一个在计算机视觉领域非常常见的任务,它用于将图像中感兴趣的区域提取出来,以便进一步进行分析和处理。
图像裁剪可以应用于很多领域,例如目标检测、人脸识别、场景分析等。
本实验旨在探索不同方法对于图像裁剪的效果和性能的影响,以及比较它们的优缺点。
实验过程实验数据准备在本实验中,我们使用了一组包含不同种类图像的数据集。
这些图像包括人物、动物、自然风景等,其中一部分图像包含了我们感兴趣的区域。
实验方法本实验选择了三种常见的图像裁剪方法进行比较:1. 手工选择裁剪区域:通过鼠标手动选择图像中感兴趣的区域,然后进行裁剪。
2. 基于边缘检测的自动裁剪:使用边缘检测算法,如Canny边缘检测,自动提取图像中的边缘区域,然后进行裁剪。
3. 基于机器学习的自动裁剪:使用已训练好的目标检测模型(如YOLO、Faster R-CNN等),自动识别图像中的目标区域,并进行裁剪。
实验步骤以下是我们进行实验的步骤:1. 针对手工选择裁剪区域方法,打开一张图像,在图像上使用鼠标手动选择感兴趣的区域,并进行裁剪。
2. 针对基于边缘检测的自动裁剪方法,使用Canny边缘检测算法提取图像的边缘区域,然后根据边缘区域进行裁剪。
3. 针对基于机器学习的自动裁剪方法,使用已训练好的目标检测模型,在图像中识别感兴趣的目标区域,并进行裁剪。
4. 对比比较不同方法下裁剪的结果,分析它们的优缺点。
5. 测量比较不同方法下裁剪的时间和资源消耗,分析它们的性能差异。
实验结果我们对实验数据集中的多张图像进行了裁剪,并对不同方法下的结果进行了比较。
以下是我们的观察和结论:- 手工选择裁剪区域:这种方法需要人工干预,能够灵活地选择感兴趣的区域,并且无需额外的算法支持。
然而,它需要用户具备一定的图像处理知识,并且在处理大量图像时,工作量相对较大。
- 基于边缘检测的自动裁剪:这种方法能够自动提取图像中的边缘区域,并取得了不错的效果。
cohensutherland裁剪算法实验报告Cohen-Sutherland裁剪算法是计算机图形学中一种常用的线段裁剪算法,它能够快速地确定一个线段是否在一个给定的窗口内部,以及剪切后的线段如何变化。
该算法的基本思想是将给定的窗口划分为九个区域,其中一种情况是窗口内没有线段,另一种情况是线段完全位于窗口内部,其他情况下需要进行裁剪处理。
具体来说,算法根据线段的起点和终点的位置判断其所处区域,并使用二进制编码进行表示。
Cohen-Sutherland裁剪算法使用四位标记,分别表示线段位于左、右、下、上四个区域。
二进制编码规则如下:左边界:0001右边界:0010下边界:0100上边界:1000当线段的二进制编码全为0时,表示线段完全位于窗口内部;当线段的二进制编码与给定窗口的二进制编码进行与运算时,结果全为0时,表示线段与窗口无交集;其他情况下则需要进行裁剪。
裁剪的具体过程如下:1. 首先计算线段起点和终点的编码,并确定是否需要裁剪;2. 若线段的编码全为0,则直接绘制该线段;3. 若线段与窗口的编码进行与运算结果全为0,则表明线段与窗口无交集,不进行绘制;4. 若线段需要进行裁剪,则计算线段与窗口的交点,并更新线段的起点和终点;5. 重复步骤2-4,直到线段裁剪完成。
Cohen-Sutherland裁剪算法的优点在于能够快速地判断线段是否与窗口有交集,并进行有效的裁剪处理。
它只需要对线段起点和终点进行编码,并进行一系列的与运算和位运算即可完成整个裁剪过程。
此外,该算法也适用于三维空间中的线段裁剪。
然而,Cohen-Sutherland裁剪算法也存在一些局限性。
当线段与窗口有交集时,该算法只能找到线段与窗口的交点,而无法找到线段与窗口的所有交点。
此外,在处理多边形的裁剪时,该算法效果不佳。
总结起来,Cohen-Sutherland裁剪算法是一种简单且高效的线段裁剪算法,适用于二维和三维空间中的线段裁剪。
cohensutherland裁剪算法实验报告Cohen-Sutherland裁剪算法是一种用于计算机图形学中线段裁剪的算法。
该算法用于确定一个给定的线段是否跨越了一个裁剪窗口,并且在必要的情况下将该线段裁剪到窗口内。
Cohen-Sutherland算法是一种基于二进制编码的线框裁剪算法,其运算速度很快,广泛应用于计算机图形学中。
实验内容:本次实验主要内容是使用Cohen-Sutherland裁剪算法对线段图形进行裁剪。
具体实验过程如下:1. 对于给定的线段和裁剪窗口,首先需要对线段进行编码。
2. 判断线段是否在裁剪窗口内。
如果线段的两个端点都在裁剪窗口内,则该线段完全位于裁剪窗口内,不需要进行裁剪。
3. 如果线段的两个端点都在裁剪窗口外,则该线段完全位于裁剪窗口外,在此情况下可以直接将该线段丢弃。
4. 如果线段的一个端点在裁剪窗口内,而另一个端点在裁剪窗口外,则需要对该线段进行裁剪。
5. 根据线段的编码,在裁剪窗口的不同区域内确定该线段与裁剪窗口的相交点。
6. 在裁剪窗口内,将线段裁剪到与裁剪窗口相交的部分,并输出裁剪后的线段。
实验步骤:本次实验使用Python语言编写程序,具体代码实现如下:# 定义裁剪窗口的左,下,右,上位置LEFT = 100BOTTOM = 100RIGHT = 500TOP = 400# 定义编码区域INSIDE = 0LEFT_EDGE = 1RIGHT_EDGE = 2BOTTOM_EDGE = 4TOP_EDGE = 8# 定义裁剪函数def cohen_sutherland(x1, y1, x2, y2):# 对线段进行编码code1 = encode(x1, y1)code2 = encode(x2, y2)accept = Falsewhile True:# 如果两端点都在裁剪窗口内if code1 == INSIDE and code2 == INSIDE:accept = Truebreak# 如果两端点都不在裁剪窗口内elif (code1 & code2) != 0:break# 如果有一个端点在裁剪窗口内,但另一个端点不在else:x = 0y = 0if code1 != INSIDE:code_out = code1else:code_out = code2if code_out & TOP_EDGE:x = x1 + (x2 - x1) * (TOP - y1) / (y2 - y1)y = TOPelif code_out & BOTTOM_EDGE:x = x1 + (x2 - x1) * (BOTTOM - y1) / (y2 - y1) y = BOTTOMelif code_out & RIGHT_EDGE:y = y1 + (y2 - y1) * (RIGHT - x1) / (x2 - x1)x = RIGHTelif code_out & LEFT_EDGE:y = y1 + (y2 - y1) * (LEFT - x1) / (x2 - x1)x = LEFTif code_out == code1:x1 = xy1 = ycode1 = encode(x1, y1)else:x2 = xy2 = ycode2 = encode(x2, y2)if accept:print("Line accepted from %.2f, %.2f to %.2f, %.2f." %(x1, y1, x2, y2))# 实现点编码函数def encode(x, y):code = INSIDEif x < LEFT:code = LEFT_EDGEelif x > RIGHT:code = RIGHT_EDGEif y < BOTTOM:code = BOTTOM_EDGEelif y > TOP:code = TOP_EDGEreturn code# 输入线段坐标并进行裁剪cohen_sutherland(50, 200, 600, 300)实验结果:输入线段坐标(50, 200)和(600, 300),运行裁剪函数,输出结果为:Line accepted from 100.00, 240.00 to 500.00, 300.00.结果说明,经过裁剪后,线段(50, 200)和(600, 300)被裁剪到了裁剪窗口内,从(100, 240)到(500, 300)。
计算机科学与技术学院2013-2014学年第一学期《计算机图形学》实验报告班级:110341B班学号:110341228姓名:王陈教师:惠康华成绩:实验项目: 二维裁剪一、实验目的与要求(1)掌握线段裁剪算法原理,并实现其算法。
(2)理解多边形裁剪、字符裁剪算法思想,能编程实现其算法。
二、实验内容(1)实现直线段的标号法、矩形窗口裁剪算法。
(2)参考教材中的算法,用矩形窗口实现多边形的裁剪算法。
三、重要算法分析(一)线段裁剪Cohen-Sutherland算法实验原理:1、线段裁剪生成算法:对于矩形的窗口,任何直线至多只有一段处于该窗口之内,即在此窗口范围内永远不会产生一条直线的两条或更多的可见部分线段。
该算法的基本思想为:对于每条待裁剪的线段分完全在窗口内(此时不需要裁剪,全部显示)、完全在窗口外(此时不需要裁剪,整条线段不显示)、部分在窗口内部分在窗口外三种情况讨论。
将窗口及其周围的八个方向以四位的二进制数进行编码,用来快速判断一条直线段与窗口属于何种关系。
其中全为0的区域为裁剪窗口。
(1) 判断线段两个端点的四位二进制编码,如果全为0,即两端点编码逻辑或运算为0,那么该线段完全位于窗口内,可直接保留;(2) 对两端点的四位二进制编码进行逻辑与运算,若结果不为0,那么整条线段必位于窗口外,可直接舍弃。
(3) 如果以上两种情况皆不是,则这条线段既不能直接保留,也不能直接舍弃,它可能与窗口相交。
此时,需要对线段进行再分割,即找到与窗口边线的一个交点,根据交点位置,赋予四位二进制编码,并对分割后的线段按照一定的顺序(左右下上)进行检查,决定保留、舍弃或再次进行分割。
(4) 重复第三步,直到出现正确的裁剪结果为止。
四、实验结果截图裁剪线段1、双击击鼠标左键,出现要裁剪的线段:如图3-1图3-1 生成裁剪窗口和待裁剪线段2、裁剪后的结果:如图3-2图3-2 裁剪后的结果五、总结与调试经验1、程序初期的结构搭建很重要:在VC中选择MFC APPWizard(exe),建立单文档应用程序,编辑菜单资源,重置ID,添加消息处理函数,建立类向导,最后添加程序代码。
实验三 图形裁剪算法实现实验学时:2学时 实验类型:验证型实验要求:必修在使用计算机处理图形信息时,计算机内部存储的图形往往比较大,而屏幕显示的只是图的一部分。
因此需要确定图形中哪些部分落在显示区之内,哪些落在显示区之外,以便只显示落在显示区内的那部分图形。
这个选择过程称为裁剪。
最简单的裁剪方法是把各种图形扫描转换为点之后,再判断各点是否在窗内。
但那样太费时,一般不可取。
这是因为有些图形组成部分全部在窗口外,可以完全排除,不必进行扫描转换。
所以一般采用先裁剪再扫描转换的方法,多边形裁剪示意图,如图1-1所示。
(a )裁剪前(b )裁剪后图1-1 多边形裁剪示意图直线裁剪1.直线和窗口的关系直线和窗口的关系如图1-2所示,可以分为如下3类: (1)整条直线在窗口内。
此时,不需剪裁,显示整条直线。
(2)整条直线在窗口外,此时,不需剪裁,不显示整条直线。
(3)部分直线在窗口内,部分直线在窗口外。
此时,需要求出直线与窗框的交点,并将窗口外的直线部分剪裁掉,显示窗口内的直线部分。
直线剪裁算法有两个主要步骤。
首先将不需剪裁的直线挑出,即删去在窗外的直线。
然后,对其余直线,逐条与窗框求交点,并将窗口外的部分删去。
2.Cohen-Sutherland 直线剪裁算法以区域编码为基础,将窗口及其周围的8个方向以4 bit 的二进制数进行编码。
如图1-3所示的编码方法将窗口及其邻域分为5个区域。
图1-2 直线与窗口的关系(1)内域:区域(0000)。
(2)上域:区域(1001,1000,1010)。
(3)下域:区域(0101, 0100, 0110)。
(4)左域:区域(1001, 0001, 0101)。
图1-3 窗口及其邻域的5个区域及与直线的关系(5)右域:区域(1010, 0010, 0110)。
当线段的两个端点的编码的逻辑“与”非零时,线段显然为不可见的。
对某线段的两各端点的区号进行位与运算,可知这两个端点是否同在视区的上、下、左、右。