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.

DS6 // 3D L-Systems Visualisation

24. September 2013

Download l_system_tree.zip Screen Shot 2013-09-23 at 7.02.01 PM Screen Shot 2013-09-23 at 6.34.16 PM Screen Shot 2013-09-23 at 6.33.48 PM Screen Shot 2013-09-23 at 5.37.23 PM Download l_system_tree.zip
import controlP5.*;

float xrot = 0;
float yrot = 0;
float zoom = 0;

ControlP5 cp5;
Slider sliderDepth;
Slider sliderAngle;
Slider sliderScale;
Textlabel labelRule;

LTree tree;

int currentDepth = 1;
float currentScale = 1;
float currentAngle = 0;
float targetAngle = currentAngle;

void setup () {
  size(1280,720, P3D);
  colorMode(HSB);
  
  cp5 = new ControlP5(this);
  sliderDepth = cp5.addSlider("L-Depth")
                         .setPosition(30,50)
                         .setSize(100,20)
                         .setValue(3)
                         .setNumberOfTickMarks(7)
                         .setRange(1,7);
  sliderAngle = cp5.addSlider("Angle")
                         .setPosition(0,height-20)
                         .setSize(width,20)
                         .setValue(60)
                         .setRange(-360,360);
  sliderScale = cp5.addSlider("Scale")
                         .setPosition(width-130,50)
                         .setSize(100,20)
                         .setNumberOfTickMarks(50)
                         .setRange(0.1, 5.0)
                         .setValue(1.0);

  currentAngle = sliderAngle.getValue();
  targetAngle = currentAngle;
  currentDepth = (int)sliderDepth.getValue();
  tree = new LTree();
    
  labelRule = cp5.addTextlabel("Rule")
             .setPosition(30,30)
             .setText(tree.getRule(0));
             
  tree.setScale(sliderScale.getValue());
  tree.generate(currentDepth);
}

void draw() {
  if (sliderDepth.getValue() != currentDepth) {
    currentDepth = (int)sliderDepth.getValue();
    tree.generate(currentDepth);
  }
  if (sliderAngle.getValue() != currentAngle) {
    currentAngle = sliderAngle.getValue();
    targetAngle = currentAngle;
    tree.setAngle(currentAngle);
  }
  if (sliderScale.getValue() != currentScale) {
    currentScale = sliderScale.getValue();
    tree.setScale(currentScale);
  }
  
  labelRule.setText(tree.getRule(0));
  
  pushMatrix();

  translate(0,0,zoom);
  background(0);
  translate(width/2,height/2);
  rotateY(radians(xrot));
  rotateX(radians(yrot));
  tree.drawTree();
  popMatrix();
  
}

void mouseDragged () {
  if (mouseButton == RIGHT) {
    zoom += (mouseY-pmouseY);
    println(zoom);
  } else if (mouseButton == LEFT) {
    xrot = xrot + ((float)(mouseX-pmouseX)) / width * 360;
    yrot = yrot + -1 * ((float)(mouseY-pmouseY)) / height * 360;
  } 
}
void keyPressed () {
  if (key == CODED) {
    switch (keyCode) {
      case RIGHT:
        sliderAngle.setValue(constrain(sliderAngle.getValue()+1, sliderAngle.getMin(), sliderAngle.getMax()));
        break;
      case LEFT:
        sliderAngle.setValue(constrain(sliderAngle.getValue()-1,sliderAngle.getMin(),sliderAngle.getMax()));
        break;
    }
  }
}

