Willkommen auf unserem Seminar-Blog

Immer auf dem aktuellen Stand bleiben

Dieser Seminar-Blog befindet sich noch im Aufbau und wird in den kommenden Tagen entsprechend verfeinert.

Member Login

Lost your password?

Registration is closed

Sorry, you are not allowed to register by yourself on this site!

You must either be invited by one of our team member or request an invitation by email at viad.info {at} zhdk {dot} ch.

13. Permutation mit Interaktion

9. Dezember 2010

Als eine Weiterentwicklung habe ich bei der Permutation, die schon auf den Mauszeiger interagiert, die Zeichen mit Beziérkurven neu erstellt, sodass ich dynamisch die Ecken der Quadrate abrunden kann. Ebenfalls habe ich weitere Parameter eingeführt und diese über Tastenkombinationen editierbar gemacht. Somit ist es mir möglich die Zeichen "on the fly" zu verändern und interessante Einstellungen mittels Screenshot zu speichern. Als letzte Anpassung habe ich eine Stack-Klasse erstellt, welche die Wertesettings dieser interessanten Permutationen speichern kann. Diese Wertesets werden nun eins nach dem anderen durchlaufen und die Werte dazwischen berechnet. Abhängig von millis(), den Millisekunden seit Programmstart, hat jede Transformation einer Permutation zu der nächsten eine definierbare Zeitspanne zur Verfügung. Somit verformen sich die verschiedenen Zeichen nahtlos in die definierten Zustände, wobei die Interaktion mit der Maus stets vorhanden bleibt. Als weiteres Vorgehen möchte ich noch mehr ansprechende Wertesets sammeln und den Gesamtablauf gestalten. Hauptprogrammcode
//import megamu.shapetween.*;
import ddf.minim.*;

import fullscreen.*;
SoftFullScreen _fullScreen;

int     anzahl = 7;
int     rand = 100;
float   xStep;
float   yStep;
int[]   permutationsIndexList = {
  0, 1, 2, 3, 4, 5, 6,
  1, 2, 3, 4, 5, 6, 5,
  2, 3, 4, 5, 6, 5, 4,
  3, 4, 5, 6, 5, 4, 3,
  4, 5, 6, 5, 4, 3, 2,
  5, 6, 5, 4, 3, 2, 1,
  6, 5, 4, 3, 2, 1, 0
};
char mode = '1';
float scaleRangeTop = 1.0;
float scaleRangeBottom = 1.0;
float strokeRangeTop = 2.0;
float strokeRangeBottom = 2.0;
float heightRangeTop = 20;
float heightRangeBottom = 10;
float borderRadiusBlack = 0;
float borderRadiusWhite = 0;
float mirrorToggle = 1; // whether negative values are set to positive ones (ring)
int keyMode = 1;

int numSigns = permutationsIndexList.length;
Sign[] signs =  new Sign[numSigns]; // holds all objects of signs

Stacks[] animationStacks = new Stacks[11]; // sets of values for animation

float prevBorderRadiusBlack = borderRadiusBlack;
float prevBorderRadiusWhite = borderRadiusWhite;
float prevScaleRangeTop = scaleRangeTop;
float prevScaleRangeBottom = scaleRangeBottom;
float prevStrokeRangeTop = strokeRangeTop;
float prevStrokeRangeBottom = strokeRangeBottom;

float prevHeightRangeTop = heightRangeTop;
float prevHeightRangeBottom = heightRangeBottom;
//int animationNextTimeLimit=0;
int animationPrevTimeLimit=0;
int timerStack=0;
int idleCompleted=0;

//WaveformRenderer waveform;
//AudioInput in;

