实验5 计算机图形学 实验报告_第1页
实验5 计算机图形学 实验报告_第2页
实验5 计算机图形学 实验报告_第3页
实验5 计算机图形学 实验报告_第4页
实验5 计算机图形学 实验报告_第5页
已阅读5页,还剩15页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、实验5实验报告格式计算机图形学实验5实验报告xxxxxx xxx xxxxxxx实验题目:多边形裁剪与填充实验内容:1 阅读理解提供的参考资料。2编写并调通一个多边形裁剪的java程序。3编写并调通一个多边形填充的java程序。参考资料:1 fillPolygon.java 2 clipSC2.java2变换与剪裁.ppt3多边形的填充.ppt基本概念:(详细叙述自己对实验内容的理解)变换与裁剪基本概念的理解:矢量:矢量是一个n元组,在坐标系中它对应于n维空间的一个点,这个点 可以代表物体在空间的位置,也可以代表其运动状态等。模型坐标系(局部坐标系):当构造单个对象的数字模型时,为了方便,可以

2、将其置于一个特定的坐标系下,即模型坐标系或局部坐标系.世界坐标系:为描述图形场景中所有图形之间的空间关系,将它们置于一个统一的坐标系中,该坐标系被称为世界坐标系。标准化设备坐标系:有些图形系统,对设备坐标系进行了规范化,将坐标范围限定在区间x,y,z | 0x1, 0y1, 0z1内,称标准化设备坐标系投影: 三维空间中的对象要在二维的屏幕或图纸上显示出来,就必须通过投影。投影的方法有两种,平行投影和透视投影。视区:在屏幕或绘图纸上定义一个矩形,称为视区,也称为视口,窗口内的景物在视区中显示。平移:点(x,y,z)由点(x, y, z)在x, y和z轴方向分别移动距离x, y和z得到。两点坐标

3、间的关系为 x=x+x y=y+y (4.1) z=z+z放大和缩小以原点为中心的缩放:设点(x, y, z)经缩放变换后得点(x,y,z)。两点坐标间的关系为其中sx,sy和sz 分别为沿x, y和z轴方向放缩的比例。其矩阵形式是图形模式:矩阵合并时,先调用的矩阵放在右边,后调用的矩阵放在左边.也称为固定坐标系模式。这种模式的特点是每一次变换均可看成相对于原始坐标系执行的。空间模式:又称活动坐标系模式。先调用的矩阵放在左边,后调用的矩阵放在右边,连续执行几次变换时,每一次变换均可看成是在上一次变换形成的新坐标系中进行的。多边形的填充:多边形的表示方法:1)顶点表示是用多边形的顶点的序列来描述

4、多边形,该表示几何意义强、占内存少,但它不能直观地说明哪些像素在多边形内。2)点阵表示是用位于多边形内的象素的集合来刻划多边形,该方法虽然没有多边形的几何信息,是面着色所需要的图像表示形式。区域是指已经表示成点阵形式的像素集合。在光栅图形中,区域可采用内点表示和边界表示两种形式进行描述。内点表示法:把位于给定区域内的所有像素一一列举出来的方法称为内点表示法。边界表示法:把位于给定区域边界上的像素一一列举出来的方法称为边界表示法。算法设计:(详细叙述自己设计的的算法)多边形裁剪算法分析: 基本思想是一次用窗口的一条边裁剪多边形,窗口的一条边以及延长线构成裁剪线,该线把平面分成两个部分:

5、可见一侧,不可见一侧。用一条裁剪边对多边形进行裁剪,得到一个顶点序列,作为下一条裁剪边处理过程的输入点。 对于每一条裁剪边,只是判断点在窗口的哪一测以及求线段与裁剪边的交点算法应随之改变。多边形裁剪的SutherlandHodgman算法   1>. SutherlandHodgman多边形裁剪算法思想 该算法的基本思想是每次用窗口的一条边界及其延长线来裁剪多边形的各边。多边形通常由它的顶点序列来表示,经过裁剪规则针对某条边界裁剪后,结果形成新的顶点序列,又留待下条边界进行裁剪,直到窗口的所有边界都裁剪完毕,算法形成最后的顶点序

6、列,才是结果多边形(它可能构成一个或多个多边形)。 当多边形一个顶点Pi相对于窗口某条边界及其延长线进行剪裁时,不外乎下列四种情况(即裁剪规则): 1、顶点Pi在内侧,前一顶点Pi-1也在内侧,则将Pi纳入新的顶点序列; 2、顶点Pi在内侧,前一顶点Pi-1在外侧,则先求交点Q,再将Q、Pi依次纳入新的顶点序列; 3、顶点Pi在外侧,前一顶点Pi-1在内侧,则先求交点Q,再将Q纳入新的顶点序列; 4、顶点Pi与前一顶点Pi-1均在外侧,则顶点序列中不增加新的顶点。多边形填充算法分析: 确定多边形所占有的最大扫描线数,得到多边形顶点的最

7、小和最大y值(ymin和ymax),从y=ymin 到 y=ymax, 每次用一条扫描进行填充。对一条扫描线填充的过程可分为四个步骤: a.求交b.排序c.交点配对d.区间填色。扫描多边形填充算法的基本原理在直角坐标系中,假设有一条从左至右的扫描线穿过多边形,从左至右开始计数,与多边形交点为奇数时,开始进入多边形,与多边形交点为偶数时,走出多边形。这样在这相邻配对的奇偶交点间的所有象素都在多边形内。如图,奇数交点a,c,都是入多边形,偶数交点b,d都是走出多边形,相邻的奇偶交点配对,a,b之间,c,d之间的象素都多边形内,可见一条扫描线上,与多边形交点个

8、数需要为偶数。依据这样的思路,扫描线从上到下从左到右依次扫过多边形即可求得多边形所占据的象素。(注意退化情况的处理,也就是扫描线刚好经过顶点或者多边形的边本身就是水平的情况)bdca扫描多边形填充的原理代码:(给出和实验内容相关的Java程序和注解,不要辅助代码,否则扣分) /Sutherland_Cohen裁减算法 public void Sutherland_Cohen(Graphics g,float x0,float y0,float x2,float y2) int c1,c2,c; float x,y,wx,wy; boolean accept=false,done=false;

9、c1=code(x0,y0); c2=code(x2,y2); do if (c1|c2)=0)/两个编码都为0,表明在窗口内 accept=true; done=true; else if(c1&c2)!=0)done=true;/两个编码的某一位为1,则必然在外侧显然在窗口外 else c=c1; if(c=0)c=c2; wx=x2-x0; wy=y2-y0; if (c&8)=8) /求交点 x=x0+wx*(yT-y0)/wy; y=yT; else if (c&4)=4) x=x0+wx*(yB-y0)/wy; y=yB; else if (c&1)

10、=1) y=y0+wy*(xL-x0)/wx; x=xL; else/即(c&2)=2 y=y0+wy*(xR-x0)/wx; x=xR; if (c=c1) /表明c1!=0,起始点不在窗口内,将交点作为新的起点重复判断步骤; x0=x; y0=y; c1=code(x0,y0); else /终点不在窗口内,交点作为新的终点 x2=x; y2=y; c2=code(x2,y2); /else while (done=false); if(accept)g.drawLine(int)100,(int)150,(int)200,(int)150);=/fillPolygon.java/

11、*定义多边形单链表类activeEdgeListclass activeEdgeList activeEdgeListEntry header=null;/链表头指针activeEdgeListEntry tailer=null;/链表尾指针/构造方法public activeEdgeList(activeEdgeListEntry element) header=tailer=element;/指向第一个边结点/把新结点插入有序排列的多边形单链表public void insert(activeEdgeListEntry element) activeEdgeListEntry sentin

12、el;/当前结点指针if(element=null | this.header=null)/新结点异常或者链表空throw new NullPointerException();/出错,抛出异常sentinel=this.header;/当前指针指向表头结点int xt=element.topx;/新结点的topxint xtold=sentinel.topx;double oldDelta=sentinel.delta;/当前结点的deltadouble newDelta=element.delta;/* 排序第一关键字结点的topx,第二关键字结点的delta */* 两个关键字由小到大*

13、/if(xtold<xt)|(xtold=xt)&&(oldDelta<newDelta)while(true)/在链表头指针之后寻找新结点element的位置if(sentinel.next=null) /当前位置是表尾sentinel.next=element;/追加到表尾this.tailer=element;break;/结束while循环activeEdgeListEntry mp=sentinel.next;/下一结点int xmt=mp.topx;double midDelta=mp.delta;if(xmt<xt)|(xmt=xt)&&

14、amp;(midDelta<newDelta)sentinel=mp;/新结点仍然大于下一结点,当前结点指针后移,继续循环else /否则,新结点就应该插入当前位置sentinel.next=element;element.next=mp;break;/结束while循环,尾指针不动/结束whileelse /新结点作为单链表头结点sentinel=this.header;this.header=element;element.next=sentinel;/插入新结点结束/把新结点作为多边形链表的头结点或者尾结点public void append(activeEdgeListEntry

15、 element) if(element=null) throw new NullPointerException();if(tailer=null) /如果单链表是空tailer=element;header=element;else /否则把新结点作为单链表尾结点tailer.next=element;tailer=element;/两个多边形单链表的合并:自身单链表与list单链表的合并public activeEdgeList merge(activeEdgeList list,int y) if(list=null) return this;activeEdgeListEntry a

