Generative Brand Design unter Verwendung von Bitcoin Daten

Generative Brand Design unter Verwendung von Bitcoin Daten

Warum ist auch für coinfinity ein 
generatives Brand Design interessant?
Einerseits verweist der technisch und ästhetisch innovative Charakter  ideal auf das innovative Geschäftsfeld, der Code dient als formgebendes Element. Andererseits liegt der Kommunikationsschwerpunkt auf den digitalen Kanälen, welche den fluiden Charakter und die wechselnde Gestalt der visuellen Marke gut abbilden welche als Metapher  die ständige Neugruppierung und Fluidität der Bitcoin-Communitiy abbilden. Für das Konzept des „Coin Village“ bietet es sich an, Instanzen des Logos für die Teilnehmer zu verwenden.

Die aktuellen Daten aus dem Bitcoin-Netzwerk werden von blockchain.info jedesmal, wenn das Logo generiert wird, abgerufen. Daher kann das Logo je nach aktuellem Handelspreis, Markkapitalisierung oder Transaktionsvolumen innerhalb der festgelegten Regeln unterschiedliche Gestalten annehmen.

Letterpress Business Cards MockUp3

// --------------------------------------------------
// Generative Brand 
// Language: Processing
// Author: Andreas Pirchner
// --------------------------------------------------

import geomerative.*;
import controlP5.*;

int nodeNumber = 400;
int size = 360;
int radius = 300;
int connectionDistance = 80;
float speed = 0.9;

int rotation = 0;
int rotVel = 10;

float currentdate = 0;
float dateinterval = 0.1;
boolean isTime = false;

RFont f;
RShape grp;
RPoint[] points;

float [] phi = new float[nodeNumber];
float [] theta = new float[nodeNumber];

int startPoint = nodeNumber;
int endPoint = nodeNumber;
int distance = 1;
float currentDistance;
float darkness;
float thickness;

float radianX, radianY;
float middleTheta, middlePhi;

PVector[] nodes = new PVector[nodeNumber];
PVector[] velocities = new PVector[nodeNumber];
PVector center = new PVector(500,500,0);
PVector middle, middleSphere;
ControlP5 cp5;
int sliderRadius = radius;
int sliderNodenumber = 80;
float sliderNodeSpeed = speed;
int sliderConnectionDistance = connectionDistance;
CheckBox timeOn;

JSONObject jsonHandelsvolumen, jsonBSPreis, jsonTransDay, jsonAdresses;
int startDate = 0;
int stepsize = 1;

int [] transdayY = new int[720];
int [] handelsvolumenY = new int[720];
int [] priceY = new int[720];
int [] adressesY = new int[720];
int transdayBorderTop = 90000;
int handelsvolumenBorderTop = 30000000;
int priceBorderTop = 1200;
int adressesBorderTop = 220000;

void setup(){
  size(1000,1000, P3D);
  smooth();
  frameRate(30);

  // Get Bitcoin-Data from Blockchain.info (actually from a .json-file)
  // ----------------------------------------------------
  jsonTransDay = loadJSONObject("01transaktionenProTag.json");
  jsonHandelsvolumen = loadJSONObject("03handelsvolumenUSD.json");
  jsonBSPreis = loadJSONObject("04HandelspreisUSD.json");
  jsonAdresses = loadJSONObject("05adressen.json");
  JSONArray transday = jsonTransDay.getJSONArray("values");
  JSONArray volume = jsonHandelsvolumen.getJSONArray("values");
  JSONArray price = jsonBSPreis.getJSONArray("values");
  JSONArray adresses = jsonAdresses.getJSONArray("values");

  for(int ang=startDate; ang < 720; ang ++){        JSONObject jsontransdayY = transday.getJSONObject(ang);        JSONObject jsonVolumeY = volume.getJSONObject(ang);        JSONObject jsonpriceY = price.getJSONObject(ang);        JSONObject jsonadressesY = adresses.getJSONObject(ang);        transdayY[ang] = jsontransdayY.getInt("y");        handelsvolumenY[ang] = jsonVolumeY.getInt("y");        priceY[ang] = jsonpriceY.getInt("y");        adressesY[ang] = jsonadressesY.getInt("y");        if (transdayY[ang] > transdayBorderTop) { transdayY[ang] = transdayBorderTop;}
       if (handelsvolumenY[ang] > handelsvolumenBorderTop) { handelsvolumenY[ang] = handelsvolumenBorderTop;}
       if (priceY[ang] > priceBorderTop) { priceY[ang] = priceBorderTop;}
       if (adressesY[ang] > adressesBorderTop) { adressesY[ang] = adressesBorderTop;}

       if (priceY[ang] < 150) { priceY[ang] = 150;}
  }

  RG.init(this);  // allways initialize geomerative library in setup
  grp = RG.getText("CO", "TwCenMT.ttf", 130, CENTER);
  RG.setPolygonizer(RG.UNIFORMLENGTH);
  RG.setPolygonizerLength(60);
  points = grp.getPoints();

  cp5 = new ControlP5(this);

  cp5.addSlider("sliderRadius")
     .setPosition(50,50)
     .setRange(50,400)
     ;

  cp5.addSlider("sliderNodenumber")
     .setPosition(50,80)
     .setRange(50,300)
     ;

  cp5.addSlider("sliderNodeSpeed")
     .setPosition(50,110)
     .setRange(0.1,5)
     .setValue(2.1)
     ;

  cp5.addSlider("sliderConnectionDistance")
     .setPosition(50,140)
     .setRange(10,150)
     ;
  cp5.addSlider("date")
     .setPosition(50,950)
     .setRange(0,720)
     .setWidth(800)
     .setSliderMode(Slider.FLEXIBLE)
     ;
  timeOn = cp5.addCheckBox("timeOn")
     .setPosition(50, 170)
     .setColorForeground(color(120))
     .setColorActive(color(255))
     .setColorLabel(color(255))
     .setSize(40, 40)
     .addItem("start/stop timer", 0)
     ;

  for (int i=0; i< nodes.length; i++) {
      nodes[i] = new PVector(0,0,0);
      theta[i] = random(PI);
      phi[i] = random(2*PI);
      velocities[i] = new PVector(random(-speed,speed), random(-speed,speed));
  } 

  for (int n=0; n< points.length; n++) {
      nodes[n].x = points[n].x;
      nodes[n].y = points[n].y;
      nodes[n].z = radius;
      velocities[n].set(0,0,0);
  }   
}