void keyReleased () {
  // for demo purposes
  if (key == CODED) {
    switch (keyCode) {
      case UP:
        sliderDepth.setValue(constrain(sliderDepth.getValue()+1,sliderDepth.getMin(),sliderDepth.getMax()));
        break;
      case DOWN:
        sliderDepth.setValue(constrain(sliderDepth.getValue()-1,sliderDepth.getMin(),sliderDepth.getMax()));
        break;
    }
  } else {
    switch (key) {
      case '0':
        tree.setRule(0, "F[+F]F[-F]F");
        tree.setAxiom("F");
        tree.generate(currentDepth);
        break;
      case '1':
        tree.setRule(0, "F[+F][-F][aF][zF]");
        tree.setAxiom("F+FaF+FzF+F");
        tree.generate(currentDepth);
        break;
      case '2':
        tree.setRule(0, "+z[+Fzaaz]FF[zaazF+]z+");
        tree.setAxiom("F");
        tree.generate(currentDepth);
        break;
      case '3':
        tree.setRule(0, "F[-zF[zF]]");
        tree.setAxiom("F");
        tree.generate(currentDepth);
        break;
      case '4':
        tree.setRule(0, "F[FF]z+a-a+F[+Fzaaz]");
        tree.setAxiom("F");
        tree.generate(currentDepth);
        break;
      case '5':
        tree.setRule(0, "a+FzFFzF+");
        tree.setAxiom("F");
        tree.generate(currentDepth);
        break;
      case '6':
        tree.setRule(0, "F+z+F");
        tree.setAxiom("F");
        tree.generate(currentDepth);
        break;
      case '7':
        tree.setRule(0, "-F++[aFz]");
        tree.setAxiom("F");
        tree.generate(currentDepth);
        break;
      case '8':
        tree.setRule(0, "-FzF-");
        tree.setAxiom("F");
        tree.generate(currentDepth);
        break;
      case '9':
        tree.setRule(0, "+FaFzFaF+");
        tree.setAxiom("F");
        tree.generate(currentDepth);
        break;
      case 'y':
        sliderScale.setValue(constrain(sliderScale.getValue()-0.1,sliderScale.getMin(),sliderScale.getMax()));
        break;
      case 'x':
        sliderScale.setValue(constrain(sliderScale.getValue()+0.1,sliderScale.getMin(),sliderScale.getMax()));
        break;
    }
    
    /*
    
    +FaFzFaF+
    
    // Some sample rules for the "F"
    // taken from http://web.mit.edu/~eric_r/Public/lsystems/lsys3D12.pde
    
    "Fz-F+F";
    "zF-[F]";
    "F[a+F[z--F]]";
    "FaF-F";
    "+F+aFa-";
    "[F+]FzFz-";
    "[-F+a[F]]";
    "[z]Fz+aFa";
    "aFaaFF+zF";
    "aFF-z";
    "FF[F+F]z+";
    "-F[aF]";
    "a+a+FzF";            //the broken dome
    "FzzFaF+";            //the worm
    "a+F+F+-za";
    "Fz++zF";             //the wheel
    "F-zaF[a+F]";         //Qsplosion
    "-F++[aFz]";          //shaman
    "zFz-F";              //flowerish
    "Fz+FzFF";            //turkey...
    "F[-zF[zF]]";         //a nice tree
    "aFaF[z[+F]]";        //freaky tree
    "F+z+F";              // mandala
    "+FFz[-z-F]";         //thorn bush
    "-FzF-";              //indescribably awesome geometric
    "aF+zF";              // ball of string
    "F[[Fa]+aF]";         //treekazoid
    "F[+F][-F][aF][zF]";  //symmetree
    "[+F]F[zF]";          // yet another tree thing
    "F[+F][--F][aF][zzF]";//asymmetree (awesome)
    "[-aF]FFFa";          //freakstarfishcake
    "FaF-";               //geode ashtray
    "[F-F]FFa";           //star
    "F+FaF-FzF";
    "a+FzFFzF+";          //a 90 d 3 s .5 
    "F[FF]z+a-a+F[+Fzaaz]"; //thornwheel
    
    */
  }
  
}
class LSystem {
  
  protected char[] l_alphabet = {'F', '+', '-', '[', ']'};
  protected String[] l_rules = {"F[+F]F[-F]F", "+", "-", "[", "]"};
  
