在Lua中的位运算

我尝试解析 gpx 文件并输出 encoded polylinesGoogle algorithm),代码如下:

file = io.open(arg[1], "r")
io.input(file)

function round(number, precision)
   return math.floor(number*math.pow(10,precision)+0.5) / math.pow(10,precision)
end

function encodeNumber(number)
  local num = number
  num = num * 2
  if num < 0
  then
    num = (num * -1) - 1
  end
  while num >= 32
  do
    local num2 = 32 + (num % 32) + 63
    print(string.char(num2))
    num = num / 32
  end
  print(string.char(num + 63) .. "\n-----")
end

local Olatitude = 0
local Olongitude = 0

while true do
  local line = io.read()
  if line == nil
  then
    break
  end
  if string.match(line, "trkpt") then
    local latitude
    local longitude
    local encnum
    latitude = string.match(line, 'lat="(.-)"')
    longitude = string.match(line, 'lon="(.-)"')
    latitude = round(latitude,5)*100000
    longitude = round(longitude,5)*100000
    encnum = encodeNumber(latitude-Olatitude)
    print(encnum)
    encnum = encodeNumber(longitude-Olongitude)
    print(encnum)
    Olatitude = latitude
    Olongitude = longitude
  end
end

其中 encodeNumber 函数需要实现。Mapquest 提供了一个 Javascript 实现,如下所示:

function encodeNumber(num) {
   var num = num << 1;
   if (num < 0) {
      num = ~(num);
   }
   var encoded = '';
   while (num >= 0x20) {
      encoded += String.fromCharCode((0x20 | (num & 0x1f)) + 63);
      num >>= 5;
   }
   encoded += String.fromCharCode(num + 63);
   return encoded;
}

我们需要将这个函数翻译成 Lua 版本的实现方式。一个参考方案如下:

function encodeNumber(number)
  local num = number
  num = num * 2
  if num < 0
  then
    num = (num * -1) - 1
  end
  while num >= 32
  do
    local num2 = 32 + (num % 32) + 63
    print(string.char(num2))
    num = num / 32
  end
  print(string.char(num + 63) .. "\n-----")
end

但是需要注意的是这个方案的输出结果与期望的结果不完全一致,需要进一步调整。

点赞
用户33252
用户33252

encodeNumber 分模块处理...

   var num = num << 1;

这相当于 num = num * 2

   num = ~(num);

这相当于 num = (- num) - 1

   0x20 | (num & 0x1f)

这相当于 32 + (num % 32)

   num >>= 5

这相当于 num = math.floor(num / 32)

附录

使用表来连接字符:

function encodeNumber(number)
  local num = number
  num = num * 2
  if num < 0
  then
    num = (num * -1) - 1
  end
  local t = {}
  while num >= 32
  do
    local num2 = 32 + (num % 32) + 63
    table.insert(t,string.char(num2))
    num = math.floor(num / 32) -- 注意使用 floor 保留整数部分
  end
  table.insert(t,string.char(num + 63))
  return table.concat(t)
end
2014-08-14 16:20:53