interpolate 0.2.1 → 0.2.2

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.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