lib/interpolate/add/core.rb in interpolate-0.2.3 vs lib/interpolate/add/core.rb in interpolate-0.2.4

- old
+ new

@@ -1,123 +1,2 @@ -# 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. -# -# Interpolation objects are constructed with a Hash object, wherein each key -# is a real number value and each value can respond to +interpolate+ to -# determine the resulting value based on its neighbor value and the balance -# ratio between the two points. -# -# For objects which can't respond to +interpolate+ (or to override the default -# behaviour), a block can be passed to +new+ which will be called whenever two -# values need to be interpolated. -# -# 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.3' - - # creates an Interpolation object with Hash object that specifies - # each point location (Numeric) and value (up to you) - # - # the optional+block+ can be used to interpolate objects that can't - # respond to +interpolate+ on their own - # - # +block+ will receive the following arguments: "left" (lower) side - # value, "right" (higher) side value, and the balance ratio from 0.0 - # to 1.0 - def initialize(points = {}, &block) - @points = {} - @block = block - 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) - - # given block should be called - return @block.call(left_value, right_value, balance) if @block - - # otherwise, we need to interpolate - return left_value.interpolate(right_value, balance) if left_value.respond_to?(:interpolate) - - raise ArgumentError, "no block given and interpolation point doesn't respond to :interpolate" - 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 - end - end - -end - +require 'interpolate/add/core/numeric' +require 'interpolate/add/core/array'