lesson 4 分形之美

分形的原理,是利用某一算法,迭代(一般用循环或者递归)获得新的图形来形成分形图形的。
在分形的学习中,掌握了递归这一个处理算法的工具,那么对于递归,我的看法是对一个或者一组数据进行相同而多次重复操作时使用的,它必须具备一个出口,不然会变成死递归,然后还可能需要对每一步递归进行一些变量的变化,一般通过递归方法的参数的传递来实现。
那么除了递归还可以用循环来实现,感觉关于分形,涉及到数学公式的迭代用循环比较好,而根据图形的规律来画出整个图形的话则用递归比较好。
下面用我画毕达哥拉斯曲线的过程来谈下我的经验。

画分形主要是算法问题,所以大部分代码集中在鼠标监听器,实现根据按下的点的坐标来做递归的第一层,然后根据点击的次数来增加递归的次数,使得树生长起来。
这是UI界面:
public class Pythagoras {

private Graphics g;
public static void main(String[] args) {

Pythagoras rc = new Pythagoras();
rc.show();
}

public void show() {
//初始化窗口
JFrame jf = new JFrame();
jf.setSize(1100, 800);
jf.setDefaultCloseOperation(3);
jf.setLocationRelativeTo(null);

jf.setVisible(true);

//获得画布
g = jf.getGraphics();
MyMouseListener ml = new MyMouseListener(g);
jf.addMouseListener(ml);
}
}


然后是鼠标监听器,开始以为挺简单的,就只在监听器里面加了个画图的方法,但是发现没把方法封装起来,感觉还是很乱,就比如在计算图形的顶点的时候用到了三角函数来计算,但是需要获得某两边的夹角,由于JFrame里面的坐标和我们熟悉的xy坐标有一点不一样,y的方向是往下的,所以在进行角的数值判断的时候BUG很多,一直调不好,导致递归出来的图形奇形怪状。
然后我就把分析角度,从而获得角度的环节封装在了一个getAngle方法里面,然后在这里方法里面很全面地分析了各种情况产生出来的角度。然后用起来也很方便,也便利了其他递归图形,比如科赫曲线,也用到了这个方法。
public class MyMouseListener extends MouseAdapter {

private int x1,y1;
private Graphics g;
private int count=1;
private double angle=Math.PI/6;

public MyMouseListener(Graphics g){
this.g = g;
}

public void mousePressed(MouseEvent e) {

x1 = e.getX();
y1 = e.getY();
/* for(int i=0;i<1000;i++){
g.clearRect(0, 0, 1100, 800);
angle = angle + Math.PI/3600;
draw(x1,y1,x1+100,y1,15,angle);
try {
Thread.sleep(10);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}*/

g.clearRect(0, 0, 1100, 800);
draw(x1,y1,x1+100,y1,count,angle);
count++;

}

public void draw(double x1,double y1,double x2,double y2, int n,double angle){


//退出递归的条件
if(n<=0)
return;

g.setColor(new Color(139, 0, 255));
double L = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
double a = getAngle(x1,y1,x2,y2);
double x3 = x1 + Math.cos(a - Math.PI/2)*L;
double y3 = y1 + Math.sin(a - Math.PI/2)*L;
double x4 = x1 + Math.cos(a - Math.PI/4)*L*Math.sqrt(2);
double y4 = y1 + Math.sin(a - Math.PI/4)*L*Math.sqrt(2);
g.drawLine((int)x1, (int)y1, (int)x2, (int)y2);
g.drawLine((int)x2, (int)y2, (int)x4, (int)y4);
g.drawLine((int)x4, (int)y4, (int)x3, (int)y3);
g.drawLine((int)x3, (int)y3, (int)x1, (int)y1);


a = getAngle(x3, y3, x4, y4);
double sanx = x3 + Math.cos(a - angle)*L*Math.cos(angle);
double sany = y3 + Math.sin(a - angle)*L*Math.cos(angle);
g.drawLine((int)x3, (int)y3, (int)sanx, (int)sany);
g.drawLine((int)sanx, (int)sany, (int)x4, (int)y4);


draw(x3,y3,sanx,sany,n-1,angle);
draw(sanx,sany,x4,y4,n-1,angle);
}

public double getAngle(double x1,double y1,double x2,double y2){
//定义逆时针为负角度
double a=0.0;
if(x1 == x2){//说明两点在同一竖线
if(y1 > y2)
a = Math.PI*3/2;
else if(y1 < y2)
a = Math.PI/2;
}else{
double temp_angle = Math.atan((y2 - y1)/(x2 - x1));
if(x2 > x1){//说明x2在左边
a = temp_angle;
}else if(x2 < x1){//说明x2在右边
a = temp_angle + Math.PI;
}
}
return a;
}

}

上面的注释段是想通过改变三角形的角度从而使得树生长的方向改变,然后用循环来做出左右摇摆的感觉,但是好像用法太简单,导致在摆的过程中一直闪,期待学到新知识解决这个问题!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值