L-system方法是生成分形的其中一种方法,它可以从简简单单的图形开始,连续的拼接,可以生成美妙的图形。我的这个L-system方法的实现呢,
是很简单的一种,通过生成字符串,来遍历字符串的每一个字母,对应的字母代表一种含义,然后可以将含义告诉计算机,让计算机遍历字符串的时
候执行字符对应动作,这样就可以了。而字符的生成过程,如图所示:
如上图就是字符生成过程,我们可以在实现过程中,可以在字符串数组中先保存一个'F',然后遍历数组,然后再取得每一个字母,对应生成其所对应的字符串,
那么就可以形成数组中的下一个元素了。
然后在自己的程序中,给每一种字符赋予一种含义,像上面就有三种字符,'F','-','+',那么我们就为这三种字符赋予它的含义,'F'代表向前面走一次,'—'代
表逆时针旋转,'+'代表顺时针旋转,等等。你可以自己为他们赋予你自己所想的任何计算机可以执行的动作,然后在后面让计算机遍历数组,得到字符,那么就
可以进行我们自己想要的创作了。如下,是我实现时的简单代码:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* L-system的实现,采用层层对的模式进行代码编写,来对实现进行层次化的进行
* @author LONG 2013-04-08
* @version 1.0
*
*/
public class LSystem extends JFrame{
private static final long serialVersionUID = 1L;
private static double PI = Math.PI; //定义常量圆周率PI
private Dimension di = null; //用来得到屏幕尺寸
private JPanel jp = null; //声明面板类型变量
private Graphics gr = null; //声明画布类型变量
private static String[] lsystem = new String[20]; //用来存储编码的字符串数组
private static int count = 0; //用来记录画了几次
private static double length = 500.0; //定义初始画的时候,应该画的长度
//以下三个参数用来调整图形形状
private static int b_1 = 2;
private static int b_2 = 2;
private static int b_3 = 2;
/**
* 程序的入口
* @param args
*/
public static void main(String[] args){
LSystem ls = new LSystem(); //创建窗体对象
lsystem[0] = "F"; //给字符数组的第一位赋值
ls.doInit(); //调用内部方法
}
/**
* 初始化生成用于绘画的面板
*/
private void doInit(){
this.setTitle("L-system的实现");
Toolkit tl = Toolkit.getDefaultToolkit();
di = tl.getScreenSize();
this.setSize(di.width*7/8,di.height*7/8);
this.setDefaultCloseOperation(3);
this.setLocation(di.width/16, di.height/16);
jp = new JPanel();
jp.setPreferredSize(new Dimension(di.width*7/8,di.height*7/8));
this.add(jp);
this.setResizable(false);
jp.setBackground(Color.BLACK);
this.setVisible(true);
gr = jp.getGraphics();
jp.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
repaint();
}
public void mouseReleased(MouseEvent e){
firstStep(e);
}
});
}
/**
* 第一步函数,进行初始化和给数组的下一位生成编码元素
*/
private void firstStep(MouseEvent e){
String goal = lsystem[count++];
String values = "";
for(int i = 0; i < goal.length(); i++){ //循环对于读取出来的字符串进行遍历
if(goal.charAt(i) == 'F'){
values = values + "F-F++F*F";
}else if(goal.charAt(i) == '-'){
values = values + "-";
}else if(goal.charAt(i) == '+'){
values = values + "+";
}else if(goal.charAt(i) == '*'){
values = values + "*";
}
}
lsystem[count] = values; //将生成的下一次会用到的字符码付给了数组的下一个位置
secondStep(goal,count - 1,e); //调用下一步的函数,进行遍历读取字符,进行绘画
}
/**
* 接受编码,和绘画的次数,来进行绘画
* @param goa 用来绘制的字符编码
* @param mu 绘画的次数
*/
private void secondStep(String goa,int mu,MouseEvent e){
double temp_length = length/(Math.pow(3.0, mu));
if(mu > 3){
temp_length = 5;
}
double x1 = e.getX();
double y1 = e.getY();
double angle = 0.0;
for(int i = 0; i < goa.length();i++){ //循环读取字符串里面的字符
char temp = goa.charAt(i);
if(temp == 'F'){ //如果为划线
double x2 = x1 + temp_length*Math.cos(angle);
double y2 = y1 + temp_length*Math.sin(angle);
gr.setColor(Color.green);
gr.drawLine((int)x1, (int)y1, (int)x2, (int)y2);
x1 = x2;
y1 = y2;
}else if(temp == '-'){ //如果是'-'号则逆时针旋转PI/3
angle -= PI/b_1;
}else if(temp == '+'){ //如果是'+'号则顺时针旋转PI/3
angle += PI/b_2;
}else if(temp == '*'){ //如果是'*'号则逆时针旋转PI/6
angle -= PI/b_3;
}
}
}
}
以上代码就是简单的实现,读者可以试着更改里面的三个参数(b_1,b_2,b_3),可以得到不同的形状。
一下是我通过更改参数所得到的的图形:
图一:
b_1 = 3
b_2 = 4
b_3 = 3
图二:
b_1 = 3
b_2 = 4
b_3 = 3
图三:
b_1 = 4
b_2 = 2
b_3 = 4
图四:
b_1 = 3
b_2 = 3
b_3 = 4
图五:
b_1 = 5
b_2 = 6
b_3 = 9
图六:
b_1 = 3
b_2 = 3
b_3 = 7