interpolate 0.2.3 → 0.2.4
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/{History.txt → CHANGELOG.md} +5 -6
- data/{LICENSE.txt → LICENSE} +1 -1
- data/Manifest.txt +8 -6
- data/{README.txt → README.md} +57 -52
- data/Rakefile +31 -15
- data/VERSION +1 -0
- data/examples/arrays.rb +1 -0
- data/examples/buckets.rb +32 -0
- data/examples/colors.rb +20 -17
- data/examples/nested.rb +2 -2
- data/interpolate.gemspec +65 -0
- data/lib/interpolate.rb +1 -2
- data/lib/interpolate/add/core.rb +2 -123
- data/lib/interpolate/add/{array.rb → core/array.rb} +0 -0
- data/lib/interpolate/add/{numeric.rb → core/numeric.rb} +0 -0
- data/lib/interpolate/interpolation.rb +117 -0
- data/test/test_all.rb +11 -34
- metadata +38 -55
- data.tar.gz.sig +0 -0
- data/examples/zones.rb +0 -28
- metadata.gz.sig +0 -0
@@ -1,19 +1,18 @@
|
|
1
|
-
== 0.2.
|
1
|
+
== 0.2.4 (2011.4.10)
|
2
2
|
|
3
|
-
*
|
3
|
+
* Project cleanup: minor updates to the lib/ file structure and documentation
|
4
4
|
|
5
5
|
== 0.2.2 (2008.2.4)
|
6
6
|
|
7
7
|
* Single source file has been split into Class files
|
8
|
-
* Tests now use +freeze
|
8
|
+
* Tests now use +freeze+
|
9
9
|
* Better edge case testing in the Array and Numeric +interpolate+ methods
|
10
10
|
|
11
11
|
== 0.2.1 (2008.1.27)
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
* Project Cleanup:
|
13
|
+
First public release
|
16
14
|
|
15
|
+
Project Cleanup:
|
17
16
|
* Documentation enhancements and updates.
|
18
17
|
* +add+ is now +merge+
|
19
18
|
|
data/{LICENSE.txt → LICENSE}
RENAMED
data/Manifest.txt
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
|
2
|
-
LICENSE
|
1
|
+
CHANGELOG.md
|
2
|
+
LICENSE
|
3
3
|
Manifest.txt
|
4
|
-
README.txt
|
5
4
|
Rakefile
|
5
|
+
README.md
|
6
|
+
VERSION
|
6
7
|
examples/arrays.rb
|
8
|
+
examples/buckets.rb
|
7
9
|
examples/colors.rb
|
8
10
|
examples/nested.rb
|
9
|
-
examples/zones.rb
|
10
11
|
lib/interpolate.rb
|
11
|
-
lib/interpolate/
|
12
|
+
lib/interpolate/interpolation.rb
|
12
13
|
lib/interpolate/add/core.rb
|
13
|
-
lib/interpolate/add/
|
14
|
+
lib/interpolate/add/core/array.rb
|
15
|
+
lib/interpolate/add/core/numeric.rb
|
14
16
|
test/test_all.rb
|
data/{README.txt → README.md}
RENAMED
@@ -1,39 +1,40 @@
|
|
1
|
-
|
1
|
+
# Interpolate
|
2
2
|
|
3
|
-
|
3
|
+
## Author
|
4
4
|
|
5
|
-
Adam Collins [adam
|
5
|
+
Adam Collins [adam@m104.us]
|
6
6
|
|
7
7
|
|
8
|
-
|
8
|
+
## Description
|
9
9
|
|
10
10
|
Library for generic Interpolation objects. Useful for such things as generating
|
11
11
|
linear motion between points (or arrays of points), multi-channel color
|
12
12
|
gradients, piecewise functions, or even just placing values within intervals.
|
13
13
|
|
14
14
|
|
15
|
-
|
15
|
+
## General Usage
|
16
16
|
|
17
17
|
Specify the interpolation as a Hash, where keys represent numeric points
|
18
|
-
along the gradient and values represent the known values along that
|
18
|
+
along the gradient and values represent the known (key) values along that
|
19
|
+
gradient.
|
19
20
|
|
20
|
-
Here's an example for
|
21
|
-
of a set falls into:
|
21
|
+
Here's an example for placing values within one of seven buckets:
|
22
22
|
|
23
23
|
require 'rubygems'
|
24
24
|
require 'interpolate'
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
0.
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
26
|
+
# min_value => bucket
|
27
|
+
buckets = {
|
28
|
+
0.000 => 1,
|
29
|
+
0.427 => 2,
|
30
|
+
1.200 => 3,
|
31
|
+
3.420 => 4,
|
32
|
+
27.50 => 5,
|
33
|
+
45.20 => 6,
|
34
|
+
124.4 => 7,
|
34
35
|
}
|
35
36
|
|
36
|
-
|
37
|
+
bucketizer = Interpolation.new(buckets)
|
37
38
|
|
38
39
|
values = [
|
39
40
|
-20.2,
|
@@ -45,47 +46,51 @@ of a set falls into:
|
|
45
46
|
]
|
46
47
|
|
47
48
|
values.each do |value|
|
48
|
-
|
49
|
-
puts "A value of #{value} falls into
|
49
|
+
bucket = bucketizer.at(value).floor
|
50
|
+
puts "A value of #{value} falls into bucket #{bucket}"
|
50
51
|
end
|
51
52
|
|
52
53
|
|
53
|
-
|
54
|
+
## Non-Numeric Gradients
|
54
55
|
|
55
56
|
For non-Numeric gradient value objects, you'll need to implement +interpolate+
|
56
|
-
for the class in question
|
57
|
-
|
57
|
+
for the class in question. Here's an example using an RGB color gradient with
|
58
|
+
the help of the 'color' gem:
|
58
59
|
|
59
60
|
require 'rubygems'
|
60
61
|
require 'interpolate'
|
61
62
|
require 'color'
|
62
63
|
|
64
|
+
# we need to implement +interpolate+ for Color::RGB
|
65
|
+
# in order for Interpolation to work
|
66
|
+
class Color::RGB
|
67
|
+
def interpolate(other, balance)
|
68
|
+
mix_with(other, balance * 100.0)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
63
72
|
# a nice weathermap-style color gradient
|
64
73
|
points = {
|
65
|
-
|
66
|
-
|
67
|
-
#
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
7 => Color::RGB::DarkGray
|
74
|
+
1 => Color::RGB::White,
|
75
|
+
2 => Color::RGB::Lime,
|
76
|
+
# 3 => ? (between Lime and Yellow; Interpolate will figure it out)
|
77
|
+
4 => Color::RGB::Yellow,
|
78
|
+
5 => Color::RGB::Orange,
|
79
|
+
6 => Color::RGB::Red,
|
80
|
+
7 => Color::RGB::Magenta
|
73
81
|
}
|
74
82
|
|
75
|
-
gradient = Interpolation.new(points)
|
76
|
-
left.mix_with(right, balance * 100.0)
|
77
|
-
end
|
83
|
+
gradient = Interpolation.new(points)
|
78
84
|
|
79
|
-
# what are the colors of the gradient from
|
85
|
+
# what are the colors of the gradient from 1 to 7
|
80
86
|
# in increments of 0.2?
|
81
|
-
(
|
87
|
+
(1).step(7, 0.2) do |value|
|
82
88
|
color = gradient.at(value)
|
83
89
|
puts "A value of #{value} means #{color.html}"
|
84
90
|
end
|
85
91
|
|
86
92
|
|
87
|
-
|
88
|
-
== Array-based Interpolations
|
93
|
+
## Array-based Interpolations
|
89
94
|
|
90
95
|
Aside from single value gradient points, you can interpolate over uniformly sized
|
91
96
|
arrays. Between two interpolation points, let's say +a+ and +b+, the final result
|
@@ -100,28 +105,28 @@ Here is an example:
|
|
100
105
|
require 'pp'
|
101
106
|
|
102
107
|
# a non-linear set of multi-dimensional points;
|
103
|
-
# perhaps the location of
|
108
|
+
# perhaps the location of an actor in relation to time
|
104
109
|
time_frames = {
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
110
|
+
1 => [0, 0, 0],
|
111
|
+
2 => [1, 0, 0],
|
112
|
+
3 => [0, 1, 0],
|
113
|
+
4 => [0, 0, 2],
|
114
|
+
5 => [3, 0, 1],
|
115
|
+
6 => [1, 2, 3],
|
116
|
+
7 => [0, 0, 0]
|
112
117
|
}
|
113
118
|
|
114
119
|
path = Interpolation.new(time_frames)
|
115
120
|
|
116
|
-
# play the
|
117
|
-
(
|
121
|
+
# play the actor's positions in time increments of 0.25
|
122
|
+
(1).step(7, 0.25) do |time|
|
118
123
|
position = path.at(time)
|
119
124
|
puts ">> At #{time}s, actor is at:"
|
120
125
|
p position
|
121
126
|
end
|
122
127
|
|
123
128
|
|
124
|
-
|
129
|
+
## Nested Array Interpolations
|
125
130
|
|
126
131
|
As long as each top level array is uniformly sized in the first dimension
|
127
132
|
and each nested array is uniformly sized in the second dimension (and so
|
@@ -134,8 +139,8 @@ Here's an example of a set of 2D points being morphed:
|
|
134
139
|
require 'pp'
|
135
140
|
|
136
141
|
|
137
|
-
# a
|
138
|
-
#
|
142
|
+
# a number of sets 2D vertices, each set corresponding to a particular
|
143
|
+
# shape on the grid
|
139
144
|
time_frames = {
|
140
145
|
0 => [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], # a horizontal line
|
141
146
|
1 => [[0, 0], [1, 0], [3, 0], [0, 4], [0, 0]], # a triangle
|
@@ -155,11 +160,11 @@ Here's an example of a set of 2D points being morphed:
|
|
155
160
|
end
|
156
161
|
|
157
162
|
|
158
|
-
|
163
|
+
## License
|
159
164
|
|
160
165
|
(The MIT License)
|
161
166
|
|
162
|
-
Copyright (c) 2008-
|
167
|
+
Copyright (c) 2008-2011 Adam Collins [adam@m104.us]
|
163
168
|
|
164
169
|
Permission is hereby granted, free of charge, to any person obtaining
|
165
170
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
@@ -1,19 +1,35 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
$:.unshift(File.dirname(__FILE__) + "/lib")
|
4
|
-
require 'interpolate'
|
1
|
+
require 'jeweler'
|
2
|
+
require 'rake'
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
4
|
+
require './lib/interpolate/interpolation'
|
5
|
+
|
6
|
+
Jeweler::Tasks.new do |g|
|
7
|
+
doc_sections = File.read('README.md').delete("\r").split(/^## /)
|
8
|
+
|
9
|
+
g.name = 'interpolate'
|
10
|
+
g.summary = 'Create linear interpolations from key points and values'
|
11
|
+
g.description = doc_sections[2].chomp.chomp # mmmm... tasty!
|
12
|
+
g.email = 'adam@m104.us'
|
13
|
+
g.homepage = "http://github.com/m104/interpolate"
|
14
|
+
g.authors = ["Adam Collins"]
|
15
|
+
g.version = Interpolation::VERSION
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'rake/testtask'
|
19
|
+
Rake::TestTask.new(:test) do |test|
|
20
|
+
test.test_files = FileList.new('test/test_*.rb') do |list|
|
21
|
+
list.exclude 'test/test_helper.rb'
|
22
|
+
end
|
23
|
+
test.libs << 'test'
|
24
|
+
test.verbose = true
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'rake/rdoctask'
|
28
|
+
Rake::RDocTask.new do |rdoc|
|
29
|
+
rdoc.rdoc_dir = 'rdoc'
|
30
|
+
rdoc.title = 'interpolate'
|
31
|
+
rdoc.rdoc_files.include('README.markdown')
|
32
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
33
|
end
|
16
34
|
|
17
|
-
desc "Release and publish documentation"
|
18
|
-
task :repubdoc => [:release, :publish_docs]
|
19
35
|
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.4
|
data/examples/arrays.rb
CHANGED
data/examples/buckets.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'interpolate'
|
3
|
+
|
4
|
+
# min_value => bucket
|
5
|
+
buckets = {
|
6
|
+
0.000 => 1,
|
7
|
+
0.427 => 2,
|
8
|
+
1.200 => 3,
|
9
|
+
3.420 => 4,
|
10
|
+
27.50 => 5,
|
11
|
+
45.20 => 6,
|
12
|
+
124.4 => 7,
|
13
|
+
}
|
14
|
+
|
15
|
+
bucketizer = Interpolation.new(buckets)
|
16
|
+
|
17
|
+
values = [
|
18
|
+
-20.2,
|
19
|
+
0.234,
|
20
|
+
65.24,
|
21
|
+
9.234,
|
22
|
+
398.4,
|
23
|
+
4000
|
24
|
+
]
|
25
|
+
|
26
|
+
values.each do |value|
|
27
|
+
bucket = bucketizer.at(value).floor
|
28
|
+
puts "A value of #{value} falls into bucket #{bucket}"
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
|
data/examples/colors.rb
CHANGED
@@ -1,30 +1,33 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'interpolate'
|
3
2
|
require 'color'
|
3
|
+
require 'interpolate'
|
4
|
+
|
5
|
+
# we need to implement +interpolate+ for Color::RGB
|
6
|
+
# in order for Interpolation to work
|
7
|
+
class Color::RGB
|
8
|
+
def interpolate(other, balance)
|
9
|
+
mix_with(other, balance * 100.0)
|
10
|
+
end
|
11
|
+
end
|
4
12
|
|
5
13
|
# a nice weathermap-style color gradient
|
6
14
|
points = {
|
7
|
-
|
8
|
-
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
7 => Color::RGB::DarkGray
|
15
|
+
1 => Color::RGB::White,
|
16
|
+
2 => Color::RGB::Lime,
|
17
|
+
# 3 => ? (between Lime and Yellow; Interpolate will figure it out)
|
18
|
+
4 => Color::RGB::Yellow,
|
19
|
+
5 => Color::RGB::Orange,
|
20
|
+
6 => Color::RGB::Red,
|
21
|
+
7 => Color::RGB::Magenta
|
15
22
|
}
|
16
23
|
|
17
|
-
|
18
|
-
# so rather than monkey patch the :interpolate method, you can pass
|
19
|
-
# a block with the instantiation of a new Interpolation object
|
20
|
-
gradient = Interpolation.new(points) do |left, right, balance|
|
21
|
-
left.mix_with(right, balance * 100.0)
|
22
|
-
end
|
24
|
+
gradient = Interpolation.new(points)
|
23
25
|
|
24
|
-
# what are the colors of the gradient from
|
26
|
+
# what are the colors of the gradient from 1 to 7
|
25
27
|
# in increments of 0.2?
|
26
|
-
(
|
28
|
+
(1).step(7, 0.2) do |value|
|
27
29
|
color = gradient.at(value)
|
28
30
|
puts "A value of #{value} means #{color.html}"
|
29
31
|
end
|
30
32
|
|
33
|
+
|
data/examples/nested.rb
CHANGED
@@ -3,8 +3,8 @@ require 'interpolate'
|
|
3
3
|
require 'pp'
|
4
4
|
|
5
5
|
|
6
|
-
# a
|
7
|
-
#
|
6
|
+
# a number of sets 2D vertices, each set corresponding to a particular
|
7
|
+
# shape on the grid
|
8
8
|
time_frames = {
|
9
9
|
0 => [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]], # a horizontal line
|
10
10
|
1 => [[0, 0], [1, 0], [3, 0], [0, 4], [0, 0]], # a triangle
|
data/interpolate.gemspec
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{interpolate}
|
8
|
+
s.version = "0.2.4"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Adam Collins"]
|
12
|
+
s.date = %q{2011-04-10}
|
13
|
+
s.description = %q{Description
|
14
|
+
|
15
|
+
Library for generic Interpolation objects. Useful for such things as generating
|
16
|
+
linear motion between points (or arrays of points), multi-channel color
|
17
|
+
gradients, piecewise functions, or even just placing values within intervals.
|
18
|
+
}
|
19
|
+
s.email = %q{adam@m104.us}
|
20
|
+
s.extra_rdoc_files = [
|
21
|
+
"LICENSE",
|
22
|
+
"README.md"
|
23
|
+
]
|
24
|
+
s.files = [
|
25
|
+
"CHANGELOG.md",
|
26
|
+
"LICENSE",
|
27
|
+
"Manifest.txt",
|
28
|
+
"README.md",
|
29
|
+
"Rakefile",
|
30
|
+
"VERSION",
|
31
|
+
"examples/arrays.rb",
|
32
|
+
"examples/buckets.rb",
|
33
|
+
"examples/colors.rb",
|
34
|
+
"examples/nested.rb",
|
35
|
+
"interpolate.gemspec",
|
36
|
+
"lib/interpolate.rb",
|
37
|
+
"lib/interpolate/add/core.rb",
|
38
|
+
"lib/interpolate/add/core/array.rb",
|
39
|
+
"lib/interpolate/add/core/numeric.rb",
|
40
|
+
"lib/interpolate/interpolation.rb",
|
41
|
+
"test/test_all.rb"
|
42
|
+
]
|
43
|
+
s.homepage = %q{http://github.com/m104/interpolate}
|
44
|
+
s.require_paths = ["lib"]
|
45
|
+
s.rubygems_version = %q{1.3.7}
|
46
|
+
s.summary = %q{Create linear interpolations from key points and values}
|
47
|
+
s.test_files = [
|
48
|
+
"examples/arrays.rb",
|
49
|
+
"examples/buckets.rb",
|
50
|
+
"examples/colors.rb",
|
51
|
+
"examples/nested.rb",
|
52
|
+
"test/test_all.rb"
|
53
|
+
]
|
54
|
+
|
55
|
+
if s.respond_to? :specification_version then
|
56
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
57
|
+
s.specification_version = 3
|
58
|
+
|
59
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
60
|
+
else
|
61
|
+
end
|
62
|
+
else
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
data/lib/interpolate.rb
CHANGED
data/lib/interpolate/add/core.rb
CHANGED
@@ -1,123 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# gradients, piecewise functions, or even just placing values within intervals.
|
4
|
-
#
|
5
|
-
# Interpolation objects are constructed with a Hash object, wherein each key
|
6
|
-
# is a real number value and each value can respond to +interpolate+ to
|
7
|
-
# determine the resulting value based on its neighbor value and the balance
|
8
|
-
# ratio between the two points.
|
9
|
-
#
|
10
|
-
# For objects which can't respond to +interpolate+ (or to override the default
|
11
|
-
# behaviour), a block can be passed to +new+ which will be called whenever two
|
12
|
-
# values need to be interpolated.
|
13
|
-
#
|
14
|
-
# At or below the lower bounds of the interpolation, the result will be equal to
|
15
|
-
# the value of the lower bounds interpolation point. At or above the upper
|
16
|
-
# bounds of the graient, the result will be equal to the value of the upper
|
17
|
-
# bounds interpolation point.
|
18
|
-
#
|
19
|
-
#
|
20
|
-
# ==Author
|
21
|
-
#
|
22
|
-
# {Adam Collins}[mailto:adam.w.collins@gmail.com]
|
23
|
-
#
|
24
|
-
#
|
25
|
-
# ==License
|
26
|
-
#
|
27
|
-
# Licensed under the MIT license.
|
28
|
-
#
|
29
|
-
|
30
|
-
class Interpolation
|
31
|
-
VERSION = '0.2.3'
|
32
|
-
|
33
|
-
# creates an Interpolation object with Hash object that specifies
|
34
|
-
# each point location (Numeric) and value (up to you)
|
35
|
-
#
|
36
|
-
# the optional+block+ can be used to interpolate objects that can't
|
37
|
-
# respond to +interpolate+ on their own
|
38
|
-
#
|
39
|
-
# +block+ will receive the following arguments: "left" (lower) side
|
40
|
-
# value, "right" (higher) side value, and the balance ratio from 0.0
|
41
|
-
# to 1.0
|
42
|
-
def initialize(points = {}, &block)
|
43
|
-
@points = {}
|
44
|
-
@block = block
|
45
|
-
merge!(points)
|
46
|
-
end
|
47
|
-
|
48
|
-
# creates an Interpolation object from the receiver object,
|
49
|
-
# merged with the interpolated points you specify
|
50
|
-
def merge(points = {})
|
51
|
-
Interpolation.new(points.merge(@points))
|
52
|
-
end
|
53
|
-
|
54
|
-
# merges the interpolation points with the receiver object
|
55
|
-
def merge!(points = {})
|
56
|
-
@points.merge!(points)
|
57
|
-
normalize_data
|
58
|
-
end
|
59
|
-
|
60
|
-
# returns the interpolated value of the receiver object at the point specified
|
61
|
-
def at(point)
|
62
|
-
# deal with the two out-of-bounds cases first
|
63
|
-
if (point <= @min_point)
|
64
|
-
return @data.first.last
|
65
|
-
elsif (point >= @max_point)
|
66
|
-
return @data.last.last
|
67
|
-
end
|
68
|
-
|
69
|
-
# go through the interpolation intervals, in order, to determine
|
70
|
-
# into which this point falls
|
71
|
-
1.upto(@data.length - 1) do |zone|
|
72
|
-
left = @data.at(zone - 1)
|
73
|
-
right = @data.at(zone)
|
74
|
-
zone_range = left.first..right.first
|
75
|
-
|
76
|
-
if (zone_range.include?(point))
|
77
|
-
# what are the points in question?
|
78
|
-
left_point = left.first.to_f
|
79
|
-
right_point = right.first.to_f
|
80
|
-
|
81
|
-
# what are the values in question?
|
82
|
-
left_value = left.last
|
83
|
-
right_value = right.last
|
84
|
-
|
85
|
-
# span: difference between the left point and right point
|
86
|
-
# balance: ratio of right point to left point
|
87
|
-
span = right_point - left_point
|
88
|
-
balance = (point.to_f - left_point) / span
|
89
|
-
|
90
|
-
# catch the cases where the point in quesion is
|
91
|
-
# on one of the zone's endpoints
|
92
|
-
return left_value if (balance == 0.0)
|
93
|
-
return right_value if (balance == 1.0)
|
94
|
-
|
95
|
-
# given block should be called
|
96
|
-
return @block.call(left_value, right_value, balance) if @block
|
97
|
-
|
98
|
-
# otherwise, we need to interpolate
|
99
|
-
return left_value.interpolate(right_value, balance) if left_value.respond_to?(:interpolate)
|
100
|
-
|
101
|
-
raise ArgumentError, "no block given and interpolation point doesn't respond to :interpolate"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# we shouldn't get to this point
|
106
|
-
raise "couldn't come up with a value for some reason!"
|
107
|
-
end
|
108
|
-
|
109
|
-
private
|
110
|
-
|
111
|
-
def normalize_data # :nodoc:
|
112
|
-
@data = @points.sort
|
113
|
-
@min_point = @data.first.first
|
114
|
-
@max_point = @data.last.first
|
115
|
-
|
116
|
-
# make sure that all values respond_to? :interpolate
|
117
|
-
@data.each do |point|
|
118
|
-
value = point.last
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
end
|
123
|
-
|
1
|
+
require 'interpolate/add/core/numeric'
|
2
|
+
require 'interpolate/add/core/array'
|
File without changes
|
File without changes
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# Library for generic interpolation objects. Useful for such things as generating
|
2
|
+
# linear motion between points (or arrays of points), multi-channel color
|
3
|
+
# gradients, piecewise functions, or even just placing values within intervals.
|
4
|
+
#
|
5
|
+
# The only requirement is that each interpolation point value must be able to
|
6
|
+
# figure out how to interpolate itself to its neighbor value(s). Numeric
|
7
|
+
# objects and uniformly sized arrays are automatically endowed with this
|
8
|
+
# ability by this gem, but other classes will require an implementation
|
9
|
+
# of +interpolate+. See the example color.rb in the examples directory for
|
10
|
+
# a brief demonstration using Color objects provided by the 'color' gem.
|
11
|
+
#
|
12
|
+
# Interpolation objects are constructed with a Hash object, wherein each key
|
13
|
+
# is a real number value and each value is can respond to +interpolate+ and
|
14
|
+
# determine the resulting value based on its neighbor value and the balance
|
15
|
+
# ratio between the two points.
|
16
|
+
#
|
17
|
+
# At or below the lower bounds of the interpolation, the result will be equal to
|
18
|
+
# the value of the lower bounds interpolation point. At or above the upper
|
19
|
+
# bounds of the graient, the result will be equal to the value of the upper
|
20
|
+
# bounds interpolation point.
|
21
|
+
#
|
22
|
+
#
|
23
|
+
# ==Author
|
24
|
+
#
|
25
|
+
# {Adam Collins}[mailto:adam@m104.us]
|
26
|
+
#
|
27
|
+
#
|
28
|
+
# ==License
|
29
|
+
#
|
30
|
+
# Licensed under the MIT license.
|
31
|
+
#
|
32
|
+
|
33
|
+
class Interpolation
|
34
|
+
VERSION = '0.2.4'
|
35
|
+
|
36
|
+
# creates an Interpolation object with Hash object that specifies
|
37
|
+
# each point location (Numeric) and value (up to you)
|
38
|
+
def initialize(points = {})
|
39
|
+
@points = {}
|
40
|
+
merge!(points)
|
41
|
+
end
|
42
|
+
|
43
|
+
# creates an Interpolation object from the receiver object,
|
44
|
+
# merged with the interpolated points you specify
|
45
|
+
def merge(points = {})
|
46
|
+
Interpolation.new(points.merge(@points))
|
47
|
+
end
|
48
|
+
|
49
|
+
# merges the interpolation points with the receiver object
|
50
|
+
def merge!(points = {})
|
51
|
+
@points.merge!(points)
|
52
|
+
normalize_data
|
53
|
+
end
|
54
|
+
|
55
|
+
# returns the interpolated value of the receiver object at the point specified
|
56
|
+
def at(point)
|
57
|
+
# deal with the two out-of-bounds cases first
|
58
|
+
if (point <= @min_point)
|
59
|
+
return @data.first.last
|
60
|
+
elsif (point >= @max_point)
|
61
|
+
return @data.last.last
|
62
|
+
end
|
63
|
+
|
64
|
+
# go through the interpolation intervals, in order, to determine
|
65
|
+
# into which this point falls
|
66
|
+
1.upto(@data.length - 1) do |interval|
|
67
|
+
left = @data.at(interval - 1)
|
68
|
+
right = @data.at(interval)
|
69
|
+
interval_range = left.first..right.first
|
70
|
+
|
71
|
+
if (interval_range.include?(point))
|
72
|
+
# what are the points in question?
|
73
|
+
left_point = left.first.to_f
|
74
|
+
right_point = right.first.to_f
|
75
|
+
|
76
|
+
# what are the values in question?
|
77
|
+
left_value = left.last
|
78
|
+
right_value = right.last
|
79
|
+
|
80
|
+
# span: difference between the left point and right point
|
81
|
+
# balance: ratio of right point to left point
|
82
|
+
span = right_point - left_point
|
83
|
+
balance = (point.to_f - left_point) / span
|
84
|
+
|
85
|
+
# catch the cases where the point in quesion is
|
86
|
+
# on one of the interval's endpoints
|
87
|
+
return left_value if (balance == 0.0)
|
88
|
+
return right_value if (balance == 1.0)
|
89
|
+
|
90
|
+
# otherwise, we need to interpolate
|
91
|
+
return left_value.interpolate(right_value, balance)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# we shouldn't get to this point
|
96
|
+
raise "couldn't come up with a value for some reason!"
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def normalize_data # :nodoc:
|
102
|
+
@data = @points.sort
|
103
|
+
@min_point = @data.first.first
|
104
|
+
@max_point = @data.last.first
|
105
|
+
|
106
|
+
# make sure that all values respond_to? :interpolate
|
107
|
+
@data.each do |point|
|
108
|
+
value = point.last
|
109
|
+
unless value.respond_to?(:interpolate)
|
110
|
+
raise ArgumentError, "found an interpolation point that doesn't respond to :interpolate"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
|
data/test/test_all.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
|
-
#!/usr/bin/env
|
1
|
+
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'test/unit'
|
4
|
-
require '
|
4
|
+
require 'interpolate'
|
5
5
|
|
6
6
|
|
7
7
|
class InterpolationTest < Test::Unit::TestCase
|
8
|
-
|
8
|
+
# acceptable delta; floating point values won't be exact
|
9
9
|
DELTA = 1e-7
|
10
10
|
|
11
11
|
def setup
|
12
|
-
|
12
|
+
decimal_points = {
|
13
13
|
0 => 0,
|
14
14
|
1 => 0.1,
|
15
15
|
2 => 0.2,
|
@@ -23,28 +23,29 @@ class InterpolationTest < Test::Unit::TestCase
|
|
23
23
|
10 => 1
|
24
24
|
}.freeze
|
25
25
|
|
26
|
-
|
26
|
+
array_points = {
|
27
27
|
100 => [1, 10, 100],
|
28
28
|
200 => [5, 50, 500],
|
29
29
|
500 => [10, 100, 1000]
|
30
30
|
}.freeze
|
31
31
|
|
32
|
-
@dec_gradient = Interpolation.new(
|
33
|
-
@array_gradient = Interpolation.new(
|
32
|
+
@dec_gradient = Interpolation.new(decimal_points).freeze
|
33
|
+
@array_gradient = Interpolation.new(array_points).freeze
|
34
34
|
end
|
35
35
|
|
36
|
-
|
36
|
+
|
37
|
+
def test_bad_points
|
37
38
|
bad_points = {
|
38
39
|
0 => 4.2,
|
39
40
|
1 => "hello", # not allowed by default
|
40
41
|
2 => 3.4,
|
41
42
|
3 => 4.8
|
42
43
|
}
|
43
|
-
gradient = Interpolation.new(bad_points)
|
44
44
|
|
45
45
|
assert_raise ArgumentError do
|
46
|
-
gradient.
|
46
|
+
gradient = Interpolation.new(bad_points)
|
47
47
|
end
|
48
|
+
|
48
49
|
end
|
49
50
|
|
50
51
|
def test_lower_bounds
|
@@ -133,30 +134,6 @@ class InterpolationTest < Test::Unit::TestCase
|
|
133
134
|
assert_equal(@array_gradient.at(350), [7.5, 75, 750])
|
134
135
|
end
|
135
136
|
|
136
|
-
def test_given_block_left
|
137
|
-
gradient = Interpolation.new(@decimal_points) {|l, r, bal| l}
|
138
|
-
assert_in_delta(gradient.at(1.5), 0.1, DELTA)
|
139
|
-
assert_in_delta(gradient.at(2.5), 0.2, DELTA)
|
140
|
-
assert_in_delta(gradient.at(3.5), 0.3, DELTA)
|
141
|
-
end
|
142
|
-
|
143
|
-
def test_given_block_right
|
144
|
-
gradient = Interpolation.new(@decimal_points) {|l, r, bal| r}
|
145
|
-
assert_in_delta(gradient.at(1.5), 0.2, DELTA)
|
146
|
-
assert_in_delta(gradient.at(2.5), 0.3, DELTA)
|
147
|
-
assert_in_delta(gradient.at(3.5), 0.4, DELTA)
|
148
|
-
end
|
149
|
-
|
150
|
-
def test_given_block_mean_squared
|
151
|
-
# squared balance, not linear
|
152
|
-
gradient = Interpolation.new(@decimal_points) do |l, r, bal|
|
153
|
-
l + ((r - l).to_f * bal * bal)
|
154
|
-
end
|
155
|
-
assert_in_delta(gradient.at(1.5), 0.12500, DELTA)
|
156
|
-
assert_in_delta(gradient.at(2.75), 0.25625, DELTA)
|
157
|
-
assert_in_delta(gradient.at(3.99), 0.39801, DELTA)
|
158
|
-
end
|
159
|
-
|
160
137
|
def test_frozen_points
|
161
138
|
a = @array_gradient.at(200)
|
162
139
|
assert_nothing_raised RuntimeError do
|
metadata
CHANGED
@@ -1,48 +1,23 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: interpolate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 2
|
8
|
+
- 4
|
9
|
+
version: 0.2.4
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Adam Collins
|
8
13
|
autorequire:
|
9
14
|
bindir: bin
|
10
|
-
cert_chain:
|
11
|
-
- |
|
12
|
-
-----BEGIN CERTIFICATE-----
|
13
|
-
MIIDPjCCAiagAwIBAgIBADANBgkqhkiG9w0BAQUFADBFMRcwFQYDVQQDDA5hZGFt
|
14
|
-
LncuY29sbGluczEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQB
|
15
|
-
GRYDY29tMB4XDTA4MDEyNDA4NTEyOFoXDTA5MDEyMzA4NTEyOFowRTEXMBUGA1UE
|
16
|
-
AwwOYWRhbS53LmNvbGxpbnMxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmS
|
17
|
-
JomT8ixkARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMP8
|
18
|
-
3Nz8g1K+Z4p59/keyov5ihFgzJuhlnvbRLr0y2jtDybeyc0TSMnY7sjhx+T0yVI5
|
19
|
-
9tEtUMo3d2m0woaHw7kc3VAo68GQKGAN02bdaPc4ODcObL9DAr8Y3CCwml5CiLtX
|
20
|
-
L5Lz8zO9EU6jv6bTecRW5DsY9nPjc/TLqXjYxDgSL8dppBmHs2k82bJCaCaTFj9M
|
21
|
-
ORRZpdkdTBdecI7p8DKt2WAX12deT/XUan7mpiBChKJsNVpcAe6CUqVfb6hMGA95
|
22
|
-
KtW+GxvK6F6UgkcFG8ljrXks8Dfm4jMYVkpmw1YUGYU9Wj9R8X94ecAi9By/ngJ7
|
23
|
-
svhO6ouvVk9J9hgpWukCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAw
|
24
|
-
HQYDVR0OBBYEFIpBCufIdqpuVqh/Mt46Gq9FKa0pMA0GCSqGSIb3DQEBBQUAA4IB
|
25
|
-
AQBbwpirH1tNzkESxQIBZd10xK3Dca141G9+lHl7OK3UCk1ZF6TiXxgl7Qnug4A5
|
26
|
-
3mEn/catvIdMYcA1GLNWL7qlW2Fpk2w0qgVbx1agK724BrZm5Op6lain+vi6BXd3
|
27
|
-
QM32MqZAL96e40i6UCutsNIdZeRDfR7hRcmqPTkoSUEu/3X6qegnvJHpVw36dsG6
|
28
|
-
trlR7ps6/GSlnZNkD5TayaybO3TiA+KGA19/zQhO6DMPds+swW0Jz7xv2VBzIWg5
|
29
|
-
RAnseWJ5nOAftsE9D1NGp3TEH+ceNKO3IP0OtDl9L2F0a/9XbPJdmsaQR+FPX30Z
|
30
|
-
xJc09X9KG2jBdxa4tp+uy7KZ
|
31
|
-
-----END CERTIFICATE-----
|
15
|
+
cert_chain: []
|
32
16
|
|
33
|
-
date:
|
17
|
+
date: 2011-04-10 00:00:00 -07:00
|
34
18
|
default_executable:
|
35
|
-
dependencies:
|
36
|
-
|
37
|
-
name: hoe
|
38
|
-
type: :development
|
39
|
-
version_requirement:
|
40
|
-
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
requirements:
|
42
|
-
- - ">="
|
43
|
-
- !ruby/object:Gem::Version
|
44
|
-
version: 2.3.3
|
45
|
-
version:
|
19
|
+
dependencies: []
|
20
|
+
|
46
21
|
description: |
|
47
22
|
Description
|
48
23
|
|
@@ -50,59 +25,67 @@ description: |
|
|
50
25
|
linear motion between points (or arrays of points), multi-channel color
|
51
26
|
gradients, piecewise functions, or even just placing values within intervals.
|
52
27
|
|
53
|
-
email: adam
|
28
|
+
email: adam@m104.us
|
54
29
|
executables: []
|
55
30
|
|
56
31
|
extensions: []
|
57
32
|
|
58
33
|
extra_rdoc_files:
|
59
|
-
-
|
60
|
-
-
|
61
|
-
- Manifest.txt
|
62
|
-
- README.txt
|
34
|
+
- LICENSE
|
35
|
+
- README.md
|
63
36
|
files:
|
64
|
-
-
|
65
|
-
- LICENSE
|
37
|
+
- CHANGELOG.md
|
38
|
+
- LICENSE
|
66
39
|
- Manifest.txt
|
67
|
-
- README.
|
40
|
+
- README.md
|
68
41
|
- Rakefile
|
42
|
+
- VERSION
|
69
43
|
- examples/arrays.rb
|
44
|
+
- examples/buckets.rb
|
70
45
|
- examples/colors.rb
|
71
46
|
- examples/nested.rb
|
72
|
-
-
|
47
|
+
- interpolate.gemspec
|
73
48
|
- lib/interpolate.rb
|
74
|
-
- lib/interpolate/add/array.rb
|
75
49
|
- lib/interpolate/add/core.rb
|
76
|
-
- lib/interpolate/add/
|
50
|
+
- lib/interpolate/add/core/array.rb
|
51
|
+
- lib/interpolate/add/core/numeric.rb
|
52
|
+
- lib/interpolate/interpolation.rb
|
77
53
|
- test/test_all.rb
|
78
54
|
has_rdoc: true
|
79
|
-
homepage: http://interpolate
|
55
|
+
homepage: http://github.com/m104/interpolate
|
80
56
|
licenses: []
|
81
57
|
|
82
58
|
post_install_message:
|
83
|
-
rdoc_options:
|
84
|
-
|
85
|
-
- README.txt
|
59
|
+
rdoc_options: []
|
60
|
+
|
86
61
|
require_paths:
|
87
62
|
- lib
|
88
63
|
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
89
65
|
requirements:
|
90
66
|
- - ">="
|
91
67
|
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 0
|
92
70
|
version: "0"
|
93
|
-
version:
|
94
71
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
95
73
|
requirements:
|
96
74
|
- - ">="
|
97
75
|
- !ruby/object:Gem::Version
|
76
|
+
segments:
|
77
|
+
- 0
|
98
78
|
version: "0"
|
99
|
-
version:
|
100
79
|
requirements: []
|
101
80
|
|
102
|
-
rubyforge_project:
|
103
|
-
rubygems_version: 1.3.
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.3.7
|
104
83
|
signing_key:
|
105
84
|
specification_version: 3
|
106
|
-
summary:
|
85
|
+
summary: Create linear interpolations from key points and values
|
107
86
|
test_files:
|
87
|
+
- examples/arrays.rb
|
88
|
+
- examples/buckets.rb
|
89
|
+
- examples/colors.rb
|
90
|
+
- examples/nested.rb
|
108
91
|
- test/test_all.rb
|
data.tar.gz.sig
DELETED
Binary file
|
data/examples/zones.rb
DELETED
@@ -1,28 +0,0 @@
|
|
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
|
metadata.gz.sig
DELETED
Binary file
|