如何转换为Google编码的折线算法格式?

问题描述 投票:0回答:5

Google 地图的编码折线格式存储纬度/经度信息以及缩放级别。

我有一个巨大的文本文件,其中包含纬度/经度对,我想将其转换为这种格式并用于折线的不同部分(即我需要执行批量转换)

有人知道执行此操作的代码吗?

google-maps-api-3 polyline
5个回答
7
投票

关于编码和解码折线的权威参考是 Mark McClure 教授,位于 http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/

https://web.archive.org/web/20080722112929/http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/

它包含实用程序、算法讨论以及将 Javascript 代码移植到 Perl、Ruby、PHP、Java 和 Mathematica 中。

注意:对于版本 3,您不需要版本 2 所需的

levels
字符串。版本 3 会自行计算级别。


6
投票

我不知道您需要哪种语言。您可以从 Google here 获取总体思路。然而,我发现这些说明并不是 100% 准确。这就是我的理解,使用同一篇文章中的例子。我用 Java 实现了它,转换为 JavaScript 或 PHP 应该很容易。

  public class MapMath {
    private final static double MULTIPLIER = 100000;
    private final static int FIVE_BIT_MASK = 0x1f;

    public MapMath() {
      double[][] coords = new double[][]{
        {-12.422187,130.854922},
          {-12.422445,130.854937},
          {-12.422234,130.854886}
      };

      StringBuilder encodedStrings = new StringBuilder();
      for (int i = 0; i < 3; i++){
        encodedStrings.append(
            encodeCoordinate(coords[i][0]) + 
            encodeCoordinate(coords[i][1]) + "\n"
            );
      }
      System.out.println(encodedStrings);
    }

    private String encodeCoordinate(double coordinate) {
      StringBuilder encodedCoordinate = new StringBuilder();
      boolean hasNext;

      coordinate *= MULTIPLIER;
      int value = (int) coordinate;
      value <<= 1;
      if(coordinate < 0) value = ~value;  

      do {
        int next = (value >> 5);
        hasNext = (next > 0);
        int encVal = value & FIVE_BIT_MASK;
        if(hasNext) encVal |= 0x20;
        encVal += 0x3f;
        value = next;
        encodedCoordinate.append((char)(encVal));
      } while (hasNext);

      return encodedCoordinate.toString();
    } 

    public static double toRadians(double degrees) {
      return (degrees*Math.PI)/180;
    }

    public static void main(String[] args){
      new MapMath();
    }
  }

请注意,连续的坐标应该是相对于前一个坐标的偏移量。 希望它对您有用,如果需要任何进一步的帮助,请告诉我。


2
投票

我还看到了一些不太准确的算法实现(也有一些非常糟糕的代码)。这是我的编码函数(用VB.NET编写)。该函数仅对传递给它的一个值进行编码,因此您必须在其他地方进行所有差异计算。返回的结果与 Google 的“编码折线算法格式”页面上显示的结果完全匹配。 (我的一些代码可以压缩和优化,但我试图使算法的每一步都清晰)。我希望有人觉得这很有用! ''' <summary> ''' Encodes a latitude or longitude value by using Google's Polyline algorithm ''' </summary> ''' <param name="ToEnc">Latitude or Longitude to encode (or a difference value) (Single)</param> ''' <returns>Polyline encoded point (String)</returns> ''' <remarks>This function doesn't care what value you pass it, whether it's an absolute coordinate or a difference. Make sure you do all of the point difference calculations somewhere else before calling this method.</remarks> Private Function Encode(ByVal ToEnc As Single) As String Dim Coord As Integer 'The integer version of the coordinate, as per steps 2 and 3 Dim B(5) As Byte 'The 5-bit chunks, as per steps 6 and 7. Note that all 6 bytes may not be used Dim I As Integer 'Generic counter Dim C(5) As Char 'The chunks converted from bytes to characters '2., 3. Take the decimal value and multiply is by 1e5, rounding the result. Convert the decimal value to binary. Coord = Math.Sign(ToEnc) * Int(Math.Abs(ToEnc) * 100000.0) '4. Left-shift the binary value one bit Coord <<= 1 '5. If the original decimal value is negative, invert this encoding If ToEnc < 0 Then Coord = Not Coord '6. Break the binary value out into 5-bit chunks (starting from the right hand side) '7. Place the 5-bit chunks in reverse order 'Steps 6 and 7 are done at the same time B(0) = Coord And &H1F B(1) = (Coord And &H3E0) >> 5 B(2) = (Coord And &H7C00) >> 10 B(3) = (Coord And &HF8000) >> 15 B(4) = (Coord And &H1F00000) >> 20 B(5) = (Coord And &H3E000000) >> 25 '8. OR each value with 0x20 if another bit chunk follows 'Go through the 5-bit chunks looking for the first one that isn't zero 'When we find it, that means the one BEFORE that is the last to get the 0x20 modification Dim E As Integer = -1 'Penultimate byte that contains data, the last one to get ORed by 0x20 For I = 5 To 1 Step -1 If B(I) <> 0 Then 'This is the first nonzero value we've encountered, so keep track of this position and exit the loop E = I - 1 Exit For End If Next 'Apply the 0x20 modification For I = 0 To E B(I) = B(I) Or &H20 Next '10. Add 63 to each value For I = 0 To 5 If B(I) > 0 Then B(I) += 63 Next '11. Convert each value to its ASCII equivalent For I = 0 To 5 C(I) = Chr(B(I)) Next 'Turn the char array into a string and return it Return New String(C, 0, E + 2) End Function



2
投票

https://github.com/tonydspaniard/Yii-extensions/blob/master/extensions/EGMap/EGMapPolylineEncoder.php

它基于

http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/

上提供的一些代码,但已完善为适当的类。


1
投票
http://www.excely.com/excel-vba/bit-shifting-function.shtml#.UoUFM8ZSiSo

''' <summary> ''' Encodes a latitude or longitude value by using Google's Polyline algorithm ''' </summary> ''' <param name="ToEnc">Latitude or Longitude to encode (or a difference value) (Single)</param> ''' <returns>Polyline encoded point (String)</returns> ''' <remarks>This function doesn't care what value you pass it, whether it's an absolute coordinate or a difference. Make sure you do all of the point difference calculations somewhere else before calling this method.</remarks> Function Encode(ByVal ToEnc As Single) As String Dim Coord As Double 'The integer version of the coordinate, as per steps 2 and 3 Dim B(5) As Byte 'The 5-bit chunks, as per steps 6 and 7. Note that all 6 bytes may not be used Dim i As Integer 'Generic counter Dim C(5) As String 'The chunks converted from bytes to characters Dim E As Integer E = -1 'Penultimate byte that contains data, the last one to get ORed by 0x20 '2., 3. Take the decimal value and multiply is by 1e5, rounding the result. Convert the decimal value to binary. Coord = Math.Sgn(ToEnc) * Int(Math.Abs(ToEnc) * 100000) '4. Left-shift the binary value one bit Coord = shl(Coord, 1) '5. If the original decimal value is negative, invert this encoding If ToEnc < 0 Then Coord = Not Coord '6. Break the binary value out into 5-bit chunks (starting from the right hand side) '7. Place the 5-bit chunks in reverse order 'Steps 6 and 7 are done at the same time B(0) = Coord And &H1F B(1) = shr((Coord And &H3E0), 5) B(2) = shr((Coord And &H7C00), 10) B(3) = shr((Coord And &HF8000), 15) B(4) = shr((Coord And &H1F00000), 20) B(5) = shr((Coord And &H3E000000), 25) '8. OR each value with 0x20 if another bit chunk follows 'Go through the 5-bit chunks looking for the first one that isn't zero 'When we find it, that means the one BEFORE that is the last to get the 0x20 modification For i = 5 To 1 Step -1 If B(i) <> 0 Then 'This is the first nonzero value we've encountered, so keep track of this position and exit the loop E = i - 1 Exit For End If Next 'Apply the 0x20 modification For i = 0 To E B(i) = B(i) Or &H20 Next '10. Add 63 to each value For i = 0 To 5 If B(i) > 0 Then B(i) = B(i) + 63 Next '11. Convert each value to its ASCII equivalent For i = 0 To 5 C(i) = Chr(B(i)) Encode = Encode + C(i) Next 'Turn the char array into a string and return it End Function Public Function shr(ByVal Value As Long, ByVal Shift As Byte) As Long Dim i As Byte shr = Value If Shift > 0 Then shr = Int(shr / (2 ^ Shift)) End If End Function Public Function shl(ByVal Value As Long, ByVal Shift As Byte) As Long shl = Value If Shift > 0 Then Dim i As Byte Dim m As Long For i = 1 To Shift m = shl And &H40000000 shl = (shl And &H3FFFFFFF) * 2 If m <> 0 Then shl = shl Or &H80000000 End If Next i End If End Function

© www.soinside.com 2019 - 2024. All rights reserved.