`
felixour
  • 浏览: 31716 次
  • 性别: Icon_minigender_1
  • 来自: 湖南
社区版块
存档分类
最新评论

L-system

    博客分类:
  • JAVA
阅读更多

也许是不小心又翻到了去年暑假的那个分形PPT,让我想起来还有一个没有完成的任务,就是L-system。

 

当时刚接触java,还是属于很年轻的,但是经过了那么久的积淀,我觉得我可以解决这个问题。

 

于是,我开始了探求L-system之旅。

 

首先我们还是来回顾一下Koch雪花,当时我们是直接用递归来解决的问题:

/**
 * 画雪花的方法
 * 
 * @param g图形对象
 * @param x1左边点的横坐标
 * @param y1左边点的纵坐标
 * @param x2右边点的横坐标
 * @param y2右边点的纵坐标
 * @param count画线的次数
 */
public void drawkoch(Graphics g, double x1, double y1, double x2,
		double y2, int count) {
	if (count <= 1) {
		g.drawLine((int) x1, (int) y1, (int) x2, (int) y2);// 画线
	} else {
		double x3 = (2 * x1 + x2) / 3;// 第一个三等份点的x坐标
		double y3 = (2 * y1 + y2) / 3;// 第一个三等份点的y坐标
		double x4 = (x1 + 2 * x2) / 3;// 第二个三等份点的x坐标
		double y4 = (y1 + 2 * y2) / 3;// 第二个三等份点的y坐标
		double k = (x1 - x2) * (y1 - y2);// 线的斜率
		double x5 = x1, y5 = y1;// 第一个三等份点的x坐标
		if (y3 == y4)// 直线
		{
			x5 = (x3 + x4) / 2;
			y5 = y3 - (x4 - x3) * Math.sqrt(3) / 2;
		} else if (k < 0)// 左斜线
		{
			x5 = x1;
			y5 = y4;
		} else if (k > 0)// 右斜线
		{
			x5 = x2;
			y5 = y3;
		}
		if (x3 == x4) // 如果斜线为竖线
		{
			x5 = x3;
			y5 = y3;
		}
		// 画尖端的左面那条线
		drawkoch(g, x3, y3, x5, y5, count - 1);
		// 画尖端的右面那条线
		drawkoch(g, x5, y5, x4, y4, count - 1);
		// 画左边那条直线
		drawkoch(g, x1, y1, x3, y3, count - 1);
		// 画右边那条直线
		drawkoch(g, x4, y4, x2, y2, count - 1);
	}
}

 

但是这一次,我们使用的并不仅仅是递归,而是用字母表和符号串来表达生成的对象的初始形式,称之为公理(axiom)。

 

现在我们可以定义如下字符规则:

F:在当前方向前进一个单位,并画线

+:逆时针旋转α角度

-:顺时针旋转α角度

 

我们再定义一个字符转换规则:F -> F-F++F-F

那么下一步将会转成:F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F

以此类推,我们取α=60度,便得到我们以前画的Koch雪花。

 

那么如果我们在每画完一条直线时,稍微附带着偏转一个角度,结果会更加的令人惊讶的!

 

public static final String strF = "F-F++F-F";// 基础字符串
private double theta = Math.PI * 60 / 180;// 偏转固定的角度
String axiom = "F-F++F-F";// "公理"字符串
double d = 50;// 单位长度
double garma = 3;// 微调时的偏转角度
double x1, y1;// 画线的初始点

/**
 * 根据字符串axiom,画出图形
 * 
 * @param axiom
 * @param g
 */
public void drawLS(String axiom, Graphics g) {
	// 把中点坐标定到屏幕正中心
	x1 = getWidth() / 2;
	y1 = getHeight() / 2;
	double x2 = x1, y2 = y1;// 用于存取下一步的位置
	double alpha = 0;// 当前所指向的角度
	// 循环遍历字符串,根据字符串所给出的提示,F表示前进一个单位,+表示逆时针旋转α,-表示顺时针旋转α
	for (int i = 0; i < axiom.length(); i++) {
		switch (axiom.charAt(i)) {
		case 'F':// 如果是F就走一部
			// 计算下一步的坐标
			x2 = x1 + d * Math.cos(alpha);
			y2 = y1 + d * Math.sin(alpha);
			// 根据坐标画线
			g.drawLine((int) x1, (int) y1, (int) x2, (int) y2);
			// x1,y1变到新的坐标点
			x1 = x2;
			y1 = y2;
			break;
		case '-':// -表示顺时针旋转α
			alpha -= theta;
			// 在两个strF中间,要进行一个小角度的偏转,使得图形偏转角度趋于混乱
			if (i < axiom.length() - 2) {
				if (axiom.charAt(i + 1) == 'F'
						&& axiom.charAt(i + 2) == '+') {
					double a = Math.PI * garma / 180;// 根据γ计算出偏转角度a
					alpha -= a;// α再逆时针旋转a
				}
			}
			break;
		case '+':// +表示逆时针旋转α
			alpha += theta;
			break;
		}
	}
}

/**
 * 字符串递归的方法
 * 
 * @param str如果是small就是变小
 *            ,如果是large就是变大
 */
public void dealAxiom(String str) {
	if (str.equals("small")) {
		if (!axiom.equals("F")) {
			axiom = axiom.replace(strF, "F");// 用"F"代替strF
		}
	}
	if (str.equals("large")) {
		axiom = axiom.replace("F", strF);// 用strF代替"F"
	}
}

 



 

 

 

 

 

学习永远没有尽头,to be continue...

  • 大小: 30.2 KB
  • 大小: 42.3 KB
  • 大小: 46.9 KB
  • 大小: 18.2 KB
  • 大小: 19.7 KB
3
3
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics