Recently I've been looking at Povray, pyprocessing, and cfdg (version 3.0) as tools for creating digital images. I have branched two separate blogs where I mainly explore jruby + processing and processing.py

Thursday, 23 August 2012

Another context sensitive plant for pyprocessing

This sketch re-uses my python csgrammar library, here I have reworked the sketch to use a dictionary of functions (in place of switch or if/else block). Further to make the plant look more realistic, the trunk and branches are truncated cones instead of rods. Also the branch length and diameter are reduced on looping. Full code available at github.
from pyprocessing import *
from math import pi, sin
from lsystems import csgrammar
from lsystems.arcball import ArcBall

myball = None          # needs exposure at module level
THETA = (6.5* pi)/36  #  32.5 degrees in radians
production = None   # needs exposure at module level
distance = 90
repeat = 1
count = 0
scale_factor = [0.55, 0.65, 0.72, 0.75, 0.8,  0.85]
AXIOM = 'F'
IGNORE = '[]+-^&3'
RULES = {
  'F': 'F[-EF[3&A]]E[+F[3^A]]',   # context free rule
  'F<E': 'F[&F[3+A]][^F[3-A]]'    # context sensitive rule 
}
    
def setup():
    """
    processing setup
    """
    size(800, 600)
    global production,  myball
    myball = ArcBall(width/2.0, height/2.0, (width - 20) * 0.5)
    myball.selectAxis(1)
    production = csgrammar.repeat(6, AXIOM, RULES, IGNORE)
    fill(0, 200, 0)
    noStroke()    

def draw():
    """
    Animate a 3D context free plant in processing/pyglet draw loop
    """
    background(20, 20, 180)
    lights()      
    translate(width/2.0, height * 0.8) 
    lightSpecular(204, 204, 204) 
    specular(255, 255, 255) 
    shininess(1.0)  
    update()  
    for val in production:
        evaluate(val)    
    
def __noop():
    pass

def __yawRight():
    global repeat
    rotateX(-THETA * repeat)
    repeat = 1
    
def __yawLeft():
    global repeat
    rotateX(THETA * repeat)
    repeat = 1
    
def __rollRight():
    global repeat
    rotateZ(-THETA * repeat)
    repeat = 1
    
def __rollLeft():
    global repeat
    rotateZ(THETA * repeat)
    repeat = 1
     
def __thriceRepeat():
    global repeat
    repeat = 3

def __pushStack():
    pushMatrix()
    
def __popStack():
    popMatrix()
    
def __drawRod():
    global distance,  count
    sides = 16
    radius1 = distance/6
    radius2 = distance/(6 *  scale_factor[count])
    angle = 0
    angleIncrement = TWO_PI / sides    
    beginShape(QUAD_STRIP)
    for i in range(sides+1):
        normal(cos(angle), 0, sin(angle))        
        vertex(radius2*cos(angle), 0, radius2*sin(angle))
        vertex(radius1*cos(angle), -distance, radius1*sin(angle))
        angle += angleIncrement
    endShape()        
    # draw the spherical top cap
    translate(0, -distance, 0)
    sphereDetail(16)
    sphere(radius1)
    if (count> 0):
        scale(scale_factor[count]);
    if (count< len(scale_factor) - 1):              
        count += 1
    
####
# A dictionary of lsystem operations 
####

lsysOp = {
    '+' : __yawRight,
    '-' : __yawLeft,
    '^' : __rollLeft,
    '&' : __rollRight,
    '3' : __thriceRepeat,
    'F' : __drawRod,
    '[' : __pushStack,
    ']' : __popStack,    
    'A' : __noop,   
    'E' : __noop  
}

def update():
    """
    wrap arcball update and rotation as a local function
    """
    theta,  x,  y,  z = myball.update()
    rotate(theta,  x,  y,  z)    
    
def mousePressed():
    myball.mousePressed(mouse.x, mouse.y)
  
def mouseDragged():
    myball.mouseDragged(mouse.x, mouse.y) 
    
