Class: TerminalVis::Interpolation::BilinearInterpolation

Inherits:
Object
  • Object
show all
Defined in:
lib/math/bilinear_interpolation.rb

Overview

math class to interpolate data between a set of points

Raises:

  • (RangeError)

    when the provided coordinates do not lie within the data area of the MetaData::VisMetaData

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Attribute Details

#data_setDataSet (readonly, private)

Returns the used data set.

Returns:

  • (DataSet)

    the used data set



44
45
46
# File 'lib/math/bilinear_interpolation.rb', line 44

def data_set
  @data_set
end

#meta_dataVisMetaData (readonly, private)

Returns the used meta data.

Returns:

  • (VisMetaData)

    the used meta data



46
47
48
# File 'lib/math/bilinear_interpolation.rb', line 46

def 
  @meta_data
end

Class Method Details

.apply_bilinear_interpolation(x, y) ⇒ Float (private)

singleton method to calculate the bilinear interpolation applies the formula:

(1-r)*(1-s)*d(x,y) + r*(1-s)*d(x+1,y) +
r*s*d(x+1,y+1) + (1-r)*s*d(x,y+1)

Parameters:

  • x (Float)

    x-coordinate of the interpolation point

  • y (Float)

    y-coordinate of the interpolation point

Returns:

  • (Float)

    the interpolated data value for (x,y)



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/math/bilinear_interpolation.rb', line 90

def self.apply_bilinear_interpolation(x, y)
  return boundary_case(x,y) if check_for_upper_boundary(x, y)
  boundary = calculate_boundary_datapoints(x, y)

  # interpolate
  r = Interpolation::calculate_interpolation_factor(boundary[:d_xy],
                                                    boundary[:d_x1y],
                                                    x, y)
  s = Interpolation::calculate_interpolation_factor(boundary[:d_xy],
                                                    boundary[:d_xy1],
                                                    x, y)

  calculate_interpolation_result(1-r, 1-s, boundary[:d_xy].value) +
  calculate_interpolation_result(r, 1-s, boundary[:d_x1y].value) +
  calculate_interpolation_result(r, s, boundary[:d_x1y1].value) +
  calculate_interpolation_result(1-r, s, boundary[:d_xy1].value)
end

.bilinear_interpolation(meta_data, data_set, x, y) ⇒ Float

method for bilinear interpolation

Parameters:

  • meta_data (VisMetaData)

    meta data of the used dataset

  • data_set (DataSet)

    dataset where a coordinate should be interpolated

  • x (Float)

    x-coordinate of the interpolation point

  • y (Float)

    y-coordinate of the interpolation point

Returns:

  • (Float)

    the interpolated data value for (x,y)



25
26
27
28
29
30
# File 'lib/math/bilinear_interpolation.rb', line 25

def self.bilinear_interpolation(, data_set, x, y)
  set_attributes(, data_set)
  check_data_range(x, y)

  apply_bilinear_interpolation(x, y)
end

.boundary_case(x, y) ⇒ Float (private)

singleton method to apply the interpolation on a boundary case

Parameters:

  • x (Float)

    x-coordinate of the interpolation point

  • y (Float)

    y-coordinate of the interpolation point

Returns:

  • (Float)

    the interpolated value



203
204
205
206
207
208
209
210
211
# File 'lib/math/bilinear_interpolation.rb', line 203

def self.boundary_case(x, y)
  if (x == @meta_data.domain_x.upper && y == @meta_data.domain_y.upper)
    return get_upper_boundary(x,y)
  end

  return LinearInterpolation.
         linear_interpolation(create_data_point(0, 0, x, y),
                create_upper_data_point(@meta_data.domain_x, x, y), x, y)
end

.calculate_boundary_datapoints(x, y) ⇒ Hash (private)

singleton method to calculate the necessary boundary points

Parameters:

  • x (Float)

    x-coordinate of the interpolation point

  • y (Float)

    y-coordinate of the interpolation point

Returns:

  • (Hash)

    the data points that will be used for the interpolation



168
169
170
171
172
173
174
175
176
177
178
# File 'lib/math/bilinear_interpolation.rb', line 168

def self.calculate_boundary_datapoints(x, y)
  boundary = Hash.new()

  #getting boundary data points
  boundary[:d_xy] = create_data_point(  0, 0, x, y)
  boundary[:d_x1y] = create_data_point( 1, 0, x, y)
  boundary[:d_xy1] = create_data_point( 0, 1, x, y)
  boundary[:d_x1y1] = create_data_point(1, 1, x, y)

  return boundary
end

.calculate_interpolation_result(r, s, value) ⇒ Float (private)

singleton method to calculate the result of the bilinear interpolation

Parameters:

  • r (Float)

    the interpolation factor in x

  • s (Float)

    the interpolation factor in y

  • value (Float)

    the data value for this factors

Returns:

  • (Float)

    the result of the product of the variables



185
186
187
# File 'lib/math/bilinear_interpolation.rb', line 185

def self.calculate_interpolation_result(r, s, value)
  r * s * value
end

.check_data_range(x, y) ⇒ Object (private)

singleton method to check if the provided coordinates (x,y) lie within the data area specified by the meta information

Parameters:

  • x (Float)

    x-coordinate of the provided point

  • y (Float)

    y-coordinate of the provided point

Raises:

  • (RangeError)

    if the data lies outside the meta data boundaries



64
65
66
67
68
69
70
# File 'lib/math/bilinear_interpolation.rb', line 64

def self.check_data_range(x, y)
  if ( !coordinate_in_dataset(@meta_data.domain_x, x) ||
       !coordinate_in_dataset(@meta_data.domain_y, y))
    raise RangeError, " Error: coordinate (#{x}, #{y}) does not lie" \
               " in the data domain provided by meta_data.".red
  end
end

.check_for_upper_boundary(x, y) ⇒ Boolean (private)

singleton method to check if the provided coordinates lie on one of the upper dimension boundaries

Parameters:

  • x (Float)

    x-coordinate of the interpolation point

  • y (Float)

    y-coordinate of the interpolation point

Returns:

  • (Boolean)

    true: if upper boundary, false: if not



194
195
196
197
# File 'lib/math/bilinear_interpolation.rb', line 194

def self.check_for_upper_boundary(x, y)
  return (x == @meta_data.domain_x.upper ||
          y == @meta_data.domain_y.upper)
end

.coordinate_in_dataset(data_domain, coordinate) ⇒ Boolean (private)

singleton method to check if the provided coordinate lies within the given domain of the dataset

Parameters:

  • data_domain (DataDomain)

    domain of the MetaData::VisMetaData corresponding to the coordinate

  • coordinate (DataPoint)

    component of the coordinate to check

Returns:

  • (Boolean)

    true, if in dataset, false: if not



151
152
153
# File 'lib/math/bilinear_interpolation.rb', line 151

def self.coordinate_in_dataset(data_domain, coordinate)
  (coordinate <= data_domain.upper && coordinate >= data_domain.lower)
end

.create_data_point(delta_x, delta_y, x, y) ⇒ DataPoint (private)

creation of the boundary data points for the bilinear interpolation

Parameters:

  • delta_x (Integer)

    delta value in x for the grid with values in the interval of 0 to 1

  • delta_y (Integer)

    delta value in y for the grid with values in the interval of 0 to 1

  • x (Float)

    x-coordinate of the interpolation point

  • y (Float)

    y-coordinate of the interpolation point

Returns:



116
117
118
119
120
121
122
123
124
125
# File 'lib/math/bilinear_interpolation.rb', line 116

def self.create_data_point(delta_x, delta_y, x, y)
  indices = get_data_indices(x, y) # with [x_index, y_index]
  coordinates = determine_coordinates(indices, delta_x, delta_y)
  begin
    data = @data_set.data[indices[:y] + delta_y][indices[:x] + delta_x]
    DataPoint.new(coordinates[:x], coordinates[:y], data)
  rescue StandardError
    DataPoint.new(coordinates[:x], coordinates[:y], nil)
  end
end

.create_upper_data_point(domain, x, y) ⇒ DataPoint (private)

method to create the upper data point based on the given boundary

Parameters:

  • domain (DataDomain)

    the domain in x dimension

  • x (Float)

    x-coordinate of the interpolation point

  • y (Float)

    y-coordinate of the interpolation point