16、=this.header;/自身单链表的头指针activeEdgeListEntry b=list.header;/单链表list的头指针activeEdgeListEntry save=null;/指向链表结点的工作指针activeEdgeListEntry anext,bnext;/指向链表结点的工作指针activeEdgeList result=null;/合并结果链表while(true) if(a=null&&b=null) return result; /两个空表else if(a=null) /自身为空表if(save!=null) save.next=b;res

17、ult.tailer=list.tailer;return result; else if(b=null)/list为空表 if(save!=null) save.next=a;result.tailer=this.tailer;return result; /*两个表都不空*/int xa=(int)(a.topx+(a.topy-y)*a.delta);/自身链表int xb=b.topx;/list链表头结点的topxif(xa<=xb) /决定合并后两个表的先后anext=a.next;a.next=null;if(result=null) /结果链表为空,则a表在前result

18、=new activeEdgeList(a);save=result.tailer;else result.append(a);/结果链表不空,则a表在后save=a;a=anext;else bnext=b.next;b.next=null;if(result=null) /结果链表为空,则b表在前result=new activeEdgeList(b);save=result.tailer;else result.append(b);/结果链表不空,则b表在后save=b;b=bnext; /结束while/单链表合并结束/删除多边形单链表的结点public void remove(act

19、iveEdgeListEntry element) activeEdgeListEntry p,q;if(header=element) /要删除的是头结点header=element.next;if(tailer=element) tailer=header;return;p=q=header;while(p!=element) q=p;p=p.next;if(p=null) throw new NullPointerException();/查无此结点if(element=tailer) tailer=q;/要删除的是尾结点q.next=p.next;/要删除的是非头尾结点/多边形单链表的

20、相邻结点public void traverse() activeEdgeListEntry p,q,r,tmp;p=r=header;while(p!=null)q=p.next;if(q=null) break;/到达末尾if(q.x<p.x) /多边形单链表相邻结点的x坐标要由小到大tmp=q.next;/交换两个结点if(p=header) header=q; else r.next=q;q.next=p;p.next=tmp;r=p;/指向尾结点p=p.next;/下一个结点/结束whiletailer=r;/多边形单链表新的尾指针/结束多边形单链表类/*定义直线类class

21、Line public double x1,y1;public double x2,y2;public Line(double x1,double y1,double x2,double y2) this.x1=x1;this.y1=y1;this.x2=x2;this.y2=y2; /结束直线类/*定义多边形的填充类*/public class fillPolygon extends Applet /继承鼠标事件监听接口implements MouseListener,MouseMotionListener protected MyCanvas m;/定义MyCanvas的对象/扫描行处理用

22、数据protected activeEdgeListEntry edgeData=null;/边结点数组protected activeEdgeList bucket=null;/多边形单链表数组protected activeEdgeList activeHeader=null;/当前边单链表的头指针protected int numEdge=5;/多边形的边数/鼠标相关数据protected boolean isFirstClicked=true;/鼠标最初点击protected boolean isDoubleClicked=false;/双击标志protected boolean is

23、SingleClicked=false;/单击标志/绘图区域protected int width,height;/Applet绘图区的大小protected Image image=null;/图像区域protected MemoryImageSource mis=null;/内存图像protected int pixel=null;/内存图像配色数组protected int pixelWidth;/图像宽度protected int pixelHeight;/图像高度protected int xoffset;/pixel数据的窗口内显示偏移量protected int yoffset;

24、protected double leftTopx;/pixel数据的起始点protected double leftTopy;/多边形的绘图数据protected double x0,y0;/边的起点protected double lastx,lasty;/边的终点位置protected double movingx,movingy;/用户坐标系下一个点的坐标protected int numPoints=0;/顶点计数器protected boolean isPolygonMode=true;/标志protected Vector lines=new Vector(256,256);/J

25、ava的向量类/APPLET程序的初始化public void init()m=new MyCanvas(this);/本APPLET容器的MyCanvas对象addMouseListener(this);/定义鼠标按钮监听器addMouseMotionListener(this);/定义鼠标按钮监听器Dimension d=getSize();/本APPLET容器的大小width=d.width; height=d.height;/成员变量初始化public void initData()isFirstClicked=true;/鼠标最初点击isPolygonMode=true;/标志描绘多

