rubysketch 0.3.2 → 0.3.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83aecf951db1320693714768446ccc95aa0a87f23012e02fff31b032c88be3c6
4
- data.tar.gz: 6d1f67cbe65c15468cb606666acceacf19f56bf8c83dd1abae2a1b21d7daf94b
3
+ metadata.gz: 41b3a75aeb6c8bdc443d2d87e44c60361a527e4d6b8b3918e8b1eaa2503f92e4
4
+ data.tar.gz: 7f373d0f3fdb31d38bb76d8e8ed88ce2f3cedca0c696d8a5f571ded1e78fb15d
5
5
  SHA512:
6
- metadata.gz: 9946ba3029ce56a90042daa9be9e6c2f74f5d7ef7d318b5263b10c03ca35c26f5f7e67c61e6f78bd90f4224c267f732dcb937d86030adbe2b0ac51350a225f6e
7
- data.tar.gz: 627eb17aa1e83da474f9ab9457b449b278ecf95d84956f98b82d3185c6bc87fa9b5788ad65c1144f80364171b14a4f7322d86a42066925ccbca8f2e19ff46cc3
6
+ metadata.gz: ffcba1a2e5ae98525c4c1512230d249995071e6be9183918b6f62ed5293d9ac8f530d38aa5f544d2d4fc431ca17f38c7746955df313e9609e0ee528551045a51
7
+ data.tar.gz: cb49daa453cdf6dd9027a59c508363a63fed2e210b0acbcfa311e66334b107a88471e5b8b59dac7f77b5aa04423aaa2d0cd2b2fa0c4b1221b76997a93ce89e79
@@ -0,0 +1,62 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ['v[0-9]*']
6
+
7
+ jobs:
8
+ release:
9
+ runs-on: macos-latest
10
+
11
+ steps:
12
+ - name: checkout
13
+ uses: actions/checkout@v2
14
+
15
+ - name: ruby 2.6
16
+ uses: actions/setup-ruby@v1
17
+ with:
18
+ ruby-version: 2.6.x
19
+
20
+ - name: install gems
21
+ run: |
22
+ gem install bundler
23
+ bundle install --jobs 4 --retry 3
24
+
25
+ - name: version
26
+ id: version
27
+ run: |
28
+ echo ::set-output name=value::$(ruby -e 'print "${{ github.ref }}"[/\/v([\w\.\-]+)/, 1]')
29
+
30
+ - name: create gem
31
+ run: rake clean gem
32
+
33
+ - name: create release
34
+ id: create_release
35
+ uses: actions/create-release@v1
36
+ env:
37
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
38
+ with:
39
+ tag_name: ${{ github.ref }}
40
+ release_name: ${{ github.ref }}
41
+ draft: false
42
+ prerelease: false
43
+
44
+ - name: upload to releases
45
+ uses: actions/upload-release-asset@v1
46
+ env:
47
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48
+ with:
49
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
50
+ asset_path: ./rubysketch-${{ steps.version.outputs.value }}.gem
51
+ asset_name: rubysketch-${{ steps.version.outputs.value }}.gem
52
+ asset_content_type: application/zip
53
+
54
+ - name: upload to rubygems
55
+ env:
56
+ GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_AUTH_TOKEN }}
57
+ run: |
58
+ mkdir -p $HOME/.gem
59
+ touch $HOME/.gem/credentials
60
+ chmod 0600 $HOME/.gem/credentials
61
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
62
+ rake upload
@@ -0,0 +1,27 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: macos-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+
16
+ - name: ruby 2.6
17
+ uses: actions/setup-ruby@v1
18
+ with:
19
+ ruby-version: 2.6.x
20
+
21
+ - name: install gems
22
+ run: |
23
+ gem install bundler
24
+ bundle install --jobs 4 --retry 3
25
+
26
+ - name: test
27
+ run: rake test
@@ -1,6 +1,39 @@
1
1
  # RubySketch ChangeLog
2
2
 
3
3
 
4
+ ## [0.3.7] - 2020-11-18
5
+
6
+ - add Capture class
7
+ - add log(), exp(), sqrt() and PI
8
+ - add examples/camera.rb
9
+ - add examples/breakout.rb
10
+ - fix error on calling image()
11
+
12
+
13
+ ## [0.3.6] - 2020-08-02
14
+
15
+ - random() can take array or nothing
16
+ - use github actions to release gem package
17
+
18
+
19
+ ## [0.3.5] - 2020-08-02
20
+
21
+ - add random()
22
+ - add sin(), cos(), tan(), asin(), acos(), atan() and atan2()
23
+ - make Vector class accessible from user script context
24
+ - fix error on calling rotate()
25
+
26
+
27
+ ## [0.3.4] - 2020-08-02
28
+
29
+ - delete Utility module
30
+
31
+
32
+ ## [0.3.3] - 2020-08-01
33
+
34
+ - add Vector class
35
+
36
+
4
37
  ## [0.3.2] - 2020-07-22
5
38
 
6
39
  - text() draws to the baseline by default
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'yard'
4
+ gem 'reflexion'
data/Rakefile CHANGED
@@ -18,6 +18,7 @@ MODULES = [Xot, Rucy, Rays, Reflex, RubySketch]
18
18
 
19
19
  ENV['RDOC'] = 'yardoc --no-private'
20
20
 
21
+ test_ruby_extension
21
22
  generate_documents
22
23
  build_ruby_gem
23
24
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.2
1
+ 0.3.7
@@ -0,0 +1,212 @@
1
+ %w[xot rays reflex rubysketch]
2
+ .map {|s| File.expand_path "../../#{s}/lib", __dir__}
3
+ .each {|s| $:.unshift s if !$:.include?(s) && File.directory?(s)}
4
+
5
+ require 'rubysketch-processing'
6
+
7
+
8
+ PADDING = 50
9
+ BRICK_COUNT = 10
10
+
11
+ $objs = []
12
+ $bar = nil
13
+ $gameover = false
14
+
15
+ setup do
16
+ addWalls
17
+ addBricks
18
+
19
+ colorMode HSB, 360, 100, 100
20
+ ellipseMode CORNER
21
+ background 0
22
+ noStroke
23
+ fill 0, 0, 100
24
+ end
25
+
26
+ draw do
27
+ background 0
28
+ $objs.each do |o|
29
+ o.update
30
+ o.draw
31
+ end
32
+ drawTexts
33
+ end
34
+
35
+ mousePressed do
36
+ start unless started?
37
+ end
38
+
39
+ mouseDragged do
40
+ $bar.pos.x = mouseX - $bar.w / 2 if $bar
41
+ end
42
+
43
+ def start()
44
+ $bar = Bar.new
45
+ $objs += [$bar, Ball.new($bar)]
46
+ end
47
+
48
+ def started?()
49
+ $bar
50
+ end
51
+
52
+ def gameover?()
53
+ started? &&
54
+ $objs.count {|o| o.kind_of? Ball} == 0
55
+ end
56
+
57
+ def cleared?()
58
+ started? && !gameover? &&
59
+ $objs.count {|o| o.kind_of? Brick} == 0
60
+ end
61
+
62
+ def addWalls()
63
+ left = Obj.new 0, 0, 10, height
64
+ top = Obj.new 0, 0, width, 10
65
+ right = Obj.new width - 10, 0, 10, height
66
+ bottom = Bottom.new 0, height - 10, width, 10
67
+ $objs += [top, bottom, left, right]
68
+ end
69
+
70
+ def addBricks()
71
+ brickW = (width - PADDING * 2) / BRICK_COUNT
72
+ 5.times do |y|
73
+ BRICK_COUNT.times do |x|
74
+ xx = PADDING + brickW * x
75
+ yy = PADDING + 30 * y
76
+ $objs.push Brick.new(xx, yy, brickW - 5, 20, y * 60)
77
+ end
78
+ end
79
+ end
80
+
81
+ def drawTexts()
82
+ push do
83
+ textAlign CENTER, CENTER
84
+
85
+ if !started?
86
+ fill 50, 100, 100
87
+ textSize 50
88
+ text "BREAKOUT", 0, 0, width, height
89
+ textSize 20
90
+ translate 0, 100
91
+ text "Tap to start!", 0, 0, width, height
92
+ elsif cleared?
93
+ fill 100, 80, 100
94
+ textSize 50
95
+ text "CLEAR!", 0, 0, width, height
96
+ elsif gameover?
97
+ fill 0, 20, 100
98
+ textSize 50
99
+ text "GAMEOVER", 0, 0, width, height
100
+ end
101
+ end
102
+ end
103
+
104
+ class Obj
105
+ attr_reader :pos, :w, :h, :vel
106
+
107
+ def initialize(x, y, w, h, vx = 0, vy = 0)
108
+ @pos = createVector x, y
109
+ @w, @h = w, h
110
+ @vel = createVector vx, vy
111
+ end
112
+
113
+ def update()
114
+ @pos.add @vel
115
+ end
116
+
117
+ def draw()
118
+ rect @pos.x, @pos.y, @w, @h
119
+ end
120
+
121
+ def bounds()
122
+ x, y = @pos.x, @pos.y
123
+ return x, y, x + @w, y + @h
124
+ end
125
+
126
+ def center()
127
+ createVector @pos.x + @w / 2, @pos.y + @h / 2
128
+ end
129
+ end
130
+
131
+ class Ball < Obj
132
+ def initialize(bar)
133
+ super bar.pos.x, bar.pos.y - bar.h, 20, 20
134
+ self.vel = createVector random(-1, 1), -1
135
+ end
136
+
137
+ def vel=(v)
138
+ @vel = v.dup.normalize.mult 8
139
+ end
140
+
141
+ def update()
142
+ b = bounds.dup
143
+ super
144
+ checkHit b
145
+ end
146
+
147
+ def checkHit(prevBounds)
148
+ x1, y1, x2, y2 = prevBounds
149
+ hitH = hitV = false
150
+ hits = []
151
+ $objs.each do |o|
152
+ next if o == self
153
+ next unless intersect? o
154
+ hits.push o
155
+ ox1, oy1, ox2, oy2 = o.bounds
156
+ hitH ||= !overlap?(x1, x2, ox1, ox2)
157
+ hitV ||= !overlap?(y1, y2, oy1, oy2)
158
+ end
159
+ vel.x *= -1 if hitH
160
+ vel.y *= -1 if hitV
161
+
162
+ hits.each {|o| hit o}
163
+ end
164
+
165
+ def intersect?(o)
166
+ x1, y1, x2, y2 = bounds
167
+ ox1, oy1, ox2, oy2 = o.bounds
168
+ overlap?(x1, x2, ox1, ox2) && overlap?(y1, y2, oy1, oy2)
169
+ end
170
+
171
+ def overlap?(a1, a2, b1, b2)
172
+ a1 <= b2 && b1 <= a2
173
+ end
174
+
175
+ def hit(o)
176
+ case o
177
+ when Bar then self.vel = center.sub o.center
178
+ when Brick then $objs.delete o
179
+ when Bottom then $objs.delete self unless cleared?
180
+ end
181
+ end
182
+ end
183
+
184
+ class Bar < Obj
185
+ def initialize()
186
+ w = 100
187
+ super (width - w) / 2, height - 50, w, 20
188
+ end
189
+ end
190
+
191
+ class Brick < Obj
192
+ def initialize(x, y, w, h, hue)
193
+ super x, y, w, h
194
+ @hue = hue
195
+ end
196
+
197
+ def draw()
198
+ push do
199
+ fill @hue, 50, 100
200
+ super
201
+ end
202
+ end
203
+ end
204
+
205
+ class Bottom < Obj
206
+ def draw()
207
+ push do
208
+ fill 0, 0, 50
209
+ super
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,14 @@
1
+ %w[xot rays reflex rubysketch]
2
+ .map {|s| File.expand_path "../../#{s}/lib", __dir__}
3
+ .each {|s| $:.unshift s if !$:.include?(s) && File.directory?(s)}
4
+
5
+ require 'rubysketch-processing'
6
+
7
+
8
+ cam = Capture.new
9
+ cam.start
10
+
11
+ draw do
12
+ background 0
13
+ image cam, 0, 0
14
+ end
@@ -2,10 +2,18 @@ require 'rubysketch'
2
2
 
3
3
 
4
4
  begin
5
- include RubySketch::Processing::Context
5
+ window = RubySketch::Window.new {start}
6
+ context = RubySketch::Processing::Context.new window
6
7
 
7
- window = RubySketch::Window.new {start}
8
- setup__ window
8
+ (context.methods - Object.instance_methods).each do |method|
9
+ define_method method do |*args, &block|
10
+ context.__send__ method, *args, &block
11
+ end
12
+ end
13
+
14
+ context.class.constants.each do |const|
15
+ self.class.const_set const, context.class.const_get(const)
16
+ end
9
17
 
10
18
  window.__send__ :begin_draw
11
19
  at_exit do
@@ -6,13 +6,574 @@ module RubySketch
6
6
  module Processing
7
7
 
8
8
 
