最近老师叫研究分形算法,还提供了一个以前的java源码(http://pan.baidu.com/s/1qWqKe5Y)供参考。但其源码设计多线程,基于Applet但是又在main中启动,设计思路有点混乱,修改过程也是问题频出。于是打算干脆在最简单AWT组件例子上,实现其思想好了,希望可以帮到对分形算法和java小程序感兴趣的同学。
了解分形几何学的理论,从计算机图形学的角度进行植物模拟的方法主要有3种,包括:
迭代函数系统(IFS)、L-System文法和递归方法[1],
其中最为灵活实用的是LS文法。{!IFS留给学术狗去研究吧,递归方法对单个问题实现简单,但是通用性不好,(http://my.oschina.net/SnifferApache/blog/336381#OSC_h1_1)便是使用递归方法实现分形算法的例子}
我们接下来要使用LS文法来实现“一棵牛逼的树”,Lets go!
非常详尽和通俗的解释(http://my.oschina.net/SnifferApache/blog/336381#OSC_h1_2)
简单讲,就是用符号定义一些简单的动作(包括评议、旋转和辅助动作)。然后用计算机实现这些简单动作即可
F:表示在当前的位置画一条长为l的直线段。l是由用户事先任意设定的数值,表示基本线段的长度。
+:表示逆时针旋转一个角θ,θ的数值由用户事先确定;
-:表示顺时针旋转一个角θ;
[:表示暂时保存当前的画图状态
]:表示提取出保存的画图状态。 “[”和“]”要成对的出现。这样,确定了开始的坐标和方向,由上面符号组成的任意的一系列指令就能指导画图了。比如:FF+F,其中长度l=1,θ=90度角,开始坐标是2,0,开始方向角是90度,那么画出来的图就是:
其中蓝色的线条是画图指令画出的图。
开始的时候画图状态为(2,0,90),也就是说起点在2,0这个点,并且这个时候画图的方向是朝上的,
然后开始画指令F,它的意思是方向不变,往前走1个步长并且画线连接上起始的点和下一个将要移动到的点(2,1),
因此画图机器就往正上方画了一条蓝色的长度为1的线段,并且把当前的状态改为了(2,1,90)就是说坐标移动到了2,1这个点,而方向角没变还是垂直向上。
接下来画下一个F,仍然是朝上方画一个长度为1的线段。
然后是+表示画图状态的方向逆时针旋转90度,
然后这个时候的状态变为(2,2,180),就是说坐标为(2,2)方向朝左方。
然后再画一个F,就是往左画一个小线段状态改为(1,2,90),到此画图命令FF+F执行结束。
很明显,如果有上面的公式1:F->FF+F(表示F可以用FF+F来替换),那么替换指定的次数之后我们可以的到一段无限长的语句L,我们把这个L交给计算机去执行,它就会画出最后的图形。{!当然,公式1替换得到的L画出来不知道是什么鬼东西,恐怕也没什么意义,但这不是我们要关心的,我们要做的是:怎么把现有的一个有意义的公式在计算机上实现出来}
F->F[+F]F[-F]F在代码中可以用
statement=“F”;
replacement=“F[+F]F[-F]F”;
来表示。其中statement表示表达式,replacement表示替换规则。在java中用循环实现替换5次的statement应该不难吧!
现在我们假设一个实现好的画图函数paint(String statement),那直接调用paint函数就大功告成了,good,我们已经完成70%的任务了。
既然一个replacement那么简单就想到解决方案了,那如果我们有3个replacement,替换的时候随机调用其中一个replacement,这就实现了随机生成的功能。
接下来我们先实现LS文法的直接替换和随机替换的控制台输出,再实现画图功能就ok啦。
补充一点:
我们也可以使用递归思想每次替换statement的过程中调用paint来画临时的statement,最终也会完成最终的任务。
摘自源码L.java(http://pan.baidu.com/s/1qWqKe5Y);
首先约定一下变量含义
int pStartX =340; //起始点
int pStartY =20;
double direction_init =60; // 作画时的初始方向
double direction;
double lengthF =3.3; // 步距
double rotation =-3; // 给定转角
int StartDepth =7; //画图深度
int initDepth;
int ruleNumber =2; //规则数
String sStart; //公理;即所要画的字符串
String sRule[][]; //规则
通过下拉列表选择图形
int k=choice1.getSelectedIndex(); if(k==0){ //斜草 pStartX =340; pStartY =20; direction_init =60; lengthF =3.3; rotation =-3; StartDepth =7; ruleNumber =2; sStart = "G"; sRule[0][0]="G"; sRule[0][1]="GFX[+++++GFG][-----GFG]"; sRule[1][0]="X"; sRule[1][1]="F-XF"; } else if(k==1){ //三角形 pStartX =200; pStartY =50; direction_init =0; lengthF =6; rotation =-60; StartDepth =6; ruleNumber =2; sStart = "X"; sRule[0][0]="X"; sRule[0][1]="--FXF++FXF++FXF--"; sRule[1][0]="F"; sRule[1][1]="FF"; } else if(k==2){ //树伞 pStartX =200; pStartY =20; direction_init =90; lengthF =4.5; rotation =30; StartDepth =5; ruleNumber =1; sStart = "F"; sRule[0][0]="F"; sRule[0][1]="F[+F[+F][-F]F][-F[+F][-F]F]F[+F][-F]F"; } else if(k==3){ //有花蕾的植物 pStartX =200; pStartY =210; direction_init =-90; lengthF =9.5; rotation =-18; StartDepth =13; ruleNumber =4; sStart = "K"; sRule[0][0]="S"; sRule[0][1]="[+++G][---H]FFS"; sRule[1][0]="G"; sRule[1][1]="+G[-FH]F"; sRule[2][0]="H"; sRule[2][1]="-H[+FG]F"; sRule[3][0]="K"; sRule[3][1]="FSF"; } else if(k==4){ //枝 pStartX =200; pStartY =5; direction_init =90; lengthF =1.5; rotation =-25.7341; StartDepth =6; ruleNumber =1; sStart = "F"; sRule[0][0]="F"; sRule[0][1]="F[+F]F[-F]F"; //reinit(); } else if(k==5){ //星 pStartX =15; pStartY =200; direction_init =0; lengthF =4.5; rotation =-60; StartDepth =5; ruleNumber =1; sStart = "F"; sRule[0][0]="F"; sRule[0][1]="F-F++F-F"; } else if(k==6){ //蒲公英 pStartX =200; pStartY =10; direction_init =90; lengthF =0.37; rotation =30; StartDepth = 10; ruleNumber =2; sStart = "Y"; sRule[0][0]="X"; sRule[0][1]="X[-FFF][+FFF]FX"; sRule[1][0]="Y"; sRule[1][1]="YFX[+Y][-Y]"; } else if(k==7){ //灌木丛 pStartX =250; pStartY =20; direction_init =90; lengthF =3.5; rotation =-30; StartDepth =6; ruleNumber =1; sStart = "F"; sRule[0][0]="F"; sRule[0][1]="FF-[-F+F+F]+[+F-F-F]"; } else if(k==8){ //棕榈 pStartX =200; pStartY =20; direction_init =90; lengthF =5.6; rotation =-18; StartDepth =12; ruleNumber =5; sStart = "SLFFF"; sRule[0][0]="S"; sRule[0][1]="[+++H][---G]TS"; sRule[1][0]="G"; sRule[1][1]="+H[-G]L"; sRule[2][0]="H"; sRule[2][1]="-G[+H]L"; sRule[3][0]="T"; sRule[3][1]="TL"; sRule[4][0]="L"; sRule[4][1]="[-FFF][+FFF]F"; } else if(k==9){ //开花的草 pStartX =200; pStartY =10; direction_init =90; lengthF =3; rotation =-30; StartDepth = 8; ruleNumber =2; sStart = "G"; sRule[0][0]="G"; sRule[0][1]="[+FGF][-FGF]XG"; sRule[1][0]="X"; sRule[1][1]="XFX"; } else if(k==10){ //灌木丛 pStartX =370; pStartY =30; direction_init =90; lengthF =2; rotation =-1.2; StartDepth =6; ruleNumber =1; sStart = "F"; sRule[0][0]="F"; sRule[0][1]="F[+++++++++++++++++++++++++F]-F[-------------------------F]F"; } else if(k==11){ //杨柳 pStartX =170; pStartY =0; direction_init =90; lengthF =7; rotation =-22.5; StartDepth =5; ruleNumber =1; sStart = "F"; sRule[0][0]="F"; sRule[0][1]="FF+[+F-F-F]-[-F+F+F]"; } else if(k==12){ //Juliet集 pStartX =95; pStartY =250; direction_init =0; lengthF =1; rotation =90; StartDepth = 17; ruleNumber =2; sStart = "X"; sRule[0][0]="X"; sRule[0][1]="X+YF+"; sRule[1][0]="Y"; sRule[1][1]="-FX-Y"; } else if(k==13){ //砖墙 pStartX =30; pStartY =40; direction_init =0; lengthF =13; rotation =90; StartDepth = 4; ruleNumber =2; sStart = "X"; sRule[0][0]="X"; sRule[0][1]="XFYFX+F+YFXFY-F-XFYFX"; sRule[1][0]="Y"; sRule[1][1]="YFXFY-F-XFYFX+F+YFXFY"; } else if(k==14){ //砖砌X形 pStartX =80; pStartY =90; direction_init =0; lengthF =3.5; rotation =90; StartDepth =4; ruleNumber =1; sStart = "F+F+F+F"; sRule[0][0]="F"; sRule[0][1]="F+F-F-FF+F+F-F"; } else if(k==15){ //三角绕三角 pStartX =200; pStartY =10; direction_init =0; lengthF =1.7; rotation =-60; StartDepth = 6; ruleNumber =2; sStart = "X"; sRule[0][0]="X"; sRule[0][1]="--FXF++FXF++FXF--"; sRule[1][0]="F"; sRule[1][1]="FFF"; } else if(k==16){ //一笔迷宫 pStartX =50; pStartY =30; direction_init =0; lengthF =10; rotation =-90; StartDepth = 6; ruleNumber =2; sStart = "X"; sRule[0][0]="X"; sRule[0][1]="-YF+XFX+FY-"; sRule[1][0]="Y"; sRule[1][1]="+XF-YFY-FX+"; } else if(k==17){ //树 pStartX =200; pStartY =10; direction_init =90; lengthF =0.35; rotation =30; StartDepth = 10; ruleNumber =2; sStart = "X"; sRule[0][0]="X"; sRule[0][1]="F[+X]F[-X]+X"; sRule[1][0]="F"; sRule[1][1]="FF"; } else if(k==18){ //对称的树 pStartX =200; pStartY =10; direction_init =90; lengthF =0.35; rotation =30; StartDepth = 10; ruleNumber =2; sStart = "X"; sRule[0][0]="X"; sRule[0][1]="F[+X][-X]FX"; sRule[1][0]="F"; sRule[1][1]="FF"; }
{![2]中Python的实现真简洁,怪不得说“人生苦短,我用Python”}
代码中注释详细,不用多说了
package myFenxing.console; /** * @author Jason * @Corp LLC lab * @version original Console Output * @reference blog.csdn.net/michael2012zhao/article/details/1494379 */ public class randomConsoleOriginal { /**全局变量,存储表达式和替换规则*/ String statement,replacement; String sRule[][]; //规则 /**构造方法*/ public randomConsoleOriginal() { //用来随机抽取,绘制随机植物 sRule = new String [10][2]; sRule[0][0]="F"; sRule[0][1]="F[+F]F[-F]F" ; sRule[1][0]="F"; sRule[1][1]="F[+F[+F]]F[-F]"; sRule[2][0]="F"; sRule[2][1]="F+F-[-F+F-F][+F-F+F]"; } /** 我的方法-生成最终的statement*/ //1、直接替换 public String caluStatement1(int depth){ for(;depth > 0; depth--){ String newStatement=""; for(int i=0;i< statement.length();i++){ if(statement.charAt(i)== 'F') newStatement += replacement; else newStatement += statement.charAt(i); //防止字符串数组爆了,其最大长度取决于字符串在常量池中的存储大小 if(newStatement.length() >= 65534){//2^16-1=65535 return newStatement; } } statement = newStatement; } return statement; } //2、随机替换 public String caluStatement2(int depth){//三条规则随机选择 for(;depth > 0; depth--){ String newStatement=""; for(int i=0;i< statement.length();i++){ replacement= sRule[(int)(Math.random()*3)][1]; if(statement.charAt(i)== 'F') newStatement += replacement; else newStatement += statement.charAt(i); //防止字符串数组爆了 if(newStatement.length() >= 65534){//2^16-1=65535 return newStatement; } } statement = newStatement; } return statement; } ///* The End*/ /**Main method*/ public static void main(String args[]){ randomConsoleOriginal instance1= new randomConsoleOriginal(); instance1.statement = "F"; instance1.replacement = "F[+F]F[-F]F" ; System.out.println(instance1.caluStatement1(5)); System.out.println(instance1.caluStatement2(5)); } }
输出结果是这一坨:
F[+F]F[-F]F[+F[+F]F[-F]F]……
…………
①LS文法(http://my.oschina.net/SnifferApache/blog/353418)
②画图功能的实现(http://my.oschina.net/SnifferApache/blog/353426)
③窗口菜单和Button事件响应(http://my.oschina.net/SnifferApache/blog/353431)
[1]赵慧兰.基于分形几何学的植物图形计算机模拟[J].浙江师范大学学报,2007,30(3).
[2]第二月.LS文法构图算法.http://blog.csdn.net/michael2012zhao/article/details/1494379.