interpolate 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
@@ -1,3 +1,9 @@
1
+ == 0.2.2 (2008.2.4)
2
+
3
+ * Single source file has been split into Class files
4
+ * Tests now use +freeze
5
+ * Better edge case testing in the Array and Numeric +interpolate+ methods
6
+
1
7
  == 0.2.1 (2008.1.27)
2
8
 
3
9
  * First public release
@@ -1,4 +1,4 @@
1
- CHANGELOG.txt
1
+ History.txt
2
2
  LICENSE.txt
3
3
  Manifest.txt
4
4
  README.txt
@@ -8,4 +8,7 @@ examples/colors.rb
8
8
  examples/nested.rb
9
9
  examples/zones.rb
10
10
  lib/interpolate.rb
11
+ lib/interpolate/interpolation.rb
12
+ lib/interpolate/ruby_array.rb
13
+ lib/interpolate/ruby_numeric.rb
11
14
  test/test_all.rb
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ Hoe.new('Interpolate', Interpolation::VERSION) do |p|
10
10
  p.url = "http://interpolate.rubyforge.org"
11
11
  p.description = File.read('README.txt').delete("\r").split(/^== /)[2].chomp.chomp
12
12
  p.summary = p.description
13
- p.changes = File.read('CHANGELOG.txt').delete("\r").split(/^== /)[1].chomp
13
+ p.changes = File.read('History.txt').delete("\r").split(/^== /)[1].chomp
14
14
  p.remote_rdoc_dir = '' # Release to root
15
15
  end
16
16
 
@@ -1,156 +1,3 @@
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.w.collins@gmail.com]
26
- #
27
- #
28
- # ==License
29
- #
30
- # Licensed under the MIT license.
31
- #
32
-
33
- class Interpolation
34
- VERSION = '0.2.1' # :nodoc:
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 |zone|
67
- left = @data.at(zone - 1)
68
- right = @data.at(zone)
69
- zone_range = left.first..right.first
70
-
71
- if (zone_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 zone'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
-
118
- # all numeric objects should be supported
119
- class Numeric # :nodoc:
120
- def interpolate(other, balance)
121
- left = self.to_f
122
- right = other.to_f
123
- delta = (right - left).to_f
124
- return left + (delta * balance)
125
- end
126
- end
127
-
128
-
129
- # a little more complicated, but there's no reason why we can't
130
- # interpolate between two equal length arrays as long as each element
131
- # responds to +interpolate+
132
- class Array # :nodoc:
133
- def interpolate(other, balance)
134
- if (self.length < 1) then
135
- raise ArgumentError, "cannot interpolate array with no values"
136
- end
137
-
138
- if (self.length != other.length) then
139
- raise ArgumentError, "cannot interpolate between arrays of different length"
140
- end
141
-
142
- final = Array.new
143
-
144
- self.each_with_index do |left, index|
145
- unless (left.respond_to? :interpolate) then
146
- raise "array element does not respond to :interpolate"
147
- end
148
-
149
- right = other[index]
150
-
151
- final[index] = left.interpolate(right, balance)
152
- end
153
-
154
- return final
155
- end
156
- end
1
+ require 'interpolate/interpolation'
2
+ require 'interpolate/ruby_array'
3
+ require 'interpolate/ruby_numeric'
@@ -0,0 +1,116 @@
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.w.collins@gmail.com]
26
+ #
27
+ #
28
+ # ==License
29
+ #
30
+ # Licensed under the MIT license.
31
+ #
32
+
33
+ class Interpolation
34
+ VERSION = '0.2.2'
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 |zone|
67
+ left = @data.at(zone - 1)
68
+ right = @data.at(zone)
69
+ zone_range = left.first..right.first
70
+
71
+ if (zone_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 zone'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
+
@@ -0,0 +1,59 @@
1
+ # Extension(s) for the Ruby Array class.
2
+ #
3
+ #
4
+ # ==Author
5
+ #
6
+ # {Adam Collins}[mailto:adam.w.collins@gmail.com]
7
+ #
8
+ #
9
+ # ==License
10
+ #
11
+ # Licensed under the MIT license.
12
+ #
13
+
14
+ class Array
15
+ # Returns a new Array in which each element is the interpolated value
16
+ # between +self+ and +other+. +balance+ should be a Float from 0.0
17
+ # to 1.0 where the value is a ratio between +self+ and +other+. +self+
18
+ # and +other+ should be arrays of equal, non-zero length.
19
+ #
20
+ # Between two interpolation points, let's say +a+ and +b+, the final result
21
+ # will be +c+ where <tt>c[0]</tt> is the interpolation of <tt>a[0]</tt> and
22
+ # <tt>b[0]</tt> and <tt>c[1]</tt> is interpolated between <tt>a[1]</tt> and
23
+ # <tt>b[1]</tt> and so on, up to <tt>c[c.length - 1]</tt>.
24
+ #
25
+ # This method is intentionally abstract to allow for the interpolation
26
+ # of nested arrays. In this case, both arrays need to have the same array
27
+ # structure (same number of dimensions, equal length in each dimension),
28
+ # but the contents can, of course, be different.
29
+ #
30
+ # A balance greater than or equal to 0.0 returns +self+, while a
31
+ # balance less than or equal to 1.0 returns +other+.
32
+ def interpolate(other, balance)
33
+ if (self.length < 1) then
34
+ raise ArgumentError, "cannot interpolate array with no values"
35
+ end
36
+
37
+ if (self.length != other.length) then
38
+ raise ArgumentError, "cannot interpolate between arrays of different length"
39
+ end
40
+
41
+ # catch the easy cases
42
+ return self.dup if (balance <= 0.0)
43
+ return other.dup if (balance >= 1.0)
44
+
45
+ final = Array.new
46
+
47
+ self.each_with_index do |left, index|
48
+ unless (left.respond_to? :interpolate) then
49
+ raise "array element does not respond to :interpolate"
50
+ end
51
+
52
+ right = other[index]
53
+
54
+ final[index] = left.interpolate(right, balance)
55
+ end
56
+
57
+ return final
58
+ end
59
+ end
@@ -0,0 +1,34 @@
1
+ # Extension(s) for the Ruby Numeric class.
2
+ #
3
+ #
4
+ # ==Author
5
+ #
6
+ # {Adam Collins}[mailto:adam.w.collins@gmail.com]
7
+ #
8
+ #
9
+ # ==License
10
+ #
11
+ # Licensed under the MIT license.
12
+ #
13
+
14
+ class Numeric
15
+ # Returns a Float that is equal to the interpolated value between
16
+ # +self+ and +other+. +balance+ should be a Float from 0.0 to 1.0,
17
+ # where the value is a ratio between +self+ and +other+.
18
+ #
19
+ # A balance greater than or equal to 0.0 returns +self+, while a
20
+ # balance less than or equal to 1.0 returns +other+.
21
+ def interpolate(other, balance)
22
+ balance = balance.to_f
23
+ left = self.to_f
24
+ right = other.to_f
25
+
26
+ # catch the easy cases
27
+ return left if (balance <= 0.0)
28
+ return right if (balance >= 1.0)
29
+
30
+ delta = (right - left).to_f
31
+ return left + (delta * balance)
32
+ end
33
+ end
34
+
@@ -21,16 +21,16 @@ class InterpolationTest < Test::Unit::TestCase
21
21
  8 => 0.8,
22
22
  9 => 0.9,
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(decimal_points)
33
- @array_gradient = Interpolation.new(array_points)
32
+ @dec_gradient = Interpolation.new(decimal_points).freeze
33
+ @array_gradient = Interpolation.new(array_points).freeze
34
34
  end
35
35
 
36
36
 
@@ -133,6 +133,15 @@ class InterpolationTest < Test::Unit::TestCase
133
133
  assert_equal(@array_gradient.at(200), [5, 50, 500])
134
134
  assert_equal(@array_gradient.at(350), [7.5, 75, 750])
135
135
  end
136
+
137
+ def test_frozen_points
138
+ a = @array_gradient.at(200)
139
+ assert_nothing_raised RuntimeError do
140
+ a[0] = 10
141
+ a[1] = 70
142
+ a[2] = 100
143
+ end
144
+ end
136
145
 
137
146
  end
138
147
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: interpolate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Collins
@@ -30,7 +30,7 @@ cert_chain:
30
30
  xJc09X9KG2jBdxa4tp+uy7KZ
31
31
  -----END CERTIFICATE-----
32
32
 
33
- date: 2008-01-27 00:00:00 -08:00
33
+ date: 2008-02-05 00:00:00 -08:00
34
34
  default_executable:
35
35
  dependencies:
36
36
  - !ruby/object:Gem::Dependency
@@ -40,7 +40,7 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 1.4.0
43
+ version: 1.5.0
44
44
  version:
45
45
  description: Description Library for generic Interpolation objects. 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.
46
46
  email: adam.w.collins@gmail.com
@@ -49,12 +49,12 @@ executables: []
49
49
  extensions: []
50
50
 
51
51
  extra_rdoc_files:
52
- - CHANGELOG.txt
52
+ - History.txt
53
53
  - LICENSE.txt
54
54
  - Manifest.txt
55
55
  - README.txt
56
56
  files:
57
- - CHANGELOG.txt
57
+ - History.txt
58
58
  - LICENSE.txt
59
59
  - Manifest.txt
60
60
  - README.txt
@@ -64,6 +64,9 @@ files:
64
64
  - examples/nested.rb
65
65
  - examples/zones.rb
66
66
  - lib/interpolate.rb
67
+ - lib/interpolate/interpolation.rb
68
+ - lib/interpolate/ruby_array.rb
69
+ - lib/interpolate/ruby_numeric.rb
67
70
  - test/test_all.rb
68
71
  has_rdoc: true
69
72
  homepage: http://interpolate.rubyforge.org
metadata.gz.sig CHANGED
Binary file