9
+ # @private
10
+ DEG2RAD__ = Math::PI / 180.0
11
+
12
+ # @private
13
+ RAD2DEG__ = 180.0 / Math::PI
14
+
15
+
16
+ # Vector class.
17
+ #
18
+ class Vector
19
+
20
+ include Comparable
21
+
22
+ # Initialize vector object.
23
+ #
24
+ # @overload new()
25
+ # @overload new(x)
26
+ # @overload new(x, y)
27
+ # @overload new(x, y, z)
28
+ # @overload new(v)
29
+ # @overload new(a)
30
+ #
31
+ # @param x [Numeric] x of vector
32
+ # @param y [Numeric] y of vector
33
+ # @param z [Numeric] z of vector
34
+ # @param v [Vector] vector object to copy
35
+ # @param a [Array] array like [x, y, z]
36
+ #
37
+ def initialize (x = 0, y = 0, z = 0, context: nil)
38
+ @point = case x
39
+ when Rays::Point then x.dup
40
+ when Vector then x.getInternal__.dup
41
+ when Array then Rays::Point.new x[0] || 0, x[1] || 0, x[2] || 0
42
+ else Rays::Point.new x || 0, y || 0, z || 0
43
+ end
44
+ @context = context || Context.context__
45
+ end
46
+
47
+ # Initializer for dup or clone
48
+ #
49
+ def initialize_copy (o)
50
+ @point = o.getInternal__.dup
51
+ end
52
+
53
+ # Copy vector object
54
+ #
55
+ # @return [Vector] duplicated vector object
56
+ #
57
+ alias copy dup
58
+
59
+ # Sets x, y and z.
60
+ #
61
+ # @overload set(x)
62
+ # @overload set(x, y)
63
+ # @overload set(x, y, z)
64
+ # @overload set(v)
65
+ # @overload set(a)
66
+ #
67
+ # @param x [Numeric] x of vector
68
+ # @param y [Numeric] y of vector
69
+ # @param z [Numeric] z of vector
70
+ # @param v [Vector] vector object to copy
71
+ # @param a [Array] array with x, y, z
72
+ #
73
+ # @return [nil] nil
74
+ #
75
+ def set (*args)
76
+ initialize *args
77
+ self
78
+ end
79
+
80
+ # Gets x value.
81
+ #
82
+ # @return [Numeric] x value of vector
83
+ #
84
+ def x ()
85
+ @point.x
86
+ end
87
+
88
+ # Gets y value.
89
+ #
90
+ # @return [Numeric] y value of vector
91
+ #
92
+ def y ()
93
+ @point.y
94
+ end
95
+
96
+ # Gets z value.
97
+ #
98
+ # @return [Numeric] z value of vector
99
+ #
100
+ def z ()
101
+ @point.z
102
+ end
103
+
104
+ # Sets x value.
105
+ #
106
+ # @return [Numeric] x value of vector
107
+ #
108
+ def x= (x)
109
+ @point.x = x
110
+ end
111
+
112
+ # Sets y value.
113
+ #
114
+ # @return [Numeric] y value of vector
115
+ #
116
+ def y= (y)
117
+ @point.y = y
118
+ end
119
+
120
+ # Sets z value.
121
+ #
122
+ # @return [Numeric] z value of vector
123
+ #
124
+ def z= (z)
125
+ @point.z = z
126
+ end
127
+
128
+ # Returns the interpolated vector between 2 vectors.
129
+ #
130
+ # @overload lerp(v, amount)
131
+ # @overload lerp(x, y, amount)
132
+ # @overload lerp(x, y, z, amount)
133
+ #
134
+ # @param v [Vector] vector to interpolate
135
+ # @param x [Numeric] x of vector to interpolate
136
+ # @param y [Numeric] y of vector to interpolate
137
+ # @param z [Numeric] z of vector to interpolate
138
+ # @param amount [Numeric] amount to interpolate
139
+ #
140
+ # @return [Vector] interporated vector
141
+ #
142
+ def lerp (*args, amount)
143
+ v = toVector__ *args
144
+ self.x = x + (v.x - x) * amount
145
+ self.y = y + (v.y - y) * amount
146
+ self.z = z + (v.z - z) * amount
147
+ self
148
+ end
149
+
150
+ # Returns the interpolated vector between 2 vectors.
151
+ #
152
+ # @param v1 [Vector] vector to interpolate
153
+ # @param v2 [Vector] vector to interpolate
154
+ # @param amount [Numeric] amount to interpolate
155
+ #
156
+ # @return [Vector] interporated vector
157
+ #
158
+ def self.lerp (v1, v2, amount)
159
+ v1.dup.lerp v2, amount
160
+ end
161
+
162
+ # Returns x, y, z as an array
163
+ #
164
+ # @return [Array] array of x, y, z
165
+ #
166
+ def array ()
167
+ @point.to_a 3
168
+ end
169
+
170
+ # Adds a vector.
171
+ #
172
+ # @overload add(v)
173
+ # @overload add(x, y)
174
+ # @overload add(x, y, z)
175
+ #
176
+ # @param v [Vector] vector to add
177
+ # @param x [Vector] x of vector to add
178
+ # @param y [Vector] y of vector to add
179
+ # @param z [Vector] z of vector to add
180
+ #
181
+ # @return [Vector] added vector
182
+ #
183
+ def add (*args)
184
+ @point += toVector__(*args).getInternal__
185
+ self
186
+ end
187
+
188
+ # Subtracts a vector.
189
+ #
190
+ # @overload sub(v)
191
+ # @overload sub(x, y)
192
+ # @overload sub(x, y, z)
193
+ #
194
+ # @param v [Vector] vector to subtract
195
+ # @param x [Vector] x of vector to subtract
196
+ # @param y [Vector] y of vector to subtract
197
+ # @param z [Vector] z of vector to subtract
198
+ #
199
+ # @return [Vector] subtracted vector
200
+ #
201
+ def sub (*args)
202
+ @point -= toVector__(*args).getInternal__
203
+ self
204
+ end
205
+
206
+ # Multiplies a vector by scalar.
207
+ #
208
+ # @param num [Numeric] number to multiply the vector
209
+ #
210
+ # @return [Vector] multiplied vector
211
+ #
212
+ def mult (num)
213
+ @point *= num
214
+ self
215
+ end
216
+
217
+ # Divides a vector by scalar.
218
+ #
219
+ # @param num [Numeric] number to divide the vector
220
+ #
221
+ # @return [Vector] divided vector
222
+ #
223
+ def div (num)
224
+ @point /= num
225
+ self
226
+ end
227
+
228
+ # Adds a vector.
229
+ #
230
+ # @param v [Vector] vector to add
231
+ #
232
+ # @return [Vector] added vector
233
+ #
234
+ def + (v)
235
+ dup.add v
236
+ end
237
+
238
+ # Subtracts a vector.
239
+ #
240
+ # @param v [Vector] vector to subtract
241
+ #
242
+ # @return [Vector] subtracted vector
243
+ #
244
+ def - (v)
245
+ dup.sub v
246
+ end
247
+
248
+ # Multiplies a vector by scalar.
249
+ #
250
+ # @param num [Numeric] number to multiply the vector
251
+ #
252
+ # @return [Vector] multiplied vector
253
+ #
254
+ def * (num)
255
+ dup.mult num
256
+ end
257
+
258
+ # Divides a vector by scalar.
259
+ #
260
+ # @param num [Numeric] number to divide the vector
261
+ #
262
+ # @return [Vector] divided vector
263
+ #
264
+ def / (num)
265
+ dup.div num
266
+ end
267
+
268
+ # Adds 2 vectors.
269
+ #
270
+ # @overload add(v1, v2)
271
+ # @overload add(v1, v2, target)
272
+ #
273
+ # @param v1 [Vector] a vector
274
+ # @param v2 [Vector] another vector
275
+ # @param target [Vector] vector to store added vector
276
+ #
277
+ # @return [Vector] added vector
278
+ #
279
+ def self.add (v1, v2, target = nil)
280
+ v = v1 + v2
281
+ target.set v if self === target
282
+ v
283
+ end
284
+
285
+ # Subtracts 2 vectors.
286
+ #
287
+ # @overload sub(v1, v2)
288
+ # @overload sub(v1, v2, target)
289
+ #
290
+ # @param v1 [Vector] a vector
291
+ # @param v2 [Vector] another vector
292
+ # @param target [Vector] vector to store subtracted vector
293
+ #
294
+ # @return [Vector] subtracted vector
295
+ #
296
+ def self.sub (v1, v2, target = nil)
297
+ v = v1 - v2
298
+ target.set v if self === target
299
+ v
300
+ end
301
+
302
+ # Multiplies a vector by scalar.
303
+ #
304
+ # @overload mult(v, num)
305
+ # @overload mult(v, num, target)
306
+ #
307
+ # @param v [Vector] a vector
308
+ # @param num [Numeric] number to multiply the vector
309
+ # @param target [Vector] vector to store multiplied vector
310
+ #
311
+ # @return [Vector] multiplied vector
312
+ #
313
+ def self.mult (v1, num, target = nil)
314
+ v = v1 * num
315
+ target.set v if self === target
316
+ v
317
+ end
318
+
319
+ # Divides a vector by scalar.
320
+ #
321
+ # @overload div(v, num)
322
+ # @overload div(v, num, target)
323
+ #
324
+ # @param v [Vector] a vector
325
+ # @param num [Numeric] number to divide the vector
326
+ # @param target [Vector] vector to store divided vector
327
+ #
328
+ # @return [Vector] divided vector
329
+ #
330
+ def self.div (v1, num, target = nil)
331
+ v = v1 / num
332
+ target.set v if self === target
333
+ v
334
+ end
335
+
336
+ # Returns the length of the vector.
337
+ #
338
+ # @return [Numeric] length
339
+ #
340
+ def mag ()
341
+ @point.length
342
+ end
343
+
344
+ # Returns squared length of the vector.
345
+ #
346
+ # @return [Numeric] squared length
347
+ #
348
+ def magSq ()
349
+ Rays::Point::dot(@point, @point)
350
+ end
351
+
352
+ # Changes the length of the vector.
353
+ #
354
+ # @overload setMag(len)
355
+ # @overload setMag(target, len)
356
+ #
357
+ # @param len [Numeric] length of new vector
358
+ # @param target [Vector] vector to store new vector
359
+ #
360
+ # @return [Vector] vector with new length
361
+ #
362
+ def setMag (target = nil, len)
363
+ (target || self).set @point.normal * len
364
+ end
365
+
366
+ # Changes the length of the vector to 1.0.
367
+ #
368
+ # @param target [Vector] vector to store the normalized vector
369
+ #
370
+ # @return [Vector] normalized vector
371
+ #
372
+ def normalize (target = nil)
373
+ (target || self).set @point.normal
374
+ end
375
+
376
+ # Changes the length of the vector if it's length is greater than the max value.
377
+ #
378
+ # @param max [Numeric] max length
379
+ #
380
+ # @return [Vector] new vector
381
+ #
382
+ def limit (max)
383
+ setMag max if magSq > max ** 2
384
+ self
385
+ end
386
+
387
+ # Returns the distance of 2 vectors.
388
+ #
389
+ # @param v [Vector] a vector
390
+ #
391
+ # @return [Numeric] the distance
392
+ #
393
+ def dist (v)
394
+ (self - v).mag
395
+ end
396
+
397
+ # Returns the distance of 2 vectors.
398
+ #
399
+ # @param v1 [Vector] a vector
400
+ # @param v2 [Vector] another vector
401
+ #
402
+ # @return [Numeric] the distance
403
+ #
404
+ def self.dist (v1, v2)
405
+ v1.dist v2
406
+ end
407
+
408
+ # Calculates the dot product of 2 vectors.
409
+ #
410
+ # @overload dot(v)
411
+ # @overload dot(x, y)
412
+ # @overload dot(x, y, z)
413
+ #
414
+ # @param v [Vector] a vector
415
+ # @param x [Numeric] x of vector
416
+ # @param y [Numeric] y of vector
417
+ # @param z [Numeric] z of vector
418
+ #
419
+ # @return [Numeric] result of dot product
420
+ #
421
+ def dot (*args)
422
+ Rays::Point::dot getInternal__, toVector__(*args).getInternal__
423
+ end
424
+
425
+ # Calculates the dot product of 2 vectors.
426
+ #
427
+ # @param v1 [Vector] a vector
428
+ # @param v2 [Vector] another vector
429
+ #
430
+ # @return [Numeric] result of dot product
431
+ #
432
+ def self.dot (v1, v2)
433
+ v1.dot v2
434
+ end
435
+
436
+ # Calculates the cross product of 2 vectors.
437
+ #
438
+ # @overload cross(v)
439
+ # @overload cross(x, y)
440
+ # @overload cross(x, y, z)
441
+ #
442
+ # @param v [Vector] a vector
443
+ # @param x [Numeric] x of vector
444
+ # @param y [Numeric] y of vector
445
+ # @param z [Numeric] z of vector
446
+ #
447
+ # @return [Numeric] result of cross product
448
+ #
449
+ def cross (a, *rest)
450
+ target = self.class === rest.last ? rest.pop : nil
451
+ v = self.class.new Rays::Point::cross getInternal__, toVector__(a, *rest).getInternal__
452
+ target.set v if self.class === target
453
+ v
454
+ end
455
+
456
+ # Calculates the cross product of 2 vectors.
457
+ #
458
+ # @param v1 [Vector] a vector
459
+ # @param v2 [Vector] another vector
460
+ #
461
+ # @return [Numeric] result of cross product
462
+ #
463
+ def self.cross (v1, v2, target = nil)
464
+ v1.cross v2, target
465
+ end
466
+
467
+ # Rotate the vector.
468
+ #
469
+ # @param angle [Numeric] the angle of rotation
470
+ #
471
+ # @return [Vector] rotated this object
472
+ #
473
+ def rotate (angle)
474
+ angle = @context ? @context.toAngle__(angle) : angle * RAD2DEG__
475
+ @point.rotate! angle
476
+ self
477
+ end
478
+
479
+ # Returns the angle of rotation for this vector.
480
+ #
481
+ # @return [Numeric] the angle in radians
482
+ #
483
+ def heading ()
484
+ Math.atan2 y, x
485
+ end
486
+
487
+ # Returns rotated new vector.
488
+ #
489
+ # @param angle [Numeric] the angle of rotation
490
+ # @param target [Vector] vector to store new vector
491
+ #
492
+ # @return [Vector] rotated vector
493
+ #
494
+ def self.fromAngle (angle, target = nil)
495
+ v = self.new(1, 0, 0).rotate(angle)
496
+ target.set v if target
497
+ v
498
+ end
499
+
500
+ # Returns angle between 2 vectors.
501
+ #
502
+ # @param v1 [Vector] a vector
503
+ # @param v2 [Vector] another vector
504
+ #
505
+ # @return [Numeric] angle in radians
506
+ #
507
+ def self.angleBetween (v1, v2)
508
+ x1, y1, z1 = v1.array
509
+ x2, y2, z2 = v2.array
510
+ return 0 if (x1 == 0 && y1 == 0 && z1 == 0) || (x2 == 0 && y2 == 0 && z2 == 0)
511
+
512
+ x = dot(v1, v2) / (v1.mag * v2.mag)
513
+ return Math::PI if x <= -1
514
+ return 0 if x >= 1
515
+ return Math.acos x
516
+ end
517
+
518
+ # Returns a new 2D unit vector with a random direction.
519
+ #
520
+ # @param target [Vector] a vector to store the new vector
521
+ #
522
+ # @return [Vector] a random vector
523
+ #
524
+ def self.random2D (target = nil)
525
+ v = self.fromAngle rand 0.0...(Math::PI * 2)
526
+ target.set v if target
527
+ v
528
+ end
529
+
530
+ # Returns a new 3D unit vector with a random direction.
531
+ #
532
+ # @param target [Vector] a vector to store the new vector
533
+ #
534
+ # @return [Vector] a random vector
535
+ #
536
+ def self.random3D (target = nil)
537
+ angle = rand 0.0...(Math::PI * 2)
538
+ z = rand -1.0..1.0
539
+ z2 = z ** 2
540
+ x = Math.sqrt(1.0 - z2) * Math.cos(angle)
541
+ y = Math.sqrt(1.0 - z2) * Math.sin(angle)
542
+ v = self.new x, y, z
543
+ target.set v if target
544
+ v
545
+ end
546
+
547
+ # @private
548
+ def inspect ()
549
+ "<##{self.class.name} #{x}, #{y}, #{z}>"
550
+ end
551
+
552
+ # @private
553
+ def <=> (o)
554
+ @point <=> o.getInternal__
555
+ end
556
+
557
+ # @private
558
+ protected def getInternal__ ()
559
+ @point
560
+ end
561
+
562
+ # @private
563
+ private def toVector__ (*args)
564
+ self.class === args.first ? args.first : self.class.new(*args)
565
+ end
566
+
567
+ end# Vector
568
+
569
+
9
570
  # Image object.
