# Diffusion Limited Aggregation

**URL:** <https://discourse.processing.org/t/diffusion-limited-aggregation/21006>\
**Category:** Coding Questions\
**Tags:** homework\
**Created:** [May 18, 2020, 9:19am UTC](https://discourse.processing.org/t/diffusion-limited-aggregation/21006 "2020-05-18T09:19:15Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![MonkeyDLuffy](https://avatars.discourse-cdn.com/v4/letter/m/ac8455/32.png) [@MonkeyDLuffy](https://discourse.processing.org/u/MonkeyDLuffy)\
**Post date:** [May 18, 2020, 9:19am UTC](https://discourse.processing.org/t/diffusion-limited-aggregation/21006/1 "2020-05-18T09:19:15Z")

</div>

Hello, I am trying to visualize Diffusion Limited Aggregation and some of my circles are overlapping. I tried repositioning them but they still overlap. How can I fix this? My code is below:

```auto
import java.lang.Math;

ArrayList<Particle> brownianTree = new ArrayList<Particle>();
ArrayList<Particle> particles = new ArrayList<Particle>();
int initialParticles = 100; // initial number of mobile partilces on screen
int max = 600; // maximum number of particles on screen
float d = 15; // diameter of circles
float hue = 0; // hue value
int hueStart; // starting value of hue
int noOfTimes = 100; // speed indicator of particles
int maxNoOfTimes = 400; // maximum speed of particles
int minNoOfTimes = 10; //minimum speed of particles
float ratio = 1.001; // rate of decrease of circles' radii

void setup() {
  size(1280,720);
    
  brownianTree.add(new Particle(new PVector(width/2, height/2), true));
  d /= ratio;
  generatePosition();
}

void draw() {
  background(0);
 
  
  for (int i = 0; i < brownianTree.size(); i ++) {
    // change hue of particles as they are added to the list
    hue = map(i, 0, max, hueStart, 255);
    
    brownianTree.get(i).display();
  }
  for (int i = 0; i < particles.size(); i ++) {
    particles.get(i).displayParticles();
  }
  
  for (int k = 0; k < noOfTimes; k ++) { // make particle move faster
   for (int i = 0; i < particles.size(); i ++) {
      particles.get(i).move();
      if (particles.get(i).isAttached()) {
        Particle currentParticle = particles.get(i);
        brownianTree.add(currentParticle);//add particle to tree
        particles.remove(currentParticle); // remove particle from the 'particles' list
      }
    }
  }
}

// particles generated around the edge
void generatePosition() {
  
  for (int i = 0; i < initialParticles/4; i ++) {
    particles.add(new Particle(new PVector(random(width), 0), false));
    d /= ratio;
  } 
  for (int i = 0; i < initialParticles/4; i ++) {
    particles.add(new Particle(new PVector(random(width), height), false));
    d /= ratio;
  } 
  for (int i = 0; i < initialParticles/4; i ++) {
    particles.add(new Particle(new PVector(0, random(height)), false));
    d /= ratio;
  } 
  for (int i = 0; i < initialParticles/4; i ++) {
    particles.add(new Particle(new PVector(width, random(height)), false));
    d /= ratio;
  } 
} 

/*
USER INTERACTIONS
*/

void keyPressed() {
  if (key == '2') {
    
    //initialise arrays
    brownianTree = new ArrayList<Particle>();
    particles = new ArrayList<Particle>();
    
    max = 1000;
    ratio = 1.0005;
    initialParticles = 100;
    d = 15; // 'reset' value of diameter
    
    // add tree to bottom
    for (int x = 0; x < width; x += d) {
      brownianTree.add(new Particle(new PVector(x, height), true));
      d /= ratio;
    }
    
    // add particles to top
    for (int i = 0; i < initialParticles; i ++) {
      particles.add(new Particle(new PVector(random(width),0), false));
      d /= ratio;
    }
  }
    
  if (key == '3') {
      
    brownianTree = new ArrayList<Particle>();
    particles = new ArrayList<Particle>();
      
    max = 1450;
    ratio = 1.0001;
    initialParticles = 50;
    d = 15;
      
    // add circles on the boundaries of the sketch
    for (int x = 0; x < width; x += d) {
      brownianTree.add(new Particle(new PVector(x, height), true));
      d /= ratio;
    }
    for (int x = 0; x < width; x += d) {
      brownianTree.add(new Particle(new PVector(x, 0), true));
      d /= ratio;
    }
    for (int y = 0; y < width; y += d) {
      brownianTree.add(new Particle(new PVector(0, y), true));
      d /= ratio;
    }
    for (int y = 0; y < width; y += d) {
      brownianTree.add(new Particle(new PVector(width, y), true));
      d /= ratio;
    }
    for (int i = 0; i < initialParticles; i ++) {
      particles.add(new Particle(new PVector(width/2, height/2,0), false));
      d /= ratio;
    } 
  }
  
  if (key == '1') {
    
    brownianTree = new ArrayList<Particle>();
    particles = new ArrayList<Particle>();
    
    max = 600;
    ratio = 1.001;
    initialParticles = 100;
    d = 15;
    
    brownianTree.add(new Particle(new PVector(width/2, height/2), true)); 
    d /= ratio;
    generatePosition();
  }
    
  if (key == 'r') {
    hueStart = 2; // start with red circles
  }
  if (key == 'b') {
    hueStart = 170; // start with blue circles
  }
  if (key == 'g') {
    hueStart = 85; // start with green circles
  }
  
  if (key == CODED) {
    if (keyCode == UP) {
      if (noOfTimes < maxNoOfTimes) {
        noOfTimes += 10; // increase speed of particles
      }
    }
  }
  
  if (key == CODED) {
    if (keyCode == DOWN) {
      if (noOfTimes > minNoOfTimes) {
        noOfTimes -= 10; // decrease speed of particles
      }
    }
  }
}

void mousePressed() {
  int number = 5;
  
  if (mousePressed && (mouseButton == LEFT)) {
     // number of particles on screen does not exceed max
     if (particles.size() + brownianTree.size() + number <= max) {
       for (int i = 0; i < number; i ++) { //add 5 particles
         particles.add(new Particle(new PVector(mouseX, mouseY), false));
         d /= ratio;
       }
     }
  }
  if (mousePressed && (mouseButton == RIGHT)) {
    if (particles.size() > number*2) { // moving particles on screen must be at least 10
      for (int i = 0; i < number; i ++) { // remove 5 particles
        Particle current = particles.get(i);
        particles.remove(current);
        d *= ratio;
      }
    }
  }
}

class Particle {
  PVector location; 
  boolean attached;
  float size;

  // constructor
  public Particle(PVector position, boolean stuck) {
    location = position;
    attached = stuck;
    size = d;
  }
  
  // move particles around the screen
  void move() {
    PVector velocity = PVector.random2D();
    location.add(velocity);
    
    // prevent particles from leaving the sketch
    location.x = constrain(location.x, 0, width);
    location.y = constrain(location.y, 0, height);
  }
  
  // Checks whether particles are attached or not
  boolean isAttached() {
    for (int i = 0; i < brownianTree.size(); i ++) {
      Particle current = brownianTree.get(i);
      float distance = calcDistance(location.x, location.y, current.location.x, current.location.y);
      if (distance < (d/2+current.size/2)*(d/2+current.size/2)) {
        
           // reposition circles so they do not overlap
           float angle = atan2(location.y-current.location.y, location.x-current.location.x);
           println("dy is: " + (location.y - current.location.y));
           println("dx is: " + (location.x - current.location.x));
           float distanceBetween = sqrt(calcDistance(location.x,location.y,current.location.x,current.location.y));
           float distToMove = d/2+current.size/2 - distanceBetween;
           if (distToMove > 0) { // if distToMove is equal to 0, do not reposition circles
             PVector displacement = new PVector(cos(angle)*distToMove, cos(angle)*distToMove);
             location.add(displacement); 
             println("Distance to move is: " + distToMove);
             println("Distance between is: " + distanceBetween);
             println("Angle is: " + angle);
             println("Displacement is: " + cos(angle)*distToMove);
           }        
           attached = true;
           return true;
      }
    }
    return false;
  }
  
  // display tree-particles
  void display() {
    strokeWeight(0.5);
    colorMode(HSB);
    fill(hue, 255, 255);
    ellipse(location.x, location.y, size, size);
  }
  
  /* Calculates the square of the distance betweeen 2 particles.
     Also avoids using square root so program runs faster */
  float calcDistance(float a1, float b1, float a2, float b2) {
    float adj = a2 - a1;
    float opp = b2 - b1;
    float distSquared = adj*adj+opp*opp; // calculates hypotenuse*hypotenuse
    return distSquared; 
  } 
  
  // display moving particles
  void displayParticles() {
    strokeWeight(0.5);
    colorMode(RGB);
    fill(255, 255, 255);
    ellipse(location.x, location.y, size, size);
  } 
}
  
    

```

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [May 20, 2020, 5:15pm UTC](https://discourse.processing.org/t/diffusion-limited-aggregation/21006/2 "2020-05-20T17:15:55Z")

</div>

> [@MonkeyDLuffy](#):
>
> some of my circles are overlapping. I tried repositioning them but they still overlap

Do you mean your red circles in the center?

 ![Screen Shot 2020-05-20 at 10.14.03 AM](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/3/3f992e66263d9a4976e225b1d09cf911bf7494e2.png)

When you say “overlapping” are you talking about this?

![Screen Shot 2020-05-20 at 10.15.06 AM](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/d/da0b9ad7996295767c5969fe4fd357a442b24ba6.png)

---

<div class="post-metadata">

**Author:** ![MonkeyDLuffy](https://avatars.discourse-cdn.com/v4/letter/m/ac8455/32.png) [@MonkeyDLuffy](https://discourse.processing.org/u/MonkeyDLuffy)\
**Post date:** [May 20, 2020, 5:28pm UTC](https://discourse.processing.org/t/diffusion-limited-aggregation/21006/3 "2020-05-20T17:28:06Z")

</div>

Yeah. My problems is that they intersect.  
I tried to fix it with trigonometry and still have the same problem

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [May 20, 2020, 5:29pm UTC](https://discourse.processing.org/t/diffusion-limited-aggregation/21006/4 "2020-05-20T17:29:23Z")

</div>

> [@MonkeyDLuffy](#):
>
> `float distToMove = d/2+current.size/2 - distanceBetween;`

I’m not sure if it is affecting your tests, but this should be:

`float distToMove = size/2+current.size/2 - distanceBetween;`

…and I wonder whether you are seeing an artifact of small alignment changes in stroke antialiasing. When I changed to noStroke(), I got this:

 ![Screen Shot 2020-05-20 at 10.24.22 AM](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/6/6aef919dddfdfbf3156a0b52815d4fa8aeea706c.png)

You may still be getting variations of half a pixel or so, but given the way you are calculating displacement that kind of precision isn’t unexpected.

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [May 20, 2020, 5:34pm UTC](https://discourse.processing.org/t/diffusion-limited-aggregation/21006/5 "2020-05-20T17:34:30Z")

</div>

An alternate way is to simply scale the vector. This way precision isn’t an issue (or anyway, you are getting the best precision you can).

Untested pseudocode:

```auto
PVector offset = PVector(x-current.x, y-current.y).setMag(size/2 + current.size/2);

```

_(edit–make clear the variable is the offset, not the location)_

---

<div class="post-metadata">

**Author:** ![MonkeyDLuffy](https://avatars.discourse-cdn.com/v4/letter/m/ac8455/32.png) [@MonkeyDLuffy](https://discourse.processing.org/u/MonkeyDLuffy)\
**Post date:** [May 20, 2020, 5:35pm UTC](https://discourse.processing.org/t/diffusion-limited-aggregation/21006/6 "2020-05-20T17:35:40Z")

</div>

I tried changing the d/2 to size/2 but in this case the problem is the Stroke. My method isn’t 100% precise so some minor overlapping should be expected I guess.  
Thanks!

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [May 20, 2020, 5:36pm UTC](https://discourse.processing.org/t/diffusion-limited-aggregation/21006/7 "2020-05-20T17:36:36Z")

</div>

Definitely also try setMag and see if it gives you better results.

[https://processing.org/reference/PVector\_setMag\_.html](https://processing.org/reference/PVector_setMag_.html)

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [May 20, 2020, 5:45pm UTC](https://discourse.processing.org/t/diffusion-limited-aggregation/21006/8 "2020-05-20T17:45:56Z")

</div>

Here, this should help:

```auto
  // Checks whether particles are attached or not
  boolean isAttached() {
    for (int i = 0; i < brownianTree.size(); i ++) {
      Particle current = brownianTree.get(i);
      float distance = calcDistance(location.x, location.y, current.location.x, current.location.y);
      if (distance < (d/2+current.size/2)*(d/2+current.size/2)) {
        // reposition circles so they do not overlap
        PVector offset = PVector.sub(location, current.location);
        offset.setMag(size/2 + current.size/2);
        location = PVector.add(current.location, offset);
        attached = true;
        return true;
      }
    }
    return false;
  }

```

Gives:

 ![Screen Shot 2020-05-20 at 10.44.38 AM](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/0/08ab4c871e207dc512ae104dfa5c922a2bea685a.png)

---

<div class="post-metadata">

**Author:** ![MonkeyDLuffy](https://avatars.discourse-cdn.com/v4/letter/m/ac8455/32.png) [@MonkeyDLuffy](https://discourse.processing.org/u/MonkeyDLuffy)\
**Post date:** [May 20, 2020, 6:18pm UTC](https://discourse.processing.org/t/diffusion-limited-aggregation/21006/9 "2020-05-20T18:18:10Z")

</div>

> [@jeremydouglass](#):
>
> ```auto
> if (distance < (d/2+current.size/2)*(d/2+current.size/2)) {
> // reposition circles so they do not overlap
> PVector offset = PVector.sub(location, current.location);
> offset.setMag(size/2 + current.size/2);
> location = PVector.add(current.location, offset);
> attached = true;
> return true;
> 
> ```

Yeah. The circles stopped overlapping.  
Thanks a lot!
