class GeoElevation::Undulations

EGM stands for “Earth Gravitational Model” and is a parser for the EGM2008 file obtained from earth-info.nga.mil/GandG/wgs84/gravitymod/egm2008/index.html

Public Class Methods

new() click to toggle source
# File lib/geoelevation.rb, line 169
def initialize
    # Just in case...
    json = Retriever::prepare_folder

    @file_name = GeoElevation::EGM2008_URL.split('/')[-1]
    @local_file_name = File.join(GeoElevation::DIR_NAME, @file_name.gsub(/.gz$/, ''))

    if !File.exists?(@local_file_name)
        puts "Downloading and ungzipping #{GeoElevation::EGM2008_URL}"
        GeoElevation::Utils::ungzip(open(GeoElevation::EGM2008_URL), @local_file_name)
    end

    # EGM files will not be loaded in memory because they are too big.
    # file.seek will be used to read values.

    file_size = File.size?(@local_file_name)

    lines = Math.sqrt(file_size / 2)
    puts "lines: #{lines}"
    lines == lines.to_i or raise "Invalid file size:#{file_size}"

    @rows = 180 * 24 * 2
    @columns = 360 * 24 + 2
    @file = open(@local_file_name)
end

Public Instance Methods

get_local_file_name() click to toggle source
# File lib/geoelevation.rb, line 195
def get_local_file_name()
     @local_file_name
end
get_undulation(latitude, longitude) click to toggle source
# File lib/geoelevation.rb, line 199
def get_undulation(latitude, longitude)
    # TODO: Constants:
    la = -latitude + 90
    lo = longitude < 0 ? longitude + 360 : longitude
    row = (la * 24).floor
    column = (lo * 24).floor
    position = row * @columns + column

    #puts "#{latitude}, #{longitude} -> #{column}, #{row} -> #{position}"

    get_value_at_file_position(position)
end
get_value_at_file_position(position) click to toggle source

Loads a value from the n-th position in the EGM file. Every position is a 4-byte real number.

# File lib/geoelevation.rb, line 214
def get_value_at_file_position(position)
    @file.seek(4 + position * 4)
    bytes = @file.read(4)

    begin
        value = bytes[0].ord * 256**0 + bytes[1].ord * 256**1 + bytes[2].ord * 256**2 + bytes[3].ord * 256**3
        result = unpack(value)
    rescue
        result = 0
    end

    result
end
unpack(n) click to toggle source

Unpacks a number from the EGM file

# File lib/geoelevation.rb, line 229
def unpack(n)
    sign = n >> 31
    exponent = (n >> (32 - 9)) & 0b11111111
    value = n & 0b11111111111111111111111

    resul = nil
    if 1 <= exponent and exponent <= 254
        result = (-1)**sign * (1 + value * 2**(-23)) * 2**(exponent - 127)
    elsif exponent == 0
        result = (-1)**sign * value * 2**(-23) * 2**(-126)
    else
        # NaN, infinity...
        raise 'Invalid binary'
    end

    result.to_f
end