cf3 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.yardopts +5 -0
- data/CHANGELOG +3 -0
- data/CONTRIBUTING.md +32 -0
- data/Gemfile +4 -0
- data/LICENSE.md +675 -0
- data/README.md +35 -0
- data/Rakefile +15 -0
- data/bin/cf3samples +16 -0
- data/cf3ruby.gemspec +29 -0
- data/lib/cf3.rb +240 -0
- data/lib/cf3/version.rb +3 -0
- data/samples/accident.rb +98 -0
- data/samples/alhambra.rb +79 -0
- data/samples/bar_code.rb +85 -0
- data/samples/city.rb +60 -0
- data/samples/creature.rb +59 -0
- data/samples/dark_star.rb +47 -0
- data/samples/data/java_args.txt +2 -0
- data/samples/dragon.rb +40 -0
- data/samples/escher.rb +124 -0
- data/samples/fern.rb +46 -0
- data/samples/grapher.rb +47 -0
- data/samples/hex_tube.rb +47 -0
- data/samples/isosceles.rb +36 -0
- data/samples/levy.rb +38 -0
- data/samples/pcr.rb +89 -0
- data/samples/sierpinski.rb +44 -0
- data/samples/spiral.rb +53 -0
- data/samples/tree.rb +98 -0
- data/samples/tree4.rb +65 -0
- data/samples/vine.rb +57 -0
- data/samples/y.rb +46 -0
- data/test/test_cf3.rb +26 -0
- metadata +128 -0
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# cf3ruby
|
2
|
+
|
3
|
+
**context-free DSL for ruby-1.9 and CF3 syntax**
|
4
|
+
|
5
|
+
Very much derived from [context-free.rb][] by Jeremy Ashkenas this version is updated to be more in line with CF3 and ruby 1.9 syntax. Tested as working with last rubygems release of ruby-processing (v 1.0.11) as well as the current [version][] (v 2.1.0).
|
6
|
+
[context-free.rb]:https://github.com/jashkenas/context_free/
|
7
|
+
[version]:https://github.com/monkstone/ruby-processing/releases/
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'cf3ruby'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install cf3
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
TODO: Write usage instructions here
|
25
|
+
|
26
|
+
## Contributing
|
27
|
+
|
28
|
+
1. Fork it
|
29
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
30
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
31
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
32
|
+
5. Create new Pull Request
|
33
|
+
|
34
|
+

