递归在java中有着很重要的作用,我们可以通过递归来绘制仿真山。首先我们先通一个绘画曲线例子来明白仿真山的绘画方式。
曲线的样式如下:
这种曲线是通过改变两点之间中点的y坐标来实现的,先改变起点与终点之间中点的坐标,在改变将中点作为起点和终点与原来的终点和起点取中点,并不断重复这个过程,直到满足相应的条件跳出递归,代码如下:
public void drawBrokenLine(int x1,int y1,int x2,int y2,Graphics g){
if(Math.abs(x1-x2)<10){
g.drawLine(x1,y1,x2,y2);
return;
}
int x=(x1+x2)/2;
Random r=new Random();
int y,m=Math.abs(x1-x2)/2;
if(r.nextInt(2)==0) {
y = r.nextInt(m) + (y1 + y2) / 2;
}
else{
y= (y1 + y2) / 2-r.nextInt(m);
}
drawBrokenLine(x1,y1,x,y,g);
drawBrokenLine(x2,y2,x,y,g);
}
这里需要运用随机数来生成中点的y坐标,并且为了使线条平缓,这就要将随机数的值与进行绘画时两点的坐标联系起来,否则绘画出来的图案如下图:
这样画出来的曲线看起不就不顺滑。
仿真山的绘画过程与上述曲线绘画过程十分相像,仿真山是通过改变三角形的三边中点的坐标,此时三角形形成了四块三角形,再将这四块三角形重复上述步骤,直到满足条件,将三角形的三个点和三个中点进行连接,再将三个中点进行连接,过程如下:
执行的代码如下:
public void drawArtificialMountain(int x,int y,int x1,int y1,int x2,int y2,Graphics g){
int x3=(x+x1)/2,x4=(x1+x2)/2,x5=(x+x2)/2,
y3=(y1+y)/2,y4=(y1+y2)/2,y5=(y+y2)/2;
if(Math.abs((x1-x)*(y2-y)-(y1-y)*(x2-x))/2<30){
g.drawLine(x,y,x3,y3);
g.drawLine(x3,y3,x2,y2);
g.drawLine(x2,y2,x4,y4);
g.drawLine(x4,y4,x1,y1);
g.drawLine(x1,y1,x5,y5);
g.drawLine(x5,y5,x,y);
g.drawLine(x3,y3,x4,y4);
g.drawLine(x4,y4,x5,y5);
g.drawLine(x5,y5,x3,y3);
return;
}
Random r=new Random();
int m1=Math.abs(x-x2)+1;
int m2=Math.abs(x1-x2)+1;
int m3=Math.abs(x1-x)+1;
if(r.nextInt(2)==0) {
y3 = r.nextInt(m1)/3 + (y + y2) / 2;
y4 = r.nextInt(m2)/3 + (y1 + y2) / 2;
y5 = r.nextInt(m3)/3 + (y1 + y) / 2;
}
else{
y3= (y + y2) / 2-r.nextInt(m1)/3;
y4= (y1 + y2) / 2-r.nextInt(m2)/3;
y5= (y1 + y) / 2-r.nextInt(m3)/3;
}
drawArtificialMountain(x,y,x5,y5,x3,y3,g);
drawArtificialMountain(x5,y5,x1,y1,x4,y4,g);
drawArtificialMountain(x3,y3,x4,y4,x2,y2,g);
drawArtificialMountain(x4,y4,x3,y3,x5,y5,g);
}
绘制的结果如下:
还有一些细节部分例如重写刷新方式和对执行动作的存储。首先创建一个类Shape,再在监听器接口中创建shape的动态数组存储绘画的图案,在重写刷新方式时调用。重写的刷新方式如下:
public class DrawJFrame extends JFrame {
DrawMountainListener d1;
public void paint(Graphics g){
super.paint(g);
for (int i = 0; i <= d1.shapeCount; i++) {
Shape myShape = d1.shapeList[i];
if (myShape == null) {
return;
}
if(myShape.action.equals("折线图")) {
d1.drawBrokenLine(myShape.x1, myShape.y1, myShape.x2, myShape.y2, myShape.g);
}
if(myShape.action.equals("仿真山")){
int x=(d1.x1+d1.x2)/2;
d1.drawArtificialMountain(x,myShape.y1,myShape.x1, myShape.y2, myShape.x2, myShape.y2, myShape.g);
}
}
}
}
还有当绘画的图案超过一定的范围时就不进行绘画,例如在绘画曲线时图案超过绘画的范围,图案就会如下图: