大概思路就是给定两个点(x1,y1),(x2,y2),然后取他们的中点(px,py),然后再取(x1,y1)和(px,py)的中点和(x2,y2)和(px,py)的中点,同时给定一个范围[-range,range]和一个比率rate,每次取中点后的中点纵坐标都加上这个范围内的随机值,每次中点后range都乘以rate来缩小range的范围。当两个点的横坐标小于某个值或者不能再取中点时就连接起来,即可。
递归方法的代码
public void draw(double x1,double y1,double x2,double y2,int range,double rate) {
if(Math.abs(x1-x2)<=1|range==0) {
//画线
g.drawLine((int)x1,(int) y1, (int)x2,(int) y2);
}else {
double Px=(x1+x2)/2;
double Py=(y1+y2)/2;
//在[-range,range]范围内震荡y值
Random random=new Random();
int num = random.nextInt(range*2) - range;
//缩小range
range = (int)(range*rate);
//递归调用
sm(x1,y1,Px,Py-num,range,rate);
sm(Px,Py-num,x2,y2,range,rate);
}
}
调用方法draw(x1,y1,x2,y2,500,0.55);的效果为
调用时加个for循环,加上填充图形等方法就可以完成平面山脉的绘制,效果如下:
2,3D山脉的绘制首先,要会递归分形画带有立体感的三角形,效果如下:
大概思路就是三角形每两个点之间取中点,但是要给所求的中点的纵坐标加上某个范围内的值,实现中点的震荡,这样就能实现带有一定立体感的三角形。代码如下:
//画立体三角形
public void draw(double x1,double y1,double x2,double y2,double x3,double y3,double count,int range,int rate) {
if(count<0) {
int[] px = { (int)x1, (int)x2, (int)x3 };
int[] py = { (int)y1, (int)y2, (int)y3 };
Color color = new Color(100, 100, 100, 80);
g.drawPolygon(px, py, 3);
return;
}
count--;
//中点坐标
double ax,ay,bx,by,cx,cy;
//用随机数类实现纵坐标的偏移
Random random1=new Random();
ax=(x1+x2)/2;
ay=(y1+y2)/2+random1.nextInt(range);
bx=(x1+x3)/2;
by=(y1+y3)/2+random1.nextInt(range);
cx=(x2+x3)/2;
cy=(y2+y3)/2+random1.nextInt(range);
//缩小range的值
range*=rate;
//递归分形
draw(x1,y1,ax,ay,bx,by,count,range,rate);
draw(x2,y2,ax,ay,cx,cy,count,range,rate);
draw(x3,y3,cx,cy,bx,by,count,range,rate);
}
这代码并不完善,中间还有许多倒三角形空白,所以还要给中间的倒三角形加上递归分形。效果如下:
这时就会出现问题了。在之前递归中,倒三角形的边上已经有了中值震荡点,在加上中间倒三角形的递归分形后,倒三角形边上的所有中值震荡点会重新再取一遍,这样就会产生两给中点,不解决这个问题,最后的立体山脉就会出现空白和不完整问题。如何解决呢?
解决方法很简单,当倒三角形递归分形时,每当其取震荡中点时,判断以前是不是有过,有就直接取用之前的震荡中值点,没有则自己取震荡中值点。判断之前是不是有过震荡中值点,就需要把之前取到的震荡中值点都存起来,每当要取震荡中值点的时候就拿出来一一比较。
我能力有限,只会用数组,但其实用数组来存点的效率是很低的,或许以后学到更好的方法会加以改进吧。
//数组来存点
public Arry[] arry=new Arry[100000];
public class Arry {
double x,y,z;
public Arry(double x,double y,double z) {
this.x=x;//中点值横坐标
this.y=y;//中点值纵坐标
this.z=z;//中点值偏移量
}
}
创建一个类用来存点,每当取到新的震荡中值点就放入数组中保存。
int index=0; Arry arry=new Arry(x,y,z); arry[index++]=arry;
每次再取震荡中点时,遍历数组比较即可。方法代码如下:
public void draw(double x1,double y1,double x2,double y2,double x3,double y3,double count,int range) {
if(count<0) {
int[] px = { (int)x1, (int)x2, (int)x3 };
int[] py = { (int)y1, (int)y2, (int)y3 };
Color color = new Color(100, 100, 100, 80);
g.drawPolygon(px, py, 3);
return;
}
count--;
int flag1=1,flag2=1,flag3=1;
int u=0,j=0,k=0;
double ax=0,ay=0,az=0,bx=0,by=0,bz=0,cx=0,cy=0,cz=0;
Random random1=new Random();
for(int i=0;i
效果如下:
然后给增加递归层数,加上填充(Polygon)的方法,



