2010-10-04 17 views
24

¿Alguien tiene una implementación concisa y robusta de Google Encoded Polyline Algorithm en C#?Implementación C# del 'Algoritmo de polilínea codificada' de Google

que quieren esencialmente la aplicación de esta firma:

public string Encode(IEnumerable<Point> points); 
+1

Para quien haya votado cerrar, siga el enlace, lea el artículo y luego explique cómo esta no es una pregunta contestable. –

+1

El algoritmo parece bastante trivial de implementar. ¿Por qué no darle luz verde? – spender

+2

@spender, lo estoy haciendo ahora mismo. Solo pensé que sería el tipo de cosa que vale la pena documentar en SO :) –

Respuesta

40

Ésta es la aplicación que se establecieron en:

public static string Encode(IEnumerable<GeoLocation> points) 
{ 
    var str = new StringBuilder(); 

    var encodeDiff = (Action<int>)(diff => { 
     int shifted = diff << 1; 
     if (diff < 0) 
      shifted = ~shifted; 
     int rem = shifted; 
     while (rem >= 0x20) 
     { 
      str.Append((char)((0x20 | (rem & 0x1f)) + 63)); 
      rem >>= 5; 
     } 
     str.Append((char)(rem + 63)); 
    }); 

    int lastLat = 0; 
    int lastLng = 0; 
    foreach (var point in points) 
    { 
     int lat = (int)Math.Round(point.Latitude * 1E5); 
     int lng = (int)Math.Round(point.Longitude * 1E5); 
     encodeDiff(lat - lastLat); 
     encodeDiff(lng - lastLng); 
     lastLat = lat; 
     lastLng = lng; 
    } 
    return str.ToString(); 
} 

la esperanza de que ayude a alguien más ahí fuera.

+0

¿tiene la función Decode disponible? – jaxxbo

+1

Acabo de encontrar uno: http://www.codeproject.com/Tips/312248/Google-Maps-Direction-API-V-Polyline-Decoder – jaxxbo

+0

¿Sabe si la polilínea codificada OTP es igual que la polilínea codificada de Google? – jaxxbo

6

aplicación Javascript, por si alguien está interesado:

var polyline_encoder = (function() { 
    var _ = {}; 

    var invert_bits = function(str) { 
     var ret = ""; 
     for(var i=0; i<str.length; i++) { 
      if(str.charAt(i) == "1") 
       ret += "0"; 
      else 
       ret += "1"; 
     } 
     return ret; 
    }; 

    var get_binary = function(num) { 
     var binary = parseInt(num).toString(2); 
     var bit_difference = 32 - binary.length; 
     for(var i=0; i<bit_difference; i++) 
      binary = "0" + binary; 
     if(num < 0) { 
      binary = invert_bits(binary); 
      binary = parseInt(binary, 2); 
      binary++; 
      return parseInt(binary).toString(2); 
     } 
     return binary; 
    }; 

    _.encode_polyline = function(points) { 
     var ret = ""; 
     var last_point, val_1, val_2; 
     for(var i=0; i<points.length; i++) { 
      if(!last_point) { 
       val_1 = points[i][0]; 
       val_2 = points[i][1]; 
      } else { 
       val_1 = points[i][0] - last_point[0]; 
       val_2 = points[i][1] - last_point[1]; 
      } 
      last_point = points[i]; 
      ret += _.encode_polyline_value(val_1) + _.encode_polyline_value(val_2); 
     } 
     return ret; 
    }; 

    _.encode_polyline_value = function(value) { 
     var ret = ""; 
     value = Math.round(value * 100000); 
     var shifted = value << 1; 
     if(shifted < 0) 
      shifted = ~shifted; 
     var rem = shifted; 
     while(rem >= 32) { 
      ret += get_ascii_value(((0x20 | (rem & 0x1f)) + 63)); 
      rem >>= 5; 
     } 
     ret += get_ascii_value(rem + 63); 
     return ret; 
    }; 

    var get_ascii_value = function(num) { 
     var ascii_table = 
     // 0 thru 9 
     "??????????" + 
     // 10 thru 19 
     "??????????" + 
     // 20 thru 29 
     "??????????" + 
     // 30 thru 39 
     "?? !\"#$%&'" + 
     // 40 thru 49 
     "()*+,-./01" + 
     // 50 thru 59 
     "23456789:;" + 
     // 60 thru 69 
     "<=>[email protected]" + 
     // 70 thru 79 
     "FGHIJKLMNO" + 
     // 80 thru 89 
     "PQRSTUVWXY" + 
     // 90 thru 99 
     "Z[\\]^_`abc" + 
     // 100 thru 109 
     "defghijklm" + 
     // 110 thru 119 
     "nopqrstuvw" + 
     // 120 thru 127 
     "xyz{|}~?"; 

     var value = ascii_table.substr(num, 1); 
     if(value == "?") 
      value = ""; 
     return value; 
    }; 

    return _; 
})(); 
+0

