JAVA第三课——L-system分形的初次接触

首次接触分形这种东西,觉得特别有趣!为什么呢,首先说一下自己的感想,我们所熟悉的万物其实可以分成两种——有规则和没有规则。有些时候我们看的东西虽然复杂,但是仔细去寻找还是可以发现规律,只要找出它的最小组成单元就可以画出整个物体。但是有时候看似比较简单,但是没有规律可循,额(⊙o⊙)…这就尴尬了,差不多只能手动暴力模拟了吧。那么这次我们讲的分形,简单的就是找规律然后重塑物体。

比如,当我们看到下面这个图形的时候会想到什么呢?

也许会觉得很复杂,不要急,我们再看看下一张图片:

这个是不是就觉得简单点了??不急,我们再看下一张:

这个是不是更简单了???没事,还有更简单的!:

行啦!不能再简单了 !!!!!

细心的同学很快就会发现这几张图片的联系。从最后一张张图片开始,不断的迭代 ——每条边都用本图形代替就会得到第一张图片,也就是说,最后一张图片是第一张图片的最小单元。

那么问题就可以说很好办了。为什么?我们只需要做几件事情就可以了,首先想办法得到最小单元,然后得到迭代的次数,之后最终画出我们想得到的图形。那么也有新的问题,最然我们知道JAVA给我们提供了画图形的方法——画线,画圆等等,我们也可以看出上面的图形就是线条画出来的,但是怎么画呢?????不急,我们先分析一下,最小的单元就是从起点开始向左画一条线段,变向60度,再画一条线段,再变向120度,再画一条线段,再变向60,再画一条线段,这样我们就画出了最简单的图形。但是计算机是很笨的,我们必须指明每一步怎么画才行。那么我们可以利用正则表达式来解决——F-F++F-F。F表示画一条单位长度的线段,-表示以线条的方向为正方向向左偏移60度,+则相反。那么根据这个表达式我们不就可以画出最简单的图形了吗?

那怎么画第二个图形呢?刚才说了,无论多么复杂的图形都是最简单的图形迭代来的,那么我们可以把F-F++F-F中的每个F用F-F++F-F来代替,那么根据新的正则表达式得出的图形就是倒数第二个图形。好了,讲到这里估计大家就都明白了吧,那就赶快去试一下吧!

同样贴出自己的代码:

package L_System;

public class Manager 
{
	public static void main(String[] args) 
	{
		Manager mag=new Manager(); 
		mag.Draw();
	}
	
	public void Draw()
	{
		 String axiom="F-F++F-F";//母串
		 int count=3;//表示迭代的次数
		 Curve curve=new Curve(axiom,count);
		 
//		 try {
//			Thread.sleep(1000);
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
//		 
//		 curve.init();
//		 curve.draw();
//		 curve.curve();
		 curve.paint(curve.getGraphics());
	}
}