10
571
  #
11
572
  class Image
12
573
 
13
574
  # @private
14
575
  def initialize (image)
15
- @image__ = image
576
+ @image = image
16
577
  end
17
578
 
18
579
  # Gets width of image.
@@ -20,7 +581,7 @@ module RubySketch
20
581
  # @return [Numeric] width of image
21
582
  #
22
583
  def width ()
23
- @image__.width
584
+ @image.width
24
585
  end
25
586
 
26
587
  # Gets height of image.
@@ -28,7 +589,7 @@ module RubySketch
28
589
  # @return [Numeric] height of image
29
590
  #
30
591
  def height ()
31
- @image__.height
592
+ @image.height
32
593
  end
33
594
 
34
595
  # Resizes image.
@@ -39,8 +600,8 @@ module RubySketch
39
600
  # @return [nil] nil
40
601
  #
41
602
  def resize (width, height)
42
- @image__ = Rays::Image.new(width, height).paint do |painter|
43
- painter.image @image__, 0, 0, width, height
603
+ @image = Rays::Image.new(width, height).paint do |painter|
604
+ painter.image @image, 0, 0, width, height
44
605
  end
45
606
  nil
46
607
  end
@@ -64,7 +625,7 @@ module RubySketch
64
625
  #
65
626
  def copy (img = nil, sx, sy, sw, sh, dx, dy, dw, dh)
66
627
  img ||= self
67
- @image__.paint do |painter|
628
+ @image.paint do |painter|
68
629
  painter.image img.getInternal__, sx, sy, sw, sh, dx, dy, dw, dh
69
630
  end
70
631
  end
@@ -74,12 +635,12 @@ module RubySketch
74
635
  # @param filename [String] file name to save image
75
636
  #
76
637
  def save (filename)
77
- @image__.save filename
638
+ @image.save filename
78
639
  end
79
640
 
80
641
  # @private
81
642
  def getInternal__ ()
82
- @image__
643
+ @image
83
644
  end
84
645
 
85
646
  end# Image
@@ -167,43 +728,110 @@ module RubySketch
167
728
  end# Touch
168
729
 
169
730
 
170
- # Drawing context
731
+ # Camera object.
171
732
  #
172
- module GraphicsContext
733
+ class Capture
173
734
 
174
- # PI / 2
735
+ # Returns a list of available camera device names
175
736
  #
176
- HALF_PI = Math::PI / 2
177
-
178
- # PI / 4
737
+ # @return [Array] device name list
179
738
  #
180
- QUARTER_PI = Math::PI / 4
739
+ def self.list ()
740
+ ['default']
741
+ end
181
742
 
182
- # PI * 2
743
+ # Initialize camera object.
183
744
  #
