| This code was written with the _ALPHA_ version of Processing and it may not run correctly with the current vesion.
    // Matchboxes
    // by Schoenerwissen

    // Reassembling a movieclip database by using the properties of the
    // collected information to generate a new visual data matrix

    // This program will not run if you cut and paste it into your Processing environment.
    // It relies on the text file "sc.db", the font "Univers55.vlw.gz"
    // and the image "schoenerwissen.gif"

    String[] dataLines;
    String[][] finalData;
    ScreenMatrix[] sm;
    GeoLocation[] gl;
    String[] geoLocation;
    BFont fontA;
    BImage swLogo;

    int[] geoCount;
    static int NAME = 0, ACTIVITY = 1, GREYSCALE = 2, MOTION = 4, DISTANCE = 5, GEOLOCATION = 6, SUBJECT = 8;
    static float SGREY = 240;
    static char SEPARATOR = '\t';
    static int TEXTSHOWTIME = 48;
    static float FAR, MEDIUM, CLOSE, VERYCLOSE, NODIST;
    static float fixedist = 6.6;
    int frameCounter = TEXTSHOWTIME + 1;
    int clipselect = 0;
    float maxgrey = 0;

    void setup() {
      size(640, 480);
      colorMode(RGB, 255);
      background(255, 255, 255);

      VERYCLOSE = width/fixedist;
      CLOSE = width/(fixedist*2);
      FAR = width/(fixedist*4);
      MEDIUM = width/(fixedist*8);
      NODIST = width/(fixedist*16);

      fontA = loadFont("Univers55.vlw.gz");
      setFont(fontA);

      swLogo = loadImage("schoenerwissen.gif");

      loadData();
      computeGeolocations();
      organizeLocations();
      calculateMatrix();
    }

    void loop() {

      for (int geolo = 0; geolo < gl.length; geolo++) {
        gl[geolo].draw();
      }
      paintStandards();
      for (int clips = 0; clips < sm.length; clips++) {
        sm[clips].update();
        sm[clips].draw();
      }
      if (frameCounter > TEXTSHOWTIME) {
        clipselect = (int)(random(sm.length));
        frameCounter = 0;
      }
      frameCounter++;

      sm[clipselect].subject(finalData[clipselect][SUBJECT]);
    }

    void loadData() {
      dataLines = loadStrings("sc.db");
      finalData = new String[dataLines.length][];

      for (int dataline = 0; dataline < dataLines.length; dataline++) {
        finalData[dataline] = splitStrings(dataLines[dataline], SEPARATOR);
      }
    }

    void calculateMatrix() {
      sm = new ScreenMatrix[dataLines.length];

      for (int dataline = 0; dataline < dataLines.length; dataline++) {
        float grey = Float.valueOf(finalData[dataline][GREYSCALE]).floatValue();
        if (grey > maxgrey) {
          maxgrey = grey;
        }
        for (int geoline = 0; geoline < geoCount.length; geoline++) {
          if (gl[geoline].name.equals(finalData[dataline][GEOLOCATION])) {
            float distance = calculateDistance(finalData[dataline][DISTANCE]);
            float activity = Float.valueOf(finalData[dataline][ACTIVITY]).floatValue()*(width/800);
            Point motion = calculateMotion(finalData[dataline][MOTION]);
            sm[dataline] = new ScreenMatrix(distance * motion.x, distance * motion.y, gl[geoline].x, gl[geoline].y, distance,
            activity*100, motion, gl[geoline].c1, grey);
          }
        }
      }
    }

    void computeGeolocations() {
      String allGeolocations = "";

      for(int dataline = 0; dataline < dataLines.length; dataline++) {
        if(allGeolocations.indexOf(finalData[dataline][GEOLOCATION]) == -1) {
          allGeolocations += finalData[dataline][GEOLOCATION] + SEPARATOR;
        }
      }

      geoLocation = splitStrings(allGeolocations, SEPARATOR);
      geoCount = new int[geoLocation.length];

      for(int dataline = 0; dataline < dataLines.length; dataline++) {
        for(int geoline = 0; geoline < geoLocation.length; geoline++) {
          if (finalData[dataline][GEOLOCATION].equals(geoLocation[geoline])) {
            geoCount[geoline]++;
          }
        }
      }

    }

    void organizeLocations() {
      gl = new GeoLocation[geoCount.length];
      float x, y = 0;
      int[] geoCountBuffer = new int[geoCount.length];
      String[] geoLocationBuffer = new String[geoCount.length];

      for (int geoline = 0; geoline < geoCount.length; geoline++) {
        int maximl = maxPoint(geoCount);
        geoCountBuffer[geoline] = geoCount[maximl];
        geoLocationBuffer[geoline] = geoLocation[maximl];
        geoCount[maximl] = 0;
      }

      int halfArray = (int)(geoCount.length/2);

      for (int geoline = 0; geoline < geoCount.length; geoline = geoline+2) {
        geoCount[halfArray] = geoCountBuffer[geoline];
        geoLocation[halfArray] = geoLocationBuffer[geoline];
        halfArray--;
      }

      halfArray = geoCount.length-1;

      for (int geoline = geoCount.length-2; geoline > 0; geoline = geoline-2) {
        geoCount[halfArray] = geoCountBuffer[geoline];
        geoLocation[halfArray] = geoLocationBuffer[geoline];
        halfArray--;
      }

      for (int geoline = 0; geoline < geoCount.length; geoline++) {
        x = (width/(geoCount.length))*geoline+((width/(geoCount.length))/2);
        y = (height/(geoCount.length))*geoline+((height/(geoCount.length))/2);
        float c1 = random(255), c2 = random(255), c3 = random(255);
        gl[geoline] = new GeoLocation(x, y, geoLocation[geoline], c1, c2, c3);
      }
    }

    class GeoLocation {
      float x, y, c1, c2, c3, cross;
      String name;

      GeoLocation(float ix, float iy, String iname, float ic1, float ic2, float ic3) {
        x = ix;
        y = iy;
        name = iname;
        c1 = ic1;
        c2 = ic2;
        c3 = ic3;
        cross = 15;
        if (name.length() > 6) {
          cross = 30;
        }
      }

      void draw() {
        stroke(SGREY);
        line(0, y, width, y);
        line(x, 0, x, height);
        fill(0);
        push();
        scale(1.2);
        text(name, (x-cross)/1.2, (y-5)/1.2);
        pop();
      }
    }

    class ScreenMatrix {
      float x, y, xc, yc, distance, activity, angle, cross, col, grey;
      Point motion;

      ScreenMatrix(float ix, float iy, float iw, float ih, float idistance, float iactivity, Point imotion, float icol, float igrey) {
        x = iw+ix;
        y = ih+iy;
        xc = iw;
        yc = ih;
        distance = idistance;
        activity = iactivity;
        motion = imotion;
        col = icol;
        grey = igrey;
        angle = 0;
        cross = distance/8;
      }

      void update() {
        x += (motion.x) * activity;
        y += (motion.y) * activity;

        if ( motion.x == 0 && motion.y == 0) {
        if (angle > 360) { angle = 0; }
          x =  xc + (distance * sin(PI * angle));
          y =  yc + (-distance * cos(PI * angle));
          angle += activity * .01;
        } else {
          if ( x > width ) {
            x = 0;
          } else if ( x < 0) {
            x = width;
          } else if ( y > height) {
            y = 0;
          } else if ( y < 0) {
            y = height;
          }

        }
      }

      void draw() {
        noStroke();
        colorMode(HSB, 255);
        fill(col, 255-((grey*255)/maxgrey), 255-((grey*255)/maxgrey));
        rect(x, y, cross, cross);
        colorMode(RGB, 255);
      }

      void subject(String txt) {
        stroke(160);
        rect(x, y, cross, cross);
        line(x, y, xc, yc);
        push();
        scale(1.5);
        noStroke();
        fill(255, 0, 255);
        text(txt, (x + 5)/1.5, (y - 5)/1.5);
        pop();
      }
    }

    float calculateDistance(String distance) {
      float distf = 0;

      if (distance.equals("far")) {
        distf = FAR;
      } else if (distance.equals("medium")) {
        distf = MEDIUM;
      } else if (distance.equals("close")) {
        distf = CLOSE;
      } else if (distance.equals("very_close")) {
        distf = VERYCLOSE;
      } else {
        distf = NODIST;
      }
      return dist;
    }

    Point calculateMotion(String motion) {
      Point p = new Point(0,0);

      if (motion.equals("forward")) {
        p.x = 0;
        p.y = -1;
      } else if (motion.equals("right")) {
        p.x = 1;
        p.y = 0;
      } else if (motion.equals("left")) {
        p.x = -1;
        p.y = 0;
      } else if (motion.equals("away")) {
        p.x = 0;
        p.y = 1;
      } else {
        p.x = 0;
        p.y = 0;
      }

      return p;
    }

    int maxPoint(int[] value) {
      int maximum = Integer.MIN_VALUE;
      int mp = 0;

      for (int aset=0; aset < value.length; aset++) {
        if (value[aset] > maximum) {
          maximum = value[aset];
          mp = aset;
        }
      }
      return mp;
    }

    void paintStandards() {
      stroke(SGREY);
      line(0, 0, width, height);
      unhint(SMOOTH_IMAGES);
      image(swLogo, 0, height-50);
      hint(SMOOTH_IMAGES);
    }