void setup()
{
  size(880, 880);
  smooth();
  
  PFont font;
  font = loadFont("Archer-Book-48.vlw");
  textFont(font, 14);

  xStep = (width - 2 * rand) / (float)(anzahl-1);
  yStep = (height - 2 * rand) / (float)(anzahl-1);

  frameRate(24);

  int permutationsIndex = 0;
  for(int y=0; y<anzahl;y++)
  {
    for(int x=0; x<anzahl;x++)
    {
      signs[permutationsIndex] = new Sign(permutationsIndexList[permutationsIndex]);
      ++permutationsIndex;
    }
  }
  
  int keyAnim = 0;
  
  animationStacks[keyAnim] = new Stacks();
  animationStacks[keyAnim].setDuration(0);
  animationStacks[keyAnim]._completed = true;
  keyAnim++;
  animationStacks[keyAnim] = new Stacks();
  animationStacks[keyAnim].setDuration(6000);
  animationStacks[keyAnim].setBorderRadiusBlack(74);
  animationStacks[keyAnim].setBorderRadiusWhite(68);
  animationStacks[keyAnim].setHeightRange(0, 10);
  animationStacks[keyAnim].setScaleRange(2.1, 0.9);
  animationStacks[keyAnim].setStrokeRange(0.5, 6.5);
  keyAnim++;
  animationStacks[keyAnim] = new Stacks();
  animationStacks[keyAnim].setDuration(6000);
  animationStacks[keyAnim].setBorderRadiusBlack(2.0);
  animationStacks[keyAnim].setBorderRadiusWhite(2.0);
  animationStacks[keyAnim].setHeightRange(0, 10);
  animationStacks[keyAnim].setScaleRange(1.0, 2.0);
  animationStacks[keyAnim].setStrokeRange(0.5, 6.5);
  keyAnim++;
  animationStacks[keyAnim] = new Stacks();
  animationStacks[keyAnim].setDuration(6000);
  animationStacks[keyAnim].setBorderRadiusBlack(27.0);
  animationStacks[keyAnim].setBorderRadiusWhite(32.0);
  animationStacks[keyAnim].setHeightRange(10, 20);
  animationStacks[keyAnim].setScaleRange(2.9, -0.3);
  animationStacks[keyAnim].setStrokeRange(2.0, 2.0);
  keyAnim++;
  animationStacks[keyAnim] = new Stacks();
  animationStacks[keyAnim].setDuration(6000);
  animationStacks[keyAnim].setBorderRadiusBlack(2.0);
  animationStacks[keyAnim].setBorderRadiusWhite(2.0);
  animationStacks[keyAnim].setHeightRange(9, 14);
  animationStacks[keyAnim].setScaleRange(2.2, -1.3);
  animationStacks[keyAnim].setStrokeRange(0.5, 0.5);
  keyAnim++;
  animationStacks[keyAnim] = new Stacks();
  animationStacks[keyAnim].setDuration(6000);
  animationStacks[keyAnim].setBorderRadiusBlack(27.0);
  animationStacks[keyAnim].setBorderRadiusWhite(24.0);
  animationStacks[keyAnim].setHeightRange(10, 20);
  animationStacks[keyAnim].setScaleRange(2.6, -1.8);
  animationStacks[keyAnim].setStrokeRange(2.0, 2.0);
  keyAnim++;
  animationStacks[keyAnim] = new Stacks();
  animationStacks[keyAnim].setDuration(6000);
  animationStacks[keyAnim].setBorderRadiusBlack(-26.0);
  animationStacks[keyAnim].setBorderRadiusWhite(-20.0);
  animationStacks[keyAnim].setHeightRange(0, 27);
  animationStacks[keyAnim].setScaleRange(1.9, 0.2);
  animationStacks[keyAnim].setStrokeRange(0.5, 14.5);
  keyAnim++;
  animationStacks[keyAnim] = new Stacks();
  animationStacks[keyAnim].setDuration(6000);
  animationStacks[keyAnim].setBorderRadiusBlack(46.0);
  animationStacks[keyAnim].setBorderRadiusWhite(25.0);
  animationStacks[keyAnim].setHeightRange(10, 12.5);
  animationStacks[keyAnim].setScaleRange(2.4, 0);
  animationStacks[keyAnim].setStrokeRange(8, 12);
  keyAnim++;
  animationStacks[keyAnim] = new Stacks();
  animationStacks[keyAnim].setDuration(6000);
  animationStacks[keyAnim].setBorderRadiusBlack(-7.0);
  animationStacks[keyAnim].setBorderRadiusWhite(28.0);
  animationStacks[keyAnim].setHeightRange(27, 31);
  animationStacks[keyAnim].setScaleRange(2.3, 2.4);
  animationStacks[keyAnim].setStrokeRange(0.5, 26);
  keyAnim++;
  animationStacks[keyAnim] = new Stacks();
  animationStacks[keyAnim].setDuration(6000);
  animationStacks[keyAnim].setBorderRadiusBlack(-40.0);
  animationStacks[keyAnim].setBorderRadiusWhite(98.0);
  animationStacks[keyAnim].setHeightRange(10, 25);
  animationStacks[keyAnim].setScaleRange(2.1, 2.4);
  animationStacks[keyAnim].setStrokeRange(2, 2);
  keyAnim++;
  animationStacks[keyAnim] = new Stacks();
  animationStacks[keyAnim].setDuration(6000);
  animationStacks[keyAnim].setBorderRadiusBlack(27.0);
  animationStacks[keyAnim].setBorderRadiusWhite(24.0);
  animationStacks[keyAnim].setHeightRange(10, 20);
  animationStacks[keyAnim].setScaleRange(2.6, -1.8);
  animationStacks[keyAnim].setStrokeRange(2.0, 2.0);
  
  //waveform = new WaveformRenderer();
  //Minim minim = new Minim(this);
  //AudioPlayer groove = minim.loadFile("gas.mp3", 2048);
  //groove.addListener(waveform);
  //groove.loop();
  //groove.play();
  //in = minim.getLineIn(Minim.STEREO, 512);
  
  // FULLSCREEN
  _fullScreen = new SoftFullScreen(this);
  _fullScreen.enter();
  
}

