图形学实验报告画直线圆剪裁.docx
《图形学实验报告画直线圆剪裁.docx》由会员分享,可在线阅读,更多相关《图形学实验报告画直线圆剪裁.docx(26页珍藏版)》请在冰豆网上搜索。
图形学实验报告画直线圆剪裁
一.实验目的:
1.理解并掌握中点画线算法的基本思想和算法实现在面板随意位置画线。
2.理解并掌握中点画圆算法的基本思想和算法实现在面板以任意位置为圆心画半径任意的圆。
3.理解并掌握裁剪直线的基本思想和算法实现在任意绘制的矩形中裁剪所画直线。
二.实验内容:
1.中点画线
1.1基本原理:
假定直线斜率|k|<=1,且已确定当前象素点P(Xp,Yp),然后确定下一个象素点,即T或B之一。
M为T,B中点,Q为理想直线与栅格线的交点。
若M在Q的下方,选T,否则选B。
使用直线的正负划分性来判断M和Q的位置关系(即:
F(x,y)=a*x+b*y+c=0)。
然后构造判别式:
d=F(M)=F(xp+1,yp+0.5)=a(xp+1)+b(yp+0.5)+c
其中a=y0-y1,b=x1-x0,c=x0y1-x1y0
当d<0,M在L(Q点)下方,取右上方T为下一个象素;
当d>0,M在L(Q点)上方,取右方B为下一个象素;
当d=0,选T或B均可,约定取B为下一个象素
判断了M的位置之后则可以依次的画出各个点,从而得到一条直线。
但是上面的这个算法存在浮点运算,所以将其乘以2去掉浮点运算,实现整数运算,提高效率。
而对于|k|>1的情况,只需将x与y的位置对调考虑则很容易得到正确的算法实现。
并且在本次的中点算法中可以绘制任意斜率的直线。
1.2函数流程
直线方程:
a*x+b*y+c=0,p1(x1,y1),p2(x2,y2)==>a=y1-y2;b=x2-x1.
点到直线的距离:
distance=|a*x0-b*y0+c|/sqrt(a*a+b*b)
设directionX,directionY分别为从(x1,y1)==>(x2,y2)的单位变化量(+/-1)
当直线偏向X轴时,当前象素为(xk,yk),下一个象素可能为:
(xk+directionX,yk)或者(xk+directionX,yk+directionY)这两点到直线的距离分别为:
d1=|a*xk+b*yk+c+a*directionX|/sqrt(a*a+b*b);
d2=|a*xk+b*yk+c+a*directionX+b*directonY|/sqrt(a*a+b*b);
便于运算,定义:
f(xk,yk)=d2*d2-d1*d1(将d1和d2的分母去掉了的)
=b*b+*b*directonY*(a*xk+b*yk+c+a*directionX);
当f(xk,yk)<0的时候,下一个点为(xk+directionX,yk+directionY):
f(xk+directionX,yk+directionY)=f(xk,yk)+2*b*b+2*a*b*directionX*directionY;
当f(xk,yk)>=0的时候,下一个点为(xk+directionX,yk):
f(xk+directionX,yk)=f(xk,yk)+2*a*b*directionX*directionY;
当直线偏向Y轴时,当前象素为(xk,yk),下一个象素可能为:
(xk,yk+directionY)或者(xk+directionX,yk+directionY)这两点到直线的距离分别为:
d1=|a*xk+b*yk+c+b*directionY|/sqrt(a*a+b*b);
d2=|a*xk+b*yk+c+b*directionY+a*directonX|/sqrt(a*a+b*b);
便于运算,定义:
f(xk,yk)=d2*d2-d1*d1(将d1和d2的分母去掉了的)
=a*a+*a*directonX*(a*xk+b*yk+c+b*directionY);
当f(xk,yk)<0的时候,下一个点为(xk+directionX,yk+directionY):
f(xk+directionX,yk+directionY)=f(xk,yk)+2*a*a+2*a*b*directionX*directionY;
当f(xk,yk)>=0的时候,下一个点为(xk+directionX,yk):
f(xk+directionX,yk)=f(xk,yk)+2*a*b*directionX*directionY;
1.3截图
2.中点画圆
2.1基本原理:
对于圆上的点,F(x,y)=0;对于圆外的点,F(x,y)>0;而对于圆内的点,F(x,y)<0。
假设M是P1和P2的中点,即M=(xp+1,yp-0.5)。
那么,当F(M)<0时,M在圆内,这说明P1距离圆弧更近,应取P1作为下一像素。
而当F(M)>0时,P2离圆弧更近,应取P2。
当F(M)=0时,在P1与P2之中随便取一个即可,我们约定取P2。
与中点画线法一样,构造判别式
d=F(M)=F(xp+1,yp-0.5)
=(xp+1)2+(yp-0.5)2-R2
若d<0,则应取P1为下一像素,而且再下一个像素的判别式为
d=F(xp+2,yp-0.5)=(xp+2)2+(yp-0.5)2-R2=d+2xp+3
所以,沿正右方向,d的增量为2xp+3。
而若d≥0,则P2是下一像素,而且下一像素的判别式为
d'=F(xp+2,yp–1.5)=(xp+2)2+(yp–1.5)2–R2=d+(2xp+3)+(–2yp+2)
所以,沿右下方向,判别式d的增量为2(xp–yp)+5。
由于我们这里讨论的是按顺时针方向生成第二个8分圆,因此,第一像素是(0,R),判别量d的初始值为:
d0=F(l,R–0.5)=1+(R–0.5)2–R2=1.25–R
设则判别量的初值为
递推公式中其他与d有管的狮子可以直接换成
所以
圆心位于原点的圆有四条对称轴x=0、y=0、x=y和x=-y。
从而若已知圆弧上一点P(x,y),就可以得到其关于四条对称轴的七个对称点,这种性质称为八分对称性。
因此只要能画出八分之一的圆弧,就可以利用对称性的原理得到整个圆弧。
2.2截图
3.直线剪裁
3.1基本原理:
裁剪窗口:
矩形区域
若线段两端点均落在窗口内:
线段可见;
.若线段两端点分别落在窗口的内外两侧:
计算线段与窗口边界的交点(1个),确定可见部分线段;
.若线段两端点均落在窗口外:
计算线段与窗口交点(0个或2个),若无交点,则线段不可见,否则线段部分可见。
分别记线段端点P1,P2的编码为code1,code2,当P1,P2均在窗口内:
code1=0000且code2=0000;P1,P2在同一边框线外:
code1[i]=code2[i]=1,i=1,2,3,4;即code1&code2!
=0000,
其它code1&code2=0000;code1!
=0000或code2!
=0000
利用中点分割法并采用迭代方法找到距端点最近的可见点进行剪裁
3.2流程图
3.3截图
附录 :
代码:
MAINFRAME
importjava.awt.*;importjavax.swing.*;importjava.awt.event.*;
importjavax.swing.event.*;importjavax.swing.border.*;
publicclassMainFrameextendsJFrame{
MainFrame(){
Containerc=getContentPane();
drawPanel=newPanelEX(this,730,540);
mainPanel=newJPanel();
mainPanel.setLayout(newGridBagLayout());
ctrlPanel=newJPanel();
ctrlPanel.setLayout(newBoxLayout(ctrlPanel,BoxLayout.Y_AXIS));
initButtonPanel();
ctrlPanel.add(buttonPanel);
gridBagConstraints=newGridBagConstraints();
mainPanel.add(ctrlPanel,gridBagConstraints);
gridBagConstraints.insets=newInsets(5,5,15,5);
add(mainPanel,BorderLayout.WEST);
add(drawPanel,BorderLayout.CENTER);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setTitle("画线圆剪裁——ZXJ");
setSize(885,572);
show();
}
voidinitButtonPanel(){
buttonPanel=newJPanel();
JPanelt=newJPanel(newGridLayout(6,1,6,6));
ButtonGroupbg=newButtonGroup();
line=newJToggleButton();
line.setFont(newFont("Dialog",0,30));
line.setSelected(true);
line.setText("画线");
line.addActionListener(newActionListener(){
publicvoidactionPerformed(ActionEvente){
drawPanel.setOperate(PanelEX.DrawLine);
}
});
bg.add(line);t.add(line);
clip=newJToggleButton();
clip.setFont(newFont("Dialog",0,30));
clip.setText("裁剪");
clip.addActionListener(newActionListener(){
publicvoidactionPerformed(ActionEvente){
drawPanel.setOperate(PanelEX.SegmentClip);
}
});
bg.add(clip);t.add(clip);
circle=newJToggleButton();
circle.setFont(newFont("Dialog",0,30));
circle.setText("画圆");
circle.addActionListener(newActionListener(){
publicvoidactionPerformed(ActionEvente){
drawPanel.setOperate(PanelEX.drawcircle);
}
});
bg.add(circle);t.add(circle);
clear=newJButton();
clear.setFont(newFont("Dialog",0,30));
clear.setText("清屏");
clear.addActionListener(newActionListener(){
publicvoidactionPerformed(ActionEvente){
drawPanel.clear();
}
});
t.add(clear);buttonPanel.add(t);
}
publicstaticvoidmain(Stringargs[]){
try{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}catch(Exceptione){
e.printStackTrace();
}
newMainFrame();
}
JPanelmainPanel;JPanelctrlPanel;JPanelbuttonPanel;
JToggleButtonline;JToggleButtoncircle;JToggleButtonclip;
JButtonclear;GridBagConstraintsgridBagConstraints;PanelEXdrawPanel;
}
PANELEX :
importjava.awt.*;importjava.awt.image.*;importjavax.swing.*;
importjava.awt.event.*;importjavax.swing.event.*;importjavax.swing.border.*;
importjava.math.*;
publicclassPanelEXextendsJPanelimplementsMouseMotionListener,MouseListener{
PanelEX(MainFramemf,intwidth,intheight)//绘制画图面板
{
this.mf=mf;xmin=ymin=0;xmax=width;ymax=height;
resetSize(width,height);circle=newCircleOP(this);
clip=newClipOP(this);clip.setClipRect(0,0,width,height);
line=newLineOP(this,clip);addMouseListener(this);
addMouseMotionListener(this);
}
publicvoidmousePressed(MouseEvente)//鼠标压下获取当前位置
{
if(e.getButton()==MouseEvent.BUTTON1)
{xstart=xcurrent=e.getX();ystart=ycurrent=e.getY();}
}
publicvoidmouseDragged(MouseEvente)//鼠表拖动,根据不同情况有不同处理方式
{
switch(currentOperate){
caseDrawLine:
//画线鼠标拖动过程中获取坐标并且将拖动过程显示
line.pushBack(xstart,ystart,xcurrent,ycurrent);
xcurrent=e.getX();ycurrent=e.getY();
line.pushForward(xstart,ystart,xcurrent,ycurrent);
break;
casedrawcircle:
//画圆鼠标拖动过程中获取坐标计算半径并且将拖动过程显示
intradix=(int)Math.sqrt((xstart-xcurrent)*(xstart-xcurrent)+(ystart-ycurrent)*(ystart-ycurrent));
circle.pushBack(xstart,ystart,radix);
xcurrent=e.getX();
ycurrent=e.getY();
radix=(int)Math.sqrt((xstart-xcurrent)*(xstart-xcurrent)+(ystart-ycurrent)*(ystart-ycurrent));
circle.pushForward(xstart,ystart,radix);
break;
caseSegmentClip:
//剪裁由于剪裁的为直线,所以类似直线
clip.pushBack(xstart,ystart,xcurrent,ycurrent);
xcurrent=e.getX();
ycurrent=e.getY();
clip.pushForward(xstart,ystart,xcurrent,ycurrent);
break;
}
}
publicvoidmouseReleased(MouseEvente)//松开鼠标
{
if(e.getButton()!
=MouseEvent.BUTTON1){return;}
if(currentOperate==DrawLine)//根据中点画线方法画线
{
line.pushBack(xstart,ystart,xcurrent,ycurrent);
line.MidPoint(xstart,ystart,e.getX(),e.getY());
}
if(currentOperate==drawcircle)//根据中点画圆方法画圆
{
intradix=(int)Math.sqrt((xcurrent-xstart)*(xcurrent-xstart)+(ycurrent-ystart)*(ycurrent-ystart));
circle.pushBack(xstart,ystart,radix);
radix=(int)Math.sqrt((e.getX()-xstart)*(e.getX()-xstart)+(e.getY()-ystart)*(e.getY()-ystart));
circle.MidPoint(xstart,ystart,radix);
}
if(currentOperate==SegmentClip)//剪裁
{
clip.pushBack(xstart,ystart,xcurrent,ycurrent);
if(xstart>e.getX())//获取xmin,xmax,ymin,ymax绘制剪裁矩形
{xmin=e.getX();xmax=xstart;}
else
{xmin=xstart;xmax=e.getX();}
if(ystart>e.getY())
{ymin=e.getY();ymax=ystart;}
else
{ymin=ystart;ymax=e.getY();}
if(xmin<0){xmin=0;}
if(xmax>width){xmax=width;}
if(ymin<0){ymin=0;}
if(ymax>height){ymax=height;}
clip.drawRectBoth(xmin,ymin,xmax,ymax);
clip.setClipRect(xmin,ymin,xmax,ymax);
}
}
publicvoidmouseMoved(MouseEvente){}
voidresetSize(intwidth,intheight){//绘图面板
if(this.width==width&&this.height==height){
return;
}
this.width=width;this.height=height;
bi=newBufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
g2=(Graphics2D)bi.getGraphics();g2.setColor(Color.white);
g2.fillRect(0,0,width,height);g2.dispose();
setSize(width,height);
}
publicvoidclear()//清屏
{
g2=(Graphics2D)bi.getGraphics();g2.setColor(Color.white);
g2.fillRect(0,0,width,height);g2.dispose();
paint(getGraphics());
}
publicvoidpaint(Graphicsg){g.drawImage(bi,0,0,width,height,this);}
publicvoidupdate(Graphicsg){paint(g);}
publicvoidstop(){}
publicvoidsetOperate(intop)
{currentOperate=op;needConnectPoint=false;}
publicvoidmouseClicked(MouseEvente){}
publicvoidmouseEntered(MouseEvente){}
publicvoidmouseExited(MouseEvente){}
MainFramemf;BufferedImagebi;LineOPline;ClipOPclip;
CircleOPcircle;Graphics2Dg2;intxstart;intystart;
intxcurrent;intycurrent;intxend;intyend;
privateintxmin;privateintymin;privateintxmax;privateintymax;
intwidth=0;intheight=0;intcurrentOperate=DrawLine;
Colorcolor;
booleanneedConnectPoint=false;publicstaticfinalintDrawLine=1;