package L_System;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Curve extends JFrame{
	private String axiom;
	private String production;
	private String sequence;
	private Graphics gg;
	private int count;
	private double ra,rb;
	private Point[] points;
	
	public Curve(String axiom,int count)
	{
		this.axiom=axiom;
		this.count=count;
		production=axiom;
		this.setTitle("L-System");
		this.setSize(1000,800);
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(3);
		this.setVisible(true);
		gg = this.getGraphics();
	}
	
	public void paint(Graphics g){
		//改写重绘方法
		super.paint(g);
		init();
		draw();
	}
//	public void curve()
//	{
//		init();
//		draw();
//	}
	public void init()
	{
		//换算角度
		ra = 60*Math.PI/180;
		rb = 60*Math.PI/180;
		if(count==0)
		{
			sequence=axiom;
			return ;
		}
		sequence=axiom;
		//根据迭代次数生成新的正则表达式
		for(int i=0;i<count;i++)
		{
			StringBuffer buf = new StringBuffer();
//			System.out.println(sequence);
			for(int j = 0; j < sequence.length(); j++)
			{
				if(sequence.charAt(j) == 'F')
					buf.append(production);
				else 
					buf.append(sequence.charAt(j));
			}
			sequence = buf.toString();
		}
//		System.out.println(sequence);
	}
	
	public void draw()
	{
		int n;
		//规定单位F的长度
		double len = 10;
		//设置方向向量
		double dx = 1,dy = 0;
		//设置起点坐标
		double x0 = 20,y0 = 500;
		double min_x,max_x,min_y,max_y;
		min_x=max_x=x0;
		min_y=max_y=y0;
		
		n = 1;
		for(int i = 0; i < sequence.length(); i++)
			if(sequence.charAt(i) == 'F')	n++;
		
		points = new Point[n];
		points[0] = new Point((int)x0,(int)y0);
		int num = 1;
		for(int i = 0; i < sequence.length(); i++)
		{
			if(sequence.charAt(i) == 'F')
			{
				double x1 = x0 + len*dx;
				double y1 = y0 + len*dy;
				x0 = x1;
				y0 = y1;
				if(x0 < min_x) min_x = x0;
				if(x0 > max_x) max_x = x0;
				if(y0 < min_y) min_y = y0;
				if(y0 > max_y) max_y = y0;
				points[num++] = new Point((int)x0,(int)y0);
			}else if(sequence.charAt(i) == '+')
			{
				//改变方向向量
				double _dx = dx*Math.cos(ra)-dy*Math.sin(ra);
				double _dy = dx*Math.sin(ra)+dy*Math.cos(ra);
				dx = _dx;
				dy = _dy;
			}else if(sequence.charAt(i) == '-')
			{
				double _dx = dx*Math.cos(-rb)-dy*Math.sin(-rb);
				double _dy = dx*Math.sin(-rb)+dy*Math.cos(-rb);
				dx = _dx;
				dy = _dy;
			}
		}
	
		int x1,x2,y1,y2;
		x2 = points[0].x;
		y2 = points[0].y;
		System.out.println(num);
		for(int i = 0; i < num; i++)
		{
			x1 = points[i].x;
			y1 = points[i].y;
//			System.out.println(x1+" "+y1);
//			gg.drawLine(x2, y2, x1, y1);
			Graphics2D g2d = (Graphics2D) gg;
			g2d.setStroke(new BasicStroke(2));
			gg.drawLine(x2,y2,x1,y1);
			x2 = x1;
			y2 = y1;
		}
	}
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: L-system是一种用来描述和生成自然图形和形态的形式语言和系统。如果想基于Python绘制L-system分形图,可以通过turtle库实现。具体方法可以先定义L-system产生的字符串,再定义对应的绘制规则,最后根据规则使用turtle库绘制图形。可以参考一些已有的L-system代码进行学习和实践。 ### 回答2: L-System是一种生成分形图形的方法,是由一个初始字符串经过一些规则递归生成的字符串,被称为分形生长器。在绘制L-system分形图中,Python可以非常方便地实现这些规则,并使用matplotlib或turtle绘制结果。以下是基于Python绘制L-system分形图的详细步骤和示例代码。 1. 安装matplotlib或turtle 在Python中绘制图形,可以使用matplotlib或turtle库。这里介绍两个库,读者可以选择其中一个,或者使用其他Python绘图库。将库安装到您的计算机上,如用pip工具输入: ```python pip install matplotlib或者 pip install turtle ``` 2. 定义L-system分形生长器 定义L-system分形生长器,需要一个初始字符串、一些递归的规则和迭代次数。首先,我们可以使用字符串来描述L-system。例如,龙形曲线的初始字符串可以是FX,规则可以是: ```python X → X+YF+ Y → −FX−Y ``` 规则“X→X+YF+”表示,如果字符串中有X,则用“X+YF+”替换X;规则“Y → −FX−Y”表示,如果字符串中有Y,则用“−FX−Y”替换Y。接下来,我们可以通过一个L-system函数来扩展这个字符串,乘以规则n次迭代,如下所示: ```python def lsystem(axiom, rules, n): """ axiom: 初始生成器,应该是一个字符串 rules: 给出规则应该是一个包含多个多个元组的列表,每个元组给出两个元素。 n: 分形深度 """ system = axiom for i in range(n): new_system = "" for char in system: if char in rules: new_system += rules[char] else: new_system += char system = new_system return system ``` 这个函数将返回经过n次规则的操作后的L-System字符串。 3. 用turtle或matplotlib实现L-system分形图 接下来,我们可以使用生成好的字符串进行绘图。在这里,我们使用turtle库来绘制图形。首先,定义一个函数,它将使用给定产生器进行绘图。这个函数将逐个遍历每个字符,并根据字符绘制线条。在这里,F表示向前移动,+和-表示向右或左旋转角度。 ```python def draw_lsystem(system, angle, distance, init_pos=(0, 0)): """ 使用一定角度和距离运行L-System的结果 """ turtle.penup() turtle.goto(init_pos) turtle.pendown() turtle.setheading(0) for char in system: if char == "F" or char == "G": turtle.forward(distance) elif char == "+": turtle.right(angle) elif char == "-": turtle.left(angle) ``` 这里的角度和距离是定义绘制步长的变量,init_pos(x,y)定义canvas上绘制图像的起始位置,F或G表示向前移动,+和-表示向右或左旋转角度。 如果使用matplotlib作为绘图库,可以使用类似的函数。只需要在for循环中定义如何处理F, +和-即可。 最后,将所有代码链接起来以生成最终结果。下面是一个完整的python脚本,使用turtle来绘制Sierpinski三角形作为L-system的示例图像。 ```python import turtle def lsystem(axiom, rules, n): """ axiom: 初始生成器,应该是一个字符串 rules: 给出规则应该是一个包含多个多个元组的列表,每个元组给出两个元素。 n: 分形深度 """ system = axiom for i in range(n): new_system = "" for char in system: if char in rules: new_system += rules[char] else: new_system += char system = new_system return system def draw_lsystem(system, angle, distance, init_pos=(0, 0)): """ 使用一定角度和距离运行L-System的结果 """ turtle.penup() turtle.goto(init_pos) turtle.pendown() turtle.setheading(0) for char in system: if char == "F" or char == "G": turtle.forward(distance) elif char == "+": turtle.right(angle) elif char == "-": turtle.left(angle) if __name__ == '__main__': # 定义L-system的规则和初始字符串 rules = { "A": "+B-A-B+", "B": "-A+B+A-", } axiom = "A" iterations = 4 # 计算L-System的结果 result = lsystem(axiom, rules, iterations) # 将结果绘制到turtle画布上 turtle.speed(0) draw_lsystem(result, 60, 10) turtle.done() ``` 注:在运行turtle代码时,需要等待一段时间,直到结果绘制完成。 ### 回答3: L-system分形图是一种基于迭代的图形绘制方法,广泛应用于各个领域,包括生物学、动画设计和科学计算等等。Python是一种强大的编程语言,可以使用其内置数学库、绘图库和字符串处理库来实现L-system分形图的绘制。下面是一个描述如何在Python中绘制L-system分形图的步骤: 1. 确定L-system的规则:一个L-system包含一个初始状态和一组规则。规则将一个符号或字符序列转换为另一个符号或字符序列。例如,一个L-system规则集合可以是F->F+F--F+F,其中F表示向前绘制一条线段,+表示向左转,-表示向右转。 2. 确定迭代次数:根据规则集,将初始状态迭代多次,得到最终的绘图路径。迭代次数越多,绘图路径越复杂。 3. 将绘图路径转换为坐标点:使用数学公式将绘图路径转换为坐标点列表。通过计算每次向前移动的距离、转动角度和绘图方向等参数,可以确定每条线段的起点和终点坐标。 4. 使用绘图库绘制图像:Python中提供了多种绘图库,如Matplotlib、Turtle和Pygame等。根据需要选择合适的绘图库,并使用坐标点列表绘制图像。 在具体实现中,可以将上述步骤封装为一个函数,根据输入的规则集、迭代次数和绘图参数,自动绘制出L-system分形图。例如,下面是一个基于Pygame的实现示例: ```python import pygame def lsystem(rules, iterations, angle, line_len): state = 'F' for i in range(iterations): state = ''.join(rules.get(c, c) for c in state) x, y = 0, 0 dx, dy = 0, -1 points = [(x, y)] for c in state: if c == 'F': x2 = x + dx * line_len y2 = y + dy * line_len points.append((x2, y2)) x, y = x2, y2 elif c == '+': dx, dy = dy, -dx elif c == '-': dx, dy = -dy, dx screen = pygame.display.set_mode((800, 600)) screen.fill((255, 255, 255)) pygame.draw.lines(screen, (0, 0, 0), False, points, 1) pygame.display.flip() rules = {'F': 'F+F--F+F', '+': '+', '-': '-'} lsystem(rules, 5, 60, 10) ``` 此代码将绘制一个五次迭代的L-system分形图,每个线段长度为10个单位,转角为60度。可以根据需要调整规则、迭代次数和绘图参数,生成不同风格的分形图。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值