对计算机语言越熟悉越是感觉到基础部分的重要性,数理逻辑,数据结构,算法设计与分析,都是越嚼越有味道,这几天一直在看关于递归以及尽量使用递归做东西,发现越是熟悉,越是觉得递归程式的美妙,我们且跨过递归的薄弱部分不谈,就它的优点足以让我兴奋!下面是我用递归实现的两幅图片,一副是毕达哥拉斯树,就是满足毕达哥拉斯定理(勾股定理)的一个分形树,还有一颗自定义树:
毕达哥拉斯树:
以上就是毕达哥拉斯树,大家可以明显看出最底层的那三个正方形明显就是我们第一次学勾股定理时,介绍说毕达哥拉斯发现勾股定理的三块地板砖。。。。哈哈,以此类推,每个正方形如此下去便形成毕达哥拉斯树分形。
自定义树:
如上是自定义树,自定义树与毕达哥拉斯树的不同就在于刚才我们看的那三个正方形不再是30度,60度,90度了,而是形成等腰直角三角形,这个比上面的那个看起来要规整的多了吧,其实我们还可以调整角度的,我们可以加个拉杆,让其中的一个非直角改变,就会得到不一样的美妙效果了!这么美得图,你动心了吗!?
附录源代码:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
/**
* 利用递归生成毕达哥拉斯树
* @author LONG 2013-04-11
* @version 1.0
*
*/
public class BidaTree extends JFrame {
private static final long serialVersionUID = 1L;
private static final double PI = Math.PI;
private JPanel jp = null; //声明面板类型变量
private Graphics gr = null; //声明画布类型变量
private int deepth = 0; //用来记录递归画的深度
private double x_start; //定义初始点的x坐标
private double y_start; //定义初始点的y坐标
private ButtonGroup bg = null; //声明按钮组变量
private double angle_1 = PI/6;
/**
* 程序的入口
* @param args
*/
public static void main(String[] args){
BidaTree bt = new BidaTree(); //声明并创建窗体对象
bt.initUI(); //调用自身的方法初始化界面
}
/**
* 用来初始化界面的程序
*/
private void initUI(){
this.setTitle("毕达哥拉斯树");
this.setSize(1000,600);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(3);
//添加选项按钮来选择画的树的种类
JRadioButton jr_bi = new JRadioButton("毕达哥拉斯树",true);
jr_bi.setActionCommand("bi");
jr_bi.setBackground(Color.WHITE);
JRadioButton jr_zi = new JRadioButton("自定义树");
jr_zi.setActionCommand("zi");
jr_zi.setBackground(Color.WHITE);
bg = new ButtonGroup();
bg.add(jr_bi);
bg.add(jr_zi);
//添加一个重置按钮
JButton jb_reset = new JButton("重置");
jb_reset.setPreferredSize(new Dimension(70,25));
jp = new JPanel();
jp.setPreferredSize(new Dimension(1000,570));
jp.setBackground(Color.WHITE);
JPanel jp_tool = new JPanel();
jp_tool.setPreferredSize(new Dimension(1000,30));
jp_tool.setBackground(Color.WHITE);
jp_tool.add(jr_bi);
jp_tool.add(jr_zi);
jp_tool.add(jb_reset);
this.add(jp_tool,BorderLayout.NORTH);
this.add(jp,BorderLayout.SOUTH);
this.setResizable(false);
this.setVisible(true);
gr = jp.getGraphics();
//给面板添加监听器
jp.addMouseListener(new MouseAdapter(){ //为面板添加监听器
public void mousePressed(MouseEvent e){ //当鼠标按下时,刷新面板
x_start = e.getX();
y_start = e.getY();
deepth++; //每次都是先增加deepth然后才会画的,所以初始化为0
repaint();
}
public void mouseReleased(MouseEvent e){ //当鼠标松开时,执行画的动作
String values = bg.getSelection().getActionCommand();
if(values.equals("bi")){
angle_1 = PI/6;
}else if(values.equals("zi")){
angle_1 = PI/4;
}
draw(x_start,y_start,x_start + 100,y_start,deepth);
}
});
jb_reset.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
repaint();
deepth = 0;
}
});
}
/**
* 用来递归的方法画出毕达哥拉斯树的方法
* @param x 传入的x坐标
* @param y 传入的y坐标
*/
private void draw(double x1,double y1,double x2,double y2,int de){//传入正方形的两个顶点,以及递归的深度,和角度
if(de > 0){ //来判断当递归深度大于0时执行
double extent = getLength(x1,y1,x2,y2); //用来得到两点之间的距离
double angle = getAngle(x1,y1,x2,y2);
double x3 = x1 + Math.cos(angle - PI/4)*Math.sqrt(2)*extent;
double y3 = y1 + Math.sin(angle - PI/4)*Math.sqrt(2)*extent;
double x4 = x1 + Math.cos(angle - PI/2)*extent;
double y4 = y1 + Math.sin(angle - PI/2)*extent;
int[] x = {(int)x1,(int)x2,(int)x3,(int)x4};
int[] y = {(int)y1,(int)y2,(int)y3,(int)y4};
gr.fillPolygon(x, y, 4);
double temp_x = x4 + Math.cos(angle - angle_1)*Math.cos(angle_1)*extent;
double temp_y = y4 + Math.sin(angle - angle_1)*Math.cos(angle_1)*extent;
draw(x4,y4,temp_x,temp_y,de - 1);
draw(temp_x,temp_y,x3,y3,de - 1);
}
}
/**
* 用于计算两点之间的距离
* @param x0
* @param y0
* @param x2
* @param y2
* @return
*/
private double getLength(double x1,double y1,double x2,double y2){
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}
/**
* 传入两个点,得到两点连线与x轴正方向的夹角,规定逆时针为负角度,
* 且以第一个点为起始点
* @param x0
* @param y0
* @param x2
* @param y2
* @return
*/
private double getAngle(double x1,double y1,double x2,double y2){
double angle = 0.0;
if(x1 == x2){ //说明两点在同一条竖直线上
if(y1 > y2){
angle = PI*3/2;
}else if(y2 > y1){
angle = PI/2;
}
}else{ //说明两点不在同一条竖直线上
double temp_angle = Math.atan((y2 - y1)/(x2 - x1));
if(x2 > x1){ //说明x2在x0点的左边
angle = temp_angle;
}else if(x2 < x1){ //说明x2在x0的右边
angle = temp_angle + PI;
}
}
return angle;
}
}