void draw()
{
  background(255); // ani.position()*255
  //noStroke();
  int permutationsIndex = 0;
  
  /**println(in.bufferSize());
  // draw the waveforms
  for(int i = 0; i < in.bufferSize() - 1; i++)
  {
    line(i, 50 + in.left.get(i)*50, i+1, 50 + in.left.get(i+1)*50);
    //line(i, 150 + in.right.get(i)*50, i+1, 150 + in.right.get(i+1)*50);
  }*/
  
  fill(0);
  String info = "Scale: (1) "+nf(scaleRangeBottom,0,2)+" (2) "+nf(scaleRangeTop,0,2)+"    ";
  info+= "Stroke: (3) "+nf(strokeRangeBottom,0,2)+" (4) "+nf(strokeRangeTop,0,2)+"    ";
  info+= "Height: (5) "+nf(heightRangeBottom,0,2)+" (6) "+nf(heightRangeTop,0,2)+"    ";
  info+= "Rad Black: (7) "+nf(borderRadiusBlack,0,2)+"    ";
  info+= "Rad White: (8) "+nf(borderRadiusWhite,0,2)+"    ";
  info+= "Mirror: (9) "+mirrorToggle;
  text(info,20,20);
  
  // animation
  int timerStack = millis() - animationPrevTimeLimit;
  for(int i=0; i<animationStacks.length; i++)
  {
    if (i>0 && idleCompleted==0) {
      if (((animationStacks[i-1]._completed==true && animationStacks[i]._completed==false)) && timerStack < animationStacks[i]._duration) {
       
        // single tranformation
        borderRadiusBlack = ((animationStacks[i]._borderRadiusBlack - prevBorderRadiusBlack) * timerStack / animationStacks[i]._duration) + prevBorderRadiusBlack;
        borderRadiusWhite = ((animationStacks[i]._borderRadiusWhite - prevBorderRadiusWhite) * timerStack / animationStacks[i]._duration) + prevBorderRadiusWhite;     
        scaleRangeBottom = ((animationStacks[i]._scaleRangeBottom - prevScaleRangeBottom) * timerStack / animationStacks[i]._duration) + prevScaleRangeBottom;
        scaleRangeTop = ((animationStacks[i]._scaleRangeTop - prevScaleRangeTop) * timerStack / animationStacks[i]._duration) + prevScaleRangeTop;
        strokeRangeBottom = ((animationStacks[i]._strokeRangeBottom - prevStrokeRangeBottom) * timerStack / animationStacks[i]._duration) + prevStrokeRangeBottom;
        strokeRangeTop = ((animationStacks[i]._strokeRangeTop - prevStrokeRangeTop) * timerStack / animationStacks[i]._duration) + prevStrokeRangeTop;
        heightRangeBottom = ((animationStacks[i]._heightRangeBottom - prevHeightRangeBottom) * timerStack / animationStacks[i]._duration) + prevHeightRangeBottom;
        heightRangeTop = ((animationStacks[i]._heightRangeTop - prevHeightRangeTop) * timerStack / animationStacks[i]._duration) + prevHeightRangeTop;

      } else if (animationStacks[i]._completed==false  && timerStack > animationStacks[i]._duration) {
        
        // single transformation completed
        animationStacks[i]._completed = true;
        prevBorderRadiusBlack = animationStacks[i]._borderRadiusBlack;
        prevBorderRadiusWhite = animationStacks[i]._borderRadiusWhite;
        prevScaleRangeBottom = animationStacks[i]._scaleRangeBottom;
        prevScaleRangeTop = animationStacks[i]._scaleRangeTop;
        prevStrokeRangeBottom = animationStacks[i]._strokeRangeBottom;
        prevStrokeRangeTop = animationStacks[i]._strokeRangeTop;
        prevHeightRangeBottom = animationStacks[i]._heightRangeBottom;
        prevHeightRangeTop = animationStacks[i]._heightRangeTop;
        animationPrevTimeLimit = millis()+animationStacks[i]._idleCompleted;
        timerStack = 0;
        idleCompleted = animationStacks[i]._idleCompleted;
        println("stop animation "+idleCompleted);
      }
    } else {
      // idle when at end of each transformation
       if (idleCompleted>0 && animationPrevTimeLimit < millis()) {
         idleCompleted=0; 
         println("idle "+animationPrevTimeLimit+" > "+(millis()));
       }
    }
  }
  
  // soundtrack
  //float[] wLeft = subset(waveform.left,0,1);
  //float[] wRight = subset(waveform.right,0,1);
  // audio input
  //float soundLeftS = map(in.left.get(0),-0.1,0.1,0.2,1);
  
  for(int y=0; y<anzahl;y++)
  {
    for(int x=0; x<anzahl;x++)
    {
      signs[permutationsIndex].setSize(50);
      signs[permutationsIndex].setBorderRadiusBlack(borderRadiusBlack);
      signs[permutationsIndex].setBorderRadiusWhite(borderRadiusWhite);
      signs[permutationsIndex].setHeightRange(heightRangeBottom,heightRangeTop);
      signs[permutationsIndex].setScaleRange(scaleRangeBottom,scaleRangeTop);
      signs[permutationsIndex].setStrokeRange(strokeRangeBottom,strokeRangeTop);
      signs[permutationsIndex].setPositionMouse(mouseX,mouseY);
      signs[permutationsIndex].setPosition((int)xStep*x+rand,(int)yStep*y+rand);
      signs[permutationsIndex].draw();
      ++permutationsIndex;
    }
  }
  //println(subset(waveform.left,0,1));
  //waveform.draw();
}

