interpolate 0.2.0
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.
- data/CHANGELOG +17 -0
- data/MIT-LICENSE +20 -0
- data/Manifest.txt +11 -0
- data/README.txt +11 -0
- data/Rakefile +21 -0
- data/examples/arrays.rb +26 -0
- data/examples/colors.rb +35 -0
- data/examples/nested.rb +26 -0
- data/examples/zones.rb +28 -0
- data/lib/interpolate.rb +304 -0
- data/test/test_all.rb +138 -0
- metadata +73 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
== 0.2.0
|
2
|
+
|
3
|
+
* Changed the library name to "interpolate"
|
4
|
+
* Added Array#interpolate that covers uniform arrays and nested arrays
|
5
|
+
* Added more tests, documentation, and examples
|
6
|
+
|
7
|
+
== 0.1.0
|
8
|
+
|
9
|
+
* Gadient calls :interpolate on values for OOP goodness
|
10
|
+
* Checks added for respond_to? :interpolate on values
|
11
|
+
* Added Numeric#interpolate
|
12
|
+
|
13
|
+
== 0.0.1
|
14
|
+
|
15
|
+
* Initial coding
|
16
|
+
* N-sized arbitrary floating point gradients
|
17
|
+
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Adam Collins [adam.w.collins@gmail.com]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
== Interpolate
|
2
|
+
|
3
|
+
Library for generic interpolation objects. Useful for such things as generating
|
4
|
+
linear motion between points (or arrays of points), multi-channel color
|
5
|
+
gradients, piecewise functions, or even just placing values within intervals.
|
6
|
+
|
7
|
+
== Author
|
8
|
+
|
9
|
+
Adam Collins
|
10
|
+
adam.w.collins@gmail.com
|
11
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hoe'
|
3
|
+
$:.unshift(File.dirname(__FILE__) + "/lib")
|
4
|
+
require 'interpolate'
|
5
|
+
|
6
|
+
Hoe.new('Interpolate', Interpolation::VERSION) do |p|
|
7
|
+
p.name = "interpolate"
|
8
|
+
p.author = "Adam Collins"
|
9
|
+
p.description = "Library for creating generic interpolations objects."
|
10
|
+
p.email = 'adam.w.collins@gmail.com'
|
11
|
+
p.summary = "Useful for such things as generating linear motion between points (or arrays of points), multi-channel color gradients, piecewise functions, or even just placing values within intervals."
|
12
|
+
p.url = "http://interpolate.rubyforge.org"
|
13
|
+
#p.clean_globs = [''] # Remove this directory on "rake clean"
|
14
|
+
p.remote_rdoc_dir = '' # Release to root
|
15
|
+
p.changes = p.paragraphs_of('CHANGELOG', 0..1).join("\n\n")
|
16
|
+
# * extra_deps - An array of rubygem dependencies.
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Release and publish documentation"
|
20
|
+
task :repubdoc => [:release, :publish_docs]
|
21
|
+
|
data/examples/arrays.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'interpolate'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
|
6
|
+
# a non-linear set of multi-dimensional points;
|
7
|
+
# perhaps the location of some actor in relation to time
|
8
|
+
time_frames = {
|
9
|
+
0 => [0, 0, 0],
|
10
|
+
1 => [1, 0, 0],
|
11
|
+
2 => [0, 1, 0],
|
12
|
+
3 => [0, 0, 2],
|
13
|
+
4 => [3, 0, 1],
|
14
|
+
5 => [1, 2, 3],
|
15
|
+
6 => [0, 0, 0]
|
16
|
+
}
|
17
|
+
|
18
|
+
path = Interpolation.new(time_frames)
|
19
|
+
|
20
|
+
# play the actors positions in time increments of 0.25
|
21
|
+
(0).step(6, 0.25) do |time|
|
22
|
+
position = path.at(time)
|
23
|
+
puts ">> At #{time}s, actor is at:"
|
24
|
+
p position
|
25
|
+
end
|
26
|
+
|
data/examples/colors.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'interpolate'
|
3
|
+
require 'color'
|
4
|
+
|
5
|
+
|
6
|
+
# we need to implement :interpolate for Color::RGB
|
7
|
+
# in order for Interpolation to work
|
8
|
+
class Color::RGB
|
9
|
+
def interpolate(other, balance)
|
10
|
+
mix_with(other, balance * 100.0)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# a nice weathermap-style color gradient
|
15
|
+
points = {
|
16
|
+
0 => Color::RGB::White,
|
17
|
+
1 => Color::RGB::Lime,
|
18
|
+
# 2 => ? (something between Lime and Yellow)
|
19
|
+
3 => Color::RGB::Yellow,
|
20
|
+
4 => Color::RGB::Orange,
|
21
|
+
5 => Color::RGB::Red,
|
22
|
+
6 => Color::RGB::Magenta,
|
23
|
+
7 => Color::RGB::DarkGray
|
24
|
+
}
|
25
|
+
|
26
|
+
|
27
|
+
gradient = Interpolation.new(points)
|
28
|
+
|
29
|
+
# what are the colors of the gradient from 0 to 7
|
30
|
+
# in increments of 0.2?
|
31
|
+
(0).step(7, 0.2) do |value|
|
32
|
+
color = gradient.at(value)
|
33
|
+
puts "A value of #{value} means #{color.html}"
|
34
|
+
end
|
35
|
+
|
data/examples/nested.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'interpolate'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
|
6
|
+
# a non-linear set of 2D vertexes;
|
7
|
+
# the shape changes at each frame
|
8
|
+
time_frames = {
|
9
|
+
0 => [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], # a horizontal line
|
10
|
+
1 => [[0, 0], [1, 0], [3, 0], [0, 4], [0, 0]], # a triangle
|
11
|
+
2 => [[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]], # a square
|
12
|
+
3 => [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], # a horizontal line, again
|
13
|
+
4 => [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]] # a vertical line
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
paths = Interpolation.new(time_frames)
|
18
|
+
|
19
|
+
# show the vertex positions in time increments of 0.25
|
20
|
+
(0).step(4, 0.25) do |time|
|
21
|
+
points = paths.at(time)
|
22
|
+
puts ">> At #{time}s, points are:"
|
23
|
+
p points
|
24
|
+
end
|
25
|
+
|
26
|
+
|
data/examples/zones.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'interpolate'
|
3
|
+
|
4
|
+
points = {
|
5
|
+
0.000 => 0,
|
6
|
+
0.427 => 1,
|
7
|
+
1.200 => 2,
|
8
|
+
3.420 => 3,
|
9
|
+
27.50 => 4,
|
10
|
+
45.20 => 5,
|
11
|
+
124.4 => 6,
|
12
|
+
}
|
13
|
+
|
14
|
+
zones = Interpolation.new(points)
|
15
|
+
|
16
|
+
values = [
|
17
|
+
-20.2,
|
18
|
+
0.234,
|
19
|
+
65.24,
|
20
|
+
9.234,
|
21
|
+
398.4,
|
22
|
+
4000
|
23
|
+
]
|
24
|
+
|
25
|
+
values.each do |value|
|
26
|
+
zone = zones.at(value).floor
|
27
|
+
puts "A value of #{value} falls into zone #{zone}"
|
28
|
+
end
|
data/lib/interpolate.rb
ADDED
@@ -0,0 +1,304 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
|
3
|
+
Library for generic interpolation objects. Useful for such things as generating
|
4
|
+
linear motion between points (or arrays of points), multi-channel color
|
5
|
+
gradients, piecewise functions, or even just placing values within intervals.
|
6
|
+
|
7
|
+
The only requirement is that each interpolation point value must be able to
|
8
|
+
figure out how to interpolate itself to its neighbor value(s). Numeric
|
9
|
+
objects and uniformly sized arrays are automatically endowed with this
|
10
|
+
ability by this gem, but other classes will require an implementation
|
11
|
+
of #interpolate. See the second example below for a brief demonstration
|
12
|
+
using Color objects.
|
13
|
+
|
14
|
+
Interpolation objects are constructed with a Hash object, wherein each key
|
15
|
+
is a real number value and each value is can respond to #interpolate and
|
16
|
+
determine the resulting value based on its neighbor value and the balance
|
17
|
+
ratio between the two points.
|
18
|
+
|
19
|
+
At or below the lower bounds of the interpolation, the result will be equal to
|
20
|
+
the value of the lower bounds interpolation point. At or above the upper
|
21
|
+
bounds of the graient, the result will be equal to the value of the upper
|
22
|
+
bounds interpolation point.
|
23
|
+
|
24
|
+
|
25
|
+
==Author
|
26
|
+
|
27
|
+
{Adam Collins}[mailto:adam.w.collins@gmail.com]
|
28
|
+
|
29
|
+
|
30
|
+
==General Usage
|
31
|
+
|
32
|
+
Specify the interpolation as a Hash, where keys represent numeric points
|
33
|
+
along the gradient and values represent the known values along that gradient.
|
34
|
+
|
35
|
+
Here's an example for determining which of 7 zones a set of values fall into:
|
36
|
+
|
37
|
+
require 'rubygems'
|
38
|
+
require 'interpolate'
|
39
|
+
|
40
|
+
points = {
|
41
|
+
0.000 => 0,
|
42
|
+
0.427 => 1,
|
43
|
+
1.200 => 2,
|
44
|
+
3.420 => 3,
|
45
|
+
27.50 => 4,
|
46
|
+
45.20 => 5,
|
47
|
+
124.4 => 6,
|
48
|
+
}
|
49
|
+
|
50
|
+
zones = Interpolation.new(points)
|
51
|
+
|
52
|
+
values = [
|
53
|
+
-20.2,
|
54
|
+
0.234,
|
55
|
+
65.24,
|
56
|
+
9.234,
|
57
|
+
398.4,
|
58
|
+
4000
|
59
|
+
]
|
60
|
+
|
61
|
+
values.each do |value|
|
62
|
+
zone = zones.at(value).floor
|
63
|
+
puts "A value of #{value} falls into zone #{zone}"
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
==Non-Numeric Gradients
|
68
|
+
|
69
|
+
For non-Numeric gradient value objects, you'll need to implement :interpolate
|
70
|
+
for the class in question. Here's an example using an RGB color gradient with
|
71
|
+
the help of the 'color' gem:
|
72
|
+
|
73
|
+
require 'rubygems'
|
74
|
+
require 'interpolate'
|
75
|
+
require 'color'
|
76
|
+
|
77
|
+
# we need to implement :interpolate for Color::RGB
|
78
|
+
# in order for Interpolation to work
|
79
|
+
class Color::RGB
|
80
|
+
def interpolate(other, balance)
|
81
|
+
mix_with(other, balance * 100.0)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# a nice weathermap-style color gradient
|
86
|
+
points = {
|
87
|
+
0 => Color::RGB::White,
|
88
|
+
1 => Color::RGB::Lime,
|
89
|
+
# 2 => ? (something between Lime and Yellow)
|
90
|
+
3 => Color::RGB::Yellow,
|
91
|
+
4 => Color::RGB::Orange,
|
92
|
+
5 => Color::RGB::Red,
|
93
|
+
6 => Color::RGB::Magenta,
|
94
|
+
7 => Color::RGB::DarkGray
|
95
|
+
}
|
96
|
+
|
97
|
+
|
98
|
+
gradient = Interpolation.new(points)
|
99
|
+
|
100
|
+
# what are the colors of the gradient from 0 to 7
|
101
|
+
# in increments of 0.2?
|
102
|
+
(0).step(7, 0.2) do |value|
|
103
|
+
color = gradient.at(value)
|
104
|
+
puts "A value of #{value} means #{color.html}"
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
==Array-based Interpolations
|
109
|
+
|
110
|
+
Aside from single value gradient points, you can interpolate over uniformly sized
|
111
|
+
arrays. Between two interpolation points, let's say +a+ and +b+, the final
|
112
|
+
result will be +c+ where +c[0]+ is the interpolation of +a[0]+ and +b[0]+ and
|
113
|
+
+c[1]+ is interpolated between +a[1]+ and +b[1]+ and so on up to +c[n]+.
|
114
|
+
|
115
|
+
Here is an example:
|
116
|
+
|
117
|
+
require 'rubygems'
|
118
|
+
require 'interpolate'
|
119
|
+
require 'pp'
|
120
|
+
|
121
|
+
# a non-linear set of multi-dimensional points;
|
122
|
+
# perhaps the location of some actor in relation to time
|
123
|
+
time_frames = {
|
124
|
+
0 => [0, 0, 0],
|
125
|
+
1 => [1, 0, 0],
|
126
|
+
2 => [0, 1, 0],
|
127
|
+
3 => [0, 0, 2],
|
128
|
+
4 => [3, 0, 1],
|
129
|
+
5 => [1, 2, 3],
|
130
|
+
6 => [0, 0, 0]
|
131
|
+
}
|
132
|
+
|
133
|
+
path = Interpolation.new(time_frames)
|
134
|
+
|
135
|
+
# play the actors positions in time increments of 0.25
|
136
|
+
(0).step(6, 0.25) do |time|
|
137
|
+
position = path.at(time)
|
138
|
+
puts ">> At #{time}s, actor is at:"
|
139
|
+
p position
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
==Nested Array Interpolations
|
144
|
+
|
145
|
+
As long as each top level array is uniformly sized in the first dimension
|
146
|
+
and each nested array is uniformly sized in the second dimension (and so
|
147
|
+
on...), multidimensional interpolation point values will just work.
|
148
|
+
|
149
|
+
Here's an example of a set of 2D points being morphed:
|
150
|
+
|
151
|
+
require 'rubygems'
|
152
|
+
require 'interpolate'
|
153
|
+
require 'pp'
|
154
|
+
|
155
|
+
|
156
|
+
# a non-linear set of 2D vertexes;
|
157
|
+
# the shape changes at each frame
|
158
|
+
time_frames = {
|
159
|
+
0 => [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], # a horizontal line
|
160
|
+
1 => [[0, 0], [1, 0], [3, 0], [0, 4], [0, 0]], # a triangle
|
161
|
+
2 => [[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]], # a square
|
162
|
+
3 => [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], # a horizontal line, again
|
163
|
+
4 => [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]] # a vertical line
|
164
|
+
}
|
165
|
+
|
166
|
+
|
167
|
+
paths = Interpolation.new(time_frames)
|
168
|
+
|
169
|
+
# show the vertex positions in time increments of 0.25
|
170
|
+
(0).step(4, 0.25) do |time|
|
171
|
+
points = paths.at(time)
|
172
|
+
puts ">> At #{time}s, points are:"
|
173
|
+
p points
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
==License
|
178
|
+
|
179
|
+
Licensed under the MIT license.
|
180
|
+
|
181
|
+
=end
|
182
|
+
|
183
|
+
|
184
|
+
# all numeric objects should be supported out of the box
|
185
|
+
class Numeric
|
186
|
+
def interpolate(other, balance)
|
187
|
+
left = self.to_f
|
188
|
+
right = other.to_f
|
189
|
+
delta = (right - left).to_f
|
190
|
+
return left + (delta * balance)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
# a little more complicated, but there's no reason why we can't
|
196
|
+
# interpolate between two equal length arrays as long as each element
|
197
|
+
# responds to :interpolate
|
198
|
+
class Array
|
199
|
+
def interpolate(other, balance)
|
200
|
+
if (self.length < 1) then
|
201
|
+
raise ArgumentError, "cannot interpolate array with no values"
|
202
|
+
end
|
203
|
+
|
204
|
+
if (self.length != other.length) then
|
205
|
+
raise ArgumentError, "cannot interpolate between arrays of different length"
|
206
|
+
end
|
207
|
+
|
208
|
+
final = Array.new
|
209
|
+
|
210
|
+
self.each_with_index do |left, index|
|
211
|
+
unless (left.respond_to? :interpolate) then
|
212
|
+
raise "array element does not respond to :interpolate"
|
213
|
+
end
|
214
|
+
|
215
|
+
right = other[index]
|
216
|
+
|
217
|
+
final[index] = left.interpolate(right, balance)
|
218
|
+
end
|
219
|
+
|
220
|
+
return final
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
class Interpolation
|
226
|
+
VERSION = '0.2.0'
|
227
|
+
|
228
|
+
def initialize(points = {})
|
229
|
+
@points = {}
|
230
|
+
add!(points)
|
231
|
+
end
|
232
|
+
|
233
|
+
def add(points = {})
|
234
|
+
Interpolation.new(points.merge(@points))
|
235
|
+
end
|
236
|
+
|
237
|
+
def add!(points = {})
|
238
|
+
@points.merge!(points)
|
239
|
+
normalize_data
|
240
|
+
end
|
241
|
+
|
242
|
+
|
243
|
+
def at(point)
|
244
|
+
# deal with the two out-of-bounds cases first
|
245
|
+
if (point <= @min_point)
|
246
|
+
return @data.first.last
|
247
|
+
elsif (point >= @max_point)
|
248
|
+
return @data.last.last
|
249
|
+
end
|
250
|
+
|
251
|
+
# go through the interpolation intervals, in order, to determine
|
252
|
+
# into which this point falls
|
253
|
+
1.upto(@data.length - 1) do |zone|
|
254
|
+
left = @data.at(zone - 1)
|
255
|
+
right = @data.at(zone)
|
256
|
+
zone_range = left.first..right.first
|
257
|
+
|
258
|
+
if (zone_range.include?(point))
|
259
|
+
# what are the points in question?
|
260
|
+
left_point = left.first.to_f
|
261
|
+
right_point = right.first.to_f
|
262
|
+
|
263
|
+
# what are the values in question?
|
264
|
+
left_value = left.last
|
265
|
+
right_value = right.last
|
266
|
+
|
267
|
+
# span: difference between the left point and right point
|
268
|
+
# balance: ratio of right point to left point
|
269
|
+
span = right_point - left_point
|
270
|
+
balance = (point.to_f - left_point) / span
|
271
|
+
|
272
|
+
# catch the cases where the point in quesion is
|
273
|
+
# on one of the zone's endpoints
|
274
|
+
return left_value if (balance == 0.0)
|
275
|
+
return right_value if (balance == 1.0)
|
276
|
+
|
277
|
+
# otherwise, we need to interpolate
|
278
|
+
return left_value.interpolate(right_value, balance)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
# we shouldn't get to this point
|
283
|
+
raise "couldn't come up with a value for some reason!"
|
284
|
+
end
|
285
|
+
|
286
|
+
private
|
287
|
+
|
288
|
+
def normalize_data
|
289
|
+
@data = @points.sort
|
290
|
+
@min_point = @data.first.first
|
291
|
+
@max_point = @data.last.first
|
292
|
+
|
293
|
+
# make sure that all values respond_to? :interpolate
|
294
|
+
@data.each do |point|
|
295
|
+
value = point.last
|
296
|
+
unless value.respond_to?(:interpolate)
|
297
|
+
raise ArgumentError, "found an interpolation point that doesn't respond to :interpolate"
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
|
304
|
+
|
data/test/test_all.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
#!/usr/bin/env ruby1.8 -w
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'lib/interpolate'
|
5
|
+
|
6
|
+
|
7
|
+
class InterpolationTest < Test::Unit::TestCase
|
8
|
+
|
9
|
+
DELTA = 1e-7
|
10
|
+
|
11
|
+
def setup
|
12
|
+
decimal_points = {
|
13
|
+
0 => 0,
|
14
|
+
1 => 0.1,
|
15
|
+
2 => 0.2,
|
16
|
+
3 => 0.3,
|
17
|
+
4 => 0.4,
|
18
|
+
5 => 0.5,
|
19
|
+
6 => 0.6,
|
20
|
+
7 => 0.7,
|
21
|
+
8 => 0.8,
|
22
|
+
9 => 0.9,
|
23
|
+
10 => 1
|
24
|
+
}
|
25
|
+
|
26
|
+
array_points = {
|
27
|
+
100 => [1, 10, 100],
|
28
|
+
200 => [5, 50, 500],
|
29
|
+
500 => [10, 100, 1000]
|
30
|
+
}
|
31
|
+
|
32
|
+
@dec_gradient = Interpolation.new(decimal_points)
|
33
|
+
@array_gradient = Interpolation.new(array_points)
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def test_bad_points
|
38
|
+
bad_points = {
|
39
|
+
0 => 4.2,
|
40
|
+
1 => "hello", # not allowed by default
|
41
|
+
2 => 3.4,
|
42
|
+
3 => 4.8
|
43
|
+
}
|
44
|
+
|
45
|
+
assert_raise ArgumentError do
|
46
|
+
gradient = Interpolation.new(bad_points)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_lower_bounds
|
52
|
+
assert_equal(@dec_gradient.at(0), 0)
|
53
|
+
assert_equal(@dec_gradient.at(-1), 0)
|
54
|
+
assert_equal(@dec_gradient.at(-10), 0)
|
55
|
+
assert_equal(@dec_gradient.at(-100), 0)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_upper_bounds
|
59
|
+
assert_equal(@dec_gradient.at(10), 1)
|
60
|
+
assert_equal(@dec_gradient.at(100), 1)
|
61
|
+
assert_equal(@dec_gradient.at(1000), 1)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_midpoints
|
65
|
+
assert_in_delta(@dec_gradient.at(1.5), 0.15, DELTA)
|
66
|
+
assert_in_delta(@dec_gradient.at(2.5), 0.25, DELTA)
|
67
|
+
assert_in_delta(@dec_gradient.at(3.5), 0.35, DELTA)
|
68
|
+
assert_in_delta(@dec_gradient.at(4.5), 0.45, DELTA)
|
69
|
+
assert_in_delta(@dec_gradient.at(5.5), 0.55, DELTA)
|
70
|
+
assert_in_delta(@dec_gradient.at(6.5), 0.65, DELTA)
|
71
|
+
assert_in_delta(@dec_gradient.at(7.5), 0.75, DELTA)
|
72
|
+
assert_in_delta(@dec_gradient.at(8.5), 0.85, DELTA)
|
73
|
+
assert_in_delta(@dec_gradient.at(9.5), 0.95, DELTA)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_precision
|
77
|
+
assert_in_delta(@dec_gradient.at(1.5555), 0.15555, DELTA)
|
78
|
+
assert_in_delta(@dec_gradient.at(2.5678), 0.25678, DELTA)
|
79
|
+
assert_in_delta(@dec_gradient.at(3.5701), 0.35701, DELTA)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_gradient_add
|
83
|
+
new_points = {
|
84
|
+
11 => 1.1,
|
85
|
+
12 => 1.2,
|
86
|
+
13 => 1.3,
|
87
|
+
14 => 1.4,
|
88
|
+
15 => 1.5,
|
89
|
+
16 => 1.6,
|
90
|
+
17 => 1.7,
|
91
|
+
18 => 1.8,
|
92
|
+
19 => 1.9,
|
93
|
+
20 => 2
|
94
|
+
}
|
95
|
+
|
96
|
+
original = @dec_gradient.dup
|
97
|
+
expanded = original.add(new_points)
|
98
|
+
|
99
|
+
assert_equal(original.at(5), 0.5)
|
100
|
+
assert_equal(expanded.at(5), 0.5)
|
101
|
+
|
102
|
+
assert_equal(original.at(15), 1)
|
103
|
+
assert_equal(expanded.at(15), 1.5)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_gradient_add!
|
107
|
+
new_points = {
|
108
|
+
11 => 1.1,
|
109
|
+
12 => 1.2,
|
110
|
+
13 => 1.3,
|
111
|
+
14 => 1.4,
|
112
|
+
15 => 1.5,
|
113
|
+
16 => 1.6,
|
114
|
+
17 => 1.7,
|
115
|
+
18 => 1.8,
|
116
|
+
19 => 1.9,
|
117
|
+
20 => 2
|
118
|
+
}
|
119
|
+
|
120
|
+
original = @dec_gradient.dup
|
121
|
+
expanded = original.dup
|
122
|
+
expanded.add!(new_points)
|
123
|
+
|
124
|
+
assert_equal(original.at(5), 0.5)
|
125
|
+
assert_equal(expanded.at(5), 0.5)
|
126
|
+
|
127
|
+
assert_equal(original.at(15), 1)
|
128
|
+
assert_equal(expanded.at(15), 1.5)
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_array_values
|
132
|
+
assert_equal(@array_gradient.at(150), [3, 30, 300])
|
133
|
+
assert_equal(@array_gradient.at(200), [5, 50, 500])
|
134
|
+
assert_equal(@array_gradient.at(350), [7.5, 75, 750])
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: interpolate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Collins
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-01-24 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.4.0
|
23
|
+
version:
|
24
|
+
description: Library for creating generic interpolations objects.
|
25
|
+
email: adam.w.collins@gmail.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- Manifest.txt
|
32
|
+
- README.txt
|
33
|
+
files:
|
34
|
+
- CHANGELOG
|
35
|
+
- MIT-LICENSE
|
36
|
+
- Manifest.txt
|
37
|
+
- README.txt
|
38
|
+
- Rakefile
|
39
|
+
- examples/arrays.rb
|
40
|
+
- examples/colors.rb
|
41
|
+
- examples/nested.rb
|
42
|
+
- examples/zones.rb
|
43
|
+
- lib/interpolate.rb
|
44
|
+
- test/test_all.rb
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://interpolate.rubyforge.org
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options:
|
49
|
+
- --main
|
50
|
+
- README.txt
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project: interpolate
|
68
|
+
rubygems_version: 1.0.1
|
69
|
+
signing_key:
|
70
|
+
specification_version: 2
|
71
|
+
summary: Useful for such things as generating linear motion between points (or arrays of points), multi-channel color gradients, piecewise functions, or even just placing values within intervals.
|
72
|
+
test_files:
|
73
|
+
- test/test_all.rb
|