基于processing实现
目录
效果演示
DLA(Diffusion Limited Aggrefation)介绍
通过使用化学和物理领域的物理过程模型生可以成许多迷人的图像和类似生命的结构。举个例子,扩散限制聚集或DLA,其特别描述了电解溶液中锌离子在电极上的扩散和聚集。“扩散”是由于形成结构的颗粒在将自身(“聚集”)依附到结构之前随机漫游。“扩散限制”是因为这些颗粒被认为是低浓度的,所以它们不会相互接触,而结构一次只生长一个颗粒,而不是大块颗粒地生长。自然界中有很多这样的例子,如:珊瑚生长、雷电的路径、灰尘或烟雾颗粒的聚结、以及一些晶体的生长。也许对此类过程,第一次认真研究的是Witten,T.A. 和Sander,L.M。他们并于1981年发表文章,题为“扩散限制聚集,动力学关键现象”,在Physical Review Letters. number 47。
另一种更有意思的描述则涉及到一个被小酒馆包围的城市广场。醉酒者离开酒馆,在广场上游荡,直到他们终于找到了一个没有意义的同伴,在那时候,他们躺下睡着了,传来平静的打鼾声。卷状结构是早晨睡觉人群的鸟瞰图。
这里有许多用计算机模拟这个过程的方法,也许最常见的就是从白色画布开始,除了中心的单个黑色像素。在边界上引入新的点,使其随机游走(类似于布朗运动),直到它们接近到足以粘附到现有的黑色像素上。图中就是一个典型的例子。如果一个点在其随机游走期间抵达图像的边界,则有两种策略。该点无论从边缘或图像发射都是环形结合的(从左边缘移动的点进入右边,从右边缘移动的点进入左边,顶部和底部与之类似)。 一般来说,新的点可以种植在图像区域的任何地方,而不仅仅是在边界周围,两者没有明显的视觉差异。
Figure 1. Point attractor
另一种吸引子几何图形是一条线,见上图。在这种情况下,最下面的像素行最初是黑色的,新的点从顶部进入。图像通常是水平圆周,也就是说,从左侧出发的点出现在右边,反之亦然。
Figure 2. Line attractor
图中展示了盒状吸引子,新的点进入内部(图像的中心)。常见的有效措施是在当前结构的规定范围内启动新的粒子,如果它们移动到其他范围之外就移除它们。
Figure 3. Rectangle attractor
我们有许多添加颜色的方法,上图具有圆形的种子区域(环形边界),且颗粒按照其引入的顺序着色。
Processing实现
随机游走类Walker
我们可以对真实系统建模,用一个随机过程来近似一个(受牛顿力学控制的)确定的过程,建模的要求是这两个过程具有相同的平均行为。这里的“确定的过程"指的是上述庞大的牛顿方程组的确定解。具体来说,我们把每个粒子不断受撞击而产生的复杂轨迹建模成一个“随机游走"过程,就像深夜一个醉汉在马路上晃悠一样,没有别人推搡,自己在那乱走;而且我们假设这种粒子的随机“乱走"在行为表现上等效于真实的不断受到撞击的走法。
随机生成的游走对象必须限制在界面范围内,由randomPoint函数进行限定,也可以指定游走对象的位置。也同时作为面向对象编程,其随机游走、显示于设置颜色功能也封装在内。
class Walker {
PVector pos;
boolean stuck;
float r;
float hu;
Walker() {
pos = randomPoint();
stuck = false;
r = radius;
}
Walker(float x, float y) {
pos = new PVector(x, y);
stuck = true;
r = radius;
}
void walk() {
PVector vel = PVector.random2D();
// PVector vel = createVector(random(-1, 1), random(-0.5, 1));
pos.add(vel);
pos.x = constrain(pos.x, 0, width);
pos.y = constrain(pos.y, 0, height);
}
void setHue(float hu_) {
hu = hu_;
}
void show() {
noStroke();
if (stuck) {
fill(hu, 100, 100, 200);
} else {
fill(360, 0, 100);
}
ellipse(pos.x, pos.y, r * 2, r * 2);
}
...
}
PVector randomPoint() {
int i = floor(random(4));
if (i == 0) {
float x = random(width);
return new PVector(x, height/4);
} else if (i == 1) {
float x = random(width);
return new PVector(x, height*3/4);
} else if (i == 2) {
float y = random(height);
return new PVector(width/4, y);
} else {
float y = random(height);
return new PVector(width*3/4, y);
}
}
为使游走对象在于主体相碰撞后停止运动,因此需创建一个检验函数checkStuck来对所有游走对象进行检测。
class Walker {
...
boolean checkStuck(List<Walker> others) {
for (int i = 0; i < others.size(); i++) {
float d = distSq(pos, others.get(i).pos);
Walker other = others.get(i);
if (d < (r * r + other.r * other.r + 2 * other.r * r)) {
//if (random(1) < 0.1) {
stuck = true;
return true;
//break;
//}
}
}
return false;
}
}
float distSq(PVector a, PVector b) {
float dx = b.x - a.x;
float dy = b.y - a.y;
return dx * dx + dy * dy;
}
主体逻辑
初始化场景
创建一棵树tree用于存储所被捕捉到的随机游走对象,创建一个随机游走对象列表walkers用于不断更新场景。
List<Walker> tree = new ArrayList<Walker>();
List<Walker> walkers = new ArrayList<Walker>();
int maxWalkers = 150;
int iterations = 1000;
float radius = 12;
float hue = 0;
float shrink = 0.995;
void setup() {
size(600, 600);
colorMode(HSB, 360, 100, 100);
radius *= shrink;
for (int i = 0; i < maxWalkers; i++) {
walkers.add(new Walker());
radius *= shrink;
}
...
}
Point attractor
场景中初始树节点可进行自定义。
void setup() {
...
tree.add(new Walker(width / 2, height / 2));
}
Line attractor
void setup() {
...
for(int i = 0; i < int(width/radius); i++){
tree.add(new Walker(i*2*radius, height));
}
}
Rectangle attractor
void setup() {
...
for(int i = 0; i < int(width/radius); i++){
tree.add(new Walker(i*2*radius, height));
tree.add(new Walker(i*2*radius, 0));
}
for(int i = 0; i < int(height/radius); i++){
tree.add(new Walker(0, i*2*radius));
tree.add(new Walker(width, i*2*radius));
}
}
场景更新
完全按照主体逻辑中的方法进行更新。
void draw() {
background(0);
for (int i = 0; i < tree.size(); i++) {
tree.get(i).show();
}
for (int i = 0; i < walkers.size(); i++) {
walkers.get(i).show();
}
for (int n = 0; n < iterations; n++) {
for (int i = walkers.size() - 1; i >= 0; i--) {
Walker walker = walkers.get(i);
walker.walk();
if (walker.checkStuck(tree)) {
walker.setHue(hue % 360);
hue += 1;
tree.add(walker);
walkers.remove(i);
}
}
}
//float r = walkers.get(walkers.size() - 1).r;
while (walkers.size() < maxWalkers && radius > 1) {
radius *= shrink;
walkers.add(new Walker());
}
}
参考:
DLA - Diffusion Limited Aggregation论文翻译
随机系统(stochastic systems)——以随机游走为例