如果昨天的递归分形算法画出的图案好象不那么有技术含量,那么今天的LS文法构图算法就很有档次了!CQ今天弄出了这个东西后也是非常激动啊!
好东西啊!要和大家分享!哈哈!
首先来介绍一下LS文法,这是在美国生物学家Axxx Lxxx (名字太长,不好记!不过感谢他的发明!哈哈!) 发明的一种文法描述方法: graftal上逐渐发展起来的形式语言的一个重要分支.后来人们称之为L-system.
讲了些没有实际作用的历史,现在就进入正题!
LS文法是一类独特的迭代过程,他的核心思想就是重写.作为一种形式话的语言,LS文法用字母表和符号串来表达生成对象的初始形式,称为公理.然后根据一组产生式重写规则,将初始的每个字符依次替换为新的字符形式,反复进行,直到最后生成图形.
在二维平面上,LS是这样工作的!
首先讲符号:
F: 以当前方向前进,画线
f: 以当前方向前进,不画线
+:逆时针旋转 alpha 度
-:顺时针旋转 alpha 度
[:当前信息压栈
]:将上一个[处存的信息出栈
我们来看koch曲线的LS文法生成(不知道koch曲线吗!网上找找资料吧!分形入门的时候本来要贴的,忘记了!哈哈!)
w: F (初始的形态: 一条直线段)
alpha 60 (变化的角度)
P: F-> F – F + + F – F (变化规则: 把一条直线段变成四个小直线段)
然后再进行LS文法生成:
Step 1 : F
Step 2 : F – F + + F – F
Step3 : F – F + + F – F –F – F + + F – F + + F – F + + F – F –F – F + + F – F
Setp4: …
就这样依次无限循环下去就得到了koch曲线的文法
文法有什么用呢?
当然有用,根据得到的这个文法串,我们就可以画图了!
根据这个规则来:
F: 以当前方向前进,画线
f: 以当前方向前进,不画线
+:逆时针旋转 alpha 度
-:顺时针旋转 alpha 度
[:当前信息压栈
]:将上一个[处存的信息出栈
我们可以写一个while+switch语句配合来很轻松的实现对文法串的分析:
贴个例子:假设要对一个picString进行分析就可以用以下代码实现
// 对picString进行分析,根据字符串指示信息画图
int length = picString.length();
for (int offset = 0; offset < length; offset++) {
switch (picString.charAt(offset)) {
case 'F':
forwardLine();
break;
case 'f':
forwardWithOutLine();
break;
case '+':
antiRotate(alpha);
break;
case '-':
rotate(alpha);
break;
case '[':
saveState();
break;
case ']':
loadState();
break;
}
}
下面给出我今天的成果哦!
先贴运行效果:
第二张:
还没有染色,不过如果理解了算法的话很轻松就可以染色了!
如果把rule再变换,还可以出现更多的图形!
下面就把代码贴出:
(开源积极分子J)
package fractalPanels;
/**
* 用LS 文法生成的树
* 支持单一规则
*/
import java.awt.Point;
import java.util.Stack;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
public class TreePanel extends FractalPanel {
//树的很多形态
/**
* F[-F]F[+F]F 25 向上
* FF+[+F-F-F]-[-F+F+F] 20 蓬松
* F[+F]F[-F+F] 25度 刺
*/
private int alpha;
private String rule;
private int time;
private String picString;
private int currentAngle = 90; // 当前绘图方向
private Stack<State> s = new Stack<State>();
private Point currentPoint = new Point(300,500); // 当前画笔在的点
private int length;
// 字符串参数带F
public TreePanel(String rule, int alpha, int time, int length) {
this.rule = rule;
this.alpha = alpha;
this.time = time;
this.length = length;
this.picString = rule;
initPic();
}
private void initPic() {
for (int i = 0; i < time; i++) {
LS();
}
}
// 根据规则生成字符串
private void LS() {
picString = picString.replaceAll("F", rule);
}
public void draw() {
//初始化
currentAngle = 90;
s = new Stack<State>();
currentPoint = new Point(300, 650);
// 对picString进行分析,根据字符串指示信息画图
int length = picString.length();
for (int offset = 0; offset < length; offset++) {
switch (picString.charAt(offset)) {
case 'F':
forwardLine();
break;
case 'f':
forwardWithOutLine();
break;
case '+':
antiRotate(alpha);
break;
case '-':
rotate(alpha);
break;
case '[':
saveState();
break;
case ']':
loadState();
break;
}
}
}
/***************************************************************************
* 画图辅助函数 坐标系说明: (0,0)为左上角的点,angle是以水平向右为0度
**************************************************************************/
/**
* 根据递归层数向前画线
*/
private void forwardLine() {
Graphics g = getGraphics();
int x = currentPoint.x;
int y = currentPoint.y;
int endX = (int)(x + length*Math.cos(currentAngle/180.0 * Math.PI));
int endY = (int)(y - length*Math.sin(currentAngle/180.0 * Math.PI));
g.drawLine(x,y,endX,endY);
currentPoint.setLocation(endX,endY);
}
/**
* 根据递归层树前进不画线
*/
private void forwardWithOutLine() {
int endX = (int)(currentPoint.x + length*Math.cos(currentAngle/180.0 * Math.PI));
int endY = (int)(currentPoint.y - length*Math.sin(currentAngle/180.0 * Math.PI));
currentPoint.setLocation(endX,endY);
}
/**
* 顺时针旋转
*
* @param rotateAngle
* 旋转角度
*/
private void rotate(int rotateAngle) {
currentAngle -= rotateAngle;
}
/**
* 逆时针旋转
*
* @param rotateAngle
* 旋转角度
*/
private void antiRotate(int rotateAngle) {
currentAngle += rotateAngle;
}
private void saveState() {
// State state = new State(currentPoint, currentAngle);
Point p = new Point();
p.setLocation(currentPoint.x,currentPoint.y);
State state = new State(p,currentAngle);
s.push(state);
}
private void loadState() {
State state = s.pop();
currentPoint = state.position;
currentAngle = state.angle;
}
/**
* javaBean 存放当前画笔信息
*/
private class State {
int angle;
Point position;
State(Point currentPoint, int angle) {
position = currentPoint;
this.angle = angle;
}
}
}