LSystem[][] myLSystems = new LSystem[3][3]; int nAppletSize = 600; double nSectionSize = ( (double)nAppletSize / 3.0 ); double nHalfSectionSize = ( (double)nAppletSize / 6.0 ); boolean fred = true; void setup(){ size(600,600); // so p5 can figure the applet size myLSystems[1][1] = new LSystem(nSectionSize + nHalfSectionSize, nSectionSize + nHalfSectionSize, "f[+fL][-fL]", "[+fL][-fL]", PI/10, (int)((double)Math.pow(2,23)*Math.random()), 10000, false); genChildren(); } // setup void genChildren(){ for(int x = 0; x < 3; x++){ for(int y = 0; y < 3; y++){ if(!(x == y && x == 1)){ println("init lsys "+x+","+y); myLSystems[x][y] = new LSystem(x * nSectionSize + nHalfSectionSize, y * nSectionSize + nHalfSectionSize, myLSystems[1][1].getAxiom(), myLSystems[1][1].getTransform(), myLSystems[1][1].getAngle(), myLSystems[1][1].getColor(), myLSystems[1][1].getColorVector(), true); } } } } void loop(){ background(100); int myX = (int)((int)(mouseX / nSectionSize) * nSectionSize); int myY = (int)((int)(mouseY / nSectionSize) * nSectionSize); strokeWeight(1); stroke(150); fill(150); rect(myX,myY,(int)nSectionSize,(int)nSectionSize); stroke(0); for(int x = 0; x < 3; x++){ for(int y = 0; y < 3; y++){ myLSystems[x][y].showYourself(); } } } // loop void mouseReleased(){ int myX = (int)(mouseX / nSectionSize); int myY = (int)(mouseY / nSectionSize); myLSystems[1][1] = new LSystem(nSectionSize + nHalfSectionSize, nSectionSize + nHalfSectionSize, myLSystems[myX][myY].getAxiom(), myLSystems[myX][myY].getTransform(), myLSystems[myX][myY].getAngle(), myLSystems[myX][myY].getColor(), myLSystems[myX][myY].getColorVector(), false); genChildren(); } class LSystem{ private String sAxiom = ""; private String sTransform = ""; private double dAngle = 0.0; private double dX=0, dY=0, dFx=0, dFy=0, dStartX=0, dStartY=0, dStartFx=0, dStartFy=-30; private double dWidth =0, dStartWidth=5; private double dScale = 0.6; private int nStartColor=0, nColor=0, nColorVector=0; private Stack pStack = new Stack(); private Stack vStack = new Stack(); private String sDrawString = ""; private static final double dRatio = 0.6; private static final int nIterations = 2; public LSystem(double dRootX, double dRootY){ // init with some random crap sAxiom = randomString(20); sTransform = randomString(10); dWidth = dStartWidth; dAngle = Math.random() * PI; // setup starting position dStartX = dRootX; dStartY = dRootY; generateDrawString(); } // LSystem public LSystem(double dRootX, double dRootY, String myAxiom, String myTransform, double myAngle, int myColor, int myColorVector, boolean bNoise){ dStartX = dRootX; dStartY = dRootY; dWidth = dStartWidth; sAxiom = myAxiom; sTransform = myTransform; dAngle = myAngle; nStartColor = myColor; nColor= nStartColor; nColorVector = myColorVector; if(bNoise){ addNoise(); } generateDrawString(); } // LSystem private void addNoise(){ dAngle += .4 - (.8 * Math.random()); int nColorAdd = 10000 - (int)(20000 * Math.random()); nColorVector += 1000 - (int)(2000 * Math.random()); if(nColor + nColorAdd > 0 && nColor + nColorAdd < Math.pow(2,23)){ nColor += nColorAdd; } sAxiom = addNoise(sAxiom); sTransform = addNoise(sTransform); } //addNoise private String addNoise(String s){ int d = (int)(4*Math.random()); switch(d){ case 0 : return(s); case 1 : return(addChar(s)); case 2 : return(delChar(s)); case 3 : return(flipChar(s)); } return s; //else leave alone } private String addChar(String s){ println("adding char to " + s); int i = (int)(Math.random() * (double)(s.length()-1)); if(i == 0){ return randomStringChar() + s; } if(i == s.length() - 1){ return s + randomStringChar(); } println(" to become "+s.substring(0,i) + randomStringChar() + s.substring(i+1)); return s.substring(0,i) + randomStringChar() + s.substring(i+1); } private String delChar(String s){ println("killing char from " +s + " "+ s.length()); int i = (int)(Math.random() * (double)(s.length()-1)); println(i); if(i == 0){ return s.substring(1); } if(i == s.length() - 1){ return s.substring(0,s.length()-2); } println(s.substring(0,i)); println(s.substring(i+1)); println(" to become "+s.substring(0,i) + s.substring(i+1)); return s.substring(0,i-1) + s.substring(i+1); } private String flipChar(String s){ println("fliping char in " + s); int i = (int)(Math.random() * (double)(s.length()-1)); if(i == 0){ return randomStringChar() + s.substring(1); } if(i == s.length()-1){ return s.substring(0,s.length()-2) + randomStringChar(); } println(" to become "+s.substring(0,i-1) + randomStringChar() + s.substring(0,i+1)); return s.substring(0,i-1) + randomStringChar() + s.substring(0,i+1); } public String getAxiom(){ return sAxiom; } //getAxiom public String getTransform(){ return sTransform; } public double getAngle(){ return dAngle; } private String randomString(int nUpToLength){ String sToReturn = ""; for(int i = 0; i < (int)(Math.random() * nUpToLength); i++){ sToReturn += randomStringChar(); } return sToReturn; } // randomString private String randomStringChar(){ //FIXME :: f and L have half the probability of the others int n = (int)(Math.random()*6); switch(n){ case 0 : return("f"); case 1 : return("b"); case 2 : return("+"); case 3 : return("-"); case 4 : return("["); case 5 : return("]"); case 6 : return("L"); } return ""; } private int getColor(){ return nStartColor; } private int getColorVector(){ return nColorVector; } private void reset(){ // resets the position etc and the stack dX = dStartX; dY = dStartY; dFx = dStartFx; dFy = dStartFy; nColor = nStartColor; setColor(); pStack = new Stack(); vStack = new Stack(); dWidth = dStartWidth; } private void generateDrawString(){ println(); println(); sDrawString = sAxiom; String sNewDrawString = ""; for(int i = 0; i <= nIterations; i++){ for(int p = 0; p < sDrawString.length() - 1; p++){ if(sDrawString.charAt(p) == 'L'){ sNewDrawString += sTransform; }else{ sNewDrawString += String.valueOf(sDrawString.charAt(p)); } } println(sDrawString); sDrawString = sNewDrawString; sNewDrawString = ""; } //println("axiom is " + sAxiom); //println("transform is " + sTransform); //println("drawstring is " + sDrawString); } // generateDrawString public void showYourself(){ //println("showing"); reset(); for(int i = 0; i < sDrawString.length(); i++){ switch(sDrawString.charAt(i)){ case 'f' : goForward(); break; case 'b' : goBackward(); break; case '+' : turnRight(); break; case '-' : turnLeft(); break; case '[' : pushPos(); break; case ']' : popPos(); break; } } //println("end showing"); } // showYourself private void printState(String msg){ println(msg + " -> " +dX + " " + dY + " : " +dFx + " " + dFy); } private void drawCurrentVec(){ strokeWeight((int)dWidth); line((int)dX,(int)dY,(int)(dX+dFx),(int)(dY+dFy)); } private void goForward(){ drawCurrentVec(); dX += dFx; dY += dFy; //printState("moving fwd"); } private void goBackward(){ drawCurrentVec(); dX -= dFx; dY -= dFy; //printState("moving back"); } private void rotateByAngle(double myAngle){ double oldX = dFx; double oldY = dFy; dFx = Math.cos(myAngle)*oldX - Math.sin(myAngle)*oldY; dFy = Math.sin(myAngle)*oldX + Math.cos(myAngle)*oldY; } private void turnLeft(){ // change this to use pro55ing's rotate and translate one day? // no, we need the stack, which means we need the current heading and position :-/ // and p5 doesn't give us that rotateByAngle(dAngle); //printState("turning left"); } private void turnRight(){ rotateByAngle(-dAngle); //printState("turning right"); } private void setColor(){ //println(nColor+ " "+ new Color(nColor).getRed()); stroke(new Color(nColor).getRed(), new Color(nColor).getGreen(), new Color(nColor).getBlue()); } private void pushPos(){ // push the current position and direction vector onto stacks // also need to scale the length of the draw vector pStack.push((Object)(new java.awt.geom.Point2D.Double(dX,dY))); vStack.push((Object)(new java.awt.geom.Point2D.Double(dFx,dFy))); dFx *= dScale; dFy *= dScale; dWidth *= dScale; if(nColor + nColorVector > 0 && nColor + nColorVector < Math.pow(2,23)){ nColor += nColorVector; setColor(); } //printState("pushing position"); } // push private void popPos(){ //does what it says on the tin //but ignores calls to pop an empty stack coz this is a GA and GA's fuck up if(!pStack.empty()){ java.awt.geom.Point2D.Double p = (java.awt.geom.Point2D.Double)pStack.pop(); java.awt.geom.Point2D.Double v = (java.awt.geom.Point2D.Double)vStack.pop(); dX = p.getX(); dY = p.getY(); dFx = v.getX(); dFy = v.getY(); // dont need to scale up coz the old scale was saved when we pushed dWidth /= dScale; if(nColor - nColorVector > 0 && nColor - nColorVector < Math.pow(2,23)){ nColor -= nColorVector; setColor(); } } //printState("popping position"); } // pop } // LSystem