184
- TWO_PI = Math::PI * 2
745
+ def initialize ()
746
+ @camera = Rays::Camera.new
747
+ end
185
748
 
186
- # PI * 2
749
+ # Start capturing.
187
750
  #
188
- TAU = Math::PI * 2
189
-
190
- # RGB mode for colorMode().
751
+ # @return [Capture] self
191
752
  #
192
- RGB = :RGB
753
+ def start ()
754
+ raise "Failed to start capture" unless @camera.start
755
+ self
756
+ end
193
757
 
194
- # HSB mode for colorMode().
758
+ # Stop capturing.
195
759
  #
196
- HSB = :HSB
197
-
198
- # Radian mode for angleMode().
760
+ # @return [nil] nil
199
761
  #
200
- RADIANS = :RADIANS
762
+ def stop ()
763
+ @camera.stop
764
+ nil
765
+ end
201
766
 
202
- # Degree mode for angleMode().
767
+ # Returns is the next captured image available?
203
768
  #
204
- DEGREES = :DEGREES
205
-
206
- # Mode for rectMode(), ellipseMode() and imageMode().
769
+ # @return [Boolean] true means object has next frame
770
+ #
771
+ def available ()
772
+ @camera.active?
773
+ end
774
+
775
+ # Reads next frame image
776
+ #
777
+ def read ()
778
+ @camera.image
779
+ end
780
+
781
+ # @private
782
+ def getInternal__ ()
783
+ @camera.image || dummyImage__
784
+ end
785
+
786
+ # @private
787
+ private def dummyImage__ ()
788
+ @dummy ||= Rays::Image.new 1, 1
789
+ end
790
+
791
+ end# Capture
792
+
793
+
794
+ # Drawing context
795
+ #
796
+ module GraphicsContext
797
+
798
+ # PI
799
+ #
800
+ PI = Math::PI
801
+
802
+ # PI / 2
803
+ #
804
+ HALF_PI = PI / 2
805
+
806
+ # PI / 4
807
+ #
808
+ QUARTER_PI = PI / 4
809
+
810
+ # PI * 2
811
+ #
812
+ TWO_PI = PI * 2
813
+
814
+ # PI * 2
815
+ #
816
+ TAU = PI * 2
817
+
818
+ # RGB mode for colorMode().
819
+ #
820
+ RGB = :RGB
821
+
822
+ # HSB mode for colorMode().
823
+ #
824
+ HSB = :HSB
825
+
826
+ # Radian mode for angleMode().
827
+ #
828
+ RADIANS = :RADIANS
829
+
830
+ # Degree mode for angleMode().
831
+ #
832
+ DEGREES = :DEGREES
833
+
834
+ # Mode for rectMode(), ellipseMode() and imageMode().
207
835
  #
208
836
  CORNER = :CORNER
209
837
 
@@ -254,7 +882,7 @@ module RubySketch
254
882
  @painter__ = painter
255
883
  @painter__.miter_limit = 10
256
884
 
257
- @drawing = false
885
+ @drawing__ = false
258
886
  @hsbColor__ = false
259
887
  @colorMaxes__ = [1.0] * 4
260
888
  @angleScale__ = 1.0
@@ -280,11 +908,11 @@ module RubySketch
280
908
  def beginDraw ()
281
909
  @matrixStack__.clear
282
910
  @styleStack__.clear
283
- @drawing = true
911
+ @drawing__ = true
284
912
  end
285
913
 
286
914
  def endDraw ()
287
- @drawing = false
915
+ @drawing__ = false
288
916
  end
289
917
 
290
918
  def width ()
@@ -361,7 +989,7 @@ module RubySketch
361
989
  #
362
990
  def angleMode (mode)
363
991
  @angleScale__ = case mode.upcase.to_sym
364
- when RADIANS then Utility::RAD2DEG__
992
+ when RADIANS then RAD2DEG__
365
993
  when DEGREES then 1.0
366
994
  else raise ArgumentError, "invalid angle mode: #{mode}"
367
995
  end
@@ -369,7 +997,7 @@ module RubySketch
369
997
  end
370
998
 
371
999
  # @private
372
- private def toAngle__ (angle)
1000
+ def toAngle__ (angle)
373
1001
  angle * @angleScale__
374
1002
  end
375
1003
 
@@ -848,8 +1476,9 @@ module RubySketch
848
1476
  #
849
1477
  def image (img, a, b, c = nil, d = nil)
850
1478
  assertDrawing__
851
- x, y, w, h = toXYWH__ @imageMode__, a, b, c || img.width, d || img.height
852
- @painter__.image img.getInternal__, x, y, w, h
1479
+ i = img.getInternal__
1480
+ x, y, w, h = toXYWH__ @imageMode__, a, b, c || i.width, d || i.height
1481
+ @painter__.image i, x, y, w, h
853
1482
  nil
854
1483
  end
855
1484
 
@@ -1030,8 +1659,8 @@ module RubySketch
1030
1659
  end
1031
1660
 
1032
1661
  # @private
1033
- def assertDrawing__ ()
1034
- raise "call beginDraw() before drawing" unless @drawing
1662
+ private def assertDrawing__ ()
1663
+ raise "call beginDraw() before drawing" unless @drawing__
1035
1664
  end
1036
1665
 
1037
1666
  end# GraphicsContext
@@ -1043,17 +1672,23 @@ module RubySketch
1043
1672
 
1044
1673
  include GraphicsContext
1045
1674
 
1675
+ # Initialize graphics object.
1676
+ #
1046
1677
  def initialize (width, height)
1047
1678
  @image__ = Rays::Image.new width, height
1048
1679
  setup__ @image__.painter
1049
1680
  end
1050
1681
 
1682
+ # Start drawing.
1683
+ #
1051
1684
  def beginDraw ()
1052
1685
  @painter__.__send__ :begin_paint
1053
1686
  super
1054
1687
  push
1055
1688
  end
1056
1689
 
1690
+ # End drawing.
1691
+ #
1057
1692
  def endDraw ()
1058
1693
  pop
1059
1694
  super
@@ -1063,86 +1698,325 @@ module RubySketch
1063
1698
  end# Graphics
1064
1699
 
1065
1700
 
1066
- module Utility
1701
+ # Processing context
1702
+ #
1703
+ class Context
1067
1704
 
1068
- # @private
1069
- DEG2RAD__ = Math::PI / 180.0
1705
+ include GraphicsContext
1706
+
1707
+ Vector = Processing::Vector
1708
+ Capture = Processing::Capture
1709
+ Graphics = Processing::Graphics
1710
+
1711
+ @@context__ = nil
1712
+
1713
+ def self.context__ ()
1714
+ @@context__
1715
+ end
1070
1716
 
1071
1717
  # @private
1072
- RAD2DEG__ = 180.0 / Math::PI
1718
+ def initialize (window)
1719
+ @@context__ = self
1073
1720
 
1074
- # Converts degree to radian.
1075
- #
1076
- # @param degree [Numeric] degree to convert
1077
- #
1078
- # @return [Numeric] radian
1079
- #
1080
- def radians (degree)
1081
- degree * DEG2RAD__
1721
+ @window__ = window
1722
+ @image__ = @window__.canvas
1723
+ setup__ @window__.canvas_painter.paint {background 0.8}
1724
+
1725
+ @loop__ = true
1726
+ @redraw__ = false
1727
+ @frameCount__ = 0
1728
+ @mousePos__ =
1729
+ @mousePrevPos__ = Rays::Point.new 0
1730
+ @mousePressed__ = false
1731
+ @touches__ = []
1732
+
1733
+ @window__.before_draw = proc {beginDraw}
1734
+ @window__.after_draw = proc {endDraw}
1735
+
1736
+ drawFrame = -> {
1737
+ @image__ = @window__.canvas
1738
+ @painter__ = @window__.canvas_painter
1739
+ begin
1740
+ push
1741
+ @drawBlock__.call if @drawBlock__
1742
+ ensure
1743
+ pop
1744
+ @frameCount__ += 1
1745
+ end
1746
+ }
1747
+
1748
+ @window__.draw = proc do |e|
1749
+ if @loop__ || @redraw__
1750
+ @redraw__ = false
1751
+ drawFrame.call
1752
+ end
1753
+ @mousePrevPos__ = @mousePos__
1754
+ end
1755
+
1756
+ updatePointerStates = -> event, pressed = nil {
1757
+ @mousePos__ = event.pos
1758
+ @mousePressed__ = pressed if pressed != nil
1759
+ @touches__ = event.positions.map {|pos| Touch.new pos.x, pos.y}
1760
+ }
1761
+
1762
+ @window__.pointer_down = proc do |e|
1763
+ updatePointerStates.call e, true
1764
+ (@touchStartedBlock__ || @mousePressedBlock__)&.call
1765
+ end
1766
+
1767
+ @window__.pointer_up = proc do |e|
1768
+ updatePointerStates.call e, false
1769
+ (@touchEndedBlock__ || @mouseReleasedBlock__)&.call
1770
+ end
1771
+
1772
+ @window__.pointer_move = proc do |e|
1773
+ updatePointerStates.call e
1774
+ (@touchMovedBlock__ || @mouseMovedBlock__)&.call
1775
+ end
1776
+
1777
+ @window__.pointer_drag = proc do |e|
1778
+ updatePointerStates.call e
1779
+ (@touchMovedBlock__ || @mouseDraggedBlock__)&.call
1780
+ end
1082
1781
  end
