lib/interpolate.rb in interpolate-0.2.1 vs lib/interpolate.rb in interpolate-0.2.2
- old
+ new
@@ -1,156 +1,3 @@
-# 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.
-#
-# The only requirement is that each interpolation point value must be able to
-# figure out how to interpolate itself to its neighbor value(s). Numeric
-# objects and uniformly sized arrays are automatically endowed with this
-# ability by this gem, but other classes will require an implementation
-# of +interpolate+. See the example color.rb in the examples directory for
-# a brief demonstration using Color objects provided by the 'color' gem.
-#
-# Interpolation objects are constructed with a Hash object, wherein each key
-# is a real number value and each value is can respond to +interpolate+ and
-# determine the resulting value based on its neighbor value and the balance
-# ratio between the two points.
-#
-# At or below the lower bounds of the interpolation, the result will be equal to
-# the value of the lower bounds interpolation point. At or above the upper
-# bounds of the graient, the result will be equal to the value of the upper
-# bounds interpolation point.
-#
-#
-# ==Author
-#
-# {Adam Collins}[mailto:adam.w.collins@gmail.com]
-#
-#
-# ==License
-#
-# Licensed under the MIT license.
-#
-
-class Interpolation
- VERSION = '0.2.1' # :nodoc:
-
- # creates an Interpolation object with Hash object that specifies
- # each point location (Numeric) and value (up to you)
- def initialize(points = {})
- @points = {}
- merge!(points)
- end
-
- # creates an Interpolation object from the receiver object,
- # merged with the interpolated points you specify
- def merge(points = {})
- Interpolation.new(points.merge(@points))
- end
-
- # merges the interpolation points with the receiver object
- def merge!(points = {})
- @points.merge!(points)
- normalize_data
- end
-
- # returns the interpolated value of the receiver object at the point specified
- def at(point)
- # deal with the two out-of-bounds cases first
- if (point <= @min_point)
- return @data.first.last
- elsif (point >= @max_point)
- return @data.last.last
- end
-
- # go through the interpolation intervals, in order, to determine
- # into which this point falls
- 1.upto(@data.length - 1) do |zone|
- left = @data.at(zone - 1)
- right = @data.at(zone)
- zone_range = left.first..right.first
-
- if (zone_range.include?(point))
- # what are the points in question?
- left_point = left.first.to_f
- right_point = right.first.to_f
-
- # what are the values in question?
- left_value = left.last
- right_value = right.last
-
- # span: difference between the left point and right point
- # balance: ratio of right point to left point
- span = right_point - left_point
- balance = (point.to_f - left_point) / span
-
- # catch the cases where the point in quesion is
- # on one of the zone's endpoints
- return left_value if (balance == 0.0)
- return right_value if (balance == 1.0)
-
- # otherwise, we need to interpolate
- return left_value.interpolate(right_value, balance)
- end
- end
-
- # we shouldn't get to this point
- raise "couldn't come up with a value for some reason!"
- end
-
- private
-
- def normalize_data # :nodoc:
- @data = @points.sort
- @min_point = @data.first.first
- @max_point = @data.last.first
-
- # make sure that all values respond_to? :interpolate
- @data.each do |point|
- value = point.last
- unless value.respond_to?(:interpolate)
- raise ArgumentError, "found an interpolation point that doesn't respond to :interpolate"
- end
- end
- end
-
-end
-
-
-# all numeric objects should be supported
-class Numeric # :nodoc:
- def interpolate(other, balance)
- left = self.to_f
- right = other.to_f
- delta = (right - left).to_f
- return left + (delta * balance)
- end
-end
-
-
-# a little more complicated, but there's no reason why we can't
-# interpolate between two equal length arrays as long as each element
-# responds to +interpolate+
-class Array # :nodoc:
- def interpolate(other, balance)
- if (self.length < 1) then
- raise ArgumentError, "cannot interpolate array with no values"
- end
-
- if (self.length != other.length) then
- raise ArgumentError, "cannot interpolate between arrays of different length"
- end
-
- final = Array.new
-
- self.each_with_index do |left, index|
- unless (left.respond_to? :interpolate) then
- raise "array element does not respond to :interpolate"
- end
-
- right = other[index]
-
- final[index] = left.interpolate(right, balance)
- end
-
- return final
- end
-end
+require 'interpolate/interpolation'
+require 'interpolate/ruby_array'
+require 'interpolate/ruby_numeric'