def evaluate(key):
    """
    Is a wrapper controlling access to the dict of functions
    """
    if lsysOp.has_key(key):
        lsysOp[key]()
    else:
        if not RULES.has_key(key):        # useful debugging check you could
            print("Unknown rule {0}".format(key)) # comment out these lines        
run()        
Image produced using pyprocessing takesnapshot utility

Friday, 17 August 2012

Creating 2-D PShape with my LSystems library

  1 /**
  2  * Copyright (c) 2012 Martin Prout
  3  * 
  4  * This demo & library is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2.1 of the License, or (at your option) any later version.
  8  * 
  9  * http://creativecommons.org/licenses/LGPL/2.1/
 10  * 
 11  * This library is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14  * Lesser General Public License for more details.
 15  * 
 16  * You should have received a copy of the GNU Lesser General Public
 17  * License along with this library; if not, write to the Free Software
 18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 19  */
 20 
 21 import lsystem.turtle.Turtle;
 22 import lsystem.Grammar;
 23 import lsystem.SimpleGrammar;
 24 import lsystem.util.LUT;
 25 
 26 /**
 27  * levy.pde  
 28  * (a levy carpet, created by two levy curves use axiom 'FX' for a single curve)
 29  * Demonstrates the use of a Simple Grammar with two 'substitution' rules.
 30  * A CharacterIterator instance used to create the grammar, is re-used to 
 31  * parse the hidden 'production' string.
 32  * lines are 'stored' as a PShape object
 33  * Also features use of my restricted lookup table for sin/cos which takes
 34  * degree input rather than radians (fixed precision of 1 degree), this 
 35  * example however is not improved by use of the lookup table.
 36  */
 37 
 38 final int DELTA = 45; // float only used to match turtle interface
 39 final float REDUCE = 1/sqrt(2);
 40 float drawLength;
 41 float theta;
 42 Grammar grammar;
 43 PShape levy;
 44 
 45 void setup() {
 46   size(600, 600, P2D);
 47   LUT.initialize();  // needed to initialize lookup table
 48   createLSystem();
 49   smooth(8);
 50   translateRules();
 51   background(0);
 52   noLoop();
 53 }
 54 
 55 void draw() {
 56   translate(width/4, height/2);
 57   shape(levy);
 58 }
 59 
 60 void createLSystem() {
 61   int generations = 16;                      // set no of recursions
 62   String axiom = "FX4-FX";  
 63   grammar = new SimpleGrammar(this, axiom);  // initialize library
 64   grammar.addRule('X', "+FX2-FX+");          // add rule
 65   float startLength = 80;
 66   grammar.generateGrammar(generations);
 67   drawLength = startLength * pow(REDUCE, generations);
 68 }
 69 
 70 /**
 71  * Abbreviated form and repeat saves some multiple loops
 72  */
 73 void translateRules() {
 74   int repeat = 1;
 75   Turtle turtle = new Turtle(0, 0, 0);
 76   CharacterIterator it = grammar.getIterator();
 77   levy = createShape(PShape.POLYGON);
 78   levy.noFill();
 79   levy.strokeWeight(2);
 80   levy.stroke(255, 0, 0);
 81   for (char ch = it.first(); ch != CharacterIterator.DONE; ch = it.next()) {
 82     switch (ch) {
 83     case 'F':
 84       drawLine(levy, turtle);
 85       break;
 86     case'+':
 87       turnRight(turtle, repeat);
 88       repeat = 1;
 89       break;
 90     case '-':
 91       turnLeft(turtle, repeat);
 92       repeat = 1;
 93       break;
 94     case 'X': // do nothing
 95       break;
 96     case '2':   // set repeat using char ascii code 
 97     case '4':   // 48 = ascii '0'
 98       repeat = (int)ch - 48;
 99       break;  
100     default:
101       System.err.println("character " + ch + " not in grammar");
102       break;
103     }
104   }
105     levy.end(); // yes we don't want close
106   }
107 
108   void drawLine(PShape levy, Turtle turtle) {
109     levy.vertex(turtle.getX(), turtle.getY());
110     turtle.setX(turtle.getX() + drawLength * LUT.cos(turtle.getTheta()));
111     turtle.setY(turtle.getY() - drawLength * LUT.sin(turtle.getTheta()));
112     levy.vertex(turtle.getX(), turtle.getY());
113   }
114 
115   void turnLeft(Turtle turtle, int rep) {
116     turtle.setTheta(turtle.getTheta() + DELTA * rep);
117   }
118 
119   void turnRight(Turtle turtle, int rep) {
120     turtle.setTheta(turtle.getTheta() - DELTA * rep);
121   }
122 

