本文主要是介绍Processing 分形之三 —— Diffusion-Limited Aggregation,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
人类一思考,上帝就发笑。
——米兰·昆德拉 《生命中不能承受之轻》
大自然创造出瑰丽奇特的珊瑚,Witten和Sander共同提出了DLA。唐代冯延巳有诗云:“年少王孙有俊才,登高欢醉夜忘回。歌阑赏尽珊瑚树,情厚重斟琥珀杯。但愿千千岁,金菊年年秋解开。”可世人皆知珊瑚美,哪知DLA也奇妙。
Tree Corals
They look fabulous, like underwater bonsai trees that have been painted by Salvador Dali.
3D DLA
For many years now the ultimate inspiration in DLA for me has been Andy Lomas.
More Works: http://www.andylomas.com/aggregationImages.html
##8.1 Diffusion-Limited Aggregation
###8.1.1 Basic Idea
时光易逝,容颜易老?且看度娘怎么说:
首先置一初始粒子作为种子,在远离种子的任意位置随机产生一个粒子使其做无规行走,直至与种子接触,成为集团的一部分;然后再随机产生一个粒子,重复上述过程,这样就可以得到足够大的DLA团簇(cluster)。
君未尝与吾相知,亦无所怨。你该怎么看:
故事发生在一个被小酒馆包围的城市广场上。醉鬼们离开酒馆,开始在广场上游荡。直到他们终于遇到了一个没有任何意义的同伴,而在那时候,他们躺下睡着了,传来平静的打鼾声。你是否想亲眼看看第二天早晨睡觉人群的鸟瞰图?
Learn More: 我的博客 DLA - Diffusion Limited Aggregation
In a word, DLA即颗粒通过随机移动接触并粘附到现有固定颗粒而产生支化和珊瑚状的结构。
###8.1.2 Real Life Experiments
在电沉积池中加入硫酸铜溶液, you can get results like the following images:
###8.1.3 You Should Know
创始人之一Sander曾经总结过DLA 的研究意义:
- 模型用极其简单的算法抓住了广泛的自然现象的关键成分却没有明确的物理机制;
- 通过简单的运动学和动力学过程就可以产生具有标度不变性的自相似的分形结构,从而建立分形理论和实验观察之间的桥梁,在一定程度上揭示出实际体系中分形生长的机理;
- 界面具有复杂的形状和不稳定性的性质,生长过程是一个远离平衡的动力学过程,但集团的结构却有稳定且确定的分形维数。
##8.2 The Story of the Drunkards
###Story Outlines:
① 夜黑风高,在一个被小酒馆包围的城市广场上;
size(800, 800);//地点background(0);//时间
② “半斤不是酒,一斤扶墙走,斤半墙走我不走。”不知何时,冒出来一个醉鬼,躺卧在广场的中央;
sleepers.add(new Drunkard(width/2, height/2)); //广场中央的醉鬼
③ 接着,四周纷纷又走出许多醉鬼;
//四周随机冒出醉鬼
PVector randomDrunkard() {float i = random(4); //4种可能性PVector p = new PVector();float x = random(width);float y = random(height);if (i <= 1) { //顶部p = new PVector(x, 0);} else if (i <= 2) { //底部p = new PVector(x, height);} else if (i <= 3) { //右边缘 p = new PVector(0, y);} else if (i <= 4) { //左边缘 p = new PVector(width, y);}return p;}
④ 他们在广场四周游荡,毫无目的可言;
void walk() {vel = PVector.random2D(); //毫无目的地游荡pos.add(vel);//只在广场上活动pos.x = constrain(pos.x, 0, width);pos.y = constrain(pos.y, 0, height);}
⑤ 可一旦他们瞧见脚下有睡觉的人,他们自己也会情不自禁地倒下睡觉;
//是否倒下睡觉
boolean checkStuck(Drunkard dr) {float d = dist(pos.x, pos.y, dr.pos.x, dr.pos.y);if (d < sqrt(radius * dr.radius * 2 * 2)) { if (random(1) < 0.1) {return true;}}return false;}
⑥ 第二天清晨,自广场上空飞过的无人机就拍下了这戏剧性的一幕。
//显示操作
void draw() {background(0);//显示移动的醉鬼和睡觉的醉鬼 for (Drunkard m : movers) {m.show();}for (Drunkard s : sleepers) {s.show();//限制醉鬼在广场内if (s.pos.y >= height || s.pos.y <= 0 || s.pos.x >= width || s.pos.x <= 0) {limit = true;}}for (int n = 0; n < iterations; n++) {for (int i = movers.size() - 1; i > 0; i--) {Drunkard m = movers.get(i);m.walk();for (Drunkard s : sleepers) {if (s.checkStuck(m)) {m.stuck = true;sleepers.add(m); break;}}}}//醉鬼人数的增长while (movers.size() < maxDrunkards && limit == false) {movers.add(new Drunkard());}
}
###Source Code:
Let’s make up this story——
/*** The Story of the Drunkards* @微信公众号:维度模态* @author:Hewes* @date 2017/08/26*///存储移动的醉鬼和睡觉的醉鬼们
ArrayList<Drunkard> movers = new ArrayList<Drunkard>();
ArrayList<Drunkard> sleepers = new ArrayList<Drunkard>();int maxDrunkards = 500; //醉鬼的数目
int iterations = 500; //决定图形生长速度
boolean limit = false;void setup() {size(800, 800);sleepers.add(new Drunkard(width/2, height/2)); //中央的醉鬼 //初始其余的醉鬼for (int i = 0; i < maxDrunkards; i++) {movers.add(new Drunkard());}
}//显示操作
void draw() {background(0);for (Drunkard m : movers) {m.show();}for (Drunkard s : sleepers) {s.show();//限制静止醉鬼在广场内if (s.pos.y >= height || s.pos.y <= 0 || s.pos.x >= width || s.pos.x <= 0) {limit = true;}}for (int n = 0; n < iterations; n++) {for (int i = movers.size() - 1; i > 0; i--) {Drunkard m = movers.get(i);m.walk();for (Drunkard s : sleepers) {if (s.checkStuck(m)) {m.stuck = true;sleepers.add(m);movers.remove(i); break;}}}}//醉鬼人数的增长while (movers.size() < maxDrunkards && limit == false) {movers.add(new Drunkard());}
}//醉鬼类
class Drunkard {PVector pos;PVector vel;boolean stuck;int radius;//移动的醉鬼Drunkard() {pos = randomDrunkard(); //随机初始位置stuck = false; //初始状态radius = 6; //粒子半径}//睡觉的醉鬼Drunkard(int x, int y) {pos = new PVector(x, y);stuck = true;radius = 6;}//四周随机出现的醉鬼PVector randomDrunkard() {float i = random(4); //4种可能性PVector p = new PVector();float x = random(width);float y = random(height);if (i <= 1) { //顶部p = new PVector(x, 0);} else if (i <= 2) { //底部p = new PVector(x, height);} else if (i <= 3) { //右边缘 p = new PVector(0, y);} else if (i <= 4) { //左边缘 p = new PVector(width, y);}return p;}//醉鬼的移动void walk() {vel = PVector.random2D(); //随机移动速度pos.add(vel);pos.x = constrain(pos.x, 0, width);pos.y = constrain(pos.y, 0, height);}//以圆代表醉鬼void show() {noStroke();if (stuck) {fill(0, 200, 0);} else {fill(300, 100, 100);}ellipse(pos.x, pos.y, radius * 2, radius * 2);}//是否睡觉boolean checkStuck(Drunkard dr) {float d = dist(pos.x, pos.y, dr.pos.x, dr.pos.y);if (d < sqrt(radius * dr.radius * 2 * 2)) { if (random(1) < 0.1) {return true;}}return false;}
}
##8.3 Processing与DLA
以黑色像素点作为醉鬼形象:
将屏幕边缘设置为睡觉的醉鬼:
以圆周作为目标区域,从广场中央走出醉鬼:
嫌像素点太小?试试这个吧:
太单调?加点颜色:
导入Box2d:
See more, try more:
##8.4 3D DLA
分享几个DLA神级作品:
####Karsten Schmidt’s Works:
####Jason’s Works:
五花马,千金裘,呼儿将出换美酒,与尔同消万古愁。The story of the drunkards
is over, I will definitely come back!
这篇关于Processing 分形之三 —— Diffusion-Limited Aggregation的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!