cf3 0.0.4 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +2 -0
  3. data/{CHANGELOG → CHANGELOG.md} +13 -0
  4. data/Gemfile +1 -1
  5. data/README.md +21 -21
  6. data/Rakefile +7 -3
  7. data/bin/cf3samples +4 -4
  8. data/cf3ruby.gemspec +12 -13
  9. data/docs/.sass-cache/cd612fe6616e7f514a2421dc73159618de35b85d/jekyll-theme-cayman.scssc +0 -0
  10. data/docs/.sass-cache/cd612fe6616e7f514a2421dc73159618de35b85d/normalize.scssc +0 -0
  11. data/docs/.sass-cache/cd612fe6616e7f514a2421dc73159618de35b85d/rouge-github.scssc +0 -0
  12. data/docs/.sass-cache/cd612fe6616e7f514a2421dc73159618de35b85d/variables.scssc +0 -0
  13. data/docs/README.md +1 -0
  14. data/docs/_config.yml +31 -0
  15. data/docs/_site/README.md +1 -0
  16. data/docs/_site/about/index.html +52 -0
  17. data/docs/_site/assets/css/style.css +809 -0
  18. data/docs/_site/assets/y.png +0 -0
  19. data/docs/_site/example/index.html +113 -0
  20. data/docs/_site/favicon.ico +0 -0
  21. data/docs/_site/feed.xml +10 -0
  22. data/docs/_site/index.html +51 -0
  23. data/docs/_site/robots.txt +1 -0
  24. data/docs/_site/sitemap.xml +12 -0
  25. data/docs/about.md +14 -0
  26. data/docs/assets/y.png +0 -0
  27. data/docs/example.md +73 -0
  28. data/docs/favicon.ico +0 -0
  29. data/docs/index.md +10 -0
  30. data/lib/cf3/version.rb +1 -1
  31. data/lib/cf3.rb +85 -100
  32. data/samples/Rakefile +30 -0
  33. data/samples/accident.rb +34 -30
  34. data/samples/alhambra.rb +32 -29
  35. data/samples/bar_code.rb +26 -22
  36. data/samples/city.rb +14 -11
  37. data/samples/creature.rb +10 -6
  38. data/samples/dark_star.rb +5 -3
  39. data/samples/data/java_args.txt +1 -2
  40. data/samples/dragon.rb +8 -4
  41. data/samples/escher.rb +115 -116
  42. data/samples/fern.rb +13 -9
  43. data/samples/hex_tube.rb +16 -13
  44. data/samples/isosceles.rb +16 -11
  45. data/samples/levy.rb +5 -2
  46. data/samples/pcr.rb +28 -24
  47. data/samples/rubystar.rb +23 -17
  48. data/samples/sierpinski.rb +15 -11
  49. data/samples/spiral.rb +14 -10
  50. data/samples/star.rb +10 -6
  51. data/samples/tree.rb +20 -17
  52. data/samples/tree4.rb +12 -8
  53. data/samples/vine.rb +11 -7
  54. data/samples/xcross.rb +10 -7
  55. data/samples/y.rb +13 -9
  56. data/test/test_cf3.rb +11 -7
  57. metadata +50 -42
Binary file
@@ -0,0 +1,113 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en-US">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+
6
+ <!-- Begin Jekyll SEO tag v2.4.0 -->
7
+ <title>A simple example with weighted shapes | ContextFreeArt gem for JRubyArt</title>
8
+ <meta name="generator" content="Jekyll v3.7.2" />
9
+ <meta property="og:title" content="A simple example with weighted shapes" />
10
+ <meta property="og:locale" content="en_US" />
11
+ <meta name="description" content="The cf3ruby gem is a kind of ruby DSL for contextfreeart. It is just a toy really see https://www.contextfreeart.org/ for original." />
12
+ <meta property="og:description" content="The cf3ruby gem is a kind of ruby DSL for contextfreeart. It is just a toy really see https://www.contextfreeart.org/ for original." />
13
+ <link rel="canonical" href="http://localhost:4000/example/" />
14
+ <meta property="og:url" content="http://localhost:4000/example/" />
15
+ <meta property="og:site_name" content="ContextFreeArt gem for JRubyArt" />
16
+ <script type="application/ld+json">
17
+ {"description":"The cf3ruby gem is a kind of ruby DSL for contextfreeart. It is just a toy really see https://www.contextfreeart.org/ for original.","@type":"WebPage","url":"http://localhost:4000/example/","headline":"A simple example with weighted shapes","@context":"http://schema.org"}</script>
18
+ <!-- End Jekyll SEO tag -->
19
+
20
+ <meta name="description" content="The cf3ruby gem is a kind of ruby DSL for contextfreeart. It is just a toy really see https://www.contextfreeart.org/ for original.
21
+ "/>
22
+ <meta name="viewport" content="width=device-width, initial-scale=1">
23
+ <meta name="theme-color" content="#157878">
24
+ <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
25
+ <link rel="stylesheet" href="/assets/css/style.css?v=">
26
+ </head>
27
+ <body>
28
+ <section class="page-header">
29
+ <h1 class="project-name">ContextFreeArt gem for JRubyArt</h1>
30
+ <h2 class="project-tagline">The cf3ruby gem is a kind of ruby DSL for contextfreeart. It is just a toy really see https://www.contextfreeart.org/ for original.
31
+ </h2>
32
+
33
+
34
+ </section>
35
+
36
+ <section class="main-content">
37
+ <div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># city.rb after city.cfdg</span>
38
+
39
+ <span class="nb">require</span> <span class="s1">'cf3'</span>
40
+
41
+ <span class="k">def</span> <span class="nf">setup_the_city</span>
42
+ <span class="vi">@city</span> <span class="o">=</span> <span class="no">ContextFree</span><span class="p">.</span><span class="nf">define</span> <span class="k">do</span>
43
+
44
+ <span class="n">shape</span> <span class="ss">:neighborhood</span> <span class="k">do</span>
45
+ <span class="nb">split</span> <span class="k">do</span>
46
+ <span class="n">block</span> <span class="ss">x: </span><span class="o">-</span><span class="mf">0.25</span><span class="p">,</span> <span class="ss">y: </span><span class="o">-</span><span class="mf">0.25</span>
47
+ <span class="n">rewind</span>
48
+ <span class="n">block</span> <span class="ss">x: </span><span class="mf">0.25</span><span class="p">,</span> <span class="ss">y: </span><span class="o">-</span><span class="mf">0.25</span>
49
+ <span class="n">rewind</span>
50
+ <span class="n">block</span> <span class="ss">x: </span><span class="mf">0.25</span><span class="p">,</span> <span class="ss">y: </span><span class="mf">0.25</span>
51
+ <span class="n">rewind</span>
52
+ <span class="n">block</span> <span class="ss">x: </span><span class="o">-</span><span class="mf">0.25</span><span class="p">,</span> <span class="ss">y: </span><span class="mf">0.25</span>
53
+ <span class="k">end</span>
54
+ <span class="k">end</span>
55
+
56
+ <span class="n">shape</span> <span class="ss">:block</span> <span class="k">do</span>
57
+ <span class="n">buildings</span> <span class="ss">size: </span><span class="mf">0.85</span>
58
+ <span class="k">end</span>
59
+
60
+ <span class="n">shape</span> <span class="ss">:block</span><span class="p">,</span> <span class="mi">5</span> <span class="k">do</span>
61
+ <span class="n">neighborhood</span> <span class="ss">size: </span><span class="mf">0.5</span><span class="p">,</span> <span class="ss">rotation: </span><span class="nb">rand</span><span class="p">(</span><span class="o">-</span><span class="no">PI</span><span class="o">..</span><span class="no">PI</span><span class="p">),</span> <span class="ss">hue: </span><span class="nb">rand</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="ss">brightness: </span><span class="nb">rand</span><span class="p">(</span><span class="mf">0.75</span><span class="o">..</span><span class="mf">1.75</span><span class="p">)</span>
62
+ <span class="k">end</span>
63
+
64
+ <span class="n">shape</span> <span class="ss">:block</span><span class="p">,</span> <span class="mf">0.1</span> <span class="k">do</span>
65
+ <span class="c1"># Do nothing</span>
66
+ <span class="k">end</span>
67
+
68
+ <span class="n">shape</span> <span class="ss">:buildings</span> <span class="k">do</span>
69
+ <span class="n">square</span>
70
+ <span class="k">end</span>
71
+
72
+ <span class="k">end</span>
73
+ <span class="k">end</span>
74
+
75
+ <span class="k">def</span> <span class="nf">settings</span>
76
+ <span class="n">size</span> <span class="mi">600</span><span class="p">,</span> <span class="mi">600</span>
77
+ <span class="k">end</span>
78
+
79
+ <span class="k">def</span> <span class="nf">setup</span>
80
+ <span class="n">sketch_title</span> <span class="s1">'City'</span>
81
+ <span class="n">setup_the_city</span>
82
+ <span class="vi">@background</span> <span class="o">=</span> <span class="n">color</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">255</span>
83
+ <span class="n">draw_it</span>
84
+ <span class="k">end</span>
85
+
86
+ <span class="k">def</span> <span class="nf">draw</span>
87
+ <span class="c1"># Do nothing</span>
88
+ <span class="k">end</span>
89
+
90
+ <span class="k">def</span> <span class="nf">draw_it</span>
91
+ <span class="n">background</span> <span class="vi">@background</span>
92
+ <span class="vi">@city</span><span class="p">.</span><span class="nf">render</span> <span class="ss">:neighborhood</span><span class="p">,</span>
93
+ <span class="ss">start_x: </span><span class="n">width</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span> <span class="ss">start_y: </span><span class="n">height</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span>
94
+ <span class="ss">size: </span><span class="n">height</span><span class="o">/</span><span class="mf">2.5</span><span class="p">,</span> <span class="ss">color: </span><span class="p">[</span><span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">]</span>
95
+ <span class="k">end</span>
96
+
97
+ <span class="k">def</span> <span class="nf">mouse_clicked</span>
98
+ <span class="n">draw_it</span>
99
+ <span class="k">end</span>
100
+
101
+
102
+ </code></pre></div></div>
103
+
104
+
105
+ <footer class="site-footer">
106
+
107
+ <span class="site-footer-credits">This page was generated by <a href="https://pages.github.com">GitHub Pages</a>.</span>
108
+ </footer>
109
+ </section>
110
+
111
+
112
+ </body>
113
+ </html>
Binary file
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <feed xmlns="http://www.w3.org/2005/Atom">
3
+ <generator uri="http://jekyllrb.com" version="3.7.2">Jekyll</generator>
4
+ <link href="http://localhost:4000/feed.xml" rel="self" type="application/atom+xml" />
5
+ <link href="http://localhost:4000/" rel="alternate" type="text/html" />
6
+ <updated>2018-02-13T19:38:01+00:00</updated>
7
+ <id>http://localhost:4000/</id>
8
+ <subtitle>The cf3ruby gem is a kind of ruby DSL for contextfreeart. It is just a toy really see https://www.contextfreeart.org/ for original.
9
+ </subtitle>
10
+ </feed>
@@ -0,0 +1,51 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en-US">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+
6
+ <!-- Begin Jekyll SEO tag v2.4.0 -->
7
+ <title>Welcome to cf3ruby gem website | ContextFreeArt gem for JRubyArt</title>
8
+ <meta name="generator" content="Jekyll v3.7.2" />
9
+ <meta property="og:title" content="Welcome to cf3ruby gem website" />
10
+ <meta property="og:locale" content="en_US" />
11
+ <meta name="description" content="The cf3ruby gem is a kind of ruby DSL for contextfreeart. It is just a toy really see https://www.contextfreeart.org/ for original." />
12
+ <meta property="og:description" content="The cf3ruby gem is a kind of ruby DSL for contextfreeart. It is just a toy really see https://www.contextfreeart.org/ for original." />
13
+ <link rel="canonical" href="http://localhost:4000/" />
14
+ <meta property="og:url" content="http://localhost:4000/" />
15
+ <meta property="og:site_name" content="ContextFreeArt gem for JRubyArt" />
16
+ <script type="application/ld+json">
17
+ {"name":"ContextFreeArt gem for JRubyArt","description":"The cf3ruby gem is a kind of ruby DSL for contextfreeart. It is just a toy really see https://www.contextfreeart.org/ for original.","@type":"WebSite","url":"http://localhost:4000/","headline":"Welcome to cf3ruby gem website","@context":"http://schema.org"}</script>
18
+ <!-- End Jekyll SEO tag -->
19
+
20
+ <meta name="description" content="The cf3ruby gem is a kind of ruby DSL for contextfreeart. It is just a toy really see https://www.contextfreeart.org/ for original.
21
+ "/>
22
+ <meta name="viewport" content="width=device-width, initial-scale=1">
23
+ <meta name="theme-color" content="#157878">
24
+ <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
25
+ <link rel="stylesheet" href="/assets/css/style.css?v=">
26
+ </head>
27
+ <body>
28
+ <section class="page-header">
29
+ <h1 class="project-name">ContextFreeArt gem for JRubyArt</h1>
30
+ <h2 class="project-tagline">The cf3ruby gem is a kind of ruby DSL for contextfreeart. It is just a toy really see https://www.contextfreeart.org/ for original.
31
+ </h2>
32
+
33
+
34
+ </section>
35
+
36
+ <section class="main-content">
37
+ <h3 id="example-output">Example output</h3>
38
+ <p><a href="/about">About</a> <a href="/example">Example</a></p>
39
+
40
+ <p><img src="/assets/y.png" alt="y.png" /></p>
41
+
42
+
43
+ <footer class="site-footer">
44
+
45
+ <span class="site-footer-credits">This page was generated by <a href="https://pages.github.com">GitHub Pages</a>.</span>
46
+ </footer>
47
+ </section>
48
+
49
+
50
+ </body>
51
+ </html>
@@ -0,0 +1 @@
1
+ Sitemap: http://localhost:4000/sitemap.xml
@@ -0,0 +1,12 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3
+ <url>
4
+ <loc>http://localhost:4000/about/</loc>
5
+ </url>
6
+ <url>
7
+ <loc>http://localhost:4000/example/</loc>
8
+ </url>
9
+ <url>
10
+ <loc>http://localhost:4000/</loc>
11
+ </url>
12
+ </urlset>
data/docs/about.md ADDED
@@ -0,0 +1,14 @@
1
+ ---
2
+ layout: default
3
+ title: Welcome to cf3ruby gem website
4
+ permalink: /about/
5
+ categories: jruby_art contextfreeart
6
+ ---
7
+ The inspiration for cf3ruby is [contextfreeart][] and the jashkenas [original][], so what is context free art?
8
+
9
+ Chris Coyne created a small language for design grammars called CFDG. These grammars are sets of non-deterministic rules to produce images. The images are surprisingly beautiful, often from very simple grammars.
10
+ In the original version there were 3 terminals of a TRIANGLE, SQUARE and CIRCLE see cfdg [how_to][].
11
+
12
+ [contextfreeart]:http://www.contextfreeart.org/
13
+ [original]:https://github.com/jashkenas/context_free
14
+ [how_to]:http://www.contextfreeart.org/mediawiki/index.php/CFDG_HOWTO
data/docs/assets/y.png ADDED
Binary file
data/docs/example.md ADDED
@@ -0,0 +1,73 @@
1
+ ---
2
+ layout: default
3
+ title: A simple example with weighted shapes
4
+ permalink: /example/
5
+ categories: jruby_art contextfreeart
6
+ ---
7
+ ```ruby
8
+ # city.rb after city.cfdg
9
+
10
+ require 'cf3'
11
+
12
+ def setup_the_city
13
+ @city = ContextFree.define do
14
+
15
+ shape :neighborhood do
16
+ split do
17
+ block x: -0.25, y: -0.25
18
+ rewind
19
+ block x: 0.25, y: -0.25
20
+ rewind
21
+ block x: 0.25, y: 0.25
22
+ rewind
23
+ block x: -0.25, y: 0.25
24
+ end
25
+ end
26
+
27
+ shape :block do
28
+ buildings size: 0.85
29
+ end
30
+
31
+ shape :block, 5 do
32
+ neighborhood size: 0.5, rotation: rand(-PI..PI), hue: rand(2), brightness: rand(0.75..1.75)
33
+ end
34
+
35
+ shape :block, 0.1 do
36
+ # Do nothing
37
+ end
38
+
39
+ shape :buildings do
40
+ square
41
+ end
42
+
43
+ end
44
+ end
45
+
46
+ def settings
47
+ size 600, 600
48
+ end
49
+
50
+ def setup
51
+ sketch_title 'City'
52
+ setup_the_city
53
+ @background = color 255, 255, 255
54
+ draw_it
55
+ end
56
+
57
+ def draw
58
+ # Do nothing
59
+ end
60
+
61
+ def draw_it
62
+ background @background
63
+ @city.render :neighborhood,
64
+ start_x: width/2, start_y: height/2,
65
+ size: height/2.5, color: [0.1, 0.1, 0.1]
66
+ end
67
+
68
+ def mouse_clicked
69
+ draw_it
70
+ end
71
+
72
+
73
+ ```
data/docs/favicon.ico ADDED
Binary file
data/docs/index.md ADDED
@@ -0,0 +1,10 @@
1
+ ---
2
+ layout: default
3
+ title: Welcome to cf3ruby gem website
4
+ categories: jruby_art contextfreeart
5
+ ---
6
+
7
+ ### Example output
8
+ [About]({{ site.github.url }}/about) [Example]({{ site.github.url }}/example) [Wiki](https://github.com/monkstone/cf3ruby/wiki)
9
+
10
+ ![y.png]({{ site.github.url }}/assets/y.png)
data/lib/cf3/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Cf3
2
- VERSION = "0.0.4"
2
+ VERSION = '1.2.0'
3
3
  end
data/lib/cf3.rb CHANGED
@@ -1,42 +1,37 @@
1
- # A Context-Free library for Ruby-Processing, inspired by
2
- # based on context_free.rb by Jeremy Ashkenas. Which in turn
3
- # was inspired by contextfreeart.org
4
-
5
1
  module Processing
6
-
2
+ # A Context-Free library for JRubyArt, inspired by and
3
+ # based on context_free.rb by Jeremy Ashkenas. That in turn
4
+ # was inspired by contextfreeart.org
7
5
  class ContextFree
8
-
9
6
  include Processing::Proxy
10
-
11
7
  attr_accessor :rule, :app, :width, :height
12
8
 
13
- AVAILABLE_OPTIONS = [:x, :y, :w, :h, :rotation, :size, :flip, :color, :hue, :saturation, :brightness, :alpha]
14
- HSB_ORDER = {hue: 0, saturation: 1, brightness: 2, alpha: 3}
15
- TRIANGLE_TOP = -1 / Math.sqrt(3)
16
- TRIANGLE_BOTTOM = Math.sqrt(3) / 6
9
+ AVAILABLE_OPTIONS = %i[
10
+ x y w h rotation size flip color hue saturation brightness alpha
11
+ ].freeze
12
+ HSB_ORDER = { hue: 0, saturation: 1, brightness: 2, alpha: 3 }.freeze
13
+ TRIANGLE_TOP = -1 / Math.sqrt(3)
14
+ TRIANGLE_BOTTOM = Math.sqrt(3) / 6
17
15
  RADIANS = (Math::PI / 180.0)
18
16
  # Define a context-free system. Use this method to create a ContextFree
19
17
  # object. Call render() on it to make it draw.
20
18
  def self.define(&block)
21
19
  cf = ContextFree.new
22
- cf.instance_eval &block
20
+ cf.instance_eval(&block)
23
21
  cf
24
22
  end
25
23
 
26
-
27
24
  # Initialize a bare ContextFree object with empty recursion stacks.
28
25
  def initialize
29
- @app = $app
30
- @graphics = $app.g
31
- @width = $app.width
32
- @height = $app.height
33
- @finished = false
26
+ @app = Processing.app
27
+ @graphics = @app.g
28
+ @width = @app.width
29
+ @height = @app.height
34
30
  @rules = {}
35
31
  @rewind_stack = []
36
32
  @matrix_stack = []
37
33
  end
38
34
 
39
-
40
35
  # Create an accessor for the current value of every option. We use a values
41
36
  # object so that all the state can be saved and restored as a unit.
42
37
  AVAILABLE_OPTIONS.each do |option_name|
@@ -45,66 +40,64 @@ module Processing
45
40
  end
46
41
  end
47
42
 
48
-
49
43
  # Here's the first serious method: A Rule has an
50
44
  # identifying name, a probability, and is associated with
51
45
  # a block of code. These code blocks are saved, and indexed
52
46
  # by name in a hash, to be run later, when needed.
53
47
  # The method then dynamically defines a method of the same
54
48
  # name here, in order to determine which rule to run.
55
- def shape(rule_name, prob=1, &proc)
56
- @rules[rule_name] ||= {procs: [], total: 0}
49
+ def shape(rule_name, prob = 1, &proc)
50
+ @rules[rule_name] ||= { procs: [], total: 0 }
57
51
  total = @rules[rule_name][:total]
58
- @rules[rule_name][:procs] << [(total...(prob+total)), proc]
52
+ @rules[rule_name][:procs] << [(total...(prob + total)), proc]
59
53
  @rules[rule_name][:total] += prob
60
- unless ContextFree.method_defined? rule_name
61
- self.class.class_eval do
62
- eval <<-METH
63
- def #{rule_name}(options)
64
- merge_options(@values, options)
65
- pick = determine_rule(#{rule_name.inspect})
66
- @finished = true if @values[:size] < @values[:stop_size]
67
- unless @finished
68
- get_ready_to_draw
69
- pick[1].call(options)
70
- end
71
- end
72
- METH
54
+ return if ContextFree.method_defined? rule_name
55
+
56
+ instance_eval do
57
+ eval <<-METH
58
+ def #{rule_name}(options)
59
+ merge_options(@values, options)
60
+ pick = determine_rule(#{rule_name.inspect})
61
+ return if (@values[:size] - @values[:stop_size]) < 0
62
+ prepare_to_draw
63
+ pick[1].call(options)
73
64
  end
65
+ METH
74
66
  end
75
67
  end
76
68
 
77
-
78
69
  # Rule choice is random, based on the assigned probabilities.
79
70
  def determine_rule(rule_name)
80
71
  rule = @rules[rule_name]
81
- chance = rand * rule[:total]
82
- pick = @rules[rule_name][:procs].select {|the_proc| the_proc[0].include?(chance) }
83
- return pick.flatten
72
+ chance = rand(0.0..rule[:total])
73
+ @rules[rule_name][:procs].select do |the_proc|
74
+ the_proc[0].include?(chance)
75
+ end.flatten
84
76
  end
85
77
 
86
-
87
78
  # At each step of the way, any of the options may change, slightly.
88
79
  # Many of them have different strategies for being merged.
89
80
  def merge_options(old_ops, new_ops)
90
81
  return unless new_ops
82
+
91
83
  # Do size first
92
- old_ops[:size] *= new_ops[:size] if new_ops[:size]
84
+ old_ops[:size] *= new_ops.fetch(:size, 1.0)
93
85
  new_ops.each do |key, value|
94
86
  case key
95
- when :size
87
+ # when :size
96
88
  when :x, :y
97
- old_ops[key] = value * old_ops[:size]
89
+ old_ops[key] = value * old_ops.fetch(:size, 1.0)
98
90
  when :rotation
99
91
  old_ops[key] = value * RADIANS
100
92
  when :hue, :saturation, :brightness, :alpha
101
93
  adjusted = old_ops[:color].dup
102
- adjusted[HSB_ORDER[key]] *= value
94
+ adjusted[HSB_ORDER[key]] *= value unless key == :hue
95
+ adjusted[HSB_ORDER[key]] += value if key == :hue
103
96
  old_ops[:color] = adjusted
104
97
  when :flip
105
98
  old_ops[key] = !old_ops[key]
106
99
  when :w, :h
107
- old_ops[key] = value * old_ops[:size]
100
+ old_ops[key] = value * old_ops.fetch(:size, 1.0)
108
101
  when :color
109
102
  old_ops[key] = value
110
103
  else # Used a key that we don't know about or trying to set
@@ -113,133 +106,125 @@ module Processing
113
106
  end
114
107
  end
115
108
 
116
-
117
109
  # Using an unknown key let's you set arbitrary values,
118
110
  # to keep track of for your own ends.
119
111
  def merge_unknown_key(key, value, old_ops)
120
112
  key_s = key.to_s
121
- if key_s.match(/^set/)
122
- key_sym = key_s.sub('set_', '').to_sym
123
- if key_s.match(/(brightness|hue|saturation)/)
124
- adjusted = old_ops[:color].dup
125
- adjusted[HSB_ORDER[key_sym]] = value
126
- old_ops[:color] = adjusted
127
- else
128
- old_ops[key_sym] = value
129
- end
113
+ return unless key_s =~ /^set/
114
+ key_sym = key_s.sub('set_', '').to_sym
115
+ if key_s =~ /(brightness|hue|saturation)/
116
+ adjusted = old_ops[:color].dup
117
+ adjusted[HSB_ORDER[key_sym]] = value
118
+ old_ops[:color] = adjusted
119
+ else
120
+ old_ops[key_sym] = value
130
121
  end
131
122
  end
132
123
 
133
-
134
124
  # Doing a 'split' saves the context, and proceeds from there,
135
125
  # allowing you to rewind to where you split from at any moment.
136
- def split(options=nil, &block)
126
+ def split(options = nil)
137
127
  save_context
138
128
  merge_options(@values, options) if options
139
129
  yield
140
130
  restore_context
141
131
  end
142
132
 
143
-
144
133
  # Saving the context means the values plus the coordinate matrix.
145
134
  def save_context
146
135
  @rewind_stack.push @values.dup
147
136
  @matrix_stack << @graphics.get_matrix
148
137
  end
149
138
 
150
-
151
139
  # Restore the values and the coordinate matrix as the recursion unwinds.
152
140
  def restore_context
153
141
  @values = @rewind_stack.pop
154
142
  @graphics.set_matrix @matrix_stack.pop
155
143
  end
156
144
 
157
-
158
145
  # Rewinding goes back one step.
159
146
  def rewind
160
- @finished = false
161
147
  restore_context
162
148
  save_context
163
149
  end
164
150
 
165
-
166
151
  # Render the is method that kicks it all off, initializing the options
167
152
  # and calling the first rule.
168
- def render(rule_name, starting_values={})
169
- @values = {x: 0, y: 0,
170
- rotation: 0, flip: false,
171
- size: 20, w: nil, h: nil,
172
- start_x: width/2, start_y: height/2,
173
- color: [180, 0.5, 0.5, 1],
174
- stop_size: 1.5}
153
+ def render(rule_name, starting_values = {})
154
+ @values = defaults
175
155
  @values.merge!(starting_values)
176
- @finished = false
177
156
  @app.reset_matrix
178
157
  @app.rect_mode CENTER
179
158
  @app.ellipse_mode CENTER
180
159
  @app.no_stroke
181
- @app.color_mode HSB, 360, 1.0, 1.0, 1.0 # match cfdg
182
- @app.translate @values[:start_x], @values[:start_y]
183
- self.send(rule_name, {})
160
+ @app.color_mode HSB, 360, 1.0, 1.0, 1.0 # match cfdg
161
+ @app.translate @values.fetch(:start_x, 0), @values.fetch(:start_y, 0)
162
+ send(rule_name, {})
184
163
  end
185
164
 
165
+ def defaults
166
+ {
167
+ x: 0,
168
+ y: 0,
169
+ rotation: 0,
170
+ flip: false,
171
+ size: 20,
172
+ start_x: width / 2,
173
+ start_y: height / 2,
174
+ color: [180, 0.5, 0.5, 1],
175
+ stop_size: 1.5
176
+ }
177
+ end
186
178
 
187
179
  # Before actually drawing the next step, we need to move to the appropriate
188
180
  # location.
189
- def get_ready_to_draw
190
- @app.translate(@values[:x], @values[:y])
181
+ def prepare_to_draw
182
+ @app.translate(@values.fetch(:x, 0), @values.fetch(:y, 0))
191
183
  sign = (@values[:flip] ? -1 : 1)
192
184
  @app.rotate(sign * @values[:rotation])
193
185
  end
194
186
 
195
-
196
187
  # Compute the rendering parameters for drawing a shape.
197
188
  def get_shape_values(some_options)
198
189
  old_ops = @values.dup
199
- merge_options(old_ops, some_options) if some_options
200
- @app.fill *old_ops[:color]
201
- return old_ops[:size], old_ops
190
+ merge_options(old_ops, some_options) unless some_options.empty?
191
+ @app.fill(*old_ops[:color])
192
+ old_ops
202
193
  end
203
194
 
204
-
205
- # Square, circle, and ellipse are the primitive drawing
206
- # methods, but hopefully triangles will be added soon.
207
- def square(some_options={})
208
- size, options = *get_shape_values(some_options)
195
+ # Square, circle, ellipse and triangles are the primitive shapes
196
+ def square(some_options = {})
197
+ options = get_shape_values(some_options)
209
198
  width = options[:w] || options[:size]
210
199
  height = options[:h] || options[:size]
211
- rot = options[:rotation]
200
+ rot = options[:rotation]
212
201
  @app.rotate(rot) if rot
213
202
  @app.rect(0, 0, width, height)
214
- @app.rotate(-rot) if rot
203
+ @app.rotate(-rot) if rot
215
204
  end
216
205
 
217
-
218
- def circle(some_options={})
219
- size, options = *get_shape_values(some_options)
206
+ def circle(some_options = {})
207
+ get_shape_values(some_options)
220
208
  @app.ellipse(0, 0, size, size)
221
209
  end
222
210
 
223
- def triangle(some_options={})
224
- size, options = *get_shape_values(some_options)
225
- rot = options[:rotation]
211
+ def triangle(some_options = {})
212
+ options = get_shape_values(some_options)
213
+ rot = options[:rotation]
226
214
  @app.rotate(rot) if rot
227
215
  @app.triangle(0, TRIANGLE_TOP * size, 0.5 * size, TRIANGLE_BOTTOM * size, -0.5 * size, TRIANGLE_BOTTOM * size)
228
216
  @app.rotate(-rot) if rot
229
217
  end
230
218
 
231
-
232
- def ellipse(some_options={})
233
- size, options = *get_shape_values(some_options)
219
+ def ellipse(some_options = {})
220
+ options = get_shape_values(some_options)
234
221
  width = options[:w] || options[:size]
235
222
  height = options[:h] || options[:size]
236
- rot = some_options[:rotation]
223
+ rot = some_options[:rotation]
237
224
  @app.rotate(rot) if rot
238
225
  @app.oval(options[:x] || 0, options[:y] || 0, width, height)
239
226
  @app.rotate(-rot) if rot
240
227
  end
241
- alias_method :oval, :ellipse
242
-
228
+ alias oval ellipse
243
229
  end
244
-
245
230
  end