• fullscreen
  • Link.pde
  • OrganizingParticles.pde
  • Particle.pde
  • class Link
    {
      Particle p0;
      Particle p1;
      Link(Particle p0, Particle p1)
      {
        this.p0 = p0;
        this.p1 = p1;
      }
    
      void Draw(PGraphics pg)
      {
        float dx = p0.x - p1.x;
        float dy = p0.y - p1.y;
        float d = sqrt(dx*dx+dy*dy);
        if(d < (p0.r_view + p1.r_view) * 0.5)
        {
          pg.line(p0.x, p0.y, p1.x, p1.y);
        }
      }
    }
    
    
    import controlP5.*;
    
    ArrayList ps;
    ArrayList ls;
    PGraphics pg, pgA;
    
    ControlP5 controlP5;
    int ui_pane_width = 200;
    
    public boolean no_bg = true;
    public boolean pause = false;
    public boolean show_trail = true;
    public boolean show_brush = true;
    
    public boolean isBounded = true;
    public boolean isPeriodicBound = false;
    public boolean repulse_hard = true;
    public boolean repulse_bouncy = true;
    public boolean show_ptcls = true;
    public boolean show_vector = false;
    public boolean show_network = false;
    public boolean show_reff = false;
    public boolean show_rview = false;
    
    public int ptcl_count = 100;
    public int attractable_count = 10;
    public int max_speed = 50;
    public int dimming = 0;
    
    public int min_reff = 8;
    public int max_reff = 10;
    public float view_range = 5;
    public float breathe_scale = 0.15;
    
    public int Red, Green, Blue, Alpha;
    
    Particle selectedPtcl = null;
    
    void setup()
    {
      pg = createGraphics(400, 400, P2D);
      pg.background(255, 255, 255);
    
      pgA = createGraphics(pg.width, pg.height, P2D);
      pgA.background(255, 255, 255);
    
      size(pg.width + ui_pane_width, pg.height, P2D);
      background(255, 255, 255);
    
      Red = 255;
      Alpha = 255;
    
      InitUI();
      InitParticleSystem();  
    }
    
    void InitUI()
    {
      int ui_x = 10;
      int ui_y = 8;
      int ui_y_step = 10;
      int ui_y_space = 5;
      controlP5 = new ControlP5(this);
    
      controlP5.addToggle("pause",pause,ui_x + 90,ui_y,10,10);
      controlP5.addSlider("dimming",0,50,dimming,ui_x + 90,ui_y + 29,40,10);
      Radio r_bg = controlP5.addRadio("radio_bg",ui_x,ui_y);
      r_bg.add("no bg",0);
      r_bg.add("draw trail",1);
      r_bg.add("paint brush",2);
      r_bg.activate("no bg");
      ui_y += ui_y_step + ui_y_space + 40;
    
      controlP5.addToggle("show_ptcls",show_ptcls,ui_x,ui_y,10,10);
      controlP5.addToggle("show_vector",show_vector,ui_x + 90,ui_y,10,10);
      ui_y += ui_y_step + ui_y_space + 10;
      controlP5.addSlider("Alpha",0,255,Alpha,ui_x,ui_y,128,10);
      ui_y += ui_y_step + 10;
      controlP5.addToggle("show_reff",show_reff,ui_x,ui_y,10,10);
      controlP5.addToggle("show_rview",show_rview,ui_x + 90,ui_y,10,10);
      ui_y += ui_y_step + ui_y_space + 10;
      controlP5.addSlider("view_range",1,20,view_range,ui_x,ui_y,90,10);
      ui_y += ui_y_step + ui_y_space;
      controlP5.addSlider("breathe_scale",0,2,breathe_scale,ui_x,ui_y,90,10);
      ui_y += ui_y_step + ui_y_space;
      controlP5.addToggle("show_network",show_network,ui_x,ui_y,10,10);
      ui_y += ui_y_step + ui_y_space + 20;
    
      Radio r_bound = controlP5.addRadio("radio_bound",ui_x,ui_y);
      r_bound.add("no bound",0);
      r_bound.add("bound",1);
      r_bound.add("periodic bound",2);
      r_bound.activate("bound");
      ui_y += ui_y_step + ui_y_space + 30;
    
      controlP5.addSlider("max_speed",10,100,max_speed,ui_x,ui_y,90,10);
      ui_y += ui_y_step + ui_y_space;
      controlP5.addSlider("attractable_count",0,100,attractable_count,ui_x,ui_y,90,10);
      ui_y += ui_y_step + ui_y_space;
      controlP5.addToggle("repulse_hard",repulse_hard,ui_x,ui_y,10,10);
      controlP5.addToggle("repulse_bouncy",repulse_hard,ui_x + 90, ui_y,10,10);
      ui_y += ui_y_step + ui_y_space + 28;
    
      controlP5.addSlider("ptcl_count",0,200,ptcl_count,ui_x,ui_y,100,10);
      ui_y += ui_y_step + ui_y_space;
      controlP5.addSlider("min_reff",3,50,min_reff,ui_x,ui_y,90,10);
      ui_y += ui_y_step + ui_y_space;
      controlP5.addSlider("max_reff",3,50,max_reff,ui_x,ui_y,90,10);
      ui_y += ui_y_step + ui_y_space;
    
      controlP5.addSlider("Red",0,255,Red,ui_x,ui_y,128,10);
      ui_y += ui_y_step + 1;
      controlP5.addSlider("Green",0,255,Green,ui_x,ui_y,128,10);
      ui_y += ui_y_step + 1;
      controlP5.addSlider("Blue",0,255,Blue,ui_x,ui_y,128,10);
      ui_y += ui_y_step + 1;
    }
    
    void InitParticleSystem()
    {
      ps = new ArrayList();
      ls = new ArrayList();
      for(int i = 0; i < ptcl_count; i++)
      {
        AddNewPtcl();
      }
    }
    
    void AddNewPtcl()
    {
      Particle ptcl = new Particle();
      ptcl.SetPosition(random(width), random(height));
      ptcl.vx = random(-max_speed, max_speed);
      ptcl.vy = random(-max_speed, max_speed);
      ptcl.r_eff = random(min_reff, max_reff);
      ptcl.cR = Red;
      ptcl.cG = Green;
      ptcl.cB = Blue;
      ps.add(ptcl);
    }
    
    void draw()
    {
      background(255, 255, 255);
      noStroke();
      fill(64, 64, 64);
      rect(0, 0, ui_pane_width, height);
      stroke(100, 100, 100);
      line(0, 305, ui_pane_width - 1, 305);
    
      pgA.beginDraw();
      pgA.smooth();
      if(!pause)
      {
        if(no_bg)
        {
          pgA.background(255, 255, 255, 0);
        }
        if(dimming > 0)
        {
          pgA.noStroke();
          pgA.fill(0, 0, 0, dimming);
          pgA.rect(0, 0, pgA.width, pgA.height);
        }
        DrawA(pgA); 
      }
      pgA.endDraw();
    
      pg.beginDraw();
      pg.smooth();
      pg.background(255, 255, 255, 0);
      pg.stroke(0, 0, 0);
      if(!pause)
      {
        Update();
      }
      pg.noStroke();
      pg.image(pgA, 0, 0);
      Draw(pg); 
      pg.endDraw();
      
      image(pg, ui_pane_width, 0);
      
      if(ps.size() < ptcl_count)
      {
        AddNewPtcl();
      }
      if(ps.size() > ptcl_count)
      {
        ps.remove(0);
      }
    
      stroke(0, 0, 0);
      noFill();
      rect(0, 0, width-1, height-1);
      controlP5.draw();
    
      SelectingPtcl();
    }
    
    void Update()
    {
      ls.clear();
      pg.noFill();
      pg.stroke(0 ,0, 0);
      for(int i = 0; i < ps.size(); i++)
      {
        Particle ptcl = (Particle)ps.get(i);
        ptcl.Update();
      }
    }
    
    void Draw(PGraphics pg)
    {
      pg.noFill();
    
      if(show_reff)
      {
        for(int i = 0; i < ps.size(); i++)
        {
          Particle ptcl = (Particle)ps.get(i);
          ptcl.DrawReff(pg);
        }
      }
    
      if(show_rview)
      {
        for(int i = 0; i < ps.size(); i++)
        {
          Particle ptcl = (Particle)ps.get(i);
          ptcl.DrawRview(pg);
        }
      }
    
      if(show_network)
      {
        pg.stroke(0, 0, 0, 64);
        for(int i = 0; i < ls.size(); i++)
        {
          Link li = (Link)ls.get(i);
          li.Draw(pg);
        }
      }
    
      if(show_ptcls)
      {
        pg.noStroke();
        for(int i = 0; i < ps.size(); i++)
        {
          Particle ptcl = (Particle)ps.get(i);
          ptcl.Draw(pg);
        }
      }
    
      if(show_vector)
      {
        pg.stroke(255, 255, 255);
        for(int i = 0; i < ps.size(); i++)
        {
          Particle ptcl = (Particle)ps.get(i);
          ptcl.DrawV(pg);
        }
      }
    }
    
    void DrawA(PGraphics pg)
    {
      if(show_trail)
      {
        for(int i = 0; i < ps.size(); i++)
        {
          Particle ptcl = (Particle)ps.get(i);
          ptcl.DrawTrail(pg);
        }
      }
    
      if(show_brush)
      {
        pg.noStroke();
        for(int i = 0; i < ps.size(); i++)
        {
          Particle ptcl = (Particle)ps.get(i);
          ptcl.Draw(pg);
        }
      }
    }
    
    void radio_bound(int theID) {
      switch(theID) {
        case(0):
        isBounded = false;   
        break;  
        case(1):
        isBounded = true;
        isPeriodicBound = false;
        break;  
        case(2):
        isBounded = true;
        isPeriodicBound = true;
        break;
      }
    }
    
    void radio_bg(int theID) {
      switch(theID) {
        case(0):
        no_bg = true;
        show_trail = false;
        show_brush = false;   
        break;  
        case(1):
        no_bg = false;
        show_trail = true;
        show_brush = false;
        break;  
        case(2):
        no_bg = false;
        show_trail = false;
        show_brush = true;
        break;
      }
    }
    
    void mousePressed()
    {
      for(int i = 0; i < ps.size(); i++)
      {
        Particle ptcl = (Particle)ps.get(i);
        if(ptcl.PointInside(mouseX - ui_pane_width, mouseY))
        {
          selectedPtcl = ptcl;
        }
      }
    }
    
    void mouseReleased()
    {
      selectedPtcl = null;
    }
    
    void SelectingPtcl()
    {
      if(selectedPtcl != null)
      {
        selectedPtcl.x = mouseX - ui_pane_width;
        selectedPtcl.y = mouseY;
        selectedPtcl.cR = Red;
        selectedPtcl.cG = Green;
        selectedPtcl.cB = Blue;
        selectedPtcl.r_eff = (min_reff + max_reff) * 0.5;
        selectedPtcl.Update();
      }
    }
    
    
    
    class Particle
    {
      float x, y;
      float old_x, old_y;
      float vx, vy;
      float u_vx, u_vy;
      float speed;
      float r_eff, R_eff, r_visual, r_view;
      float r_breathe = 0;
      float dt;
      float cR, cG, cB, cD;
      int attractedCount = 0;
    
      float phase = random(PI * 2);
      float pace = random(0.01, 0.1);
    
      float repulsive_factor = 10;
    
      Particle()
      {
        dt = 0.05;
        cD = random(-64, 64);
      }
    
      void SetPosition(float x, float y)
      {
        this.x = x;
        this.y = y;
        old_x = x;
        old_y = y;
      }
    
      void Update()
      {
        r_breathe = (sin(frameCount * pace + phase) + 1) * r_eff * breathe_scale;
        R_eff = r_eff + r_breathe;
        r_view = R_eff * view_range;
        speed = sqrt(vx * vx + vy * vy);
        if(speed > 0)
        {
          u_vx = vx / speed;
          u_vy = vy / speed;
          if(speed > max_speed) speed = max_speed;
          vx = speed * u_vx;
          vy = speed * u_vy;
        }
        old_x = x;
        old_y = y;
        x += vx * dt;
        y += vy * dt;
    
        Interact();
    
        if(isBounded)
        {
          if(isPeriodicBound)
          {
            PeriodicBound();
          }
          else
          {
            Bound();
          }
        }
      }
    
      boolean PointInside(float px, float py)
      {
        float dx = px - x;
        float dy = py - y;
        float d2 = dx*dx + dy*dy;
        if(d2 < r_visual * r_visual)
        {
          return true;
        }
        return false;
      }
    
      void Interact()
      {
        attractedCount = 0;
        for(int i = 0; i < ps.size(); i++)
        {
          Particle other = (Particle)ps.get(i);
          if(this != other)
          {
            float dx = x - other.x;
            float dy = y - other.y;
            float d = sqrt(dx*dx + dy*dy);
            if(d > 0)
            {
              float u_fx = dx / d;
              float u_fy = dy / d;
              if(attractedCount < attractable_count)
              {
                Attract(other, d, u_fx, u_fy);
              }
              Repulse(other, d, u_fx, u_fy);
            }
          }
        }
      }
    
    
    
      void Repulse(Particle other, float d, float u_fx, float u_fy)
      {
        float R = R_eff + other.R_eff;
        if(d < R)
        {
          float power = (R - d) * 0.5;
    
          if(repulse_hard)
          {
            if(this != selectedPtcl)
            {
              x += u_fx * power;
              y += u_fy * power;
            }
            if(other != selectedPtcl)
            {
              other.x += -u_fx * power;
              other.y += -u_fy * power;
            }
          }
          if(repulse_bouncy)
          {
            vx += u_fx * power * repulsive_factor;
            vy += u_fy * power * repulsive_factor;
            other.vx += -u_fx * power * repulsive_factor;
            other.vy += -u_fy * power * repulsive_factor;
          }
        }  
      }
    
      void Attract(Particle other, float d, float u_fx, float u_fy)
      {
        if(d > R_eff && d < r_view)
        {
          float f = (d - R_eff) / (r_view - R_eff);
          float power = cos(f * PI * 0.5) * 2;
          vx += -u_fx * power;
          vy += -u_fy * power;
          if(show_network)
          {
            if(d < r_view)
            {
              int i0 = ps.indexOf(this);
              int i1 = ps.indexOf(other);
              if(i0 < i1)
              {
                Link li = new Link(this, other);
                if(!ls.contains(li)) ls.add(li);
              }
              else
              {
                Link li = new Link(other, this);
                if(!ls.contains(li)) ls.add(li);
              }
            }
          }
          attractedCount++;
        }   
      }
    
      void Bound()
      {
        if(x < r_eff || x > pg.width-r_eff) vx *= -1.1;
        if(y < r_eff || y > pg.height-r_eff) vy *= -1.1;
        x = constrain(x, r_eff, pg.width-r_eff);
        y = constrain(y, r_eff, pg.height-r_eff);
      }
    
      void PeriodicBound()
      {
        float r_eff2 = r_eff * 2;
        if(x < -r_eff2) x = pg.width + r_eff;
        else if(x > pg.width + r_eff2) x = -r_eff;
        if(y < -r_eff2) y = pg.height + r_eff;
        else if(y > pg.height + r_eff2) y = -r_eff;
      }
    
      void Draw(PGraphics pg)
      {
        pg.fill(cR + cD, cG + cD, cB + cD, Alpha);
        r_visual = R_eff - 5;
        pg.ellipse(x, y, r_visual * 2, r_visual * 2);
      }
    
      void DrawV(PGraphics pg)
      {
        float r = r_visual - 2;
        pg.line(x, y, x + r* u_vx, y + r * u_vy);
      }
    
      void DrawTrail(PGraphics pg)
      {
        float dx = old_x - x;
        float dy = old_y - y;
        float d = sqrt(dx*dx+dy*dy);
        if(d < max_speed)
        {
          float gr = (cR + cG + cB) / 3;
          pg.stroke(gr, gr, gr, 128);
          pg.line(old_x, old_y, x, y);
        }
      }
    
      void DrawReff(PGraphics pg)
      {
        pg.stroke(0, 255, 0, 255);
        pg.ellipse(x, y, R_eff * 2, R_eff * 2); 
      }
    
      void DrawRview(PGraphics pg)
      {
        pg.stroke(0, 0, 255, 255);
        pg.ellipse(x, y, r_view * 2, r_view * 2); 
      }
    }
    
    
    
    
    
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement

    Report Sketch

    Report for inappropriate content

    Please provide details if possible:

    Your have successfully reported the sketch. Thank you very much for helping to keep OpenProcessing clean and tidy :)

    Make a Copyright Infringement claim

    Seung Joon Choi

    Organizing Particles

    Add to Faves Me Likey@! 54
    You must login/register to add this sketch to your favorites.

    self organizing particles with simple rules. i'd like to illustrate the fact that a similar phenomenon occurs in an organization with people under interaction among them.

    this applet also can be used as an interesting painting application.

    you can check out some example images here.
    http://picasaweb.google.com/erucipe/OrganizingParticles#

    and you can check out an extension of this applet 'Organizing Critters' here.
    http://www.openprocessing.org/visuals/?visualID=6691

    gendou
    25 Dec 2009
    Very cool!
    Very nice piece of work, thank you...
    ramin
    7 Apr 2010
    very cool. i like it how for some parameter settings vortex appear (selforganization creating unstable order) and other particles join or dissolve it
    bejoscha
    30 Jul 2010
    Great. I absolutly love self-organizing networks and particlles. It is so much fun to toy with those things.
    QinYue
    27 Apr 2013
    good job
    You need to login/register to comment.