|
35
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
task :install => :build do
|
4
|
+
sh "jruby -S gem install #{Dir.glob('*.gem').join(' ')} --no-ri --no-rdoc"
|
5
|
+
end
|
6
|
+
|
7
|
+
task :build do
|
8
|
+
sh "gem build cf3ruby.gemspec"
|
9
|
+
end
|
10
|
+
|
11
|
+
task :test do
|
12
|
+
sh "jruby -S rp5 run test/test_cf3.rb"
|
13
|
+
end
|
14
|
+
|
15
|
+
task :default => [:install]
|
data/bin/cf3samples
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#####
|
3
|
+
# Extract samples into users home directory
|
4
|
+
#####
|
5
|
+
|
6
|
+
|
7
|
+
home = ENV["HOME"]
|
8
|
+
local = home + '/cf3samples'
|
9
|
+
file = __FILE__
|
10
|
+
require "pathname"
|
11
|
+
require "fileutils"
|
12
|
+
file = Pathname.new(file).realpath
|
13
|
+
|
14
|
+
sample_dir = File.expand_path(File.dirname(file) + "/../samples")
|
15
|
+
FileUtils.mkdir local unless Dir.exists? local
|
16
|
+
FileUtils.cp_r sample_dir, local
|
data/cf3ruby.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cf3/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cf3"
|
8
|
+
spec.version = Cf3::VERSION
|
9
|
+
spec.authors = ["Jeremy Ashkenas", "Martin Prout"]
|
10
|
+
spec.email = ["martin_p@lineone.net"]
|
11
|
+
spec.description = <<-EOF
|
12
|
+
A library for ruby-processing, that allows the writing of context free
|
13
|
+
sketches (like context free art) in a ruby DSL. It is a bit of a toy
|
14
|
+
compared to the c++ version. However you can get quite a bit of
|
15
|
+
satisfaction creating an interesting graphic, and you can't always
|
16
|
+
predict what you are going to get.
|
17
|
+
EOF
|
18
|
+
spec.summary = %q{A ruby-DSL library for CF3 sketches}
|
19
|
+
spec.homepage = "http://learning-ruby-processing.blogspot.co.uk/"
|
20
|
+
spec.default_executable = "cf3samples"
|
21
|
+
spec.license = "GPL3"
|
22
|
+
spec.files = `git ls-files`.split($/)
|
23
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
24
|
+
spec.executables = ["cf3samples"]
|
25
|
+
spec.require_paths = ["lib"]
|
26
|
+
spec.add_runtime_dependency 'ruby-processing', '>= 1.0.11'
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
end
|
data/lib/cf3.rb
ADDED
@@ -0,0 +1,240 @@
|
|
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
|
+
module Processing
|
6
|
+
|
7
|
+
class ContextFree
|
8
|
+
|
9
|
+
include Processing::Proxy
|
10
|
+
|
11
|
+
attr_accessor :rule, :app, :width, :height
|
12
|
+
|
13
|
+
AVAILABLE_OPTIONS = [:x, :y, :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
|
17
|
+
|
18
|
+
# Define a context-free system. Use this method to create a ContextFree
|
19
|
+
# object. Call render() on it to make it draw.
|
20
|
+
def self.define(&block)
|
21
|
+
cf = ContextFree.new
|
22
|
+
cf.instance_eval &block
|
23
|
+
cf
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
# Initialize a bare ContextFree object with empty recursion stacks.
|
28
|
+
def initialize
|
29
|
+
@app = $app
|
30
|
+
@graphics = $app.g
|
31
|
+
@width = $app.width
|
32
|
+
@height = $app.height
|
33
|
+
@finished = false
|
34
|
+
@rules = {}
|
35
|
+
@rewind_stack = []
|
36
|
+
@matrix_stack = []
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Create an accessor for the current value of every option. We use a values
|
41
|
+
# object so that all the state can be saved and restored as a unit.
|
42
|
+
AVAILABLE_OPTIONS.each do |option_name|
|
43
|
+
define_method option_name do
|
44
|
+
@values[option_name]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# Here's the first serious method: A Rule has an
|
50
|
+
# identifying name, a probability, and is associated with
|
51
|
+
# a block of code. These code blocks are saved, and indexed
|
52
|
+
# by name in a hash, to be run later, when needed.
|
53
|
+
# The method then dynamically defines a method of the same
|
54
|
+
# 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}
|
57
|
+
total = @rules[rule_name][:total]
|
58
|
+
@rules[rule_name][:procs] << [(total...(prob+total)), proc]
|
59
|
+
@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
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
# Rule choice is random, based on the assigned probabilities.
|
79
|
+
def determine_rule(rule_name)
|
80
|
+
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
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# At each step of the way, any of the options may change, slightly.
|
88
|
+
# Many of them have different strategies for being merged.
|
89
|
+
def merge_options(old_ops, new_ops)
|
90
|
+
return unless new_ops
|
91
|
+
# Do size first
|
92
|
+
old_ops[:size] *= new_ops[:size] if new_ops[:size]
|
93
|
+
new_ops.each do |key, value|
|
94
|
+
case key
|
95
|
+
when :size
|
96
|
+
when :x, :y
|
97
|
+
old_ops[key] = value * old_ops[:size]
|
98
|
+
when :rotation
|
99
|
+
old_ops[key] = value * (Math::PI / 180.0)
|
100
|
+
when :hue, :saturation, :brightness, :alpha
|
101
|
+
adjusted = old_ops[:color].dup
|
102
|
+
adjusted[HSB_ORDER[key]] *= value
|
103
|
+
old_ops[:color] = adjusted
|
104
|
+
when :flip
|
105
|
+
old_ops[key] = !old_ops[key]
|
106
|
+
when :width, :height
|
107
|
+
old_ops[key] *= value
|
108
|
+
when :color
|
109
|
+
old_ops[key] = value
|
110
|
+
else # Used a key that we don't know about or trying to set
|
111
|
+
merge_unknown_key(key, value, old_ops)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
# Using an unknown key let's you set arbitrary values,
|
118
|
+
# to keep track of for your own ends.
|
119
|
+
def merge_unknown_key(key, value, old_ops)
|
120
|
+
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
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
# Doing a 'split' saves the context, and proceeds from there,
|
135
|
+
# allowing you to rewind to where you split from at any moment.
|
136
|
+
def split(options=nil, &block)
|
137
|
+
save_context
|
138
|
+
merge_options(@values, options) if options
|
139
|
+
yield
|
140
|
+
restore_context
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
# Saving the context means the values plus the coordinate matrix.
|
145
|
+
def save_context
|
146
|
+
@rewind_stack.push @values.dup
|
147
|
+
@matrix_stack << @graphics.get_matrix
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
# Restore the values and the coordinate matrix as the recursion unwinds.
|
152
|
+
def restore_context
|
153
|
+
@values = @rewind_stack.pop
|
154
|
+
@graphics.set_matrix @matrix_stack.pop
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
# Rewinding goes back one step.
|
159
|
+
def rewind
|
160
|
+
@finished = false
|
161
|
+
restore_context
|
162
|
+
save_context
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
# Render the is method that kicks it all off, initializing the options
|
167
|
+
# 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, width: 20, height: 20,
|
172
|
+
start_x: width/2, start_y: height/2,
|
173
|
+
color: [0.5, 0.5, 0.5, 1],
|
174
|
+
stop_size: 1.5}
|
175
|
+
@values.merge!(starting_values)
|
176
|
+
@finished = false
|
177
|
+
@app.reset_matrix
|
178
|
+
@app.rect_mode CENTER
|
179
|
+
@app.ellipse_mode CENTER
|
180
|
+
@app.no_stroke
|
181
|
+
@app.color_mode HSB, 1.0
|
182
|
+
@app.translate @values[:start_x], @values[:start_y]
|
183
|
+
self.send(rule_name, {})
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
# Before actually drawing the next step, we need to move to the appropriate
|
188
|
+
# location.
|
189
|
+
def get_ready_to_draw
|
190
|
+
@app.translate(@values[:x], @values[:y])
|
191
|
+
sign = (@values[:flip] ? -1 : 1)
|
192
|
+
@app.rotate(sign * @values[:rotation])
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
# Compute the rendering parameters for drawing a shape.
|
197
|
+
def get_shape_values(some_options)
|
198
|
+
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
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
# Square, circle, and ellipse are the primitive drawing
|
206
|
+
# methods, but hopefully triangles will be added soon.
|
207
|
+
def square(some_options=nil)
|
208
|
+
size, options = *get_shape_values(some_options)
|
209
|
+
@app.rect(0, 0, size, size)
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
def circle(some_options=nil)
|
214
|
+
size, options = *get_shape_values(some_options)
|
215
|
+
@app.ellipse(0, 0, size, size)
|
216
|
+
end
|
217
|
+
|
218
|
+
def triangle(some_options=nil)
|
219
|
+
rot = some_options[:rotation]
|
220
|
+
@app.rotate(rot) if rot
|
221
|
+
size, options = *get_shape_values(some_options)
|
222
|
+
@app.triangle(0, TRIANGLE_TOP * size, 0.5 * size, TRIANGLE_BOTTOM * size, -0.5 * size, TRIANGLE_BOTTOM * size)
|
223
|
+
@app.rotate(-rot) if rot
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
def ellipse(some_options={})
|
228
|
+
rot = some_options[:rotation]
|
229
|
+
@app.rotate(rot) if rot
|
230
|
+
size, options = *get_shape_values(some_options)
|
231
|
+
width = options[:width] || options[:size]
|
232
|
+
height = options[:height] || options[:size]
|
233
|
+
@app.oval(options[:x] || 0, options[:y] || 0, width, height)
|
234
|
+
@app.rotate(-rot) if rot
|
235
|
+
end
|
236
|
+
alias_method :oval, :ellipse
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
data/lib/cf3/version.rb
ADDED
data/samples/accident.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
#########################
|
2
|
+
# rubystar.rb
|
3
|
+
#########################
|
4
|
+
require 'cf3'
|
5
|
+
|
6
|
+
PHI = (1 + Math.sqrt(5)) / 2
|
7
|
+
|
8
|
+
def setup_the_sunstar
|
9
|
+
@hexa = ContextFree.define do
|
10
|
+
############ Begin defining custom terminals, as a sharp and flat triangles
|
11
|
+
class << self
|
12
|
+
include Math
|
13
|
+
define_method(:sharp) do |some_options|
|
14
|
+
size, options = *self.get_shape_values(some_options)
|
15
|
+
rot = options[:rotation]
|
16
|
+
#f = (options[:flip])? -1 : 1
|
17
|
+
@app.rotate(rot) if rot
|
18
|
+
#@app.triangle(0, 0, size * cos(0), size * sin(0), size * cos(PI * f/5), size * sin(PI*f/5))
|
19
|
+
@app.triangle(0, 0, size * cos(0), size * sin(0), size * cos(PI/5), size * sin(PI/5))
|
20
|
+
@app.rotate(-rot) if rot
|
21
|
+
end
|
22
|
+
define_method(:flat) do |some_options|
|
23
|
+
size, options = *self.get_shape_values(some_options)
|
24
|
+
rot = options[:rotation]
|
25
|
+
f = (options[:flip])? -1 : 1 # NB custom flip adjustment
|
26
|
+
@app.triangle(0, 0, size * cos(0), size * sin(0), size/PHI * cos(PI * f/5 ), size/PHI * sin(PI * f/5))
|
27
|
+
@app.rotate(-rot) if rot
|
28
|
+
end
|
29
|
+
end
|
30
|
+
########### End definition of custom terminals 'sharp and flat'
|
31
|
+
|
32
|
+
shape :tiling do
|
33
|
+
outer brightness: 1.0
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
shape :outer do
|
38
|
+
split do
|
39
|
+
10.times do
|
40
|
+
sunstar y: sqrt((PHI)** - 0.125), rotation: 36
|
41
|
+
end
|
42
|
+
rewind
|
43
|
+
end
|
44
|
+
outer size: 1/PHI
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
shape :sunstar do
|
49
|
+
split do
|
50
|
+
sun brightness: 0.8
|
51
|
+
rewind
|
52
|
+
star brightness: 0.8, alpha: 0.8
|
53
|
+
rewind
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
shape :dart do
|
58
|
+
flat size: 1, color: [0.18, 0.6, 0.6]
|
59
|
+
flat size: 1, color: [0.18, 1.0, 1.0], flip: true
|
60
|
+
end
|
61
|
+
|
62
|
+
shape :kite do
|
63
|
+
sharp size: 1, color: [0, 0.6, 0.6]
|
64
|
+
sharp size: 1, color: [0, 1.0, 1.0], rotation: 180, flip: true
|
65
|
+
end
|
66
|
+
|
67
|
+
shape :star do
|
68
|
+
split do
|
69
|
+
5.times do |i|
|
70
|
+
dart rotation: 72 * i
|
71
|
+
rewind
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
shape :sun do
|
77
|
+
split do
|
78
|
+
5.times do |i|
|
79
|
+
kite rotation: 72 * i
|
80
|
+
rewind
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def setup
|
88
|
+
size 800, 820
|
89
|
+
background 150, 20, 0
|
90
|
+
smooth
|
91
|
+
setup_the_sunstar
|
92
|
+
draw_it
|
93
|
+
end
|
94
|
+
|
95
|
+
def draw_it
|
96
|
+
@hexa.render :tiling, start_x: width * 0.75, start_y: height/2.64,
|
97
|
+
size: height/6
|
98
|
+
end
|
data/samples/alhambra.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'cf3'
|
2
|
+
|
3
|
+
def setup_the_tiles
|
4
|
+
@tiles= ContextFree.define do
|
5
|
+
############ Begin defining custom terminal, an wavy_triangle triangle
|
6
|
+
class << self
|
7
|
+
define_method(:wavy_triangle) do |some_options| # wavy_triangle triangle
|
8
|
+
size, options = *self.get_shape_values(some_options)
|
9
|
+
rot = options[:rotation]
|
10
|
+
disp = 0.32 # could introduce a rule option?
|
11
|
+
x0 = options[:x]
|
12
|
+
y0 = options[:y]
|
13
|
+
pts = Array.new(12)
|
14
|
+
pts[0] = PVector.new(x0, y0 - size/Math.sqrt(3)) # A
|
15
|
+
pts[1] = PVector.new(x0 - 0.5 * size, y0 + (Math.sqrt(3)*size)/6) # B
|
16
|
+
pts[2] = PVector.new(x0 + 0.5 * size, y0 + (Math.sqrt(3)*size)/6) # C
|
17
|
+
pts[3] = get_mid_point(pts[0], pts[1]) # Ab
|
18
|
+
pts[4] = get_mid_point(pts[1], pts[2]) # Bc
|
19
|
+
pts[5] = get_mid_point(pts[0], pts[2]) # Ca
|
20
|
+
pts[6] = get_mid_point(pts[0], pts[3]) # Aba
|
21
|
+
adjust_bezier(pts[6], PI/3, disp*size) # Aba
|
22
|
+
pts[7] = get_mid_point(pts[3], pts[1]) # Abb
|
23
|
+
adjust_bezier(pts[7], PI/3, -disp*size) # Abb
|
24
|
+
pts[8] = get_mid_point(pts[1], pts[4])
|
25
|
+
adjust_bezier(pts[8], PI/2, -disp*size)
|
26
|
+
pts[9] = get_mid_point(pts[4], pts[2])
|
27
|
+
adjust_bezier(pts[9], PI/2, disp*size)
|
28
|
+
pts[10] = get_mid_point(pts[2], pts[5])
|
29
|
+
adjust_bezier(pts[10], -PI/3, -disp*size)
|
30
|
+
pts[11] = get_mid_point(pts[5], pts[0])
|
31
|
+
adjust_bezier(pts[11], -PI/3, disp*size)
|
32
|
+
rotate(rot) if rot
|
33
|
+
begin_shape
|
34
|
+
vertex(pts[0].x, pts[0].y)
|
35
|
+
bezier_vertex(pts[0].x, pts[0].y, pts[6].x, pts[6].y, pts[3].x, pts[3].y)
|
36
|
+
bezier_vertex(pts[3].x, pts[3].y, pts[7].x, pts[7].y, pts[1].x, pts[1].y)
|
37
|
+
bezier_vertex(pts[1].x, pts[1].y, pts[8].x, pts[8].y, pts[4].x, pts[4].y)
|
38
|
+
bezier_vertex(pts[4].x, pts[4].y, pts[9].x, pts[9].y, pts[2].x, pts[2].y)
|
39
|
+
bezier_vertex(pts[2].x, pts[2].y, pts[10].x, pts[10].y, pts[5].x, pts[5].y)
|
40
|
+
bezier_vertex(pts[5].x, pts[5].y, pts[11].x, pts[11].y, pts[0].x, pts[0].y)
|
41
|
+
end_shape(CLOSE)
|
42
|
+
rotate(-rot) if rot
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def adjust_bezier(base, theta, disp)
|
47
|
+
base.add(PVector.new(Math.cos(theta)*disp, Math.sin(theta)*disp))
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_mid_point(a, b)
|
51
|
+
mid = PVector.add(a, b)
|
52
|
+
mid.div(2)
|
53
|
+
return mid
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
########### End definition of custom terminal 'wavy_triangle' shape
|
58
|
+
shape :tiles do
|
59
|
+
10.times do |i|
|
60
|
+
10.times do |j|
|
61
|
+
wavy_triangle size: 1, x: (i + 0.5 * j%2), y: j * 0.9
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def setup
|
69
|
+
size 400, 400
|
70
|
+
background 255
|
71
|
+
smooth
|
72
|
+
setup_the_tiles
|
73
|
+
draw_it
|
74
|
+
end
|
75
|
+
|
76
|
+
def draw_it
|
77
|
+
@tiles.render :tiles, start_x: -50, start_y: 20,
|
78
|
+
size: height/6, color: [0, 0.8, 0.8, 1]
|
79
|
+
end
|