1083
1782
 
1084
- # Converts radian to degree.
1085
- #
1086
- # @param radian [Numeric] radian to convert
1087
- #
1088
- # @return [Numeric] degree
1783
+ # Define setup block.
1089
1784
  #
1090
- def degrees (radian)
1091
- radian * RAD2DEG__
1785
+ def setup (&block)
1786
+ @window__.setup = block
1787
+ nil
1092
1788
  end
1093
1789
 
1094
- # Returns the absolute number of the value.
1790
+ # Define draw block.
1095
1791
  #
1096
- # @param value [Numeric] number
1792
+ def draw (&block)
1793
+ @drawBlock__ = block if block
1794
+ nil
1795
+ end
1796
+
1797
+ def key (&block)
1798
+ @window__.key = block
1799
+ nil
1800
+ end
1801
+
1802
+ def mousePressed (&block)
1803
+ @mousePressedBlock__ = block if block
1804
+ @mousePressed__
1805
+ end
1806
+
1807
+ def mouseReleased (&block)
1808
+ @mouseReleasedBlock__ = block if block
1809
+ nil
1810
+ end
1811
+
1812
+ def mouseMoved (&block)
1813
+ @mouseMovedBlock__ = block if block
1814
+ nil
1815
+ end
1816
+
1817
+ def mouseDragged (&block)
1818
+ @mouseDraggedBlock__ = block if block
1819
+ nil
1820
+ end
1821
+
1822
+ def touchStarted (&block)
1823
+ @touchStartedBlock__ = block if block
1824
+ nil
1825
+ end
1826
+
1827
+ def touchEnded (&block)
1828
+ @touchEndedBlock__ = block if block
1829
+ nil
1830
+ end
1831
+
1832
+ def touchMoved (&block)
1833
+ @touchMovedBlock__ = block if block
1834
+ nil
1835
+ end
1836
+
1837
+ # @private
1838
+ private def size__ (width, height)
1839
+ raise 'size() must be called on startup or setup block' if @started__
1840
+
1841
+ @painter__.__send__ :end_paint
1842
+ @window__.__send__ :reset_canvas, width, height
1843
+ @painter__.__send__ :begin_paint
1844
+
1845
+ @auto_resize__ = false
1846
+ end
1847
+
1848
+ def windowWidth ()
1849
+ @window__.width
1850
+ end
1851
+
1852
+ def windowHeight ()
1853
+ @window__.height
1854
+ end
1855
+
1856
+ # Returns number of frames since program started.
1097
1857
  #
1098
- # @return [Numeric] absolute number
1858
+ # @return [Integer] total number of frames
1099
1859
  #
1100
- def abs (value)
1101
- value.abs
1860
+ def frameCount ()
1861
+ @frameCount__
1102
1862
  end
1103
1863
 
1104
- # Returns the closest integer number greater than or equal to the value.
1105
- #
1106
- # @param value [Numeric] number
1864
+ # Returns number of frames per second.
1107
1865
  #
1108
- # @return [Numeric] rounded up number
1866
+ # @return [Float] frames per second
1109
1867
  #
1110
- def ceil (value)
1111
- value.ceil
1868
+ def frameRate ()
1869
+ @window__.event.fps
1112
1870
  end
1113
1871
 
1114
- # Returns the closest integer number less than or equal to the value.
1115
- #
1116
- # @param value [Numeric] number
1872
+ # Returns pixel density
1117
1873
  #
1118
- # @return [Numeric] rounded down number
1874
+ # @return [Numeric] pixel density
1119
1875
  #
1120
- def floor (value)
1121
- value.floor
1876
+ def displayDensity ()
1877
+ @painter__.pixel_density
1122
1878
  end
1123
1879
 
1124
- # Returns the closest integer number.
1125
- #
1126
- # @param value [Numeric] number
1880
+ # Returns mouse x position
1127
1881
  #
1128
- # @return [Numeric] rounded number
1882
+ # @return [Numeric] horizontal position of mouse
1129
1883
  #
1130
- def round (value)
1131
- value.round
1884
+ def mouseX ()
1885
+ @mousePos__.x
1132
1886
  end
1133
1887
 
1134
- # Returns value raised to the power of exponent.
1135
- #
1136
- # @param value [Numeric] base number
1137
- # @param exponent [Numeric] exponent number
1888
+ # Returns mouse y position
1138
1889
  #
1139
- # @return [Numeric] value ** exponent
1890
+ # @return [Numeric] vertical position of mouse
1140
1891
  #
1141
- def pow (value, exponent)
1142
- value ** exponent
1892
+ def mouseY ()
1893
+ @mousePos__.y
1143
1894
  end
1144
1895
 
1145
- # Returns squared value.
1896
+ # Returns mouse x position in previous frame
1897
+ #
1898
+ # @return [Numeric] horizontal position of mouse
1899
+ #
1900
+ def pmouseX ()
1901
+ @mousePrevPos__.x
1902
+ end
1903
+
1904
+ # Returns mouse y position in previous frame
1905
+ #
1906
+ # @return [Numeric] vertical position of mouse
1907
+ #
1908
+ def pmouseY ()
1909
+ @mousePrevPos__.y
1910
+ end
1911
+
1912
+ # Returns array of touches
1913
+ #
1914
+ # @return [Array] Touch objects
1915
+ #
1916
+ def touches ()
1917
+ @touches__
1918
+ end
1919
+
1920
+ # Enables calling draw block on every frame.
1921
+ #
1922
+ # @return [nil] nil
1923
+ #
1924
+ def loop ()
1925
+ @loop__ = true
1926
+ end
1927
+
1928
+ # Disables calling draw block on every frame.
1929
+ #
1930
+ # @return [nil] nil
1931
+ #
1932
+ def noLoop ()
1933
+ @loop__ = false
1934
+ end
1935
+
1936
+ # Calls draw block to redraw frame.
1937
+ #
1938
+ # @return [nil] nil
1939
+ #
1940
+ def redraw ()
1941
+ @redraw__ = true
1942
+ end
1943
+
1944
+ #
1945
+ # Utilities
1946
+ #
1947
+
1948
+ # Returns the absolute number of the value.
1949
+ #
1950
+ # @param value [Numeric] number
1951
+ #
1952
+ # @return [Numeric] absolute number
1953
+ #
1954
+ def abs (value)
1955
+ value.abs
1956
+ end
1957
+
1958
+ # Returns the closest integer number greater than or equal to the value.
1959
+ #
1960
+ # @param value [Numeric] number
1961
+ #
1962
+ # @return [Numeric] rounded up number
1963
+ #
1964
+ def ceil (value)
1965
+ value.ceil
1966
+ end
1967
+
1968
+ # Returns the closest integer number less than or equal to the value.
1969
+ #
1970
+ # @param value [Numeric] number
1971
+ #
1972
+ # @return [Numeric] rounded down number
1973
+ #
1974
+ def floor (value)
1975
+ value.floor
1976
+ end
1977
+
1978
+ # Returns the closest integer number.
1979
+ #
1980
+ # @param value [Numeric] number
1981
+ #
1982
+ # @return [Numeric] rounded number
1983
+ #
1984
+ def round (value)
1985
+ value.round
1986
+ end
1987
+
1988
+ # Returns the natural logarithm (the base-e logarithm) of a number.
1989
+ #
1990
+ # @param value [Numeric] number (> 0.0)
1991
+ #
1992
+ # @return [Numeric] result number
1993
+ #
1994
+ def log (n)
1995
+ Math.log n
1996
+ end
1997
+
1998
+ # Returns Euler's number e raised to the power of value.
1999
+ #
2000
+ # @param value [Numeric] number
2001
+ #
2002
+ # @return [Numeric] result number
2003
+ #
2004
+ def exp (n)
2005
+ Math.exp n
2006
+ end
2007
+
2008
+ # Returns value raised to the power of exponent.
2009
+ #
2010
+ # @param value [Numeric] base number
2011
+ # @param exponent [Numeric] exponent number
2012
+ #
2013
+ # @return [Numeric] value ** exponent
2014
+ #
2015
+ def pow (value, exponent)
2016
+ value ** exponent
2017
+ end
2018
+
2019
+ # Returns squared value.
1146
2020
  #
1147
2021
  # @param value [Numeric] number
1148
2022
  #
@@ -1152,6 +2026,16 @@ module RubySketch
1152
2026
  value * value
1153
2027
  end
1154
2028
 
2029
+ # Returns squared value.
2030
+ #
2031
+ # @param value [Numeric] number
2032
+ #
2033
+ # @return [Numeric] squared value
2034
+ #
2035
+ def sqrt (value)
2036
+ Math.sqrt value
2037
+ end
2038
+
1155
2039
  # Returns the magnitude (or length) of a vector.
1156
2040
  #
1157
2041
  # @overload mag(x, y)
@@ -1284,292 +2168,199 @@ module RubySketch
1284
2168
  value < min ? min : (value > max ? max : value)
1285
2169
  end
1286
2170
 
1287
- # Returns the perlin noise value.
1288
- #
1289
- # @overload noise(x)
1290
- # @overload noise(x, y)
1291
- # @overload noise(x, y, z)
2171
+ # Converts degree to radian.
1292
2172
  #
1293
- # @param x [Numeric] horizontal point in noise space
1294
- # @param y [Numeric] vertical point in noise space
1295
- # @param z [Numeric] depth point in noise space
2173
+ # @param degree [Numeric] degree to convert
1296
2174
  #
1297
- # @return [Numeric] noise value (0.0..1.0)
2175
+ # @return [Numeric] radian
1298
2176
  #
1299
- def noise (x, y = 0, z = 0)
1300
- Rays.perlin(x, y, z) / 2.0 + 0.5
2177
+ def radians (degree)
2178
+ degree * DEG2RAD__
1301
2179
  end
1302
2180
 
1303
- # Loads image.
2181
+ # Converts radian to degree.
1304
2182
  #
1305
- # @param filename [String] file name to load image
1306
- # @param extension [String] type of image to load (ex. 'png')
2183
+ # @param radian [Numeric] radian to convert
1307
2184
  #
1308
- # @return [Image] loaded image object
2185
+ # @return [Numeric] degree
1309
2186
  #
1310
- def loadImage (filename, extension = nil)
1311
- filename = getImage__ filename, extension if filename =~ %r|^https?://|
1312
- Image.new Rays::Image.load filename
1313
- end
1314
-
1315
- # @private
1316
- private def getImage__ (uri, ext)
1317
- ext ||= File.extname uri
1318
- raise "unsupported image type -- #{ext}" unless ext =~ /^\.?(png)$/i
1319
-
1320
- tmpdir = Pathname(Dir.tmpdir) + Digest::SHA1.hexdigest(self.class.name)
1321
- path = tmpdir + Digest::SHA1.hexdigest(uri)
1322
- path = path.sub_ext ext
1323
-
1324
- unless path.file?
1325
- URI.open uri do |input|
1326
- tmpdir.mkdir unless tmpdir.directory?
1327
- path.open('w') do |output|
1328
- while buf = input.read(2 ** 16)
1329
- output.write buf
1330
- end
1331
- end
1332
- end
1333
- end
1334
- path.to_s
1335
- end
1336
-
1337
- def createGraphics (width, height)
1338
- Graphics.new width, height
1339
- end
1340
-
1341
- end# Utility
1342
-
1343
-
1344
- # Processing context
1345
- #
1346
- module Context
1347
-
1348
- include GraphicsContext, Utility, Math
1349
-
1350
- # @private
1351
- def setup__ (window)
1352
- @window__ = window
1353
- @image__ = @window__.canvas
1354
- super @window__.canvas_painter.paint {background 0.8}
1355
-
1356
- @loop__ = true
1357
- @redraw__ = false
1358
- @frameCount__ = 0
1359
- @mousePos__ =
1360
- @mousePrevPos__ = Rays::Point.new 0
1361
- @mousePressed__ = false
1362
- @touches__ = []
1363
-
1364
- @window__.before_draw = proc {beginDraw}
1365
- @window__.after_draw = proc {endDraw}
1366
-
1367
- drawFrame = -> {
1368
- @image__ = @window__.canvas
1369
- @painter__ = @window__.canvas_painter
1370
- begin
1371
- push
1372
- @drawBlock__.call if @drawBlock__
1373
- ensure
1374
- pop
1375
- @frameCount__ += 1
1376
- end
1377
- }
1378
-
1379
- @window__.draw = proc do |e|
1380
- if @loop__ || @redraw__
1381
- @redraw__ = false
1382
- drawFrame.call
1383
- end
1384
- @mousePrevPos__ = @mousePos__
1385
- end
1386
-
1387
- updatePointerStates = -> event, pressed = nil {
1388
- @mousePos__ = event.pos
1389
- @mousePressed__ = pressed if pressed != nil
1390
- @touches__ = event.positions.map {|pos| Touch.new pos.x, pos.y}
1391
- }
1392
-
1393
- @window__.pointer_down = proc do |e|
1394
- updatePointerStates.call e, true
1395
- (@touchStartedBlock__ || @mousePressedBlock__)&.call
1396
- end
1397
-
1398
- @window__.pointer_up = proc do |e|
1399
- updatePointerStates.call e, false
1400
- (@touchEndedBlock__ || @mouseReleasedBlock__)&.call
1401
- end
1402
-
1403
- @window__.pointer_move = proc do |e|
1404
- updatePointerStates.call e
1405
- (@touchMovedBlock__ || @mouseMovedBlock__)&.call
1406
- end
1407
-
1408
- @window__.pointer_drag = proc do |e|
1409
- updatePointerStates.call e
1410
- (@touchMovedBlock__ || @mouseDraggedBlock__)&.call
1411
- end
2187
+ def degrees (radian)
2188
+ radian * RAD2DEG__
1412
2189
  end
1413
2190
 
1414
- # Define setup block.
2191
+ # Returns the sine of an angle.
1415
2192
  #
1416
- def setup (&block)
1417
- @window__.setup = block
1418
- nil
1419
- end
1420
-
1421
- # Define draw block.
2193
+ # @param angle [Numeric] angle in radians
1422
2194
  #
1423
- def draw (&block)
1424
- @drawBlock__ = block if block
1425
- nil
1426
- end
1427
-
1428
- def key (&block)
1429
- @window__.key = block
1430
- nil
1431
- end
1432
-
1433
- def mousePressed (&block)
1434
- @mousePressedBlock__ = block if block
1435
- @mousePressed__
1436
- end
1437
-
1438
- def mouseReleased (&block)
1439
- @mouseReleasedBlock__ = block if block
1440
- nil
1441
- end
1442
-
1443
- def mouseMoved (&block)
1444
- @mouseMovedBlock__ = block if block
1445
- nil
1446
- end
1447
-
1448
- def mouseDragged (&block)
1449
- @mouseDraggedBlock__ = block if block
1450
- nil
1451
- end
1452
-
1453
- def touchStarted (&block)
1454
- @touchStartedBlock__ = block if block
1455
- nil
1456
- end
1457
-
1458
- def touchEnded (&block)
1459
- @touchEndedBlock__ = block if block
1460
- nil
1461
- end
1462
-
1463
- def touchMoved (&block)
1464
- @touchMovedBlock__ = block if block
1465
- nil
1466
- end
1467
-
1468
- # @private
1469
- private def size__ (width, height)
1470
- raise 'size() must be called on startup or setup block' if @started__
1471
-
1472
- @painter__.__send__ :end_paint
1473
- @window__.__send__ :reset_canvas, width, height
1474
- @painter__.__send__ :begin_paint
1475
-
1476
- @auto_resize__ = false
1477
- end
1478
-
1479
- def windowWidth ()
1480
- @window__.width
2195
+ # @return [Numeric] the sine
2196
+ #
2197
+ def sin (angle)
2198
+ Math.sin angle
1481
2199
  end
1482
2200
 
1483
- def windowHeight ()
1484
- @window__.height
2201
+ # Returns the cosine of an angle.
2202
+ #
2203
+ # @param angle [Numeric] angle in radians
2204
+ #
2205
+ # @return [Numeric] the cosine
2206
+ #
2207
+ def cos (angle)
2208
+ Math.cos angle
1485
2209
  end
1486
2210
 
1487
- # Returns number of frames since program started.
2211
+ # Returns the ratio of the sine and cosine of an angle.
1488
2212
  #
1489
- # @return [Integer] total number of frames
2213
+ # @param angle [Numeric] angle in radians
1490
2214
  #
1491
- def frameCount ()
1492
- @frameCount__
2215
+ # @return [Numeric] the tangent
2216
+ #
2217
+ def tan (angle)
2218
+ Math.tan angle
1493
2219
  end
1494
2220
 
1495
- # Returns number of frames per second.
2221
+ # Returns the inverse of sin().
1496
2222
  #
1497
- # @return [Float] frames per second
2223
+ # @param value [Numeric] value for calculation
1498
2224
  #
1499
- def frameRate ()
1500
- @window__.event.fps
2225
+ # @return [Numeric] the arc sine
2226
+ #
2227
+ def asin (value)
2228
+ Math.asin value
1501
2229
  end
1502
2230
 
1503
- # Returns pixel density
2231
+ # Returns the inverse of cos().
1504
2232
  #
1505
- # @return [Numeric] pixel density
2233
+ # @param value [Numeric] value for calculation
1506
2234
  #
1507
- def displayDensity ()
1508
- @painter__.pixel_density
2235
+ # @return [Numeric] the arc cosine
2236
+ #
2237
+ def acos (value)
2238
+ Math.acos value
1509
2239
  end
1510
2240
 
1511
- # Returns mouse x position
2241
+ # Returns the inverse of tan().
1512
2242
  #
1513
- # @return [Numeric] horizontal position of mouse
2243
+ # @param value [Numeric] value for valculation
1514
2244
  #
1515
- def mouseX ()
1516
- @mousePos__.x
2245
+ # @return [Numeric] the arc tangent
2246
+ #
2247
+ def atan (value)
2248
+ Math.atan value
1517
2249
  end
1518
2250
 
1519
- # Returns mouse y position
2251
+ # Returns the angle from a specified point.
1520
2252
  #
1521
- # @return [Numeric] vertical position of mouse
2253
+ # @param y [Numeric] y of the point
2254
+ # @param x [Numeric] x of the point
1522
2255
  #
1523
- def mouseY ()
1524
- @mousePos__.y
2256
+ # @return [Numeric] the angle in radians
2257
+ #
2258
+ def atan2 (y, x)
2259
+ Math.atan2 y, x
1525
2260
  end
1526
2261
 
1527
- # Returns mouse x position in previous frame
2262
+ # Returns the perlin noise value.
1528
2263
  #
1529
- # @return [Numeric] horizontal position of mouse
2264
+ # @overload noise(x)
2265
+ # @overload noise(x, y)
2266
+ # @overload noise(x, y, z)
1530
2267
  #
1531
- def pmouseX ()
1532
- @mousePrevPos__.x
2268
+ # @param x [Numeric] horizontal point in noise space
2269
+ # @param y [Numeric] vertical point in noise space
2270
+ # @param z [Numeric] depth point in noise space
2271
+ #
2272
+ # @return [Numeric] noise value (0.0..1.0)
2273
+ #
2274
+ def noise (x, y = 0, z = 0)
2275
+ Rays.perlin(x, y, z) / 2.0 + 0.5
1533
2276
  end
1534
2277
 
1535
- # Returns mouse y position in previous frame
2278
+ # Returns a random number in range low...high
1536
2279
  #
1537
- # @return [Numeric] vertical position of mouse
2280
+ # @overload random()
2281
+ # @overload random(high)
2282
+ # @overload random(low, high)
2283
+ # @overload random(choices)
1538
2284
  #
1539
- def pmouseY ()
1540
- @mousePrevPos__.y
2285
+ # @param low [Numeric] lower limit
2286
+ # @param high [Numeric] upper limit
2287
+ # @param choices [Array] array to choose from
2288
+ #
2289
+ # @return [Float] random number
2290
+ #
2291
+ def random (*args)
2292
+ return args.first.sample if args.first.kind_of? Array
2293
+ high, low = args.reverse
2294
+ rand (low || 0).to_f...(high || 1).to_f
1541
2295
  end
1542
2296
 
1543
- # Returns array of touches
2297
+ # Creates a new vector.
1544
2298
  #
1545
- # @return [Array] Touch objects
2299
+ # @overload createVector()
2300
+ # @overload createVector(x, y)
2301
+ # @overload createVector(x, y, z)
1546
2302
  #
1547
- def touches ()
1548
- @touches__
2303
+ # @param x [Numeric] x of new vector
2304
+ # @param y [Numeric] y of new vector
2305
+ # @param z [Numeric] z of new vector
2306
+ #
2307
+ # @return [Vector] new vector
2308
+ #
2309
+ def createVector (*args)
2310
+ Vector.new *args
1549
2311
  end
1550
2312
 
1551
- # Enables calling draw block on every frame.
2313
+ # Creates a camera object as a video input device.
1552
2314
  #
1553
- # @return [nil] nil
2315
+ # @return [Capture] camera object
1554
2316
  #
1555
- def loop ()
1556
- @loop__ = true
2317
+ def createCapture (*args)
2318
+ Capture.new *args
1557
2319
  end
1558
2320
 
1559
- # Disables calling draw block on every frame.
2321
+ # Creates a new off-screen graphics context object.
1560
2322
  #
1561
- # @return [nil] nil
2323
+ # @param width [Numeric] width of graphics image
2324
+ # @param height [Numeric] height of graphics image
1562
2325
  #
1563
- def noLoop ()
1564
- @loop__ = false
2326
+ # @return [Graphics] graphics object
2327
+ #
2328
+ def createGraphics (width, height)
2329
+ Graphics.new width, height
1565
2330
  end
1566
2331
 
1567
- # Calls draw block to redraw frame.
2332
+ # Loads image.
1568
2333
  #
1569
- # @return [nil] nil
2334
+ # @param filename [String] file name to load image
2335
+ # @param extension [String] type of image to load (ex. 'png')
1570
2336
  #
1571
- def redraw ()
1572
- @redraw__ = true
2337
+ # @return [Image] loaded image object
2338
+ #
2339
+ def loadImage (filename, extension = nil)
2340
+ filename = getImage__ filename, extension if filename =~ %r|^https?://|
2341
+ Image.new Rays::Image.load filename
2342
+ end
2343
+
2344
+ # @private
2345
+ private def getImage__ (uri, ext)
2346
+ ext ||= File.extname uri
2347
+ raise "unsupported image type -- #{ext}" unless ext =~ /^\.?(png)$/i
2348
+
2349
+ tmpdir = Pathname(Dir.tmpdir) + Digest::SHA1.hexdigest(self.class.name)
2350
+ path = tmpdir + Digest::SHA1.hexdigest(uri)
2351
+ path = path.sub_ext ext
2352
+
2353
+ unless path.file?
2354
+ URI.open uri do |input|
2355
+ tmpdir.mkdir unless tmpdir.directory?
2356
+ path.open('w') do |output|
2357
+ while buf = input.read(2 ** 16)
2358
+ output.write buf
2359
+ end
2360
+ end
2361
+ end
2362
+ end
2363
+ path.to_s
1573
2364
  end
1574
2365
 
1575
2366
  end# Context