给我一个点,我能画出整个世界!这正是分形的魅力所在。
今天我们不说什么很枯燥的内容,我们先来看神奇的色子。
题目这样说:
1.平面上随机选A,B,C三个点。再随机选一个点,记为P。
2.有一个三面色子,每丢一次,则选中ABC三个中一点。
开始游戏:
1.重复丢色子,如果选中A,则取A和P的中点P1,画黑。
2.如果选中B,则取B和P1的中点P2,画黑。
3.如果选中A,则取A和P2的中点P3,画黑。
4.一直重复,如每点一下鼠标,丢100次色子。
这个游戏看似有点规律,但是当你画出图片时会发生非常奇妙的东西!
public class DrawDice extends JPanel {
private Random r = new Random();// 创建随机数对象
private int len = 5;// 设置点数为3
private int x[] = new int[len];// 存x的数组
private int y[] = new int[len];// 存y的数组
private int tx = r.nextInt(600);// 随机获取第一个点的x坐标
private int ty = r.nextInt(600);// 随机获取第一个点的y坐标
public static void main(String[] args) {
DrawDice dd = new DrawDice();
dd.initUI();
}
public void initUI() {
JFrame jf = new JFrame();// 创建窗体对象
jf.setSize(new Dimension(600, 600));// 设置窗体大小
jf.setDefaultCloseOperation(3);// 设置关闭按钮
jf.setResizable(false);// 设置不可调节
jf.setLocationRelativeTo(null);// 设置窗体局中
jf.setVisible(true);// 设置窗体可见
this.setBackground(Color.WHITE);// 设置背景颜色
jf.add(this, BorderLayout.CENTER);// 将面板添加到窗体中部
for (int i = 0; i < len; i++)// 随机获取坐标
{
x[i] = r.nextInt(600);
y[i] = r.nextInt(600);
}
}
/**
* 重写paint方法
*/
public void paint(Graphics g) {
super.paint(g);// 调用父类方法
drawpoint(g);// 重绘点
}
/**
* 画点的方法
*
* @param g图形对象
*/
public void drawpoint(Graphics g) {
int p = 100000;// 画10W个点
while (p-- != 0) // 通过while进行循环
{
int t = r.nextInt(len);// 获取随机数
g.drawLine((x[t] + tx) / 2, (y[t] + ty) / 2, (x[t] + tx) / 2,
(y[t] + ty) / 2);// 连接画线
tx = (x[t] + tx) / 2;// 得到新x坐标
ty = (y[t] + ty) / 2;// 得到新y坐标
}
}
}
当我们选取5个点时,会发现更加奇妙的东西!
下面我们来介绍迭代实现分形。
所谓迭代,就是给你一个公式,然后反复把上一次的运算结果变成下一次自变量。
其实就是相当于一个数列,我们通过计算得到数据,然后将这些数据以点的形式画出来,
然后再通过放大移动将其移到屏幕中间,就可以画出非常美丽的图片啦~~
/**
* 画第一个分形图形
*
* @param g图像对象
*/
public void drawfractal1(Graphics g) {
int large = 150;// 设置放大倍数
int x0 = 350;// 设置初始x点
int y0 = 330;// 设置初始y点
double x = 0, y = 0, xt, yt;// 设置临时变量存储每一次计算出来的点
double a = -2, b = -2, c = -1.2, d = 2;// 设置参数
for (int i = 0; i < num; i++) // 循环画点
{
// g.setColor(new Color(0.1f, 0.2f, 0.3f,0.5f));
g.setColor(Color.white);// 设置点为白色
xt = (Math.sin(a * y) - Math.cos(b * x));// 计算下一个迭代点
yt = (Math.sin(c * x) - Math.cos(d * y));// 计算下一个迭代点
g.drawLine(x0 + (int) (large * xt), y0 + (int) (large * yt), x0
+ (int) (large * xt), y0 + (int) (large * yt));// 画点
x = xt;// 将新点存入
y = yt;// 将新点存入
}
}
/**
* 画第二个分形图形
*
* @param g图像对象
*/
public void drawfractal2(Graphics g) {
int large = 40;// 设置放大倍数
int x0 = 350;// 设置初始x点
int y0 = 300;// 设置初始y点
double a = 1.40, b = 1.56, c = 1.40, d = -6.56;// 设置参数
double x = 0, y = 0, xt, yt;// 设置临时变量存储每一次计算出来的点
for (int i = 0; i < num; i++) // 循环画点
{
g.setColor(Color.white);// 设置点为白色
xt = d * Math.sin(a * x) - Math.sin(b * y);// 计算下一个迭代点
yt = c * Math.cos(a * x) + Math.cos(b * y);// 计算下一个迭代点
g.drawLine(x0 + (int) (large * xt), y0 + (int) (large * yt), x0
+ (int) (large * xt), y0 + (int) (large * yt));// 画点
x = xt;// 将新点存入
y = yt;// 将新点存入
}
}
/**
* 画第三个分形图形
*
* @param g图形对象
*/
public void drawfractal3(Graphics g) {
int large = 75;// 设置放大倍数
int x0 = 350;// 设置初始x点
int y0 = 300;// 设置初始y点
double a = 0.4, b = 1, c = 0;// 设置参数
double x = 0, y = 0, xt, yt;// 设置临时变量存储每一次计算出来的点
for (int i = 0; i < 10 * num; i++) // 循环画点
{
g.setColor(Color.blue);// 设置点为白色
xt = y - Math.signum(x) * Math.sqrt(Math.abs(b * x - c));// 计算下一个迭代点
yt = a - x;// 计算下一个迭代点
g.drawLine(x0 + (int) (large * xt), y0 + (int) (large * yt), x0
+ (int) (large * xt), y0 + (int) (large * yt));// 画点
x = xt;// 将新点存入
y = yt;// 将新点存入
}
}
/**
* 画第四个分形图形
*
* @param g图形对象
*/
public void drawfractal4(Graphics g) {
double large = 1.5;// 设置放大倍数
int x0 = 350;// 设置初始x点
int y0 = 300;// 设置初始y点
double a = 1, b = 4, c = 60;// 设置参数
double x = 20, y = 20, xt, yt;// 设置临时变量存储每一次计算出来的点
for (int i = 0; i < num; i++) // 循环画点
{
g.setColor(Color.white);// 设置点为白色
xt = y - Math.signum(x) * Math.sqrt(Math.abs(b * x - c));// 计算下一个迭代点
yt = a - x;// 计算下一个迭代点
g.drawLine(x0 + (int) (large * xt), y0 + (int) (large * yt), x0
+ (int) (large * xt), y0 + (int) (large * yt));// 画点
x = xt;// 将新点存入
y = yt;// 将新点存入
}
}
private int num = 100000;
让我们来欣赏一下美丽的图片吧~