Returns:



218
219
220
221
222
223
224
# File 'lib/math/bilinear_interpolation.rb', line 218

def self.create_upper_data_point(domain, x, y)
  if (x == domain.upper)
    create_data_point(0, 1, x, y) # vertical case
  else
    create_data_point(1, 0, x, y) # horizontal case
  end
end

.determine_coordinates(indices, delta_x, delta_y) ⇒ Object (private)

singleton method to calculate the required coordinates for the requested data

Parameters:

  • indices (Hash)

    the indices corresponding to the coordinates

  • delta_x (Integer)

    delta value in x for the grid with values in the interval of 0 to 1

  • delta_y (Integer)

    delta value in y for the grid with values in the interval of 0 to 1



134
135
136
137
138
139
140
141
142
143
# File 'lib/math/bilinear_interpolation.rb', line 134

def self.determine_coordinates(indices, delta_x, delta_y)
  coordinates = Hash.new()
  coordinates[:x] = (@meta_data.domain_x.
                    get_coordinate_to_index(indices[:x])+ delta_x *
                    @meta_data.domain_x.step).round(3)
  coordinates[:y] = (@meta_data.domain_y.
                    get_coordinate_to_index(indices[:y])+ delta_y *
                    @meta_data.domain_y.step).round(3)
  return coordinates
end

.get_boundary_points(x, y) ⇒ Hash

method to return the boundary point for a calculated interpolation

Parameters:

  • x (Float)

    x-coordinate of the interpolation point

  • y (Float)

    y-coordinate of the interpolation point

Returns:

  • (Hash)

    the hash containing the boundary points for the given interpolation, if at least one interpolation has been run



37
38
39
40
# File 'lib/math/bilinear_interpolation.rb', line 37

def self.get_boundary_points(x, y)
  check_data_range(x, y)
  calculate_boundary_datapoints(x, y)
end

.get_data_indices(x, y) ⇒ Hash (private)

calculates the two nearest, lower indices for the given coordinates

Parameters:

  • x (Float)

    x-coordinate of the interpolation point

  • y (Float)

    y-coordinate of the interpolation point

Returns:

  • (Hash)

    Hash with the two indices



76
77
78
79
80
81
# File 'lib/math/bilinear_interpolation.rb', line 76

def self.get_data_indices(x, y)
  x_index = get_index_to_next_lower_datapoint(@meta_data.domain_x, x)
  y_index = get_index_to_next_lower_datapoint(@meta_data.domain_y, y)

  { :x => x_index, :y => y_index }
end

.get_index_to_next_lower_datapoint(data_domain, coordinate) ⇒ Numeric (private)

singleton method to get the index to the next down rounded datapoint

Parameters:

  • data_domain (DataDomain)

    domain of the MetaData::VisMetaData corresponding to the coordinate

  • coordinate (DataPoint)

    component of the coordinate to check

Returns:

  • (Numeric)

    the index of the next coordinate value (rounded down)



160
161
162
# File 'lib/math/bilinear_interpolation.rb', line 160

def self.get_index_to_next_lower_datapoint(data_domain, coordinate)
  ((coordinate - data_domain.lower) / data_domain.step).floor
end

.get_upper_boundary(x, y) ⇒ Float (private)

singleton method to serve the case that a boundary point os requested

Parameters:

  • x (Float)

    x-coordinate of the interpolation point

  • y (Float)

    y-coordinate of the interpolation point

Returns:

  • (Float)

    the interpolated value



230
231
232
233
# File 'lib/math/bilinear_interpolation.rb', line 230

def self.get_upper_boundary(x,y)
  indices = get_data_indices(x, y)
  @data_set.data[indices[:y]][indices[:x]]
end

.set_attributes(meta_data, data_set) ⇒ Object (private)

singleton method to set the attributes at the beginning of an interpolation

Parameters:

  • meta_data (VisMetaData)

    the meta data required for the bilinear interpolation

  • data_set (DataSet)

    the dataset required for the bilinear interpolation



54
55
56
57
# File 'lib/math/bilinear_interpolation.rb', line 54

def self.set_attributes(, data_set)
  @data_set = data_set
  @meta_data = 
end