Si utiliza la API de Google Maps para obtener una DirectionsRoute, parece que le proporciona la ['overview_polyline'] (http://stackoverflow.com/q/9217274/901048) como parte del objeto, aunque está [actualmente no documentada] (https://developers.google.com/maps/documentation/ javascript/reference # DirectionsRoute). – Blazemonger

8

Tal vez es tarde pero he resuelto el mismo problema, pero a la lista de lugares y polilíneas Decodificar Codificar, solía http://json2csharp.com/ para generar correspondientes clases en C# con el fin de deserializar la respuesta con JsonConvert como:

var googleDirectionsResponse = JsonConvert.DeserializeObject<RootObject>(responseString); 

esto me dio esta definición de la ubicación (lo limpiaré más pronto o más tarde):

public class Location 
{ 
    public double lat { get; set; } 
    public double lng { get; set; } 
} 

Y he creado una clase de convertidor para hacer el truco en ambas direcciones (no es original, es sólo un refactor de esta clase: https://gist.github.com/shinyzhu/4617989):

/// <summary> 
/// Google Polyline Converter (Encoder and Decoder) 
/// </summary> 
public static class GooglePolylineConverter 
{ 
    /// <summary> 
    /// Decodes the specified polyline string. 
    /// </summary> 
    /// <param name="polylineString">The polyline string.</param> 
    /// <returns>A list with Locations</returns> 
    public static IEnumerable<Location> Decode(string polylineString) 
    { 
     if (string.IsNullOrEmpty(polylineString)) 
      throw new ArgumentNullException(nameof(polylineString)); 

     var polylineChars = polylineString.ToCharArray(); 
     var index = 0; 

     var currentLat = 0; 
     var currentLng = 0; 

     while (index < polylineChars.Length) 
     { 
      // Next lat 
      var sum = 0; 
      var shifter = 0; 
      int nextFiveBits; 
      do 
      { 
       nextFiveBits = polylineChars[index++] - 63; 
       sum |= (nextFiveBits & 31) << shifter; 
       shifter += 5; 
      } while (nextFiveBits >= 32 && index < polylineChars.Length); 

      if (index >= polylineChars.Length) 
       break; 

      currentLat += (sum & 1) == 1 ? ~(sum >> 1) : (sum >> 1); 

      // Next lng 
      sum = 0; 
      shifter = 0; 
      do 
      { 
       nextFiveBits = polylineChars[index++] - 63; 
       sum |= (nextFiveBits & 31) << shifter; 
       shifter += 5; 
      } while (nextFiveBits >= 32 && index < polylineChars.Length); 

      if (index >= polylineChars.Length && nextFiveBits >= 32) 
       break; 

      currentLng += (sum & 1) == 1 ? ~(sum >> 1) : (sum >> 1); 

      yield return new Location 
      { 
       lat = Convert.ToDouble(currentLat)/1E5, 
       lng = Convert.ToDouble(currentLng)/1E5 
      }; 
     } 
    } 

    /// <summary> 
    /// Encodes the specified locations list. 
    /// </summary> 
    /// <param name="locations">The locations.</param> 
    /// <returns>The polyline string.</returns> 
    public static string Encode(IEnumerable<Location> locations) 
    { 
     var str = new StringBuilder(); 

     var encodeDiff = (Action<int>)(diff => 
     { 
      var shifted = diff << 1; 
      if (diff < 0) 
       shifted = ~shifted; 

      var rem = shifted; 

      while (rem >= 0x20) 
      { 
       str.Append((char)((0x20 | (rem & 0x1f)) + 63)); 

       rem >>= 5; 
      } 

      str.Append((char)(rem + 63)); 
     }); 

     var lastLat = 0; 
     var lastLng = 0; 

     foreach (var point in locations) 
     { 
      var lat = (int)Math.Round(point.lat * 1E5); 
      var lng = (int)Math.Round(point.lng * 1E5); 

      encodeDiff(lat - lastLat); 
      encodeDiff(lng - lastLng); 

      lastLat = lat; 
      lastLng = lng; 
     } 

     return str.ToString(); 
    } 
} 

espero que ayude.

+0

Decode ha sido probado para xamarin forms map, welldone. –

Cuestiones relacionadas