代码之家  ›  专栏  ›  技术社区  ›  Drew Noakes

谷歌“编码折线算法”的C#实现

  •  28
  • Drew Noakes  · 技术社区  · 14 年前

    有没有人对谷歌的 Encoded Polyline Algorithm 在C#?

    我基本上想要实现这个签名:

    public string Encode(IEnumerable<Point> points);
    
    3 回复  |  直到 14 年前
        1
  •  49
  •   Drew Noakes    14 年前

    以下是我确定的实施方案:

    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();
    }
    

    希望这能帮助别人。

        2
  •  20
  •   Juan    8 年前

    也许是晚了,但我刚刚解决了同样的问题,但编码的位置列表和解码多段线,我用 http://json2csharp.com/ 在C中生成相应的类,以便用JsonConvert反序列化响应,如:

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

    这给了我这个位置的定义(我迟早会清理它):

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

    我创建了一个converter类来实现双向转换(它不是原创的,它只是这个类的重构: 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();
        }
    }
    

        3
  •  6
  •   thordiesel    13 年前

    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
            "<=>?@ABCDE" +
            // 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 _;
    })();