void mousePressed()
{
   for(int i=0; i<animationStacks.length; i++)
  {
    if (i>0) {
      animationStacks[i]._completed=false;
      animationPrevTimeLimit = millis();
        timerStack = 0;
    }
  }
  /**
    mouseStartPos.set(mouseX,mouseY,0);
    mouseEndPos = mouseStartPos.get();
    startPosSet=true;
    endPosSet=false;
  */
}


void keyPressed()
{
  if (key == CODED) {
    if (keyCode == UP) {
      keyMode = 1;
      //println("up");
    } else if (keyCode == DOWN) {
      keyMode = -1;
      //println("down");
    }
    switch(mode) {
        case '2':
        scaleRangeTop+=0.1*keyMode;
        break;
        case '1':
        scaleRangeBottom+=0.1*keyMode;
        break;
        case '4':
        strokeRangeTop+=0.5*keyMode;
        break;
        case '3':
        strokeRangeBottom+=0.5*keyMode;
        break;
        case '6':
        heightRangeTop+=0.5*keyMode;
        break;
        case '5':
        heightRangeBottom+=1*keyMode;
        break;
        case '7':
        borderRadiusBlack+=1*keyMode;
        break;
        case '8':
        borderRadiusWhite+=1*keyMode;
        break;
        case '9':
        mirrorToggle = 1*keyMode;
        break;
      }
  } else {
  
    switch(key)
    {
    case ' ':
      save("permutation_"+hour()+"-"+minute()+"-"+second()+".jpg");
      break;
    default:
      mode = key;
      break;
    }
  
  }
}
Klasse, welche ein einzelnes Zeichen schreibt
class Sign 
{
  int _type; // type of sign (0-6)
  int _rotation; // rotation sign
  int _rotInc; // incrementation of rotation
  float _scaling; // scaling 1 = original size
  