26、边形numPoints=0;/多边形顶点计数器bucket=new activeEdgeListheight+1;/边的单链表数组for(int i=0;i<height+1;i+) bucketi=null;if(lines.size()>0) lines.removeAllElements();/向量类的对象/APPLET程序的绘图public void paint(Graphics g) if(isFirstClicked) /初始状态initData();Font f=m.MyFont(m.getFont().getName(),Font.BOLD+Font.ITALIC,

27、3);m.setFont(f);m.drawString("单击画多边形",-1,0.2);m.drawString("双击填充多边形",-4,-6);m.setBackground(new Color(220,220,220);/背景色m.setColor(Color.black);/前景色for(int i=0;i<lines.size();i+) Line l=(Line)lines.elementAt(i);/转换第i个向量m.drawLine(l.x1,l.y1,l.x2,l.y2);if(isPolygonMode&&!

28、isFirstClicked)/画线m.drawLine(lastx,lasty,movingx,movingy);if(!isPolygonMode)&&(image!=null)/填充m.myDrawImage(image,leftTopx,leftTopy,this);/APPLET程序的绘图/把多边形顶点数据生成边结点public void registerActiveEdgeEntry() numEdge=lines.size();/多边形边的数量edgeData=new activeEdgeListEntrynumEdge;for(int i=0;i<numE

29、dge;i+)/每个边的单链表头结点edgeDatai=new activeEdgeListEntry();/* 四个极值用于确定显示图像的大小和范围 */int LARGE=0x0ffffffff;int xmin=LARGE,xmax=-1,ymin=LARGE,ymax=-1;double dxmin=LARGE,dxmax=-1,dymin=LARGE,dymax=-1;for(int i=0;i<numEdge;i+) /对每个边结点数组赋值Line l=(Line)lines.elementAt(i);/转换第i个向量int ix1=m.getX(l.x1);/将用户坐标的点

30、转换到Java AWT坐标int iy1=height-m.getY(l.y1);int ix2=m.getX(l.x2);int iy2=height-m.getY(l.y2);edgeDatai.topx=0;edgeD=i;edgeDatai.next=null;if(iy1>iy2) /边的斜向edgeDatai.isHorizontal=false;edgeDatai.topy=iy1;edgeDatai.topx=ix1;edgeDatai.x=ix1;edgeDatai.boty=iy2;edgeDatai.delta=(double)(-(ix2-ix1

31、)/(iy2-iy1);if(iy2<ymin) /进行yMin yMax 计算ymin=iy2;dymin=l.y2;if(iy1>ymax) ymax=iy1;dymax=l.y1;else if(iy1<iy2) /边的斜向edgeDatai.isHorizontal=false;edgeDatai.topy=iy2;edgeDatai.topx=ix2;edgeDatai.x=ix2;edgeDatai.boty=iy1;edgeDatai.delta=(double)(-(ix1-ix2)/(iy1-iy2);if(iy1<ymin) /进行yMin yMax

32、 计算ymin=iy1;dymin=l.y1;if(iy2>ymax) ymax=iy2;dymax=l.y2;else /水平边y1=iy2edgeDatai.isHorizontal=true;if(iy1<ymin) /进行yMin yMax 计算ymin=iy1;dymin=l.y1;if(iy1>ymax) ymax=iy1;dymax=l.y1;if(ix1<ix2) /进行xMin xMax 计算if(ix1<xmin) xmin=ix1;dxmin=l.x1;if(ix2>xmax) xmax=ix2;dxmax=l.x2;else if(i

33、x2<ix1) if(ix2<xmin) xmin=ix2;dxmin=l.x2;if(ix1>xmax) xmax=ix1;dxmax=l.x1;else /垂直边ix2=ix1if(ix1<xmin) xmin=ix1;dxmin=l.x1;if(ix1>xmax) xmax=ix1;dxmax=l.x1;/结束for循环/*内存图像的数组空间及相关数据*/pixelWidth=xmax-xmin+1;pixelHeight=ymax-ymin+1;pixel=new intpixelWidth*pixelHeight;/图像的个点颜色for(int k=0;

34、k<pixelWidth*pixelHeight;k+)pixelk=0x00000000;/初值透明色xoffset=xmin;yoffset=ymin;leftTopx=dxmin;/用于显示图像方法myDrawImage();leftTopy=dymax;/生成边结点registerActiveEdgeEntry()/多边形单链表数组bucketd初始化public void bucketSort() for(int i=0;i<lines.size();i+) Line l=(Line)lines.elementAt(i);/转换第i个向量if(edgeDatai.isHo

35、rizontal) continue;/水平边不处理int yt=edgeDatai.topy;if(bucketyt=null) /该行未建立链表bucketyt=new activeEdgeList(edgeDatai);continue;bucketyt.insert(edgeDatai);/该行有链表,按顺序插入到链表i/结束for循环/多边形的扫描转换public void scanPolygon() activeHeader=null;/当前要处理的单链表for(int y=height-1;y>=0;y-) if(buckety!=null) /该指针元素存在makeAct

36、iveEdgeList(buckety,y);/建立该行的边链表processActiveEdgeList(y);/处理该行的边链表else if(activeHeader!=null&&activeHeader.header!=null)processActiveEdgeList(y);/处理该行的边链表/结束for循环/多边形的扫描转换/处理给定行的边链表public void processActiveEdgeList(int y) int xleft,xright;double xl,xr;activeEdgeListEntry left=activeHeader.he

37、ader;activeEdgeListEntry right=left.next;if(right=null) return;while(true) xl=left.x;xr=right.x;xleft=(int)xl;xright=(int)(xr+0.5);if(xleft<=xright)fillScanline(xleft,xright,y);/填充y行像素列left.x+=left.delta;/起终点右移一个步长right.x+=right.delta;if(left.boty>=y-1 && right.boty>=y-1) xleft=(int

38、)left.x;xright=(int)(right.x+0.5);if(xleft<=xright)fillScanline(xleft,xright,y-1);/填充y-1行像素列if(left.boty>=y-1) /将左面的边从当前链表中删去activeHeader.remove(left);if(right.boty>=y-1) /将左面的边从当前链表中删去activeHeader.remove(right);left=right.next;/选择当前链表中下一对结点if(left=null) break;/到达链表末尾,退出循环right=left.next;if

39、(right=null)/边链表的结点数一定为偶数throw new NullPointerException();/出错/结束whileactiveHeader.traverse();/边封闭后,重新整理单链表/处理给定行的边链表/建立指定行的边链表public void makeActiveEdgeList(activeEdgeList list,int y) if(activeHeader=null)activeHeader=list;/指定为当前单链表else/把list与当前单链表合并activeHeader=activeHeader.merge(list,y);/填充何种图案pub

40、lic boolean isTilePattern(int i,int j) if( i%8=0 | j%8=0 | i%8=1 | j%8=1 |i%8=2 | j%8=2 ) return true;/ 填充图案1return false;/ 填充图案2/设定像素颜色public void putPixel(int i,int j) int r,g,b;if(isTilePattern(i,j)r=g=b=0;/黑色else r=(int)(Math.random()*255);/0到255之间的随机数g=(int)(Math.random()*255);b=(int)(Math.rand

41、om()*255);int a=0xff000000|(r<<16)|(g<<8)|b;/像素颜色/*图像的i行j列处的颜色*/pixel(pixelHeight-1-(j-yoffset)*pixelWidth+(i-xoffset)=a;/填充指定行的像素列public void fillScanline(int xleft,int xright,int y) for(int x=xleft;x<=xright;x+)putPixel(x,y);/调用putPixel(),设定改点像素颜色/-多边形填充总控程序-public void scanLineFill

42、Polygon() registerActiveEdgeEntry();/生成边结点bucketSort();/单链表数组bucketd初始化scanPolygon();/多边形的扫描转换repaint();/paint绘图/响应鼠标击键事件public void mousePressed(MouseEvent e) int ix=e.getX();/鼠标的Jawa AWT坐标int iy=e.getY();if(isPolygonMode) /正在进行多边形填充double x,y;/鼠标的当前位置if(e.getClickCount()>=2) /双击,添加多边形的顶点isDoubl

43、eClicked=true;/标记/* 给光栅向量表增加一行,这个向量成员方法导致编译要加上参数-Xlint,会出现警告错误*/lines.addElement(new Line(lastx,lasty,x0,y0);isPolygonMode=false;scanLineFillPolygon();/多边形填充总控程序if(numEdge>2) /内存图像生成mis=new MemoryImageSource(pixelWidth,pixelHeight,pixel,0,pixelWidth);image=createImage(mis);else /单击,准备开始if(isFirst

44、Clicked) /初次点击isFirstClicked=false;/*先按照Jawa AWT坐标ix iy得到视图索引号,再由视图反向转换得到用户坐标系下的lastx lasty*/lastx=x0=m.getUserX(ix,m.getViewport(ix,iy);lasty=y0=m.getUserY(iy,m.getViewport(iy,iy);movingx=lastx; movingy=lasty;else /非初次点击/*ix iy所对应的用户坐标系下的坐标*/x=m.getUserX(ix,m.getViewport(ix,iy);y=m.getUserY(iy,m.getViewport(iy,iy);

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论