Monday, 13 August 2012

BenTilbert Processing-2.0 (featuring povwriter2)

Update March 2013 I've switched back to java.net for the processing-2.0 compatible version of my processing library.

Processing 2.0 is coming, and I've re-compiled my LSystem library against the latest version, this sketch doesn't require that (since it is only really needed with the 3DTurtle implementation). Other changes to note is that I've now dropped createGrammar syntax in favour of generateGrammar for version 0.90. The main difference is that createGrammar returned a String (production) whereas generateGrammar returns a void. Access to the production String is via the getIterator() function that now does not require any parameters (previously production String). Here's BenTilbert featuring these changes and export to povray using my povwriter2 library. Update 10th October 2012, lines 50 and 51 are not required in latest revision of code.
   1 import povexport2.*;
   2 import povexport2.povwriter.*;
   3 import lsystem.util.*;
   4 import lsystem.*;
   5 
   6 PovExporter export;
   7 float HALF = PI/360;   // introduce half a degree error
   8 String axiom = "A";
   9 float THETA = HALF_PI + HALF;
  10 float PHI = HALF_PI - HALF;
  11 ArcBall arcball;
  12 Grammar grammar;
  13 boolean record = false;
  14 final float[] ADJUST = {  // adjust center max depth = 5
  15   0.0, 0.5, 1.5, 3.5, 7.5, 15
  16 };
  17 float len = 300;
  18 int depth = 4;   // nice depth for povray (else for processing 3 is good)
  19 
  20 void setup()
  21 {
  22   size(600, 600, P3D);
  23   arcball = new ArcBall(this);
  24   export = new PovExporter(this);
  25   export.chooseTemplate();
  26   export.setPovrayPath("/usr/local/bin/povray"); //use this once to set povray path
  27   // Quality PREVIEW, MEDIUM, HIGH, HIGHEST, GRAYSCALE
  28   export.createIniFile(dataPath("benTilbert.ini"), Quality.HIGHEST);
  29   export.addDeclareOption("TransYP5", "25"); // custom declare,translates Y axis in PovRAY
  30   noStroke();
  31   grammar = new SimpleGrammar(this, axiom);
  32   grammar.addRule('A', "B>F<CFC<F>D+F-D>F<1+CFC<F<B1^");
  33   grammar.addRule('B', "A+F-CFB-F-D1->F>D-1>F-B1>FC-F-A1^");
  34   grammar.addRule('C', "1>D-1>F-B>F<C-F-A1+FA+F-C<F<B-F-D1^");
  35   grammar.addRule('D', "1>CFB>F<B1>FA+F-A1+FB>F<B1>FC1^");
  36   grammar.generateGrammar(depth);
  37   len *= pow(0.5, depth);  // scale hilbert according to depth
  38 }
  39 
  40 void draw() { 
  41   if (export.traced()) { // display traced image
  42     display();
  43   } 
  44   else {
  45     background(50, 50, 150);
  46     lights(); // NB: lights outside export
  47     ambientLight(30, 30, 30); 
  48     directionalLight(60, 60, 60, 0, 0, 1);    
  49     export.beginRaw(dataPath("benTilbert.pov"));
  50     translate(width/2, height/2); 
  51     arcball.update();
  52     export.setHue(Hue.STEEL); // sets fill processing sketch and finish PovRAY
  53     render();
  54     export.endRaw();  //end tracing
  55   }
  56 }
  57 
  58 void render() {
  59   int repeats = 1;
  60   translate(ADJUST[depth]*len, -ADJUST[depth]*len, ADJUST[depth]*len);
  61   CharacterIterator it = grammar.getIterator();
  62   for (char ch = it.first(); ch != CharacterIterator.DONE; ch = it.next()) {
  63     switch (ch) {
  64     case 'F':    
  65       translate(0, 0, -len / 2);
  66       box(5, 5, len - 1.6);     
  67       translate(0, 0, -len / 2);
  68       box(5);
  69       break;
  70     case '+':
  71       rotateX(THETA * repeats);
  72       repeats = 1;
  73       break;
  74     case '-':
  75       rotateX(-THETA * repeats);
  76       repeats = 1;
  77       break; 
  78     case '>':
  79       rotateY(THETA * repeats);
  80       repeats = 1;
  81       break;
  82     case '<':
  83       rotateY(-THETA * repeats);
  84       repeats = 1;
  85       break;
  86     case '^':
  87       rotateZ(PHI * repeats);
  88       repeats = 1;
  89       break;
  90     case '1':
  91       repeats += 1; 
  92     case 'A':
  93     case 'B':
  94     case 'C':
  95     case 'D':
  96       break;
  97     default:
  98       System.err.println("character " + ch + " not in grammar");
  99     }
 100   }
 101 }
 102 
 103 /**
 104  * Display ray traced image in sketch window
 105  */
 106 void display() {
 107   background(loadImage(dataPath("benTilbert.png")));
 108 }
This is the generated povray ini file:-
   1 ; benTilbert.ini
   2 
   3 Input_File_Name=/home/sid/sketchbook/benTilbert/data/benTilbert.pov
   4 Output_File_Name=/home/sid/sketchbook/benTilbert/data/benTilbert.png
   5 Width=600
   6 Height=600
   7 Declare=ASPECT_RATIO=1.0000
   8 Declare=ZDEPTH=173.2050
   9 Quality=11
  10 Display=off
  11 Output_File_Type=N8
  12 Max_Image_Buffer_Memory=516
  13 Antialias=on
  14 Sampling_Method=2
  15 Antialias_Threshold=0.3
  16 Declare=TransYP5=25
And an extract of the generated pov file:-
   1 // Persistence Of Vision Ray Tracer Scene Description File
   2 // File:  Simple Scene <template for povwriter2 version-0.57>
   3 // Vers: 3.7
   4 // Date: July 2012
   5 // Auth: Martin Prout 
   6 
   7 // +w300 +h300
   8 
   9 #version 3.7;
  10 
  11 global_settings{
  12   assumed_gamma 1.0
  13   radiosity{
  14     pretrace_start 0.04
  15     pretrace_end 0.01
  16     count 200
  17     recursion_limit 3
  18     nearest_count 10
  19     error_bound 0.5
  20   }
  21 }
  22 
  23 #include "colors.inc"
  24 #include "skies.inc"
  25 
  26 // --------------- begin declare adjustments to scene -------------------------
  27 
  28 // Default values in case not using ini file or they are not declared there ---
  29 #ifndef (ScaleP5)
  30 #declare ScaleP5 = 1.0;     // scale factor
  31 #end
  32 #ifndef (TransXP5)
  33 #declare TransXP5 = -10;    // translate in X axis
  34 #end
  35 #ifndef (TransYP5)
  36 #declare TransYP5 = 40;    // translate in Y axis
  37 #end
  38 #ifndef (TransZP5)
  39 #declare TransZP5 = -15;    // translate in Z axis
  40 #end
  41 #ifndef (RotYP5)
  42 #declare RotYP5 = 15;       // rotate around Y axis
  43 #end
  44 #ifndef (RotXP5)
  45 #declare RotXP5 = 0;        // rotate around X axis
  46 #end
  47 #ifndef (RotZP5)
  48 #declare RotZP5 = 0;         // rotate around Z axis
  49 #end
  50 // ---------------end of declare adjustments to scene
  51 
  52 //----------------declare default colors
  53 #declare CornellRed = rgb<0.57, 0.025, 0.025>;  // Right wall Cornell Box
  54 #declare CornellGreen = rgb<0.025, 0.236, 0.025>; // Left wall Cornell Box
  55 #declare LineFill = rgb<1.0, 0.9, 0.8>; // polygon outline color
  56 #declare LineCol = rgb<0.3, 0.225, 0.12>; // polygon outline color
  57 #declare TransFill = rgbf<1.0, 0.95, 0.8, 0.7>; // polygon outline color
  58 #declare BuddhaGold = rgb<195, 160, 4>/255; // Custom Gold
  59 //----------------end declare default colors #### paste sketch after this ####
  60 
  61 //----------------begin declare finish
  62 
  63 #declare Finish0=finish{diffuse 0.75 emission 0}  // Stroke
  64 #declare Finish1=finish{diffuse 0.78 emission 0}  // Cornell Box Light Patch
  65 #declare Finish2=finish{emission 0.1 phong 0.5 phong_size 10.0}   // Processing object finish
  66 
  67 //----------------end declare finish
  68 
  69 #declare SWIDTH=0.4; // processing equivalent is stroke width
  70 
  71 //----------------begin declare pigment
  72 
  73 #declare Pigment0 = pigment{rgb<1, 1, 1>}  // Cornell Box Light Patch
  74 
  75 //----------------end declare pigment
  76 
  77 //----------------begin declare texture
  78 
  79 #declare WhiteT=texture{pigment{White} finish{Finish0}} //
  80 #declare RedT=texture{pigment{CornellRed} finish{Finish0}}   // Cornell Box Walls
  81 #declare GreenT=texture{pigment{CornellGreen} finish{Finish0}} //
  82 #declare Texture0=texture{pigment{LineFill} finish{Finish1}} // this is for 'stroke' color
  83 
  84 //----------------end declare texture
  85 
  86 #ifndef (ASPECT_RATIO)
  87 #declare ASPECT_RATIO=1.25;
  88 #end
  89 
  90 //----------------declare scene Settings
  91 #declare camera0 = camera {            // define additional cameras to suit viewing preferences
  92    location <-1.5, 30.0, -150.0>
  93    direction <0.0, 0.0, 2.0>
  94    up  <0.0, 1.0, 0.0>
  95    right <ASPECT_RATIO, 0.0, 0.0>
  96    look_at <0.0, 25.0, 35.0>
  97 }
  98 
  99 #declare light0 = light_source { <100.0, 100.0, -200.0> colour White }
 100 
 101 #declare ground0 = plane { <0.0, 1.0, 0.0>, 0.0  // a reflective ground plane
 102    pigment { NeonBlue }
 103    finish {reflection 0.15}
 104 }
 105 
 106 //------------------end of declare scene settings
 107 
 108 // -----------------set the scene
 109 
 110 camera { camera0 }              // ------------------------------------------
 111                                 //  The use of declared values makes it possible to easily 
 112 light_source{ light0 }          //  change the way the scene is rendered. Just define an
 113                                 //  additional camera say for your template, and do the
 114 sky_sphere{ S_Cloud3 }          //  substitution here. Retain the original definition and
 115                                 //  you can easily backtrack. Definitions can also be saved
 116 plane{ ground0 }                //  as included file see colors.inc for an example.
 117                                 // ---------------------------------------------  
 118 // -----------------end set the scene
 119 
 120 // -----------------processing sketch begins here------------------------
 121 
 122 // ----------------- triangle and line macros -----------------------------------------------------------
 123 
 124 /**
 125 Adjust global triangle mesh here, or at #declare for Finish2, if you change my_hue you will lose color data
 126 from the processing sketch, however as sketch colors are also #declare, you can safely change those declares, 
 127 unless they are used in other parts of processing scene (eg checker color Red, Blue). You can change these 
 128 as well but just remember to hand edit them back to original (this is particularly important for light source)
 129 Note a built in scale to 20% of original sketch size, units in PovRAY are different
 130 */
 131 
 132 #macro my_triangle ( x1, y1, z1, x2, y2, z2, x3, y3, z3, texture0 )  
 133      triangle{<x1 * 0.2,y1 * 0.2,z1 * 0.2>,<x2 * 0.2,y2 * 0.2,z2 * 0.2>,<x3 * 0.2,y3 * 0.2,z3 * 0.2> 
 134      texture{ texture0 } }  
 135 #end 
 136 
 137 /**
 138 Adjust global line properties here, or at #declare for SWIDTH, LineCol, Texture0
 139 Note a built in scale to 50% of original sketch size, units in PovRAY are different
 140 */
 141 
 142 #macro my_line ( x1, y1, z1, x2, y2, z2 )  
 143 blob { threshold 0.65 cylinder { <x1* 0.2 , y1 * 0.2, z1 * 0.2>, <x2 * 0.2, y2* 0.2, z2 * 0.2>, SWIDTH 1 pigment{ LineCol } texture{ Texture0 } } }
 144 #end 
 145 
 146 //------------------ end of macro definitions --------------------------------------
 147 
 148 
 149 
 150 
 151 
 152 // --------------Begin declare colours from sketch
 153 // If empty then sketch colors already colored
 154 // --------------end of declare colours for sketch
 155 
 156 
 157 // --------------processing sketch begins here
 158 
 159 
 160 #include "metals.inc"
 161 #declare Texture1 = texture{ pigment{P_Chrome2} finish{ F_MetalA }} 
 162 union{
 163 my_triangle(-117.87892, -196.33084, 491.2763, -116.20359, -200.97145, 492.08743, -122.260086, -197.54916, 493.35504, Texture1)
 164 my_triangle(-116.20359, -200.97145, 492.08743, -120.58476, -202.18979, 494.16614, -122.260086, -197.54916, 493.35504, Texture1)
 165 my_triangle(-116.20359, -200.97145, 492.08743, -122.14319, -205.79828, 476.73993, -120.58476, -202.18979, 494.16614, Texture1)
 166 my_triangle(-122.14319, -205.79828, 476.73993, -126.52435, -207.0166, 478.81866, -120.58476, -202.18979, 494.16614, Texture1)
 167 my_triangle(-122.14319, -205.79828, 476.73993, -123.81851, -201.15765, 475.92883, -126.52435, -207.0166, 478.81866, Texture1)
 168 my_triangle(-123.81851, -201.15765, 475.92883, -128.19968, -202.37599, 478.00754, -126.52435, -207.0166, 478.81866, Texture1)
 169 my_triangle(-123.81851, -201.15765, 475.92883, -117.87892, -196.33084, 491.2763, -128.19968, -202.37599, 478.00754, Texture1)
 170 my_triangle(-117.87892, -196.33084, 491.2763, -122.260086, -197.54916, 493.35504, -128.19968, -202.37599, 478.00754, Texture1)
 171 my_triangle(-123.81851, -201.15765, 475.92883, -122.14319, -205.79828, 476.73993, -117.87892, -196.33084, 491.2763, Texture1)
 172 my_triangle(-122.14319, -205.79828, 476.73993, -116.20359, -200.97145, 492.08743, -117.87892, -196.33084, 491.2763, Texture1)
 173 my_triangle(-122.260086, -197.54916, 493.35504, -120.58476, -202.18979, 494.16614, -128.19968, -202.37599, 478.00754, Texture1)
 174 my_triangle(-120.58476, -202.18979, 494.16614, -126.52435, -207.0166, 478.81866, -128.19968, -202.37599, 478.00754, Texture1)
 175 ...
 176 ...
 177 ...
 178 // -----------------------------End of processing scene
 179 // -----------------------------Adjust the processing scene
 180 translate<TransXP5, TransYP5, TransZP5>
 181 rotate<RotXP5, RotYP5, RotZP5>
 182 scale<ScaleP5, ScaleP5, ScaleP5>
 183 }
Here is the genereated image:-

Followers

Blog Archive

About Me

My photo
Pembrokeshire, United Kingdom
I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2