Skip to content

Instantly share code, notes, and snippets.

@alainravet
Last active December 14, 2015 04:49
Show Gist options
  • Save alainravet/5031054 to your computer and use it in GitHub Desktop.
Save alainravet/5031054 to your computer and use it in GitHub Desktop.
extract POIs from a TomTom *.ov2 file (in Ruby)
module BinaryFileStringUtils
def byte_to_int
self.unpack('U').first
end
def little_endian_to_int
# source : http://stackoverflow.com/questions/5236059/unpack-signed-little-endian-in-ruby
arr, bits, num = self.unpack('V*'), 0, 0
arr.each do |int|
num += int << bits
bits += 32
end
num >= 2**(bits-1) ? num - 2**bits : num # Convert from unsigned to signed
end
end
String.send :include, BinaryFileStringUtils
path = File.absolute_path File.join File.dirname($FILENAME), '..', 'data/poi/Amis.ov2'
File.open(path, 'rb') do |file|
@pois = POI::Reader.new(file).extract_pois
end
puts @pois
#<struct POI type=2, x=4.12345, y=50.1234, text="Al">
#<struct POI type=2, x=4.23456, y=50.5678, text="Bob">
#<struct POI type=2, x=4.34567, y=50.9012, text="Carl">
class POI < Struct.new(:type, :x, :y, :text)
end
class POI
class Reader
attr_reader :file
def initialize(file)
@file = file
file.extend POIFileReadingUtils
end
def extract_pois
pois = []
begin
poi = extract_poi
pois << poi if poi
end until file.eof?
pois
end
private
def extract_poi
raw_type = file.read(1)
type = raw_type.byte_to_int rescue raw_type
case type
when 0 then skip_type_0_poi
when 2 then extract_type_2_poi
when 1, 3
raise "Not Implemented type : #{type.inspect}"
else
raise "Invalid type : #{type.inspect}"
end
end
def skip_type_0_poi
len = file.read_poi_record_len
rest = file.read(len - (1+4))
nil
end
def extract_type_2_poi
len = file.read_poi_record_len
x = file.read_poi_x_coordinate
y = file.read_poi_y_coordinate
text = file.read_poi_text(len - (1+4+4+4))
POI.new(2, x, y, text)
end
end
private
module POIFileReadingUtils
def read_poi_text(len)
read(len).chomp("\u0000")
end
def read_poi_record_len
read(4).little_endian_to_int
end
def read_poi_x_coordinate
read(4).little_endian_to_int/100_000.0
end
alias read_poi_y_coordinate read_poi_x_coordinate
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment