• fullscreen
  • MeshPoint.pde
  • icosahedron.pde
  • icosahedronSketch2.pde
  • class MeshPoint {
      
      public float x;
      public float y;
      public float z;
      public float size;
      public MeshPoint direction;
      
      public MeshPoint() {
        x = 0;
        y = 0;
        z = 0;
        size = 0;
        direction = new MeshPoint( true );
      }
      
      public MeshPoint( boolean nodirection ) {
        x = 0;
        y = 0;
        z = 0;
        size = 0;
      }
      
      public MeshPoint( float x, float y, float z ) {
        this.x = x;
        this.y = y;
        this.z = z;
        size = 0;
        direction = new MeshPoint( true );
      }
      
      public void set( float x, float y, float z ) {
        this.x = x;
        this.y = y;
        this.z = z;
      }
      
      public void set( MeshPoint mp ) {
        x = mp.x;
        y = mp.y;
        z = mp.z;
      }
    
      public void plus( float x, float y, float z ) {
        this.x += x;
        this.y += y;
        this.z += z;
      }
      
      public void plus( MeshPoint mp ) {
        x += mp.x;
        y += mp.y;
        z += mp.z;
      }
      
      public void minus( float x, float y, float z ) {
        this.x -= x;
        this.y -= y;
        this.z -= z;
      }
      
      public void minus( MeshPoint mp ) {
        x -= mp.x;
        y -= mp.y;
        z -= mp.z;
      }
      
      public void multiply( float m ) {
        x *= m;
        y *= m;
        z *= m;
      }
      
      public float dist( MeshPoint mp ) {
        MeshPoint d = new MeshPoint( true );
        d.plus( mp );
        d.minus( this );
        return d.len();
      }
      
      public float len() {
        return sqrt( pow( x,2 ) + pow( y,2 ) + pow( z,2 ) );
      }
      
      public void normalise() {
        float  l = len();
        l = 1/l;
        x *= l;
        y *= l;
        z *= l;
      }
      
    }
    
    // copied and adapted from http://code.google.com/p/webgltimer/source/browse/src/net/icapsid/counter/client/Icosahedron.java?r=170e4fcc41bf20700dcb6dc67272073af112c65c
    
    import java.util.Iterator;
    import java.util.List;
    
    public class Icosahedron {
            
            /*
            public List< MeshPoint > pts = new ArrayList< MeshPoint >();
            public List< Integer[] > faces = new ArrayList< Integer[] >();
            public List< MeshPoint > faceNormals = new ArrayList< MeshPoint >();
            */
            
            public MeshPoint[] pts;
            public int[][] faces;
            public MeshPoint[] faceNormals;
            
            // public List<Float> vertexNormalsList = new ArrayList<Float>();
            // public List<Float> vertexList = new ArrayList<Float>();
            
            private final float X = 0.525731112119133606f;
            private final float Z = 0.850650808352039932f;
            private final float vdata[][] = { 
                            { -X, 0.0f, Z }, 
                            { X, 0.0f, Z },
                            { -X, 0.0f, -Z }, 
                            { X, 0.0f, -Z }, 
                            { 0.0f, Z, X },
                            { 0.0f, Z, -X }, 
                            { 0.0f, -Z, X }, 
                            { 0.0f, -Z, -X },
                            { Z, X, 0.0f }, 
                            { -Z, X, 0.0f }, 
                            { Z, -X, 0.0f },
                            { -Z, -X, 0.0f }
                          };
            private final int tindices[][] = { 
                            { 0, 4, 1 }, { 0, 9, 4 }, { 9, 5, 4 }, { 4, 5, 8 }, 
                            { 4, 8, 1 }, { 8, 10, 1 }, { 8, 3, 10 }, { 5, 3, 8 }, 
                            { 5, 2, 3 }, { 2, 7, 3 }, { 7, 10, 3 }, { 7, 6, 10 }, 
                            { 7, 11, 6 }, { 11, 0, 6 }, { 0, 1, 6 }, { 6, 1, 10 }, 
                            { 9, 0, 11 }, { 9, 11, 2 }, { 9, 2, 5 }, { 7, 2, 11 } };
            
            int divisions;
            int ptsNum;
            int ptsCurrentIndex;
            int facesNum;
            int facesCurrentIndex;
            
            public Icosahedron( int divisions ) {
              
              this.divisions = divisions;
              ptsCurrentIndex = 0;
              ptsNum = renderPtsNum();
              facesCurrentIndex = 0;
              facesNum = renderFacesNum();
              
              // println( "divisions: " + divisions + " => ptsNum: "+ptsNum +" / facesNum: "+ facesNum );
              
              pts = new MeshPoint[ ptsNum ];
              faces = new int[ facesNum ][ 3 ];
              faceNormals = new MeshPoint[ facesNum ];
              
              // Iterate over points
              for (int i = 0; i < 20; ++i) {
                  subdivide(
                    vdata[tindices[i][0]], 
                    vdata[tindices[i][1]],
                    vdata[tindices[i][2]], divisions );
              }
              renderNormals();
              
            }
            
            public int renderPtsNum() {
              int output = 12;
              int d = divisions;
              while( d > 0 ) {
                output = ( ( output - 2 ) * 4 ) + 2;
                d--;
              }
              return output;
            }
            
            public int renderFacesNum() {
              return (int) (20 * pow( 4, divisions ));
            }
            
            public void renderNormals() {
              
              float third = 1.f / 3;
              
              int i = 0;
              while ( i < facesNum ) {
                
                int[] li = faces[i];
                MeshPoint mp = faceNormals[i];
                
                mp.set( 0,0,0 );
                mp.direction.set( 0,0,0 );
                
                MeshPoint ref = pts[ li[0] ];
                mp.plus( ref.x,ref.y,ref.z );
                mp.direction.plus( ref.direction.x,ref.direction.y,ref.direction.z );
                
                ref = pts[ li[1] ];
                mp.plus( ref.x,ref.y,ref.z );
                mp.direction.plus( ref.direction.x,ref.direction.y,ref.direction.z );
                
                ref = pts[ li[2] ];
                mp.plus( ref.x,ref.y,ref.z );
                mp.direction.plus( ref.direction.x,ref.direction.y,ref.direction.z );
                
                mp.multiply( third );
                mp.direction.multiply( third );
                
                i++;
                
              }
              
            }
            
            private void norm(float v[]){
                    
                    float len = 0;
                    
                    for(int i = 0; i < 3; ++i){
                            len += v[i] *  v[i];
                    }
                    
                    len = (float) Math.sqrt(len);
                    
                    for(int i = 0; i < 3; ++i){
                            v[i] /= len;
                    }
            }
            
            private int add(float v[]){
              int found = -1;
              for ( int i = 0; i < ptsCurrentIndex; i++ ) {
                MeshPoint mp = pts[i];
                if ( mp.x == v[0] && mp.y == v[1] && mp.z == v[2] ) {
                  found = i;
                  break;
                }
              }
              if ( found == -1 ) {
                pts[ptsCurrentIndex] = new MeshPoint();
                pts[ptsCurrentIndex].set( v[0], v[1], v[2] );
                pts[ptsCurrentIndex].direction.set( v[0], v[1], v[2] );
                found = ptsCurrentIndex;
                ptsCurrentIndex++;
              }
              return found;
            }
            
            private void subdivide(float v1[], float v2[], float v3[], int depth) {
              
                    if (depth == 0) {
                            int f1 = add(v1);
                            int f2 = add(v2);
                            int f3 = add(v3);
                            faces[facesCurrentIndex] = new int[] { f1,f2,f3 };
                            faceNormals[facesCurrentIndex] = new MeshPoint();
                            facesCurrentIndex++;
                            return;
                    }
                    
                    float v12[] = new float[3];
                    float v23[] = new float[3];
                    float v31[] = new float[3];
    
                    for (int i = 0; i < 3; ++i) {
                            v12[i] = (v1[i] + v2[i]) / 2f;
                            v23[i] = (v2[i] + v3[i]) / 2f;
                            v31[i] = (v3[i] + v1[i]) / 2f;
                    }
    
                    norm(v12);
                    norm(v23);
                    norm(v31);
                                    
                    subdivide(v1, v12, v31, depth - 1);
                    subdivide(v2, v23, v12, depth - 1);
                    subdivide(v3, v31, v23, depth - 1);
                    subdivide(v12, v23, v31, depth - 1);
            }
    }
    
    float margins = 150;
    
    float biggestdist = 0;
    MeshPoint barycenter;
    MeshPoint boundaryMin;
    MeshPoint boundaryMax;
    public ArrayList < MeshPoint > refpoints;
    
    Icosahedron ico;
    float icosize = 300;
    static int ICOSUBDIVISION = 2;
    
    boolean fillbag = true;
    
    void setup() {
      size( 800,600, P3D );
      lights();
      
      barycenter = new MeshPoint( true );
      
      ico = new Icosahedron( ICOSUBDIVISION );
      
      boundaryMin = new MeshPoint( true );
      boundaryMin.set( -( (width-margins) * 0.5f ), -( (height-margins) * 0.5f ), -( (height-margins) * 0.5f ) );
      boundaryMax = new MeshPoint( true );
      boundaryMax.set( ( (width-margins) * 0.5f ), ( (height-margins) * 0.5f ), ( (height-margins) * 0.5f ) );
      
      refpoints = new ArrayList < MeshPoint >();
      for ( int i = 0; i < 20; i++ ) {
        MeshPoint mp = new MeshPoint( 
          random( boundaryMin.x, boundaryMax.x ), 
          random( boundaryMin.y, boundaryMax.y ), 
          random( boundaryMin.z, boundaryMax.z ) );
        /*
        MeshPoint mp = new MeshPoint( 
          random( boundaryMin.x, boundaryMax.x ), 
          random( boundaryMin.y, boundaryMax.y ), 
          random( boundaryMin.z, boundaryMax.z ) );
        */
        mp.size = 30 + i * 10;
        mp.direction.set( random( -1,1 ), random( -1,1 ), random( -1,1 ) );
        // mp.direction.set( random( -1,1 ), random( -1,1 ), 0 );
        mp.direction.normalise();
        mp.direction.multiply( 1.f );
        refpoints.add( mp );
      }
      
      noStroke();
      fill( 255,0,0 );
    }
    
    void update() {
      for ( int i = 0; i < refpoints.size(); i++ ) {
        MeshPoint pt = refpoints.get(i);
        pt.plus( pt.direction );
        if ( pt.x + pt.direction.x < boundaryMin.x || pt.x + pt.direction.x > boundaryMax.x )
          pt.direction.x *= -1;
        if ( pt.y + pt.direction.y < boundaryMin.y || pt.y + pt.direction.y > boundaryMax.y )
          pt.direction.y *= -1;
        if ( pt.z + pt.direction.z < boundaryMin.z || pt.z + pt.direction.z > boundaryMax.z )
          pt.direction.z *= -1;
      }
      float totalsize = 0;
      for ( int i = 0; i < refpoints.size(); i++ ) { totalsize += refpoints.get(i).size; }
      barycenter.set( 0,0,0 );
      MeshPoint tmp = new MeshPoint( true );
      for ( int i = 0; i < refpoints.size(); i++ ) {
        tmp.set( refpoints.get(i) );
        tmp.multiply( refpoints.get(i).size / totalsize );
        barycenter.plus( tmp );
      }
      biggestdist = 0;
      for ( int i = 0; i < refpoints.size(); i++ ) {
        float tmd = barycenter.dist( refpoints.get(i) ) + ( refpoints.get(i).size * 0.5f ) + 10;
        if ( tmd > biggestdist ) {
          biggestdist = tmd;
        }
      }
      icosize = biggestdist;
      int previousclosest = 0;
      MeshPoint tm = new MeshPoint();
      MeshPoint m = new MeshPoint();
      for ( int i = 0; i < ico.ptsNum; i++ ) {
        tm.set( ico.pts[i] );
        tm.multiply( biggestdist );
        m.set( barycenter );
        m.plus( tm );
        // closest point
        int closest = 0;
        float d = 0;
        for ( int p = 0; p < refpoints.size(); p++ ) {
          MeshPoint pt = refpoints.get(p);
          if ( p == 0 ) {
            d = m.dist( pt ) - pt.size * 0.5f;
          } else {
            float tmd = m.dist( pt ) - pt.size * 0.5f;
            if ( d > tmd ) {
              closest = p;
              d = tmd;
            }
          }
        }
        // setting the direction towards the closest point:
        m.direction.set( refpoints.get( closest ) );
        m.direction.minus( m );
        float tml = m.direction.len();
        m.direction.normalise();
        m.direction.multiply( tml - refpoints.get( closest ).size * 0.5f );
        // smooth gaps
        /*
        if ( i > 0 && previousclosest != closest ) {
          // the current mesh point points to a different point then the prvious one!
          // creating a point in the middle
          MeshPoint prevmp = mesh.get( i-1 );
          MeshPoint middle = new MeshPoint( true );
          middle.set( prevmp.x + prevmp.direction.x, prevmp.y + prevmp.direction.y, prevmp.z + prevmp.direction.z );
          middle.minus( m.x + m.direction.x, m.y + m.direction.y, m.z + m.direction.z );
          middle.multiply( 1.f / 3 );
          m.direction.plus( middle );
          prevmp.direction.minus( middle );
        }
        */
        ico.pts[i].direction.set( m.direction );
        previousclosest = closest;
      }
    }
    
    void draw() {
      
      float rx = frameCount / 700.f;
      float ry = frameCount / 320.f;
      // float rx = 0;
      // float ry = 0;
      
      update();
      
      background( 255 );
      
      ambientLight(30, 30, 30);
      pushMatrix();
        translate( width * 0.5, height * 0.5, 0 );
        // rotateX( rx * 3 );
        directionalLight(255, 255, 255, 0, -0.3, -1);
      popMatrix();
      
      PVector f1 = new PVector();
      PVector f2 = new PVector();
      PVector f3 = new PVector();
      pushMatrix();
        translate( width * 0.5, height * 0.5, -width * 0.25 );
        rotateX( rx );
        rotateY( ry );
        
        pushMatrix();
        
          translate( barycenter.x, barycenter.y, barycenter.z );
          
          /*
          noFill();
          stroke( 255,0,0 );
          for ( int i = 0; i < ico.facesNum; i++ ) {
            beginShape();
              for ( int k = 0; k < 3; k++ )
                vertex( ico.pts[ ico.faces[i][k] ].x * icosize, ico.pts[ ico.faces[i][k] ].y * icosize, ico.pts[ ico.faces[i][k] ].z * icosize );
            endShape( CLOSE );
          }
          */
          noStroke();
          fill( 0,120,255 );
          for ( int i = 0; i < ico.ptsNum; i++ ) {
            MeshPoint mp = ico.pts[i];
            pushMatrix();
              translate( mp.x * icosize, mp.y * icosize, mp.z * icosize );
              rotateY( -ry );
              rotateX( -rx );
              noStroke();
              ellipse( 0,0, 5,5 );
            popMatrix();
            pushMatrix();
              translate( mp.x * icosize, mp.y * icosize, mp.z * icosize );
              stroke( 0,255,255 );
              line( 0,0,0, mp.direction.x, mp.direction.y, mp.direction.z );
            popMatrix();
          }
          
          if( fillbag ) {
            noStroke();
            fill( 255,0,0 );
          } else {
            noFill();
            stroke( 255,0,0 );
            strokeWeight( 2 );
          }
          for ( int i = 0; i < ico.facesNum; i++ ) {
            beginShape();
              for ( int k = 0; k < 3; k++ )
                vertex( 
                  (ico.pts[ ico.faces[i][k] ].x * icosize) + ico.pts[ ico.faces[i][k] ].direction.x,
                  (ico.pts[ ico.faces[i][k] ].y * icosize) + ico.pts[ ico.faces[i][k] ].direction.y,
                  (ico.pts[ ico.faces[i][k] ].z * icosize) + ico.pts[ ico.faces[i][k] ].direction.z );
            endShape( CLOSE );
          }
          
          strokeWeight( 1 );
          
          /*
          for ( int i = 0; i < ico.vertexList.size(); i+=9 ) {
            f1.x = ico.vertexList.get(i) * icosize;
            f1.y = ico.vertexList.get(i+1) * icosize;
            f1.z = ico.vertexList.get(i+2) * icosize;
            f2.x = ico.vertexList.get(i+3) * icosize;
            f2.y = ico.vertexList.get(i+4) * icosize;
            f2.z = ico.vertexList.get(i+5) * icosize;
            f3.x = ico.vertexList.get(i+6) * icosize;
            f3.y = ico.vertexList.get(i+7) * icosize;
            f3.z = ico.vertexList.get(i+8) * icosize;
            beginShape();
              vertex( f1.x, f1.y, f1.z );
              vertex( f2.x, f2.y, f2.z );
              vertex( f3.x, f3.y, f3.z );
            endShape( CLOSE );  
          }
    
          fill( 0,255,255 );
          for ( int i = 0; i < ico.pts.size(); i++ ) {
            MeshPoint mp = ico.pts.get(i);
            pushMatrix();
              translate( mp.x * icosize, mp.y * icosize, mp.z * icosize );
              rotateY( -ry );
              rotateX( -rx );
              noStroke();
              ellipse( 0,0, 10,10 );
            popMatrix();
            pushMatrix();
              translate( mp.x * icosize, mp.y * icosize, mp.z * icosize );
              stroke( 0,255,255 );
              line( 0,0,0, mp.direction.x, mp.direction.y, mp.direction.z );
            popMatrix();
    
            pushMatrix();
              // rotateX( rx );
              // rotateY( ry );
              // stroke( 0,255,255 );
              translate( 
                mp.x * icosize + mp.direction.x, 
                mp.y * icosize + mp.direction.y, 
                mp.z * icosize + mp.direction.z );
              rotateY( -ry );
              rotateX( -rx );
              ellipse( 0,0, 10,10 );
              // line( 0,0,0, mp.direction.x, mp.direction.y, mp.direction.z );
            popMatrix();
    
          }
          */
        
        popMatrix();
        
          // drawing the balls
        noFill();
        strokeWeight( 2 );
        for ( int i = 0; i < refpoints.size(); i++ ) {
          MeshPoint pt = refpoints.get(i);
          pushMatrix();
            translate( pt.x, pt.y, pt.z );
            rotateY( -ry );
            rotateX( -rx );
            
            stroke( 0,0,0 );
            line( -5,0, 5,0 );
            line( 0,-5, 0,5 );
            // stroke( 0,0,0 );
            ellipse( 0,0, pt.size,pt.size );
          popMatrix();
        }
        strokeWeight( 1 );
        
      popMatrix(); 
      
      /*
      fill( 0,0,0 );
      text("icosahedron division: "+int( ICOSUBDIVISION ),20,40);
      text("points: "+int( ico.ptsNum ),20,60);
      text("faces: "+int( ico.facesNum ),20,80);
      text("fps: "+int(frameRate),20,100);
      */
      
    }
    
    void keyPressed() {
      if ( keyCode == 38 ) { // [up]
        if ( ICOSUBDIVISION == 5 )
          return;
        ICOSUBDIVISION++;
        ico = new Icosahedron( ICOSUBDIVISION );
      } else if ( keyCode == 40 ) {  // [down]
        if ( ICOSUBDIVISION == 0 )
          return;
        ICOSUBDIVISION--;
        ico = new Icosahedron( ICOSUBDIVISION );
      } else if ( keyCode == 70 ) { // 'f'
        fillbag = !fillbag;
      } else {
        println( keyCode );
      }
    }
    
    
    

    code

    tweaks (0)

    about this sketch

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

    license

    advertisement

    frankie zafe

    Bag of points [3D]

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

    Same process as the bag of points in 2D.
    A sub-divided icosahedron is used to create a mesh around the points.
    Press [up] and [down] to change the mesh definition.
    Press 'f' to fill or not the mesh.

    frankie zafe
    11 Mar 2013
    i'll find a way to smooth the mesh later this week...
    frankie zafe
    14 Mar 2013
    video of latest version: https://vimeo.com/61821634
    You need to login/register to comment.