The python sketch showing importing peasycam library (

*placed in processing.py library, as not as cool as ruby-processing that picks up libraries from regular processing*).

```
1 """
2 hilbert.py by Martin Prout based on a Hilbert curve from "Algorithmic Beauty of Plants"
3 by Przemyslaw Prusinkiewicz & Aristid Lindenmayer
4 Uses a java peasycam library (Jonathan Feinberg), and a python grammar module.
5 Features processing affine transforms.
6 """
7
```**from** math **import** pi
8 **import** processing.opengl
9 **import** peasycam
10 **import** peasy.PeasyCam **as** PeasyCam
11
12 **from** grammar **import** grammar
13
14 # some lsystem constants
15 XPOS **=** 0
16 YPOS **=** 1
17 ANGLE **=** 2
18 BEN **=** pi**/**360 # just a bit of fun set BEN to zero for a regular Hilbert
19 THETA **=** pi**/**2 **+** BEN
20 PHI **=** pi**/**2 **-** BEN
21 ADJUST **=** [0, 0.5, **-**1.5, 3.5, **-**7.5, 15]
22 distance **=** 200
23 depth **=** 3
24
25 RULES **=** {
26 'A'**:** "B>F<CFC<F>D+F-D>F<1+CFC<F<B1^",
27 'B'**:** "A+F-CFB-F-D1->F>D-1>F-B1>FC-F-A1^",
28 'C'**:** "1>D-1>F-B>F<C-F-A1+FA+F-C<F<B-F-D1^",
29 'D'**:** "1>CFB>F<B1>FA+F-A1+FB>F<B1>FC1^"
30 }
31
32 AXIOM **=** 'A'
33
34 **def** render**(**production**)****:**
35 """
36 Render evaluates the production string and calls box primitive
37 uses processing affine transforms (translate/rotate)
38 """
39 **global** distance, depth
40
41 translate**(****-**distance ***** ADJUST[depth], **-**distance ***** ADJUST[depth], **-**distance ***** ADJUST[depth]**)**
42 lightSpecular**(**204, 204, 204**)**
43 specular**(**255, 255, 255**)**
44 shininess**(**1.0**)**
45 repeat **=** 3
46 **for** val **in** production**:**
47 **if** val **=****=** "F"**:**
48 translate**(**0, 0, **-**distance **/** 2 **)**
49 box**(**distance**/** 6, distance**/** 6, distance***** 5**/** 6**)**
50 translate**(**0, 0, **-**distance **/** 2 **)**
51 box**(**distance **/** 6, distance **/** 6, distance **/** 6**)**;
52 **elif** val **=****=** '+'**:**
53 rotateX**(**THETA ***** repeat**)**
54 repeat **=** 1
55 **elif** val **=****=** '-'**:**
56 rotateX**(****-**THETA ***** repeat**)**
57 repeat **=** 1
58 **elif** val **=****=** '>'**:**
59 rotateY**(**THETA ***** repeat**)**
60 repeat **=** 1
61 **elif** val **=****=** '<'**:**
62 rotateY**(****-**THETA ***** repeat**)**
63 **elif** val **=****=** '^'**:**
64 rotateZ**(**PHI ***** repeat**)**
65 repeat **=** 1
66 **elif** **(**val **=****=** '1'**)** **:**
67 repeat **+****=** 1
68 **elif** **(**val **=****=** 'A' **or** val **=****=** 'B' **or** val **=****=** 'C' **or** val **=****=** 'D'**)****:**
69 **pass** # assert as valid grammar and do nothing
70 **else****:**
71 **print****(**"Unknown grammar %s" **%** val**)**
72
73 **def** setup**(****)****:**
74 """
75 The processing setup statement
76 """
77 size**(**500, 500, P3D**)**
78 cam **=** PeasyCam**(**this, 200**)**
79 cam.setMinimumDistance**(**100**)**
80 cam.setMaximumDistance**(**500**)**
81 smooth**(**16**)**
82 **global** production, depth, distance
83 production **=** grammar.repeat**(**depth, AXIOM, RULES**)**
84 distance *******=** 1**/****(****pow****(**2, depth**)** **-** 1**)**
85 noStroke**(****)**
86 fill**(**200, 0, 180**)**
87
88
89
90
91 **def** draw**(****)****:**
92 """
93 Render a 3D Hilbert/Ben Tilbert, somewhat centered
94 """
95 lights**(****)**
96 background**(**255**)**
97 **global** production
98 render**(**production**)**
99

Here is the python lsystems library, which can cope with stochastic grammar (weighted rules) as well a simple rules used here:-

```
1 """
2 grammar.py module by Martin Prout
3 Supports the parsing of both stochastic and non-stochastic rules
4 axiom/rules are evaluated by the produce function, which uses the __weightedRule function
5 to return any stochastic rule according to the input dict, the repeat function is used to repeatedly
6 iterate the rules in a recursive fashion.
7 Example Rules:
8
9 Non-Stochastic = { "A": "A+F", "G": "GG", "X" :"G-G"}
10
11 Stochastic = {"A" : {"BCD": 5, "C+C+C":10, "ACA": 40}, "B" : {"DE-F": 5, "CCC":10, "A[C]A": 40}}
12
13 The Stochastic rule may contain non stochastic elements, in the above example there are two stochastic, elements,
14 with keys "A" and "B". The stochastic rule is detected by checking the 'value' type is dict. The dict needs to of the
15 form "string substitution" as key with the weighting as value. A test function is included for the test conscious or
16 skeptic.
17 """
18
19
```**def** __weightedRule**(**rules**)****:**
20 """
21 A private method used to choose a substitution rule from a dict of rules, according to its
22 weighted probality. 'rules' is expected to be a dict where the substition string is the 'key'
23 and the 'value' is the rule weight
24 """
25 rand **=** random**(**1.0**)**
26 prob **=** 0
27 tot **=** **sum****(**rules.values**(****)****)** # sum probabilities
28 **for** rule **in** rules.keys**(****)****:** # iterate over rule choices
29 prob **+****=** rules.get**(**rule**)** # add assigned probalities
30 **if** **(****(**rand ***** tot**)** **<** prob**)****:** # compare running total with scaled random value
31 **return****(**rule**)**
32
33 **def** produce**(**axiom, rules**)****:**
34 """
35 The single rule substitution utility, that uses type to check for dict or str
36 as key value, else declares 'Unrecognized grammar'. Does not throw exception!!!
37 """
38 str_buf **=** [] # list is much more efficient than premature string concatenation
39
40 **for** i **in** axiom**:**
41 temp **=** rules.get**(**i, i**)**
42 **if** **(****type****(**temp**)** **is** **dict****)****:**
43 str_buf.append**(**__weightedRule**(**temp**)****)**
44 **elif** **(****type****(**temp**)** **is** **str****)****:**
45 str_buf.append**(**temp**)**
46 **else****:**
47 error **=** "Unknown rule type %s\n" **%** **type****(**temp**)**
48 **print****(**error**)**
49 **return** ''.join**(**str_buf**)** # join str_buf list as a single string
50
51
52 **def** repeat**(**rpx, axiom, rules**)****:**
53 """
54 Repeat rule substitution in a recursive fashion rpx times
55 """
56 production **=** axiom
57 **for** i **in** **xrange****(**0, rpx**)****:**
58 production **=** produce**(**production, rules**)**
59 **return** production
60
61 **def** __testWeighting**(**rules, key, total**)****:**
62 """
63 Private test function see module header for examples of rules format
64 Takes a dict containing a stochastic rule with 'key' as key.
65 Tests the weighted rule function a 'total' number of times.
66 Frequency result is printed.
67 """
68 wordList **=** [] # create a big test list of replacement rules
69 **for** z **in** **range****(**0, total**)****:**
70 wordList.append**(**__weightedRule**(**rules.get**(**key**)****)****)**
71
72 # calculate each word frequency in generated list (NB: does not test the
73 # randomness of order though)
74 freqD2 **=** {}
75 **for** word2 **in** wordList**:**
76 freqD2[word2] **=** freqD2.get**(**word2, 0**)** **+** 1
77 keyList **=** freqD2.keys**(****)**
78 keyList.sort**(****)**
79
80 **print** "Frequency of each substitution string in the word list (sorted):"
81 **for** key2 **in** keyList**:**
82 **print** "%-10s %d" **%** **(**key2, freqD2[key2]**)**
83
84 **def** toRuleString**(**axiom, rules**)****:**
85 """
86 Creates a string representing the pythonic rules in a more conventional
87 manner
88 """
89 output **=** "Axiom:\t%s\n" **%** axiom
90 keys **=** rules.keys**(****)**
91 **for** key **in** keys**:**
92 temp **=** rules.get**(**key**)**
93 type_temp **=** **type****(**temp**)**
94 **if** **(**type_temp **is** **dict****)****:**
95 keys2 **=** temp.keys**(****)**
96 **for** key2 **in** keys2**:**
97 output **+****=** "Rule:\t%s => %s\t%d\n" **%** **(**key, key2, temp.get**(**key2**)****)**
98 **elif** **(**type_temp **is** **str****)****:**
99 output **+****=** "Rule:\t%s => %s\n" **%** **(**key, temp**)**
100 **else****:**
101 output **+****=** "Key:\t%s => %s an unknown rule type\n" **%** **(**key, type_temp**)**
102 **return** output
103
104
105

## No comments:

## Post a Comment