ruby-processing 2.4.2 → 2.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +5 -0
- data/CONTRIBUTING.md +2 -0
- data/README.md +5 -5
- data/lib/ruby-processing/runners/base.rb +2 -0
- data/lib/ruby-processing/runners/watch.rb +3 -4
- data/lib/ruby-processing/version.rb +1 -1
- data/library/vecmath/lib/arcball.rb +64 -0
- data/library/vecmath/lib/quaternion.rb +62 -0
- data/library/vecmath/lib/vec.rb +216 -0
- data/library/vecmath/vecmath.rb +37 -323
- data/samples/Rakefile +19 -0
- data/samples/contributed/Rakefile +30 -0
- data/samples/contributed/bezier_playground.rb +14 -6
- data/samples/contributed/drawolver.rb +17 -38
- data/samples/contributed/full_screen.rb +2 -2
- data/samples/contributed/quadraticvertex.rb +10 -2
- data/samples/processing_app/library/vecmath/Rakefile +30 -0
- data/samples/processing_app/library/vecmath/library/flock/flock.rb +4 -4
- data/samples/processing_app/library/vecmath/retained_menger.rb +96 -96
- data/samples/processing_app/topics/advanced_data/Rakefile +30 -0
- data/samples/processing_app/topics/cellular_automata/library/ca/ca.rb +3 -3
- data/samples/processing_app/topics/lsystems/Rakefile +30 -0
- data/samples/processing_app/topics/motion/Rakefile +30 -0
- data/samples/processing_app/topics/shaders/Rakefile +30 -0
- data/samples/processing_app/topics/shaders/data/FishEye.glsl +59 -0
- data/vendors/Rakefile +2 -2
- metadata +14 -4
- data/samples/processing_app/topics/shaders/dome_projection.rb +0 -143
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af2855010f2d2de32e8e7dc8c1828f51c84f56af
|
4
|
+
data.tar.gz: dab785b90f956a8ef19af5bffe4e449577397fcb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50cf01b0dd1f3a1e327abbd76448dfacb202ba8f366337b12c80a6a2d7807b7b4b8a1020c2a4ecbee25ad1e0459c837791e6491bc0741f1c591f60ac0c47c141
|
7
|
+
data.tar.gz: 844bc75fbdaea88f0f2e83d282da9c5bbb467475c56021177f60a8e01caccdfd57c95deb3a022fc86e47535a978da780d1ec975444170bd1c3eb7d152b5517c9
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
v2.4.3 Update to JRuby-1.7.11
|
2
|
+
* Added an autorun demo Rakefile to some sample directories
|
3
|
+
* Support utf-8 in sketches
|
4
|
+
* Refactor and extend vecmath (updated drawolver to use Vec3D)
|
5
|
+
|
1
6
|
v2.4.2 Update to JRuby-1.7.10
|
2
7
|
* Revised suggestions for PROCESSING_ROOT on MacOSX
|
3
8
|
|
data/CONTRIBUTING.md
CHANGED
@@ -12,6 +12,7 @@ Here are some ways *you* can contribute:
|
|
12
12
|
* by proselytizing ruby-processing, we need more champions
|
13
13
|
* by supporting [Processing.org][], nothing to do with us but we rely on them
|
14
14
|
* by figuring out if we could replace swing with javafx for control_panel etc
|
15
|
+
* by testing / contributing to the [development branch][]
|
15
16
|
|
16
17
|
## Submitting an Issue
|
17
18
|
We use the [GitHub issue tracker][issues] to track bugs and features. Before
|
@@ -31,3 +32,4 @@ the bug, including your gem version, Ruby version, and operating system.
|
|
31
32
|
[fork]: http://help.github.com/fork-a-repo/
|
32
33
|
[pr]: http://help.github.com/send-pull-requests/
|
33
34
|
[processing.org]: http://processing.org/foundation/
|
35
|
+
[development branch]: https://github.com/monkstone/JRubyArt
|
data/README.md
CHANGED
@@ -12,19 +12,19 @@ Is a ruby wrapper around the [Processing][] code art framework, built using [JRu
|
|
12
12
|
|
13
13
|
## Installation
|
14
14
|
|
15
|
-
Ideally you should install [jruby](http://jruby.org/download), at the very least you will have at least ruby-1.9.3 installed. You should [download][] and install vanilla [processing-2.0.3](https://processing.org/download/) (MacOSX) or [processing-2.1.0](https://processing.org/download/) (Windows, Linux) prior to installing this version of ruby-processing. You must also set the `PROCESSING_ROOT` in the .rp5rc yaml configuration file, the easiest way is by running the [SetProcessingRoot.pde](https://gist.github.com/monkstone/7438749) sketch in the processing ide.
|
15
|
+
Ideally you should install [jruby](http://jruby.org/download), at the very least you will have at least ruby-1.9.3 installed. You should [download][] and install vanilla [processing-2.0.3](https://processing.org/download/) (MacOSX) or [processing-2.1.0](https://processing.org/download/) (Windows, Linux) prior to installing this version of ruby-processing. You must also set the `PROCESSING_ROOT` in the .rp5rc yaml configuration file, the easiest way to do this is by running the [SetProcessingRoot.pde](https://gist.github.com/monkstone/7438749) sketch in the processing ide.
|
16
16
|
|
17
17
|
Then install ruby-processing (from rubygems-org) in the usual way
|
18
18
|
|
19
19
|
`gem install ruby-processing` some systems eg Ubuntu may require `sudo` access
|
20
20
|
|
21
|
-
To install jruby-complete use our built in tool (relies on `wget` to download [jruby-complete-1.7.
|
21
|
+
To install jruby-complete use our built in tool (relies on `wget` to download [jruby-complete-1.7.11](http://jruby.org/download))
|
22
22
|
|
23
23
|
`install_jruby_complete`
|
24
24
|
|
25
|
-
If you haven't got `wget` just download jruby-complete-1.7.
|
25
|
+
If you haven't got `wget` just download jruby-complete-1.7.11 to the vendors folder (then run above tool)
|
26
26
|
|
27
|
-
The vendored jruby-complete-1.7.
|
27
|
+
The vendored jruby-complete-1.7.11 is only required for application export, and running certain sketches (eg shader sketches see wiki).
|
28
28
|
|
29
29
|
|
30
30
|
## Documentation
|
@@ -111,7 +111,7 @@ This library has been tested with the following ruby implementations
|
|
111
111
|
|
112
112
|
## What's new
|
113
113
|
|
114
|
-
New capabilities since processing-2.0 include ability to use OPENGL VBO (PShape) and GLSL shaders (PShader), to keep abreast of latest shader developments for processing check out the [codeanticode blog](http://codeanticode.wordpress.com/2013/06/04/processing-2-0-is-out-processing-2-0-is-in/). Some worked examples using new feature are included in the samples. The update to the latest jruby is also significant as the default is to run with ruby-1.9 support, and there have been many performance improvements. Some performance improvements will not be available on the Mac as they require at least java-7+, and there is even more to come with java-8+ (adventurous Mac users can read more about [Oracle java here](http://www.java.com/en/download/faq/java_mac.xml) ). More than 330 worked examples are included in the [Samples][], many of which are rubified version of the examples included with vanilla processing, and or the contributed libraries, additions are welcome.
|
114
|
+
New capabilities since processing-2.0 include ability to use OPENGL VBO (PShape) and GLSL shaders (PShader), to keep abreast of latest shader developments for processing check out the [codeanticode blog](http://codeanticode.wordpress.com/2013/06/04/processing-2-0-is-out-processing-2-0-is-in/). Some worked examples using new feature are included in the samples. The update to the latest jruby is also significant as the default is to run with ruby-1.9 support (or even use ruby-2.0 syntax with `compat.version=2.0` in your `.jrubyrc` config), and there have been many performance improvements. Some performance improvements will not be available on the Mac as they require at least java-7+, and there is even more to come with java-8+ (adventurous Mac users can read more about [Oracle java here](http://www.java.com/en/download/faq/java_mac.xml) ). More than 330 worked examples are included in the [Samples][], many of which are rubified version of the examples included with vanilla processing, and or the contributed libraries, additions are welcome.
|
115
115
|
|
116
116
|
|
117
117
|
|
@@ -22,7 +22,7 @@ module Processing
|
|
22
22
|
if @files.detect { |file| File.exist?(file) && File.stat(file).mtime > @time }
|
23
23
|
puts "reloading sketch..."
|
24
24
|
$app && $app.close
|
25
|
-
@time = Time.now
|
25
|
+
@time = Time.now
|
26
26
|
java.lang.System.gc
|
27
27
|
start_runner
|
28
28
|
reload_files_to_watch
|
@@ -36,9 +36,8 @@ module Processing
|
|
36
36
|
def report_errors
|
37
37
|
yield
|
38
38
|
rescue Exception => e
|
39
|
-
|
40
|
-
puts e.
|
41
|
-
puts e.backtrace.join("\n")
|
39
|
+
warn "Exception occured while running sketch #{File.basename SKETCH_PATH}..."
|
40
|
+
puts "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
|
42
41
|
end
|
43
42
|
|
44
43
|
def start_runner
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative 'vec'
|
2
|
+
require_relative 'quaternion'
|
3
|
+
|
4
|
+
class ArcBall
|
5
|
+
attr_reader :center_x, :center_y, :v_down, :v_drag, :q_now, :q_drag, :q_down, :axis, :axis_set, :radius
|
6
|
+
|
7
|
+
def initialize(cx, cy, radius)
|
8
|
+
@center_x = cx
|
9
|
+
@center_y = cy
|
10
|
+
@radius = radius
|
11
|
+
@v_down = Vec3D.new
|
12
|
+
@v_drag = Vec3D.new
|
13
|
+
@q_now = Quaternion.new
|
14
|
+
@q_down = Quaternion.new
|
15
|
+
@q_drag = Quaternion.new
|
16
|
+
@axis_set = [Vec3D.new(1.0, 0.0, 0.0), Vec3D.new(0.0, 1.0, 0.0), Vec3D.new(0.0, 0.0, 1.0)]
|
17
|
+
@axis = -1
|
18
|
+
end
|
19
|
+
|
20
|
+
def select_axis(axis)
|
21
|
+
@axis = axis
|
22
|
+
end
|
23
|
+
|
24
|
+
def mouse2sphere(x, y)
|
25
|
+
v = Vec3D.new((x - center_x) / radius, (y - center_y) / radius, 0)
|
26
|
+
mag = v.mag
|
27
|
+
if (mag > 1.0)
|
28
|
+
v.normalize!
|
29
|
+
else
|
30
|
+
v.z = Math.sqrt(1.0 - mag)
|
31
|
+
end
|
32
|
+
v = constrain(v, axis_set[axis]) unless (axis == -1)
|
33
|
+
return v
|
34
|
+
end
|
35
|
+
|
36
|
+
def mouse_pressed(x, y)
|
37
|
+
@v_down = mouse2sphere(x, y)
|
38
|
+
@q_down.copy(q_now)
|
39
|
+
@q_drag.reset
|
40
|
+
end
|
41
|
+
|
42
|
+
def mouse_dragged(x, y)
|
43
|
+
@v_drag = mouse2sphere(x, y)
|
44
|
+
@q_drag.set(v_down.dot(v_drag), v_down.cross(v_drag))
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def constrain(vector, axis)
|
49
|
+
res = vector - (axis * axis.dot(vector))
|
50
|
+
res.normalize!
|
51
|
+
end
|
52
|
+
|
53
|
+
def update
|
54
|
+
@q_now = q_drag * q_down
|
55
|
+
quat2matrix(q_now)
|
56
|
+
end
|
57
|
+
|
58
|
+
def quat2matrix(q)
|
59
|
+
q.get_value
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require_relative 'vec'
|
2
|
+
|
3
|
+
class Quaternion
|
4
|
+
EPSILON = 9.999999747378752e-05 # a value used by processing.org
|
5
|
+
attr_reader :w, :x, :y, :z
|
6
|
+
|
7
|
+
def initialize(w = 1.0, x = 0, y = 0, z = 0)
|
8
|
+
@w, @x, @y, @z = w, x, y, z
|
9
|
+
end
|
10
|
+
|
11
|
+
def ==(quat)
|
12
|
+
(w - quat.w).abs < EPSILON && (x - quat.x).abs < EPSILON && (y - quat.y).abs < EPSILON && (z - quat.z).abs < EPSILON
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def reset
|
17
|
+
@w = 1.0
|
18
|
+
@x = 0.0
|
19
|
+
@y = 0.0
|
20
|
+
@z = 0.0
|
21
|
+
end
|
22
|
+
|
23
|
+
def set(w, v)
|
24
|
+
@w, @x, @y, @z = w, v.x, v.y, v.z
|
25
|
+
end
|
26
|
+
|
27
|
+
def copy(q)
|
28
|
+
@w, @x, @y, @z = q.w, q.x, q.y, q.z
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.mult(q1, q2) # class method
|
32
|
+
x0 = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y
|
33
|
+
y0 = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z
|
34
|
+
z0 = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x
|
35
|
+
w0 = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z
|
36
|
+
Quaternion.new(w0, x0, y0, z0)
|
37
|
+
end
|
38
|
+
|
39
|
+
def * (q1) # instance method
|
40
|
+
x0 = w * q1.x + x * q1.w + y * q1.z - z * q1.y
|
41
|
+
y0 = w * q1.y + y * q1.w + z * q1.x - x * q1.z
|
42
|
+
z0 = w * q1.z + z * q1.w + x * q1.y - y * q1.x
|
43
|
+
w0 = w * q1.w - x * q1.x - y * q1.y - z * q1.z
|
44
|
+
Quaternion.new(w0, x0, y0, z0)
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_value
|
48
|
+
sa = Math.sqrt(1.0 - w * w)
|
49
|
+
sa = 1.0 unless (sa >= EPSILON)
|
50
|
+
[Math.acos(w) * 2, x / sa, y / sa, z / sa]
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
"#{self.class}(w=#{w}, x=#{x}, y=#{y}, z=#{z})"
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect
|
58
|
+
self.to_s
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
@@ -0,0 +1,216 @@
|
|
1
|
+
class Vec2D
|
2
|
+
EPSILON = 9.999999747378752e-05 # a value used by processing.org
|
3
|
+
attr_accessor :x, :y, :z
|
4
|
+
|
5
|
+
def initialize(x = 0 ,y = 0, z = 0)
|
6
|
+
@x, @y, @z = x, y, z
|
7
|
+
post_initialize
|
8
|
+
end
|
9
|
+
|
10
|
+
def post_initialize
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==(vec)
|
15
|
+
(x - vec.x).abs < EPSILON && (y - vec.y).abs < EPSILON && (z - vec.z).abs < EPSILON
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.dist_squared(vec_a, vec_b)
|
19
|
+
(vec_a.x - vec_b.x)**2 + (vec_a.y - vec_b.y)**2 + (vec_a.z - vec_b.z)**2
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.dist(vec_a, vec_b)
|
23
|
+
Math.sqrt((vec_a.x - vec_b.x)**2 + (vec_a.y - vec_b.y)**2 + (vec_a.z - vec_b.z)**2)
|
24
|
+
end
|
25
|
+
|
26
|
+
def inspect
|
27
|
+
self.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def self.from_angle scalar
|
32
|
+
Vec2D.new(Math.cos(scalar), Math.sin(scalar))
|
33
|
+
end
|
34
|
+
|
35
|
+
def modulus
|
36
|
+
Math.hypot(x, y)
|
37
|
+
end
|
38
|
+
|
39
|
+
def mag_squared
|
40
|
+
x**2 + y**2
|
41
|
+
end
|
42
|
+
|
43
|
+
# vanilla processing PVector returns a Vector, rather than Scalar (defaults to 3D result with z = 0)
|
44
|
+
def cross(vec)
|
45
|
+
x * vec.y - y * vec.x
|
46
|
+
end
|
47
|
+
|
48
|
+
# Scalar product, also known as inner product or dot product
|
49
|
+
def dot(vec)
|
50
|
+
x * vec.x + y * vec.y
|
51
|
+
end
|
52
|
+
|
53
|
+
def collinear_with?(vec)
|
54
|
+
cross(vec).abs < EPSILON
|
55
|
+
end
|
56
|
+
|
57
|
+
def +(vec)
|
58
|
+
Vec2D.new(x + vec.x, y + vec.y)
|
59
|
+
end
|
60
|
+
|
61
|
+
def -(vec)
|
62
|
+
Vec2D.new(x - vec.x, y - vec.y)
|
63
|
+
end
|
64
|
+
|
65
|
+
def *(scalar)
|
66
|
+
Vec2D.new(x * scalar, y * scalar)
|
67
|
+
end
|
68
|
+
|
69
|
+
def / (scalar)
|
70
|
+
Vec2D.new(x / scalar, y / scalar) unless scalar == 0
|
71
|
+
end
|
72
|
+
|
73
|
+
# @param [Vec2D] vec
|
74
|
+
# The target vector
|
75
|
+
# @param [Float] scalar
|
76
|
+
# @return [Vec2D]
|
77
|
+
# A new Vec2D on the way to the target (all the way if scalar not in 0 .. 1.0)
|
78
|
+
|
79
|
+
def lerp(vec, scalar)
|
80
|
+
if (0 .. 1.0).include? scalar
|
81
|
+
x0, y0 = x * scalar + vec.x * (1 - scalar), y * scalar + vec.y * (1 - scalar)
|
82
|
+
else
|
83
|
+
x0, y0 = vec.x, vec.y # you will get there rather quicker than you hoped
|
84
|
+
end
|
85
|
+
Vec2D.new(x0, y0)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Change the values of current Vec2D toward a target
|
89
|
+
# @param [Vec2D] vec
|
90
|
+
# The target vector
|
91
|
+
# @param [Float] scalar
|
92
|
+
# @return [Vec2D]
|
93
|
+
# self Vec2D on the way to the target (unchanged if scalar not in 0 .. 1.0)
|
94
|
+
|
95
|
+
|
96
|
+
def lerp!(vec, scalar)
|
97
|
+
@x, @y = x * scalar + vec.x * (1 - scalar), y * scalar + vec.y * (1 - scalar) if (0 .. 1.0).include? scalar
|
98
|
+
return self
|
99
|
+
end
|
100
|
+
|
101
|
+
def heading
|
102
|
+
Math.atan2(-y, x) * -1.0
|
103
|
+
end
|
104
|
+
|
105
|
+
def normalize
|
106
|
+
magnitude = Math.hypot(x, y)
|
107
|
+
Vec2D.new( x / magnitude, y / magnitude)
|
108
|
+
end
|
109
|
+
|
110
|
+
def normalize!
|
111
|
+
magnitude = Math.hypot(x, y)
|
112
|
+
@x, @y = x / magnitude, y / magnitude
|
113
|
+
return self
|
114
|
+
end
|
115
|
+
|
116
|
+
def set_mag(scalar)
|
117
|
+
magnitude = Math.hypot(x, y)
|
118
|
+
@x, @y = (x * scalar) / magnitude, (y * scalar) / magnitude
|
119
|
+
return self
|
120
|
+
end
|
121
|
+
|
122
|
+
def to_a
|
123
|
+
[x, y]
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_s
|
127
|
+
"#{self.class}(x=#{x}, y=#{y})"
|
128
|
+
end
|
129
|
+
|
130
|
+
alias :mag :modulus
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
class Vec2DR < Vec2D
|
135
|
+
|
136
|
+
def rotate(rot)
|
137
|
+
Vec2D.new((x * Math.cos(rot)) - y * Math.sin(rot),
|
138
|
+
(x * Math.sin(rot)) + (y * Math.cos(rot)))
|
139
|
+
end
|
140
|
+
|
141
|
+
# this behaves like PVector rotate (ie changes self, except returns self rather than "void")
|
142
|
+
def rotate!(rot)
|
143
|
+
@x, @y = (x * Math.cos(rot) - y * Math.sin(rot)), (x * Math.sin(rot) + y * Math.cos(rot))
|
144
|
+
return self
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
class Vec3D < Vec2D
|
149
|
+
|
150
|
+
def modulus
|
151
|
+
Math.sqrt(x**2 + y**2 + z**2)
|
152
|
+
end
|
153
|
+
|
154
|
+
def cross(vec)
|
155
|
+
xc = y * vec.z - z * vec.y
|
156
|
+
yc = z * vec.x - x * vec.z
|
157
|
+
zc = x * vec.y - y * vec.x
|
158
|
+
Vec3D.new(xc, yc, zc)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Scalar product, also known as inner product or dot product
|
162
|
+
def dot(vec)
|
163
|
+
x * vec.x + y * vec.y + z * vec.z
|
164
|
+
end
|
165
|
+
|
166
|
+
def collinear_with?(vec)
|
167
|
+
cross(vec) == Vec3D.new
|
168
|
+
end
|
169
|
+
|
170
|
+
def to_a
|
171
|
+
[x, y, z]
|
172
|
+
end
|
173
|
+
|
174
|
+
def +(vec)
|
175
|
+
Vec3D.new(x + vec.x, y + vec.y, z + vec.z)
|
176
|
+
end
|
177
|
+
|
178
|
+
def -(vec)
|
179
|
+
Vec3D.new(x - vec.x, y - vec.y, z - vec.z)
|
180
|
+
end
|
181
|
+
|
182
|
+
def * (scalar)
|
183
|
+
Vec3D.new(x * scalar, y * scalar, z * scalar)
|
184
|
+
end
|
185
|
+
|
186
|
+
def / (scalar)
|
187
|
+
Vec3D.new(x / scalar, y / scalar, z / scalar) unless scalar.abs < EPSILON
|
188
|
+
end
|
189
|
+
|
190
|
+
def normalize
|
191
|
+
magnitude = Math.sqrt(x**2 + y**2 + z**2)
|
192
|
+
Vec3D.new( x / magnitude, y / magnitude, z / magnitude)
|
193
|
+
end
|
194
|
+
|
195
|
+
def normalize!
|
196
|
+
magnitude = Math.sqrt(x**2 + y**2 + z**2)
|
197
|
+
@x, @y, @z = x / magnitude, y / magnitude, z / magnitude
|
198
|
+
return self
|
199
|
+
end
|
200
|
+
|
201
|
+
def set_mag(scalar)
|
202
|
+
magnitude = Math.sqrt(x**2 + y**2 + z**2)
|
203
|
+
@x, @y, @z = (x * scalar) / magnitude, (y * scalar) / magnitude, (z * scalar) / magnitude
|
204
|
+
return self
|
205
|
+
end
|
206
|
+
|
207
|
+
def to_s
|
208
|
+
"#{self.class}(x=#{x}, y=#{y}, z=#{z})"
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
|
215
|
+
|
216
|
+
|