  protected String l_axiom = "F";
  protected String l_tree = "";
  
  LSystem() {
    
  }
    
  public void generate (int depth) {
    l_tree = l_axiom;
    
    // cache the lengths of each rule
    int[] ruleLengths = new int[l_alphabet.length]; 
    for (int i = 0; i < l_alphabet.length; i++) {
      ruleLengths[i] = l_rules[i].length();
    }
    
    // iterate over the tree - calculate the new tree length and then generate tree from it
      
    for (int i = 0; i < depth; i++) {
      
      int newLength = 0;
      int oldLength = l_tree.length();
      for (int j = 0; j < oldLength; j++) {
        char c = l_tree.charAt(j);
        for (int k = 0; k < l_alphabet.length; k++) {
          if (c == l_alphabet[k]) {
            newLength += ruleLengths[k];
          }
        }
      }
      
      // generate new tree
      StringBuffer newTree = new StringBuffer(newLength);
      
      for (int j = 0; j < oldLength; j++) {
        char c = l_tree.charAt(j);
        for (int k = 0; k < l_alphabet.length; k++) {
          if (c == l_alphabet[k]) {
            newTree.append(l_rules[k]);
            break;
          }
        }
      }
      // save the new tree
      l_tree = newTree.toString();
    }
    println("new tree:" + l_tree);
  }
  
  public String getTree() {
    return l_tree;
  }
  
  public String getRule (int index) {
    if (0 <= index && index < l_rules.length) {
      return l_rules[index];
    }
    return "";
  }
  
  public void reset() {
    l_alphabet = new char [] {'F', '+', '-', '[', ']'};
    l_rules = new String [] {"F[+F]F[-F]F", "+", "-", "[", "]"};
    l_axiom = "F";
  }
  
  public void setAxiom (String newAxiom) {
    l_axiom = newAxiom; // TODO: validate brackets  and chars
  }
  
  public void setAlphabet(char [] newAlphabet) {
    l_alphabet = newAlphabet;
  }
  
  public void setRules(String [] newRules) {
    l_rules = newRules; // TODO: check length?
  }
  
  public void setRule(int index, String rule) {
    if (0 <= index && index < l_rules.length) {
      l_rules[index] = rule;
    }
  }
}
class LTree extends LSystem {
  
  private float t_distance = 50;
  private float t_angle = 60;
  private float t_scaleFactor = .7;

  LTree () {
    setInit();
  }
  
  public void setInit () {
    l_axiom = "F";
    l_alphabet = new char [] {'F', '+', '-', '[', ']', 'z', 'a', 'B', 'C'};
    l_rules = new String [] {"F[+F][-F][aF][zF]", "+", "-", "[", "]", "z", "a", "B", "Ca+F"};
  }

  public void drawTree() {
    for (int i = 0; i<l_tree.length(); i++) {
      switch (l_tree.charAt(i)) {
        case 'F':
        case 'B':
          float newhue = float(i)/l_tree.length()*255;
          fill(color(newhue, 255, 255));
          translate(0,-t_distance/2,0);
          box(t_distance/4,t_distance,t_distance/4);
          translate(0,-t_distance/2,0);
          break;
        case '-':
          rotateX(radians(-t_angle));
          break;
        case '+':
          rotateX(radians(t_angle));
          break;
        case 'z':
          rotateZ(radians(t_angle));
          break;
        case 'a':
          rotateZ(radians(-t_angle));
          break;
        case '[':
          pushMatrix();  
          t_distance = t_distance * t_scaleFactor;  
          break;  
        case ']':
          popMatrix();    
          t_distance = t_distance / t_scaleFactor;
          break;
      }
    }
  }
  
  public void setAngle (float newAngle) {
    t_angle = constrain(newAngle, -360, 360);
  }
  
  public void setScale (float newScale) {
    t_scaleFactor = newScale;
  }
}