图形学实验三.docx
《图形学实验三.docx》由会员分享,可在线阅读,更多相关《图形学实验三.docx(20页珍藏版)》请在冰豆网上搜索。
![图形学实验三.docx](https://file1.bdocx.com/fileroot1/2023-1/5/5e4b618b-3fc3-49fe-a678-c5164999d14c/5e4b618b-3fc3-49fe-a678-c5164999d14c1.gif)
图形学实验三
图形学实验三
Bezier曲线
040930301陈圣楠
一、程序实现环境、硬件配置、操作系统、编程语言
1.程序实现环境
本程序在eclipse-indigo通过,使用jdk1.6
2.硬件配置
处理器:
Intel(R)Core™i3CPUM3502.27GHz
安装内存(RAM):
2.00GB
3.操作系统
Windows7旗舰版32位操作系统
4.编程语言
java
二、算法思想阐述
Bezier曲线的定义是给定空间n+1个点的位置矢量,则Bezier曲线可定义为:
Ø算法推导
设是一条抛物线上顺序三个不同的点。
过和点的两切线交于点,在点的切线交和于和,则如下比例成立
当固定,引入参数t,令上述比值为,即有:
t从0变到1,第一、二式就分别表示控制二边形的第一、二条边,它们是两条一次Bezier曲线。
将一、二式代入第三式得:
当t从0变到1时,它表示了由三顶点三点定义的一条二次Bezier曲线。
并且表明:
这二次Bezier曲线可以定义为分别由前两个顶点和后两个顶点决定的一次Bezier曲线的线性组合。
依次类推,由四个控制点定义的三次Bezier曲线可被定义为分别由和确定的二条二次Bezier曲线的线性组合,由(n+1)个控制点定义的n次Bezier曲线可被定义为分别由前、后n个控制点定义的两条(n-1)次Bezier曲线与的线性组合。
由此得到Bezier曲线的递推计算公式
三、怎样使用
本程序实现了编程实现绘制一段三次Bezier曲线和实现两段三次Bezier曲线的拼接。
双击空白可添加顶点,添加两个顶点时,两点之间自动生成直线,添加第三个顶点时,根据Bezier公式,可产生一条曲线,继续添加顶点,每三个连续的顶点之间将产生一条曲线。
其他功能包括:
双击一个顶点,可将该顶点删除,拖动一个顶点可改变顶点位置,双击右键清屏。
图1初始化程序
图2选中一个顶点
四、实验结果(图示)
ØBezier曲线
图3选中两点的结果
图4Bezier曲线
图5Bezier曲线
(2)
五、测试用例(合法用例、非法用例)
1.合法用例
在画板灰色区域鼠绘即可,如上图4和图5。
2.非法用例
本程序采用鼠标点击,无非法用例,所以在此不提供非法用例及处理。
六、实验程序适用范围
本程序可作为画板、word等其他需要绘制曲线的程序的一部分,也可用于photoshop和flash中处理图像。
[源代码]
工程名:
csn0423Proj3
包名:
test3
类名:
Bezier.java
packagetest3;
importjavax.swing.*;
importjava.awt.*;
publicclassBezier
{
booleanpackFrame=false;
publicBezier()
{
Drawframe=newDraw();
if(packFrame)
{
frame.pack();
}
else
{
frame.validate();
}
DimensionscreenSize=Toolkit.getDefaultToolkit().getScreenSize();
DimensionframeSize=frame.getSize();
if(frameSize.height>screenSize.height)
{
frameSize.height=screenSize.height;
}
if(frameSize.width>screenSize.width)
{
frameSize.width=screenSize.width;
}
frame.setLocation((screenSize.width-frameSize.width)/2,(screenSize.height-frameSize.height)/2);
frame.setVisible(true);
}
publicstaticvoidmain(String[]args)
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exceptione)
{
e.printStackTrace();
}
newBezier();
}
}
工程名:
csn0423Proj3
包名:
test3
类名:
BezierPanel.java
packagetest3;
importjava.awt.*;
importjavax.swing.*;
importjava.util.ArrayList;
classVertex
{
staticfinalColorVEXCOLOR=Color.pink;
staticfinaldoubleRADII=4;
privatedoublex,y;
publicVertex(doublexx,doubleyy)
{
x=xx;
y=yy;
}
publicdoublegetX()
{
returnx;
}
publicdoublegetY()
{
returny;
}
publicvoidsetX(doublexx)
{
x=xx;
}
publicvoidsetY(doubleyy)
{
y=yy;
}
/**判断所给坐标是否在该顶点内*/
publicbooleanisIn(doubledx,doubledy)
{
doublelen;
len=Math.sqrt(Math.pow(dy-y,2)+Math.pow(dx-x,2));
if(len<=RADII)returntrue;elsereturnfalse;
}
publicStringtoString()
{
return"("+x+","+y+")";
}
}
publicclassBezierPanelextendsJPanel
{
privatestaticfinalStringINS1="双击空白地方添加顶点";
privatestaticfinalStringINS2="双击一个顶点删除该顶点";
privatestaticfinalStringINS3="拖动一个顶点改变该顶点的位置";
privatestaticfinalStringINS4="双击右键清屏";
privatestaticfinalColorVEXLINK=Color.red;//顶点间连线的颜色
staticfinalColorBEZIERCOLOR=Color.blue;//
privateArrayListvexs;//顶点
privateint[]bim;//伯恩斯坦多项式系数
publicBezierPanel()
{
super();
vexs=newArrayList();
}
/**取得原点横坐标*/
privateintgetX0()
{
return10;
}
/**取得原点纵坐标*/
privateintgetY0()
{
returnthis.getHeight()-10;
}
/**实数横坐标转象素横坐标*/
publicinttoPelsX(doubledx)
{
returngetX0()+(int)dx;
}
/**实数纵坐标转象素纵坐标*/
publicinttoPelsY(doubledy)
{
returngetY0()-(int)dy;
}
/**象素横坐标转实数横坐标*/
publicdoubletoRealX(intpx)
{
return(double)px-(double)getX0();
}
/**象素纵坐标转实数纵坐标*/
publicdoubletoRealY(intpy)
{
return(double)getY0()-(double)py;
}
/**求杨辉三角的底边
*@paramn阶次
*@returnint[]
*/
privateint[]yangHui(intn)
{
inti,j1,j2;
int[]c,tc;
c=newint[1];
c[0]=1;
for(i=2;i<=n;i++)
{
tc=c;
c=newint[i];
c[0]=1;
for(j2=0,j1=1;j1c[j1]=1;
}
returnc;
}
/**增加一个顶点
*@parampx象素横坐标
*@parampy象素纵坐标
*/
publicvoidaddVex(intpx,intpy)
{
vexs.add(newVertex(toRealX(px),toRealY(py)));//加入顶点
bim=yangHui(vexs.size());//修改伯恩斯坦多项式系数
this.repaint();//重画
}
/**删除一个顶点
*@paramindex顶点序号
*/
publicvoidremoveVex(intindex)
{
vexs.remove(index);//删除
bim=yangHui(vexs.size());//修改伯恩斯坦多项式系数
this.repaint();//重画
}
/**删除所有顶点*/
publicvoidclear()
{
vexs.clear();
this.repaint();//重画
}
/**设置某个顶点的坐标
*@paramindex序号
*@paramdx象素横坐标
*@paramdy象素纵坐标
*/
publicvoidsetLocation(intindex,intdx,intdy)
{
Vertexvex;
if(index==-1)return;
vex=(Vertex)vexs.get(index);
vex.setX(toRealX(dx));
vex.setY(toRealY(dy));
this.repaint();
}
/**取得贝塞尔线的横坐标
*@paramt参数
*@returndouble
*/
publicdoublegetBezierX(doublet)
{
inti;
doublebx=0;
for(i=0;i{
bx+=((Vertex)vexs.get(i)).getX()*bim[i]*Math.pow(t,i)*Math.pow(1-t,vexs.size()-1-i);
}
returnbx;
}
/**取得贝塞尔线的纵坐标
*@paramt参数
*@returndouble
*/
publicdoublegetBezierY(doublet)
{
inti;
doubleby=0;
for(i=0;i{
by+=((Vertex)vexs.get(i)).getY()*bim[i]*Math.pow(t,i)*Math.pow(1-t,vexs.size()-1-i);
}
returnby;
}
/**取得选中的顶点序号
*@parampx鼠标横坐标
*@parampy鼠标纵坐标
*@return若没选中则返回-1
*/
publicintgetSelectexVexIndex(intpx,intpy)
{
inti;
doubledx,dy;
dx=toRealX(px);
dy=toRealY(py);
for(i=0;ireturn-1;
}
/**画坐标系*/
publicvoiddrawCoordinate(Graphicsg)
{
Coloroldcolor;
oldcolor=g.getColor();
//坐标轴
g.drawLine(getX0(),getY0(),this.getWidth()-10,getY0());
g.drawLine(getX0(),getY0(),getX0(),10);
g.drawString("0",getX0()-7,getY0()+10);
g.drawString("x",this.getWidth()-10,getY0()+10);
g.drawString("y",getX0()-7,10);
//说明文字
g.drawString(INS1,15,20);
g.drawString(INS2,15,32);
g.drawString(INS3,15,44);
g.drawString(INS4,15,56);
g.setColor(oldcolor);
}
/**画顶点极其连线*/
publicvoiddrawVexList(Graphicsg)
{
inti,dia;
Vertexvex1,vex2;
Coloroldcolor;
if(vexs.size()==0)return;//没有顶点则返回
oldcolor=g.getColor();//保存原来的颜色
g.setColor(Vertex.VEXCOLOR);//顶点色
dia=(int)Vertex.RADII*2;//直径
vex1=(Vertex)vexs.get(0);//第一个顶点
//fillOval()的坐标参数为左上角坐标,不是原点坐标
g.fillOval(toPelsX(vex1.getX())-(int)Vertex.RADII,toPelsY(vex1.getY())-(int)Vertex.RADII,dia,dia);//画第一个顶点
for(i=1;i{
vex2=vex1;
vex1=(Vertex)vexs.get(i);//取新顶点
g.fillOval(toPelsX(vex1.getX())-(int)Vertex.RADII,toPelsY(vex1.getY())-(int)Vertex.RADII,dia,dia);//画新顶点
g.drawLine(toPelsX(vex2.getX()),toPelsY(vex2.getY()),toPelsX(vex1.getX()),toPelsY(vex1.getY()));//画连线
}
g.setColor(oldcolor);//还原旧颜色
}
publicvoidpaintComponent(Graphicsg)
{
doubledx1,dy1,dx2,dy2,t,dt=0.01;
super.paintComponent(g);
drawCoordinate(g);
//g.drawString(INS,10,10);
drawVexList(g);
//当两个以上顶点时画曲线
if(vexs.size()>=2)
{
g.setColor(BEZIERCOLOR);
dx1=getBezierX(0);
dy1=getBezierY(0);
for(t=0;t<=1;t+=dt)
{
dx2=dx1;
dy2=dy1;
dx1=getBezierX(t);
dy1=getBezierY(t);
g.drawLine(toPelsX(dx2),toPelsY(dy2),toPelsX(dx1),toPelsY(dy1));
}
}
}
}
工程名:
csn0423Proj3
包名:
test3
类名:
Draw.java
packagetest3;
importjava.awt.*;
importjava.awt.event.*;
importjavax.swing.*;
importjavax.swing.border.*;
publicclassDrawextendsJFrame
{
JPaneljPanel;
JMenuBarjMenuBar1=newJMenuBar();
JMenujMenuFile=newJMenu();
BorderLayoutborderLayout1=newBorderLayout();
privateJPaneljpboard=newJPanel();
privateTitledBordertitledBorder1;
privateBezierPanelboard=newBezierPanel();
privateBorderLayoutborderLayout2=newBorderLayout();
privateJLabeljlloc=newJLabel();
privateintindex;//选中的顶点
publicDraw()
{
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try
{
jbInit();
}
catch(Exceptione)
{
e.printStackTrace();
}
index=-1;
}
//Componentinitialization
privatevoidjbInit()throwsException
{
jPanel=(JPanel)this.getContentPane();
titledBorder1=newTitledBorder(BorderFactory.createEtchedBorder(Color.white,newColor(165,163,151)),"bezierboard:
");
jPanel.setLayout(borderLayout1);
this.setSize(newDimension(538,417));
this.setTitle("Bezier");
jpboard.setBorder(titledBorder1);
jpboard.setLayout(borderLayout2);
board.addMouseListener(newDraw_MouseAdapter(this));
jlloc.setHorizontalAlignment(SwingConstants.RIGHT);
jlloc.setText("");
board.addMouseMotionListener(newGUI_board_mouseMotionAdapter(this));
jpboard.add(board,BorderLayout.CENTER);
jPanel.add(jpboard,BorderLayout.CENTER);
jPanel.add(jlloc,BorderLayout.SOUTH);
this.setJMenuBar(jMenuBar1);
}
/**鼠标点击*/
voidboard_mouseClicked(MouseEvente)
{
intindex;
if(e.getClickCount()!
=2)
{
return;//双击事件
}
if(e.getButton()==MouseEvent.BUTTON3)
{
board.clear();//右键双击删除所有顶点
}
elseif(e.getButton()==MouseEvent.BUTTON1)//左键双击
{
index=board.getSelectexVexIndex(e.getX(),e.getY());//取得顶点序号
if(index==-1)
{
board.addVex(e.getX(),e.getY());//若点击空白则加入顶点
}
else
{
board.removeVex(index);//删除顶点
}
}
}
/**鼠标移动*/
voidboard_mouseMoved(MouseEvente)
{
jlloc.setText("Location:
("+board.toRealX(e.getX())+","+board.toRealY(e.getY())+")");
}
/**鼠标压下*/
voidboard_mousePressed(MouseEvente)
{
index=board.getSelectexVexIndex(e.getX(),e.getY());
}
/**鼠标放开*/
voidboard_mouseReleased(MouseEvente)
{
index=-1;
}
/**鼠标拖动*/
voidboard_mouseDragged(MouseEvente)
{
intpx,py;
if(index!
=-1)
{
px=e.getX();
py=e.getY();
//将坐标限制在画板内
if(px<0)px=0;
if(px>board.getWidth())px=board.getWidth();
if(py<0)py=0;