void draw (){
  radius = sliderRadius;
  speed = sliderNodeSpeed;
  connectionDistance = sliderConnectionDistance;
  currentdate = currentdate + dateinterval;
  if (isTime == true && currentdate<720){
    cp5.getController("date").setValue(currentdate);
    sliderNodenumber = transdayY[round(currentdate)]/300;
    cp5.getController("sliderNodenumber").setValue(sliderNodenumber);
    //speed = handelsvolumenY[round(currentdate)]/250000;
    //cp5.getController("sliderNodeSpeed").setValue(speed);
    radius = priceY[round(currentdate)]/3;
    cp5.getController("sliderRadius").setValue(radius);
    connectionDistance = adressesY[round(currentdate)]/1800;
    cp5.getController("sliderConnectionDistance").setValue(connectionDistance);
  }
  fill(15,25,60,40);

  pushMatrix();
  translate(0,0,-1000);
  rect(-1000,-1000,3000,3000);
  popMatrix();
  fill(0);
  stroke(0);
  ambientLight(255, 255, 255, 0, 0, -200);

  for (int i=0; i< sliderNodenumber; i++) {              theta[i] += radians(velocities[i].x);       phi[i]  += radians(velocities[i].y);       if (theta[i]>PI){theta[i]=0;}
      if (phi[i]>2*PI){phi[i]=0;}

      nodes[i].x = (radius * cos(theta[i]) * sin(phi[i]));
      nodes[i].y = (radius * sin(theta[i]) * sin(phi[i]));
      nodes[i].z = (radius * cos(phi[i]));
      nodes[i].add(center);

      for (int q=0; q< points.length; q++) {
        nodes[q].x = points[q].x+500;
        nodes[q].y = points[q].y+540;
        nodes[q].z = radius;
        velocities[q].set(0,0,0);
      }

      stroke(0,0,0,0);
      strokeWeight(1);

      for (int k=points.length; k< sliderNodenumber; k++) {         currentDistance = nodes[i].dist(nodes[k]); // Entfernung zwischen Knotenpunkten i und k berechen                  /*if ((10000/sq(currentDistance)) > 10){
           strokeWeight(10000/sq(currentDistance));
        }*/

        darkness = sq((nodes[i].z + nodes[k].z))/40;
        if (darkness < 20){darkness = 20;}
        thickness = 1;

        if (currentDistance < connectionDistance){           // Mittelpunkt zwischen zwei naheliegenden Punkten durch Interpolation --> liegt innerhalb des Kreises
          middle = PVector.lerp(nodes[i], nodes[k], 0.5);

          // Versuch, den Mittelpunkt AUF der Kugel durch theta und phi zu berechnen. Funktioniert bisher nicht. 
          middleTheta = middleRadian(theta[k], theta[i]);
          middlePhi = middleRadian(phi[k], phi[i]);
          middleSphere = new PVector(radius * cos(middleTheta) * sin(middlePhi), radius * sin(middleTheta) * sin(middlePhi), radius * cos(middlePhi));
          middleSphere.add(center);

          stroke(100,100,100,10);
           //line(center.x, center.y, middle2.x, middle2.y);
          //stroke(random(190,255),random(100,130),random(50,70),darkness);
          stroke(150,150,170,darkness/2);
        if( i > points.length){
          line(nodes[i].x, nodes[i].y, nodes[i].z, middle.x, middle.y, middle.z); // von einem Punkt aus reicht eine Linie zum Mittelpunkt. Die andere Hälfte der Linie wird durch den anderen beteiligten Punkt erstellt. 
        }else{
          line(nodes[i].x, nodes[i].y, nodes[i].z, nodes[k].x, nodes[k].y, nodes[k].z);
        }
          //line(middle.x, middle.y, center.x+(radius * cos(theta[k]) * sin(phi[k])), center.y+(radius * sin(theta[k]) * sin(phi[k])));

        }
      }          
  } 
  // Knotenpunkte werden erst am Ende gezeichnet, damit sie über den Linien liegen.
   for (int i=0; i< sliderNodenumber; i++) {
      darkness = (nodes[i].z)/100;
        if (darkness < 10){darkness = 10;}
        fill(255,255,255,darkness*20);
        noStroke();
        pushMatrix();
        translate(nodes[i].x, nodes[i].y, nodes[i].z);
        sphere(2);
        popMatrix();
        //ellipse(nodes[i].x, nodes[i].y, 8, 8);
   }   

   pushMatrix(); 
      translate(500, 540, radius);

       //---------------------------------------------------------
      fill(255,255,255,40);
      stroke(255,255,255,255);
      strokeWeight(2);

      grp.draw();
      if(points != null){
        fill(255);
        noStroke(); 
        for(int i=0; i<points.length; i++){
          //ellipse(points[i].x, points[i].y,5,5);  
        }
      }
  popMatrix();
   //---------------------------------------------------------

}

void timeOn(float[] a) {
  isTime = !isTime;
  print(isTime);
}

void date(float sliderDate) {
  currentdate = sliderDate;
}

void sliderNodeSpeed(float sliderNodeSpeed) {

     for (int q=points.length; q< nodes.length; q++) {        velocities[q].set(random(-sliderNodeSpeed,sliderNodeSpeed),random(-sliderNodeSpeed,sliderNodeSpeed));       } } float middleRadian(float radianA, float radianB){           float middle = 0;           if (radianA >=radianB){
             if (radianA <= (radianB+PI)){                   middle = (radianB+radianA)/2;              }              if (radianA > (radianB+PI)){
                 middle = ((radianB+radianA)/2)+PI;
             }
          }
          if (radianA<radianB){
             if (radianB <= (radianA+PI)){                  middle = (radianB+radianA)/2;              }              if (radianB > (radianA+PI)){
                 middle = ((radianB+radianA)/2)+PI;
             }
          }  
          return middle;
}

float levyDistribution(float Wert1, float Wert2){
       float u = Wert1; // u = Lageparameter
       float c = Wert2; // s = Stauchung
       float x = 0;
       float y = 1;
       float fx = 0;
     while (y > fx) {
       x = random(10);
       y = random(1);
       fx = sqrt(c/(2*PI))*(exp(-c/(2*(x-u)))/pow((x-u), 3/2));
       //fx = 2 * exp(-2*x); Exponential
     }
    // point(x*100+200,500-y*500);
     return x;
}