• fullscreen
  • _02_flowVector_advanced.pde
  • interface.pde
  • math.pde
  • solver.pde
  • /**
      * Nils Seifert & Michael Muehlhaus
      *
      * www.muehlseife.de
      *
      * you can select & move the Vectors and Polygons
      * for drawing a new polygon, hold 'n'
    **/
    
    ArrayList<Polygon> polygons;
    ArrayList<Object> selected;
    
    Vector[][] grid;
    
    int gridSize = 20;
    int gridBorder = 0;
    float vectorScale = 0.3f;
    int DM = 0;
    
    Polygon newPolygon;
    boolean beginNewPolygon = false;
    Solver solver;
    
    int[] colors = {color(0, 0, 255), color(255, 0, 255), color(255, 0, 0), color(255, 255, 0), color(0, 255, 0)};
    
    void setup() {
      size(800, 600, JAVA2D); smooth();
      solver = new Solver();
      
      grid = new Vector[(int)(width / gridSize) - 2 * gridBorder / gridSize + 1]
                       [(int)(height / gridSize) - 2 * gridBorder / gridSize + 1];
      
      for (int i = 0; i < grid.length; i++) {
        for (int j = 0; j < grid[i].length; j++) {
          grid[i][j] = new Vector(i * gridSize + gridBorder, j * gridSize + gridBorder);
        }
      }
      
      polygons = new ArrayList<Polygon>();
      selected = new ArrayList<Object>();
      
      polygons.add(new Polygon(new Vector(160, 60),
                               new Vector(160, 120),
                               new Vector(340, 120),
                               new Vector(340, 60)));
      
      polygons.add(new Polygon(new Vector(160, 260),
                               new Vector(160, 420),
                               new Vector(240, 420),
                               new Vector(240, 260)));
    
      polygons.add(new Polygon(new Vector(420, 240),
                               new Vector(420, 470),
                               new Vector(580, 470),
                               new Vector(580, 240)));
    }
    
    void vecPoint(float x, float y, float sz) {
      beginShape();
      vertex(x - sz / 2, y - sz / 2);
      vertex(x - sz / 2, y + sz / 2);
      vertex(x + sz / 2, y + sz / 2);
      vertex(x + sz / 2, y - sz / 2);
      vertex(x - sz / 2, y - sz / 2);
      endShape();
    }
    
    void vecArrow(float x, float y, float dirX, float dirY, float sz) {
      PVector dirN = new PVector(dirX, dirY);
      dirN.normalize();
      PVector vertical = new PVector(-dirN.y, dirN.x);
      PVector dir = new PVector(dirX, dirY);
      
      beginShape();
      vertex(x + dir.x + dirN.x * sz, y + dir.y + dirN.y * sz); //spitze
      vertex(x + vertical.x * sz, y + vertical.y * sz);
      vertex(x - dirN.x * sz, y - dirN.y * sz);
      vertex(x - vertical.x * sz, y - vertical.y * sz);
      vertex(x + dir.x + dirN.x * sz, y + dir.y + dirN.y * sz);
      endShape();
    }
    
    void vecCompass(PVector pos, float[] values, float scale) {
      beginShape();
      for (int i = 0; i < values.length; i++) {
        vertex(pos.x + cos((float)i / 32f * PI * 2f + PI) * (values[i] * scale + 2),
               pos.y + sin((float)i / 32f * PI * 2f + PI) * (values[i] * scale + 2));
      }
      vertex(pos.x + cos((float)0 / 32f * PI * 2f + PI) * (values[0] * scale + 2),
             pos.y + sin((float)0 / 32f * PI * 2f + PI) * (values[0] * scale + 2));
      endShape();
    }
    
    void draw() {
      background(255);
      solver.update(grid);
      
      pushStyle();
      noStroke(); //stroke(0); strokeWeight(1);
      
      for (int i = 0; i < grid.length; i++) {
        for (int j = 0; j < grid[i].length; j++) {
          fill(colorGradient((grid[i][j].value / ((float)grid[i][j].count +1) - solver.lowest) / (solver.highest - solver.lowest), colors));
    
          if (DM == 0) {
            vecArrow(grid[i][j].x, grid[i][j].y, grid[i][j].dir.x / ((float)grid[i][j].count +1), grid[i][j].dir.y / ((float)grid[i][j].count +1), 2);
            //vecCompass(grid[i][j], grid[i][j].vValue, 1 / ((float)grid[i][j].count +1));
          } else vecPoint(grid[i][j].x, grid[i][j].y, 0.25 * (sqrt(sq(grid[i][j].dir.x / ((float)grid[i][j].count +1)) + sq(grid[i][j].dir.y / ((float)grid[i][j].count +1))) + 4));
        }
      }
      
      popStyle();
      
      for (Polygon poly : polygons) {poly.display();}
      
      if (!keyPressed || (keyPressed && key != 'n')) {
        if (beginNewPolygon = true) {
          if (newPolygon != null) if (newPolygon.vertices.size() > 2) {polygons.add(newPolygon); solver.reset(grid);}
        }
        beginNewPolygon = false; newPolygon = null;
      }
      
      textAlign(LEFT, TOP);
      if (beginNewPolygon) {
        fill(0); text("draw polygon by clicking left mouse button", 4, 4);
        
        if (newPolygon != null) if (newPolygon.vertices.size() > 0) {
          strokeWeight(1.5);
          noFill(); stroke(0, 125);
          beginShape();
          for (Vector vec : newPolygon.vertices) vertex(vec.x, vec.y);
          vertex(mouseX, mouseY);
          vertex(newPolygon.vertices.get(0).x, newPolygon.vertices.get(0).y);
          endShape();
        }
      } else {fill(0); text("hold 'n' for drawing new polygon", 4, 4);}
      text("press 'd' for changing display mode", 4, 16);
    }
    
    
    float selRad = 5f;
    
    void mousePressed() {
      int selectedSizeBefore = selected.size();
      selected.clear();
      if (!beginNewPolygon) {
        for (Polygon poly : polygons) {
          boolean gotVec = false;
          for (Vector vec : poly.vertices) {
            if (dist(mouseX, mouseY, vec.x, vec.y) < selRad) {
              selected.add(vec); gotVec = true;
            }
          }
          if (!gotVec) {
            if (poly.pointInPolygon((float)mouseX, (float)mouseY)) {
              for (Vector vec : poly.vertices) selected.add(vec);
              selected.add(poly); //solver.reset(grid);
            }
          }
        }
      } else {
        if (newPolygon == null) newPolygon = new Polygon();
        newPolygon.vertices.add(new Vector(mouseX, mouseY));
      }
      //if (selected.size() == 0 && selectedSizeBefore != 0) solver.reset(grid);
    }
    
    void mouseDragged() {
      for (Object sel : selected) {
        if (sel.getClass() == Vector.class) {
          Vector vec = (Vector)sel;
          vec.add(new PVector((float)(mouseX - pmouseX), (float)(mouseY - pmouseY)));
          solver.reset(grid);
        }
      }
    }
    
    void keyTyped() {
      if (key == 'n') beginNewPolygon = true;
      
      if (key == 'd') DM += 1 - DM*2;
      
      if (key == DELETE || key == BACKSPACE) {
        Object remove = null;
        for (Object sel : selected) {
          if (sel.getClass() == Polygon.class) {polygons.remove(sel); solver.reset(grid); remove = sel;}
        }
        if (remove != null) selected.remove(remove);
      }
    }
    
    public class Polygon {
      ArrayList<Vector> vertices;
    
      public Polygon() {
        vertices = new ArrayList<Vector>();
      }
      
      public Polygon(Vector... vec) {
        vertices = new ArrayList<Vector>();
        for (Vector vv : vec) {
          vertices.add(vv);
          vv.polygon = this;
        }
      }
      
      public void display() {
    
        strokeWeight(2);
        if (selected.contains(this)) {fill(255, 0, 0, 100); stroke(255, 0, 0);}
        else {fill(180, 100); stroke(0);}
        if (vertices.size() > 0) {
          beginShape();
          for (Vector vec : vertices) vertex(vec.x, vec.y);
          vertex(vertices.get(0).x, vertices.get(0).y);
          endShape();
          
          for (Vector vec : vertices) vec.display();
        }
      }
      
      public boolean pointInPolygon(float x, float y) {
        return pointInPolygon(new Vector(x, y));
      }
      
      public boolean pointInPolygon(Vector iVec1) {
        Vector iVec2 = new Vector(iVec1.x + random(200) + 10000, iVec1.y + random(-200, 200));
        int ic = 0;
        if (vertices.size() > 2) {
          Vector prevVec = vertices.get(vertices.size() - 1);
          for (Vector vec : vertices) {
            if (intersection(iVec1, iVec2, vec, prevVec) != null) ic++;
            prevVec = vec;
          }
        }
    
        if (round((float)ic / 2) == (float)ic / 2) return false;
        else return true;
      }
    }
    
    
    public Vector intersection(Vector l1v1, Vector l1v2, Vector l2v1, Vector l2v2) {
      float x1 = l1v1.x;
      float y1 = l1v1.y;
      float x2 = l1v2.x;
      float y2 = l1v2.y;
      float x3 = l2v1.x;
      float y3 = l2v1.y;
      float x4 = l2v2.x;
      float y4 = l2v2.y;
      
      float tol = 0.01f;
      
      float d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
      if (d == 0) return null;
        
      float xr = ((x3 - x4) * (x1 * y2 - y1 * x2) -
                  (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
      float yr = ((y3 - y4) * (x1 * y2 - y1 * x2) -
                  (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
      
      if (dist(x1, y1, xr, yr) + dist(x2, y2, xr, yr) - dist(x1, y1, x2, y2) < tol &&
          dist(x3, y3, xr, yr) + dist(x4, y4, xr, yr) - dist(x3, y3, x4, y4) < tol)
        return new Vector(xr, yr);
      else return null;
    }
    
    
    public class Vector extends PVector {
      Polygon polygon;
      float value = 0;
      int count = 0;
      
      float[] vValue;
      
      PVector dir;
      
      public Vector() {
        super();
        dir = new PVector();
        vValue = new float[32];
      }
      public Vector(float x, float y) {
        super(x, y);
        dir = new PVector();
        vValue = new float[32];
      }
      
      public void display() {
        pushStyle();
        if (selected.contains(this)) {
          stroke(255, 0, 0);
          strokeWeight(8);
        } else {
          stroke(0);
          strokeWeight(5);
        }
        point(x, y);
        popStyle();
      }
    }
    
    public class Solver {
      public Solver() {}
      
      PVector nullV = new PVector(1, 0);
      
      float highest = 0;
      float lowest = 0;
      int intermediate = 10000;
      
      void update(Vector[][] grid) {
        for (int i = 0; i < intermediate; i++) {
          int i1 = (int)random(grid.length);
          int j1 = (int)random(grid[0].length);
          
          float bBxMin = 100000;
          float bByMin = 100000;
          float bBxMax = 0;
          float bByMax = 0;
    
          int i2, j2;
          
          i2 = (int)random(grid.length);
          j2 = (int)random(grid[0].length);
    
          while (i1 == i2 && j1 == j2) {
            i2 = (int)random(grid.length);
            j2 = (int)random(grid[0].length);
          }
    
          Vector iVec1 = grid[i1][j1];
          Vector iVec2 = grid[i2][j2];
          
          boolean intersecting = false;
          for (Polygon poly : polygons) {
            Vector prevVec = poly.vertices.get(poly.vertices.size() - 1);
            for (Vector vec : poly.vertices) {
              if (intersection(iVec1, iVec2, vec, prevVec) != null) {intersecting = true; break;}
              prevVec = vec;
            }
            if (intersecting) break;
          }
          
          iVec1.count++;
          iVec2.count++;
          
          if (!intersecting) {
            iVec1.value++;
            PVector iV1a = new PVector((iVec2.x - iVec1.x) * vectorScale,
                                      (iVec2.y - iVec1.y) * vectorScale);
            iVec1.dir.add(iV1a);
            float aa1 = angleBetween(nullV, iV1a);
            aa1 += PI;
            aa1 /= 2 * PI;
            iVec1.vValue[(int)(aa1 * iVec1.vValue.length)] += iVec1.mag() * vectorScale;
            
            iVec2.value++;
            PVector iV2a = new PVector((iVec1.x - iVec2.x) * vectorScale,
                                      (iVec1.y - iVec2.y) * vectorScale);
            iVec2.dir.add(iV2a);
            float aa2 = angleBetween(nullV, iV2a);
            aa2 += PI;
            aa2 /= 2 * PI;
            iVec2.vValue[(int)(aa2 * iVec2.vValue.length)] += iVec2.mag() * vectorScale;
          }
        }
        highest = 0;
        lowest = 100000;
        for (int i = 0; i < grid.length; i++) {
          for (int j = 0; j < grid[i].length; j++) {
            highest = max(highest, grid[i][j].value / ((float)grid[i][j].count + 1));
            lowest = min(lowest, grid[i][j].value / ((float)grid[i][j].count + 1));
          }
        }
      }
      
      void reset(Vector[][] grid) {
        for (int i = 0; i < grid.length; i++) {
          for (int j = 0; j < grid[i].length; j++) {
            grid[i][j].value = 0;
            grid[i][j].vValue = new float[32];
            grid[i][j].count = 0;
            grid[i][j].dir = new PVector();
          }
        }
        highest = 0;
        lowest = 0;
      }
    }
    
    
    float angleBetween(PVector vv1, PVector vv2) {
      float factor = vv1.x * vv2.y - vv1.y * vv2.x;
      if (factor != 0) factor /= PApplet.abs(factor);
      
      PVector newV1 = new PVector();
      newV1.set(vv1);
      newV1.normalize();
      
      PVector newV2 = new PVector();
      newV2.set(vv2);
      newV2.normalize();
      	
      return PVector.angleBetween(newV1, newV2) * factor;
    }
    
    int colorGradient(float value, int[] colGrad) {
      float d = value;
      int ci = floor(d*((float)colGrad.length - 1));
      int cj = ci + 1;
      
      value = PApplet.abs(value);
      if (ci < colGrad.length - 1) {
        float d1 = d * (float)(colGrad.length - 1) - (float)ci;
        float d2 = d *(float)(colGrad.length - 1) - (float)cj;
        
        int a = (int)(d1 * alpha(colGrad[cj]) + abs(d2) * alpha(colGrad[ci]));
        int r = (int)(d1 * red(colGrad[cj]) + abs(d2) * red(colGrad[ci]));
        int g = (int)(d1 * green(colGrad[cj]) + abs(d2) * green(colGrad[ci]));
        int b = (int)(d1 * blue(colGrad[cj]) + abs(d2) * blue(colGrad[ci]));
        
        a = a << 24;
        r = r << 16;
        g = g << 8;
        
        return a | r | g | b;
        
      } else {
        return colGrad[colGrad.length - 1];
      }
    }
    

    code

    tweaks (0)

    about this sketch

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

    license

    advertisement

    Michael Muehlhaus, Nils Seifert

    flow vector analysis

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

    visibility analysis on a 2D map

    there are 2 different display modes (1: vectors, 2: vector scales) you can change them by pressing 'd'

    you can select & move the Vectors and Polygons
    for drawing a new polygon, hold 'n'
    for deleting polygons, select them and press the delete key

    You need to login/register to comment.