简单的说就是部分与整体以某种方式相似的形体,具有三个特性
1. 自相似性,部分是整体的缩影,2.自仿射性:局部到整体是在不同方向上的不等比例
3.精细结构,即在任意小的比例尺度包含整体
以下是编的一个分形树效果:
如果加入随机变化的颜色,就可以做成礼花效果图:
上图中的参数,没大多奥秘,其含义如下图所示,单元长度即AC,树枝伸展角度即W(程序中用A),主干生长角度即Theta(程序中用B表示),但测试结果好像树枝生长角度没多大意义,只是控制在屏幕中的旋转角度而已,分支长度系数即BE、BD、CG或者CF这四条相等线段与AC的比,主干长度系数即下一生长单元的长度与当前生长单元长度AC的比值。
下面是程序代码:class="java" name="code">
package FractalTree;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.plaf.SliderUI;
public class Test {
//用于存放文本框中字符串
//分别对应于"单元长度","树枝伸展角度","主干生长角度","分支长度系数","顶点长度系数"的值
private JTextField [] jtf=new JTextField[5];
//给对应文本框内容赋初值
private String [] jtf_str= new String[]{"120","35","15","0.6","0.4"};
JRadioButton jrb1;//选中礼花效果的单选框
JRadioButton jrb2;//选中长大效果的单选框
private boolean flag=false;//是否进入效果标志
Mylistener my;//监听器对象
Graphics g;//中间面板的画布对象
JPanel centerpal;//中间面板对象
private Random random=new Random();//新建随机数类
public static void main(String [] args){
Test test=new Test();
test.initUI();
}
//初始化界面
public void initUI(){
//新建窗体,并赋属性
JFrame jf = new JFrame();
jf.setSize(700,600);
jf.setTitle("分形树");
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(3);
jf.setResizable(false);
//创建东边面板用于参数设置,中间面板画图
centerpal=new JPanel(){
// Graphics g;
public void paint(Graphics g){
super.paint(g);
int length=0;
float a=0,b=0,z=0,c=0;//定义树枝伸展角度,主干生长角度,树枝长度系数,顶点长度系数
//将文本框的内容取出
for(int i=0;i<jtf_str.length;i++){
jtf_str[i]=jtf[i].getText();
}
//各文本框的内容转换为对应数值
a=Integer.parseInt(jtf_str[1]);
b=Integer.parseInt(jtf_str[2]);
a=(float) (a*Math.PI/180);
b=(float) (b*Math.PI/180);
length=Integer.parseInt(jtf_str[0]);
z=Float.parseFloat(jtf_str[3]);
c=Float.parseFloat(jtf_str[4]);
// if(jrb2.isSelected()){
// //选中长大效果
// if(!flag){
// flag=true;
// z=z/10;
// c=c/10;
// length=50+(length-50)/10;
// for(int i=0;i<10;i++){
// z=z+z*i;
// c=c+c*i;
// length=50+(length-50)/10*(i+1);
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// this.draw(250, 600, length,a,b,z,c,g);
// this.repaint();
// }
// }
// }
//this.draw(300, 600, 120,35*Math.PI/180, 5*Math.PI/180,0.6,0.4,g);
this.draw(250, 600, length,a,b,z,c,g);
//如果礼花效果被选中
if(jrb1.isSelected()){
for(int i=0;i<10;i++){
//休眠200ms
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//重绘
this.repaint();
}
}
}
//画生长单元的递归方法
public void draw(int X,int Y,int LEN,double A,double B,double Z,double C,Graphics g){
int len=0,x=0,y=0,x1=0,y1=0,x1l=0,y1l=0,x1r=0,y1r=0,x2=0,y2=0,x2l=0,y2l=0,x2r=0,y2r=0;
if(LEN>7){
len=(int)(LEN*Z);//获得树枝长度
//获得B点(x1,y1)坐标
x1=(int)(X+len*Math.sin(B));
y1=(int)(Y-len*Math.cos(B));
//获得B点(x1,y1)左右分支点坐标
x1l=x1+(int)(len*Math.sin(B-A));
y1l=y1-(int)(len*Math.cos(B-A));
x1r=x1+(int)(len*Math.sin(B+A));
y1r=y1-(int)(len*Math.cos(B+A));
//获得C点(x2,y2)坐标
x2=(int)(X+LEN*Math.sin(B));
y2=(int)(Y-LEN*Math.cos(B));
//获得C点(x2,y2)左右分支点坐标
x2l=x2+(int)(len*Math.sin(B-A));
y2l=y2-(int)(len*Math.cos(B-A));
x2r=x2+(int)(len*Math.sin(B+A));
y2r=y2-(int)(len*Math.cos(B+A));
//如果礼花效果选中,颜色为随机
if(jrb1.isSelected()){
g.setColor(new Color(random.nextInt(256), random.nextInt(256),random.nextInt(256)));
}
//否则,颜色固定为绿色
else {
g.setColor(Color.green);
}
g.drawLine(X, Y, x2, y2);//主干线
//B点(x1,y1)坐标处的两条分支
g.drawLine(x1, y1, x1l, y1l);
g.drawLine(x1, y1, x1r, y1r);
//C点(x2,y2)坐标处的两条分支
g.drawLine(x2, y2, x2l, y2l);
g.drawLine(x2, y2, x2r, y2r);
//递归
this.draw(x2, y2, (int)(LEN*C), A, B+B, Z, C,g);
this.draw(x1l, y1l, len, A, B-A, Z, C,g);
this.draw(x1r, y1r, len, A, B+A, Z, C,g);
this.draw(x2l, y2l, len, A, B-A, Z, C,g);
this.draw(x2r, y2r, len, A, B+A, Z, C,g);
}
}
};
//中间面板背景颜色
centerpal.setBackground(new Color(0,0,0));
//创建监听器,传入中间面板
my=new Mylistener(centerpal);
//创建东边面板
JPanel eastpal=this.creat_eastpal();
jf.add(eastpal,BorderLayout.EAST);
jf.add(centerpal,BorderLayout.CENTER);
jf.setVisible(true);//窗体可见
}
//创建东边面板方法
public JPanel creat_eastpal(){
JPanel eastpal=new JPanel();
eastpal.setPreferredSize(new Dimension(100,0));
eastpal.setBackground(new Color(222,222,222));
eastpal.setLayout(null);
//5个标签和5个文本框
String [] str_lab=new String[]{"单元长度:","树枝伸展角度:","主干生长角度:","分支长度系数:","顶点长度系数:"};
for(int i=0;i<str_lab.length;i++){
JLabel lab=new JLabel(str_lab[i]);
lab.setBounds(5, 30+50*i, 90, 20);
//每个标签下对应的文本框存入数组,方便取数
jtf[i]= new JTextField();
jtf[i].setBounds(5, 55+50*i, 90, 25);
jtf[i].setText(jtf_str[i]);
eastpal.add(lab);
eastpal.add(jtf[i]);
}
//创建单选框,选中为礼花效果,并加入东边面板中
//jcb=new JCheckBox("礼花效果");
jrb1=new JRadioButton("礼花效果");
jrb1.setBounds(5, 310, 90, 30);
jrb1.addActionListener(my);
eastpal.add(jrb1);
//创建单选框,选中为长大效果,并加入东边面板中
//jcb=new JCheckBox("长大效果");
jrb2=new JRadioButton("长大效果");
jrb2.setBounds(5, 360, 90, 30);
//jrb2.addActionListener(my);
eastpal.add(jrb2);
//确定按钮,开始绘制
JButton jb=new JButton("确定");
jb.setBounds(15, 420, 70, 30);
jb.addActionListener(my);
eastpal.add(jb);
return eastpal;
}
}
另外一个按钮监听器类:
package FractalTree;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
public class Mylistener implements ActionListener{
private JPanel panel;
public Mylistener (JPanel panel){
this.panel=panel;
}
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("确定")){
panel.repaint();
}
}
}
很遗憾,长大效果还没做出来,有待研究。
- 大小: 56.8 KB
- 大小: 139.8 KB
- 大小: 30.1 KB