Skip to content

Instantly share code, notes, and snippets.

@jheidt jheidt/wkb.rb
Last active Dec 16, 2015

Embed
What would you like to do?
Messing around with a ruby Well-Known-Binary converter.
module WellKnownBinary
require 'bindata'
TYPE_ID = {
:point => 1,
:linestring => 2,
:polygon => 3,
:multipoint => 4,
:multilinestring => 5,
:multipolygon => 6,
:geometrycollection => 7,
:circularstring => 8,
:compoundcurve => 9,
:curvepolygon => 10,
:multicurve => 11,
:multisurface => 12,
:curve => 13,
:surface => 14,
:polyhedralsurface => 15,
:tin => 16,
:triangle => 17
}.freeze
BYTE_ORDER = {
:big_endian => 0,
:xdr => 0,
:little_endian => 1,
:ndr => 1
}.freeze
class DefineByteOrder < BinData::Record
uint8 :byte_order, :initial_value => BYTE_ORDER[:little_endian]
def big_endian?
byte_order == 0
end
def little_endian?
byte_order != 0
end
end
class PointBE < BinData::Record
double_be :x
double_be :y
end
class PointLE < BinData::Record
double_le :x
double_le :y
end
class PointArrayBE < DefineByteOrder
uint32be :num_points
array :points, :initial_length => :num_points, :type => :PointBE
end
class PointArrayLE < DefineByteOrder
uint32le :num_points
array :points, :initial_length => :num_points, :type => :PointLE
end
class WKBPoint < DefineByteOrder
# uint32 :wkb_type, :value => WKB_TYPE_ID[:wkb_point]
choice :wkb_type, :copy_on_change => true, :selection => lambda { big_endian? } do
uint32be true, :value => TYPE_ID[:point]
uint32le false, :value => TYPE_ID[:point]
end
#Point :point
choice :point, :copy_on_change => true, :selection => lambda { big_endian? } do
PointBE true
PointLE false
end
end
class WKBLineString < DefineByteOrder
#uint32 :wkb_type, :value => WKB_TYPE_ID[:wkb_linestring]
choice :wkb_type,
:copy_on_change => true,
:selection => lambda { big_endian? } do
uint32be true, :value => TYPE_ID[:linestring]
uint32le false, :value => TYPE_ID[:linestring]
end
#PointArray :points
choice :point,
:copy_on_change => true,
:selection => lambda { big_endian? } do
PointArrayBE true
PointArrayLE false
end
end
end
include WellKnownBinary
# converts a byte array to a hex string
def bin_to_hex(s)
s.unpack('H*').first
end
#
# converts a hex string to a byte array
# s = hex string
def hex_to_bin(s)
s.scan(/../).map { |x| x.hex }.pack('c*')
end
# create a WKB point
foo = WKBPoint.new( :point => { :x => 47.0001, :y => 89.0011 } )
# inspect the point
# p foo
# get the byte array (WKB)
foo_bin = foo.to_binary_s
# get the hex string for the byte array
foo_hex = bin_to_hex( foo_bin )
# display the hex string
# puts " foo hex: #{foo_hex}"
# convert from hex string back to a byte array
re_foo = WKBPoint.read( hex_to_bin('01010000008D976E1283C0F33F16FBCBEEC9C30240') )
p re_foo
puts "created from string"
puts "created: #{ bin_to_hex(re_foo.to_binary_s) }"
puts ""
re_foo.byte_order = 0
puts "changed byte order to big endian"
puts
puts " big-endian: #{ bin_to_hex(re_foo.to_binary_s) }"
puts
p re_foo
re_foo.byte_order = 1
puts "changed byte order to little endian"
puts
puts " little-endian: #{ bin_to_hex(re_foo.to_binary_s) }"
puts
p re_foo
# Creating from WKB hex string: 01010000008D976E1283C0F33F16FBCBEEC9C30240
#
# {"byte_order"=>1, "wkb_type"=>1, "point"=>{"x"=>1.2345, "y"=>2.3456}}
# created from string
# created: 01010000008d976e1283c0f33f16fbcbeec9c30240
#
# changed byte order to big endian
#
# big-endian: 00000000013ff3c083126e978d4002c3c9eecbfb16
#
# {"byte_order"=>0, "wkb_type"=>1, "point"=>{"x"=>1.2345, "y"=>2.3456}}
# changed byte order to little endian
#
# little-endian: 01010000008d976e1283c0f33f16fbcbeec9c30240
#
# {"byte_order"=>1, "wkb_type"=>1, "point"=>{"x"=>1.2345, "y"=>2.3456}}
#
# > Process Exit Code: 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.