不知不觉到了毕业季,回顾10多年前在海外的大学生活,感觉即特别又辛酸。这几天翻了一下大学期间完成的一个非常有意思的模拟植物生长的小软件,进行分享,给即将步入大学的众多IT行业的学子加油。

一. L-系统原理介绍

L-系统是匈牙利生物学家Aristid LinderMayer于1968年提出的。L-系统的本质是一个重写系统,通过对植物对象生长过程的经验式概括和抽象,初始状态与描述规则,进行有限次迭代,生成字符发展序列以表现植物的拓扑结构,并对产生的字符串进行几何解释,就能生成非常复杂的分形图形。

具体例子如下:雪花曲线

v:{F,+, - }

w:F

p:F->F-F++F-F

几何解释是:

F:向前画一条线

+:右转67.5度(++即为右转135度)

-:左转45度

具体信息见下图,当迭代次数n=3时就可以得出很好的雪花形状。

二. 案例结果展示

本案例是在2005年圣诞节期间开发,采用Java开发语言,底层代码完全自己编写,未引用任何第三方包。

先展示一下系统的结果:

案例一:

规则:

如左图所示,

  • Angle: 角度,案例中为45度
  • Axiom: 初始公式, 案例中为f
  • Line length: 线条单位长度
  • Speed: 生长速度, 案例中为线条的生成速度
  • Rules: F和f的单位是一样的, 在这里, F在每次迭代后替换为FF, f 替换为F[-f]+f。中括号这里表示额外的分枝.

结果展示:

一次迭代

三次迭代

十次迭代


案例二

规则:

结果展示:

一次迭代

三次迭代

六次迭代

案例三

规则:

结果展示如下:

一次迭代 三次迭代 七次迭代

案例四

规则:

结果展示如下:

一次迭代

三次迭代

四次迭代

案例五

规则:

结果展示如下:

一次迭代

三次迭代

五次迭代

案例6

规则:

结果展示如下:

一次迭代

三次迭代

七次迭代

三. 系统界面

这里把系统界面再介绍一下,截屏如下:

界面左侧是绘图区域.

右侧在上一章节的规则部分有截图,除去已经截图的,其他部分说明如下:

  • Map Value  –  选择初始公式以及规则
  • Times          –  迭代次数
  • Color           –  选择绘制的图案颜色

四. 原始代码:

一共五个类文件:

  • Gui.java              –  主界面
  • DrawPanel.java  –  图案绘制
  • LRules.java         –  定义公式以及规则
  • Point.java           –  点对象
  • Start.java            –  启动类

下面贴出LRules.java, DrawPanel.java, 以及Point.java的原始代码,感兴趣的可以拿来使用,并且自己定义自己喜欢的风格的界面,进一步的扩充里面的规则案例.

LRules.java

import java.awt.Color;

import java.awt.Graphics;

import java.awt.Graphics2D;

import java.awt.geom.Line2D;

import java.util.Stack;

publicclass LRules {

public String combineLine(intiteration, String axioms, String rule1, String rule2)

{

String products="";

String product = axioms;

for (intn = 0; n < iteration; n++) {

products="";

for (inti = 0; i < product.length(); i++) {

charcurrent = product.charAt(i);

charcheck1 = rule1.charAt(0);

charcheck2 = rule2.charAt(0);

if (current == check1) {

products = products.concat(rule1.substring(2,rule1.length()));

}

elseif (current == check2){

products = products.concat(rule2.substring(2,rule2.length()));

}

else {

products = products.concat(String.valueOf(current));

}

}

product = products;

}

returnproducts;

}

public Stack<Point> getStack(String products,floatangle)

{

Stack<Point> st = new Stack<Point>();

inti = 0;

floatang = 90;

booleanoutbraket[] = newboolean[20];

intcount = 0;

floatangleSign[] = newfloat[20];

for (intloop = 0; loop < products.length(); loop++)

{

charletter = products.charAt(loop);

switch (letter)

{

case'F':

Point p = new Point();

if (i==0)

{

p.setStartX(400);

p.setStartY(650);

p.setAngle(90);

}

p.setAngle(ang);

st.push(p);

break;

case'f':

Point p1 = new Point();

if (i==0)

{

p1.setStartX(400);

p1.setStartY(300);

p1.setAngle(90);

}

p1.setAngle(ang);

st.push(p1);

break;

case'+':

ang = ang - angle;

break;

case'-':

ang = ang + angle;

break;

case'[':

angleSign[count] = ang;

count++;

break;

case']':

outbraket[count] = true;

count--;

ang = angleSign[count];

break;

default:

break;

}

i++;

}

returnst;

}

publicvoid  drawPic( Graphics g,Color blockColor, floatlineLength, floatangel,String sproducts,Stack<Point> points){

floatxStartPos, yStartPos, xEndPos, yEndPos;

intcount = 0;

Graphics2D g2d = (Graphics2D) g;

Point node[] = new Point[20];

intcount1 = 0;

for (intloop = 0; loop < sproducts.length(); loop++)

{

charletter = sproducts.charAt(loop);

switch (letter)

{

case'F':

Point p = (Point) points.get(count);

xStartPos = p.getStartX();

yStartPos = p.getStartY();

xEndPos = (float)(p.getStartX()+(

lineLength*Math.cos(p.getAngle()*Math.PI/180)));

yEndPos = (float) (p.getStartY()-(

lineLength*Math.sin(p.getAngle()*Math.PI/180)));

g2d.setColor(blockColor);

Line2D.Float path= new Line2D.Float(xStartPos,yStartPos,xEndPos,yEndPos);

g2d.draw(path);

if(count < points.size()-1)

{

((Point) points.get(count+1)).setStartX(xEndPos);

((Point) points.get(count+1)).setStartY(yEndPos);

}

count++;

break;

case'f':

Point p1 = (Point) points.get(count);

xStartPos = p1.getStartX();

yStartPos = p1.getStartY();

xEndPos = (float)(p1.getStartX()+(

lineLength*Math.cos(p1.getAngle()*Math.PI/180)));

yEndPos = (float) (p1.getStartY()-(

lineLength*Math.sin(p1.getAngle()*Math.PI/180)));

g2d.setColor(blockColor);

Line2D.Float path1= new Line2D.Float(xStartPos,yStartPos,xEndPos,yEndPos);

g2d.draw(path1);

if(count < points.size()-1)

{

((Point) points.get(count+1)).setStartX(xEndPos);

((Point) points.get(count+1)).setStartY(yEndPos);

}

count++;

break;

case'+':

break;

case'-':

break;

case'[':

node[count1] = (Point) points.get(count);

count1++;

break;

case']':

if(count<points.size())

{

Point p4 = (Point) points.get(count);

p4.setStartX(node[count1-1].getStartX());

p4.setStartY(node[count1-1].getStartY());

}

count1--;

break;

default :

break;

}

}

}

}

DrawPanel.java

import java.awt.Color;

import java.awt.Graphics;

import java.awt.Image;

import java.awt.Polygon;

import java.awt.geom.Point2D;

import java.util.Stack;

import javax.swing.JPanel;

publicclass DrawPanel extends JPanel {

publicfinalintWIDTH = 800;

publicfinalintHEIGHT = 800;

publicfinalintWIDTH_ADJUST = 60;

publicfinalintHEIGHT_ADJUST = 40;

publicfinaldoubleSTARTDRAWLEAF = 9999;

publicfinaldoubleENDDRAWLEAF = 99999;

publicfinalintSTART_LEFT = 0;

publicfinalintSTART_MIDDLE = 1;

public Point2D srcPoint = new Point2D.Double(0,0);

private Point2D srcPoint1 = new Point2D.Double(0,0);

public Point2D destPoint = new Point2D.Double(0,0);

publicintwidth;

private Polygon leafPoly;

privatebooleandrawLeaf = false;

privatebooleanleafCoord = false;

private Thread mainThread = null;

private Color blockColor;

privateinttimes;

privateintlength;

privatefloatangle;

privateintspeed;

private String axiom;

private String rule1;

private String rule2;

private Image im;

public Graphics offscreen;

floatlb,rb,ub,db;

// record all rectangular blocks

publiclongmySeed = System.currentTimeMillis();

publicvoid startDrawing(Color blockColor, inttimes, intlength,floatangle, intspeed, String axioms,String rule1,String rule2){

this.blockColor = blockColor;

this.times = times;

this.length = length;

this.angle = angle;

this.speed = speed;

this.axiom = axioms;

this.rule1 = rule1;

this.rule2 = rule2;

width = WIDTH;

if (mainThread == null){

mainThread = new Thread(new RunnableObject());

mainThread.start();

}

}

publicvoid stop(){

offscreen = null;

repaint();

pause();

}

publicvoid pause(){

if(mainThread != null){

mainThread.stop();

mainThread = null;

}

}

privateclass RunnableObject implements Runnable{

publicvoid run(){

inti = 0;

intj = 0;

intk = 0;

intl = 0;

intsrcX, srcY, destX, destY, srcX1, srcY1;

if (mainThread != null){

/*

if (leafCoord){

srcX = (int)srcPoint.getX() + width/2;// - WIDTH_ADJUST;

srcY = HEIGHT - (int)srcPoint.getY();// - HEIGHT_ADJUST;

leafPoly.addPoint(srcX, srcY);

}

else{

if (drawLeaf){

destX = (int)destPoint.getX() + width/2;// - WIDTH_ADJUST;

destY = HEIGHT - (int)srcPoint.getY();// - HEIGHT_ADJUST;

leafPoly.addPoint(destX, destY);

}

*/

repaint();

try

{

mainThread.sleep(speed);

}

catch (InterruptedException e)

{

e.printStackTrace();

}

//}

}

}

}

publicvoid paint(Graphics g)

{

if (offscreen == null)

{

im = createImage(WIDTH, HEIGHT);

offscreen = im.getGraphics();

offscreen.setColor(Color.white);

offscreen.fillRect(0,0,WIDTH,HEIGHT);

}

else

{

LRules lr = new LRules();

String axioms = lr.combineLine(times,axiom,rule1,rule2);

Stack<Point> st = lr.getStack(axioms,angle);

lr.drawPic(offscreen,blockColor, length, angle, axioms,st);

}

g.drawImage(im,0,0,this);

}

publicvoid update(Graphics g)

{

paint(g);

}

publicvoid setSpeed(intspeed)

{

this.speed = speed;

}

}

Point.java

publicclass Point {

privatefloatstartX;

privatefloatstartY;

privatefloatangle;

publicfloat getStartX()

{

returnstartX;

}

publicfloat getStartY()

{

returnstartY;

}

publicfloat getAngle()

{

returnangle;

}

publicvoid setStartX(floatstartX)

{

this.startX = startX;

}

publicvoid setStartY(floatstartY)

{

this.startY = startY;

}

publicvoid setAngle(floatangle)

{

this.angle = angle;

}

}

因为时间较早,编码中有一些东西目前已经不建议使用,例如线程用stop方法强制关闭。同时因为大学期间编码能力有限,加上当时是自己在圣诞节的一周假期额外抽时间来开发的,所以代码注释都未加,敬请见谅。不过多看几遍应该也能够明白其中的逻辑。感兴趣的可以关注微信公众号: 智能化IT系统, 进一步的沟通交流.

最后祝愿IT学子大学生活一帆风顺, 未来前程似锦.

L系统(L-System)模拟植物生长(java实现)相关推荐

  1. Android L系统mtk平台下AAL自动背光调整服务亮度曲线调试需要涉及的地方

    Android L系统mtk平台下AAL自动背光调整服务亮度曲线调试需要涉及的地方 如果你想修改MTK的AAL自动背光调整相关的内容,那么根据情况,可能需要涉及如下文件: 这是Android L版本的 ...

  2. 计算机图形学(七):三维对象的表示(分形图形的基本性质、递归模型、L系统模型)

    目录 分形图形的概念 分形图形的基本性质 分形图形的定义 分形维数的定义 分形图形的递归模型 分形图形的L系统模型 分形图形的概念 几何建模方法 - 百度文库 真实的世界并不规则,闪电不是直线,海岸线 ...

  3. ProE复杂曲线方程:Python Matplotlib 版本代码(L系统,吸引子和分形)

    对生长自动机的研究由来已久,并在计算机科学等众多学科中,使用元胞自动机的概念,用于生长模拟.而复杂花纹的生成,则可以通过重写一定的生长规则,使用生成式来模拟自然纹理.当然,很多纹理是由人本身设计的,其 ...

  4. Android L系统 剖析安卓5.0安卓L新特性

    Android L系统全新发布了!在Google I/O 2014上,Google正式发布了最新一代安卓系统Android L,安卓系统终于告别了安卓4.×,迈入了全新的版本周期.新一代安卓系统此前一 ...

  5. (15.1.14)Google正式发布Android L系统 剖析安卓5.0安卓L新特性

    Material Design.卡片.环动式设计 ART.64位计算 升级.电池续航.安全 Android L系统全新发布了!在Google I/O 2014上,Google正式发布了最新一代安卓系统 ...

  6. 计算机图形学L系统生成树的简单解释

    L系统的主要应用是植物建模,相对来说也是比较成功的一个应用.对于L系统必须要遵循以下法则: 语法规则:根据语法规则对所给字符进行迭代生成新字符串,每次迭代结果称为一代 字符解释:将字符串中的字符解释为 ...

  7. [分形学] 基于 L 系统绘制 Hilbert (希尔伯特) 曲线

    德国数学家 David Hilbert 发现了这样一种可以填满整个单位正方形的分形曲线,称它为 Hilbert 曲线.具体的我就不多做介绍了,相关内容请自己搜索.这里只说程序. 程序执行后,按数字键 ...

  8. Android平台上使用属性系统(property system)

    在使用Android的属性系统(property system)时遇到了一些问题,结合此次经历,对属性系统的使用做以简单介绍. 一.Property系统简介 属性系统是android的一个重要特性.它 ...

  9. 十八、泛型 l 注解 l Servlet3.0 l 动态代理 l 类加载器基础加强

    l 泛型 l 注解 l Servlet3.0 l 动态代理 l 类加载器 泛型 1 回顾泛型类 泛型类:具有一个或多个泛型变量的类被称之为泛型类. public class A<T> { ...

最新文章

  1. -gMIS持续优化更新, +InSiteSearch站内搜索
  2. RabbitMq 详解
  3. Python-OpenCV 杂项(二): 鼠标事件
  4. 湖北师范大学c语言考试题目,湖北师范学院2010期末C语言试卷.doc
  5. Go语言很好很强大,但我有几个问题想吐槽
  6. php中怎样表示组合框,php – 如何实现动态组合框选择系统
  7. mfc怎么获取进程的线程数_Python多线程获取小米应用商店App,看看我是怎么做到的
  8. Android RecyclerView(九)滑动监听综述
  9. 被指抄袭后 新浪微博APP绿洲更换Logo 重新上架
  10. select case when与IF的用法
  11. unix网络编程之基本套接口编程
  12. Linux学习整理-终端快捷键(常用)
  13. PreparedStatement 执行sql
  14. 有哪些曾惊艳到你了的古诗词?1024程序员读古诗词
  15. linux文件最大访问数,测试Linux最大打开文件数参数
  16. Arduino +合宙ESP32C3 +1.8/1.44 寸TFT液晶屏驱动显示
  17. 华为路由器DHCP服务设置(一)
  18. va_start函数的使用
  19. 面试进行曲之技术面试(项目经验)
  20. 服务器的操作系统和数据库关系,数据库、数据库管理系统和SQL之间的关系

热门文章

  1. post上传图片获取不到值
  2. 计算机毕业设计 SSM在线音乐网站设计与实现(源码+论文)
  3. 5.1.3 电压基准源TL431
  4. 华为EC122在HiSi3110E上移植
  5. TortoiseGit工具 修改登录用户名密码
  6. Ubuntu中的PPA源
  7. 六安市高考成绩查询入口2021,六安高考成绩查询入口
  8. newInstance过时
  9. 利用matlab对滤波器频率特性分析
  10. 微信小程序居家养老+后台管理系统