  int _posX; // position x on grid
  int _posY; // position y on grid
  PVector _position = new PVector(); 
  int _size = 75; // initial size of sign
  
  int _mouseX; // position mouse x
  int _mouseY; // position mouse y
  PVector _mousePos = new PVector();
  
  float[] _scaleRange = {3.0,1.0}; // flip range
  float[] _strokeRange = {0.2, 10.0};
  float[] _heightRange = {1.0, 2.0};
  
  float _borderRadiusBlack = 0; // radius for black rectangles
  float _borderRadiusWhite = 0; // radous for white ractangles
  
  // constructor
  Sign(int type) 
  {
    _rotation = type*30;
    _type = type;
    _rotInc = 1; //_type+1;
  }
  
  void setSize(int sizeIni) 
  {
    _size = sizeIni;  // overwrite default rotate incrementation
  }
  void setRotationInc(int rotInc) 
  {
    _rotInc = rotInc;  // overwrite default rotate incrementation
  }
  void setPosition(int posX, int posY) // position of sign
  {
    _posX = posX;
    _posY = posY; 
    _position.set(posX,posY,0);
  }
  void setPositionMouse(int mX, int mY) // mouse position
  {
    _mouseX = mX;
    _mouseY = mY; 
    _mousePos.set(mX,mY,0);
  }
  void setScaleRange(float start, float end)
  {
    _scaleRange[0] = start;
    _scaleRange[1] = end;
  }
  void setStrokeRange(float start, float end)
  {
    _strokeRange[0] = start;
    _strokeRange[1] = end;
  }
  void setHeightRange(float start, float end)
  {
    _heightRange[0] = start;
    _heightRange[1] = end;
  }
  void setBorderRadiusBlack(float radius) 
  {
    _borderRadiusBlack = radius;
  }
  void setBorderRadiusWhite(float radius) 
  {
    _borderRadiusWhite = radius;
  }
  
  
  void draw() 
  {
    // how far is this sign from mouse start point
    PVector dir = PVector.sub(_position,_mousePos);
    float distance = dir.mag(); // distance in px
  
   PVector center = new PVector();
   center.set(_posX,_posY,0);
   
   float angleMouse = atan2(_mousePos.y - center.y, _mousePos.x - center.x);
   
    // scaling depends on distance to mouse pointer
    float _scaling = map(distance,0.0,width,_scaleRange[0],_scaleRange[1]); // 2,1: inverts range -> signs nearest to mous appear the biggest
   if (mirrorToggle<0 && _scaling<0.01) {
     _scaling = 0.01; // only positive numbers allowed 
   }
      
   // rotation speed depends on sign type
   _rotation+=_rotInc;
    
    // stroke width depends on distance to mouse pointer
    float sw = map(distance,0.0,width,_strokeRange[0],_strokeRange[1]);
    if (sw<0) {
        sw*=-1; // only positive numbers allowed
    }
    
    // height range
    float hr = map(distance,0.0,30,_heightRange[0],_heightRange[1]);

    //int b1 = _size;
    pushMatrix();
    translate(_posX,_posY);
    
    scale(_scaling);
    //rotate(radians(_rotation)); //radians(_rotation)
    pushStyle();
      noFill();
      noStroke();
      
      int levels = 6;
      for(int i=0; i<levels; i++) 
      {
        pushMatrix();
        translate(1*(dir.x/hr)*i,1*(dir.y/hr)*i);
        float w = _size-(i*_size/(levels));
        
        fill(0);
        // border radius is scaled for inner rectangles
        bezierRect(-1*w/2,-1*w/2,w,w, _borderRadiusBlack*(w/_size), _borderRadiusBlack*(w/_size));
        
        fill(255);
        bezierRect(-1*(float)(w/2-sw/2),-1*(float)(w/2-sw/2),w-sw,w-sw, _borderRadiusWhite*(w/_size), _borderRadiusWhite*(w/_size));
        
        popMatrix();
      }
    popStyle();
    popMatrix();
  }
  
  
  /**
  @param x  x-coordinate of upper-left
  @param y  y-coordinate of upper-left
  @param w  width of the rectangle
  @param h  height of the rectangle
  @param xr radius to inset x-coordinate corners for bezier controls (may be negative to "outset")
  @param yr radius to inset y-coordinate corners for bezier controls (may be negative to "outset")
  */
  void bezierRect(float x, float y, float w, float h, float xr, float yr) {
    float w2=w/2f, h2=h/2f, cx=x+w2, cy=y+h2;
    /**noFill();
    stroke(0);
    ellipse(cx,cy-h2,10,10);
    ellipse(cx+w2-xr, cy-h2,5,5);
    ellipse(cx+w2, cy-h2+yr,5,5);
    ellipse( cx+w2, cy,10,10);*/
    beginShape();
    vertex(cx,cy-h2);
    bezierVertex(cx+w2-xr, cy-h2, cx+w2, cy-h2+yr, cx+w2, cy);
    bezierVertex(cx+w2, cy+h2-yr, cx+w2-xr, cy+h2, cx, cy+h2);
    bezierVertex(cx-w2+xr, cy+h2, cx-w2, cy+h2-yr, cx-w2, cy);
    bezierVertex(cx-w2, cy-h2+yr, cx-w2+xr, cy-h2, cx, cy-h2);
    endShape();
  }

}
Kleine Klasse, welche das Werteset einer Permutation speichert
/**
 * stores set of values for a specific permutation
 */
class Stacks 
{
  int _duration = 1000; // milliseconds
  int _idleCompleted = 2000; // stop for a moment when transformation ended till next begins
  
  float[] _scaleRange = {3.0,1.0}; // flip range
  float[] _strokeRange = {0.2, 10.0};
  float[] _heightRange = {1.0, 2.0};
  
  float _borderRadiusBlack = 0; // radius for black rectangles
  float _borderRadiusWhite = 0; // radous for white ractangles
  
  boolean _completed = true; // is set on mouse click to false
  
  float _scaleRangeTop;
  float _scaleRangeBottom;
  float _strokeRangeTop;
  float _strokeRangeBottom;
  float _heightRangeTop;
  float _heightRangeBottom;
  
  // constructor
  Stacks()
  {
    
  }
  
  void setDuration(int duration)
  {
    _duration = duration;
  }
  void setScaleRange(float start, float end)
  {
    _scaleRange[0] = start;
    _scaleRange[1] = end;
    _scaleRangeBottom = start;
    _scaleRangeTop = end;
  }
  void setStrokeRange(float start, float end)
  {
    _strokeRange[0] = start;
    _strokeRange[1] = end;
    _strokeRangeBottom = start;
    _strokeRangeTop = end;
  }
  void setHeightRange(float start, float end)
  {
    _heightRange[0] = start;
    _heightRange[1] = end;
    _heightRangeBottom = start;
    _heightRangeTop = end;
  }
  void setBorderRadiusBlack(float radius) 
  {
    _borderRadiusBlack = radius;
  }
  void setBorderRadiusWhite(float radius) 
  {
    _borderRadiusWhite = radius;
  }
  
}