博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
地图经纬度C#和Javascript的压缩以及解压
阅读量:5308 次
发布时间:2019-06-14

本文共 10785 字,大约阅读时间需要 35 分钟。

此方法没有只适用于数字类型。不适应于字符串类型。(转摘:,其中有些变量没有赋值,可以看转摘网址后面的评论中有说明。)

Encoding Latitude and Longitude pairs for performance

In Virtual Earth we use lat/lon pairs everywhere, for pushpins, polylines and polygons but also for map bounds like the current view. This article aims to look at a better way to store and transmit these values. The encoding algorithm used is from Google maps. You will find an explanation of how and why we use it for Virtual Earth.

What am I talking about?

Take this polyline for example (scroll down very fast):

(-10.83330598364249,142.20703125)        (-17.434510551522894,140.7568359375)        (-14.859850400601036,135.3955078125)        (-12.254127737657366,136.845703125)        (-11.307707707765436,130.2978515625)        (-14.817370620155252,129.5068359375)        (-13.710035342476668,126.298828125)        (-18.81271785640776,121.640625)        (-22.67484735118851,113.642578125)        (-26.667095801104803,113.5546875)        (-31.98944183792288,115.6201171875)        (-34.95799531086791,115.9716796875)        (-33.394759218577974,123.22265625)        (-31.802892586706747,129.19921875)        (-32.39851580247401,133.59375)        (-35.17380831799957,135.52734375)        (-33.02708758002873,137.8564453125)        (-35.8534396195918,136.9775390625)        (-36.17335693522159,139.74609375)        (-38.75408327579141,143.349609375)        (-40.58058466412763,144.66796875)        (-43.54854811091287,146.07421875)        (-43.54854811091287,147.0849609375)        (-40.97989806962013,148.0517578125)        (-40.68063802521456,144.6240234375)        (-38.616870463929736,143.3056640625)        (-37.92686760148134,149.3701171875)        (-34.19817309627723,151.083984375)        (-28.92163128242129,153.369140625)        (-25.641526373065755,153.28125)        (-18.60460138845525,146.2939453125)        (-15.24178985596171,145.0634765625)        (-10.660607953624762,142.20703125)

1,127 characters

This can be encoded into this:

d{baA}x}bZphhg@vfzGszuNhcv_@y|{NwfzGczwD`{}f@lnlTznyC{gwE`qqRvrc^vxl[hiqVxbyo@pvjWhdPton_@}krKlxbQgtcAgipHsegk@c|uHohnc@risB{hyYp`}O}sxJ_hbL{
{eMt_gPdtjDnn}@ov{Op`wN}x~TrvcJwn`GvtbQatqG?eldEautNmy {Dkmy@hn|SoarKvn`GqweCym_d@igwUuvmIkqe_@gi}Lus_ShdPwk}i@tusi@sxoSlioFkw}Zv{lP

272 characters

That’s less the 25% of the original!

 

How accurate do we need to be?

I’ve seen lat/lon values with 15 decimal places to mark the centre of a country.

0.00001° ≈ 1 m
For me, and therefore this article that is as accurate as I’m going to be for displaying and working with Virtual Earth. In my database I will store values with many more digits, I use a float(8). Let’s not forget the lessons from year 2000 bug here. We don’t want to lose accuracy for the future but it’s not required for today’s mapping. The benefit is we have far less data to deal with. You will see why that’s important in a moment.

What characters can we use and why?

We are going to encode values into plain text strings to transmit on URL query strings, store as string variables in js and .net and pass in XML. Therefore we want to use plain ASCII characters. The Google algorithm we use simply uses characters above 63 to skip <>?& etc. An interesting discovery though is for plain text emails in outlook you can’t use {}[]\ in links. If you plan to do this you easily do a replacement using numbers 0-9 for the offending characters.

Differences

If we have many lat/lon values on our map we can save space by only storing the differences in lat/lon between them. The closer the set of points, which is typical, the smaller the information we need to encode.

The Algorithm (courtesy of Google)

  1. Take the initial signed value:
    -179.9832104
  2. Take the decimal value and multiply it by 1e5, flooring the result:
    -17998321
  3. Convert the decimal value to binary. Note that a negative value must be inverted and provide padded values toward the byte boundary:
    00000001 00010010 10100001 11110001
    11111110 11101101 10100001 00001110
    11111110 11101101 01011110 00001111
  4. Shift the binary value:
    11111110 11101101 01011110 00001111 0
  5. If the original decimal value is negative, invert this encoding:
    00000001 00010010 10100001 11110000 1
  6. Break the binary value out into 5-bit chunks (starting from the right hand side):
    00001 00010 01010 10000 11111 00001
  7. Place the 5-bit chunks into reverse order:
    00001 11111 10000 01010 00010 00001
  8. OR each value with 0x20 if another bit chunk follows:
    100001 111111 110000 101010 100010 000001
  9. Convert each value to decimal:
    33 63 48 42 34 1
  10. Add 63 to each value:
    96 126 111 105 97 64
  11. Convert each value to its ASCII equivalent:
    `~oia@

Encoding

JavaScript

// Encode a signed number in the encode format.function encodeSignedNumber(num) {  var sgn_num = num << 1;  if (num < 0) {    sgn_num = ~(sgn_num);  }  return(encodeNumber(sgn_num));}// Encode an unsigned number in the encode format.function encodeNumber(num) {  var encodeString = "";  while (num >= 0x20) {    encodeString += (String.fromCharCode((0x20 | (num & 0x1f)) + 63));    num >>= 5;  }  encodeString += (String.fromCharCode(num + 63));  return encodeString;}// Create the encoded bounds.function createEncodings(points) {  var i = 0;  var plat = 0;  var plng = 0;  var encoded_points = "";  for(i = 0; i < points.length; ++i) {    var point = points[i];    var lat = point.Latitude;    var lng = point.Longitude;    var late5 = Math.floor(lat * 1e5);    var lnge5 = Math.floor(lng * 1e5);    dlat = late5 - plat;    dlng = lnge5 - plng;    plat = late5;    plng = lnge5;    encoded_points += encodeSignedNumber(dlat) + encodeSignedNumber(dlng);  }   return encoded_points;}

C#

/// /// encoded a list of latlon objects into a string/// /// the list of latlon objects to encode/// 
the encoded string
public static string EncodeLatLong(List
points){ int plat = 0; int plng = 0; int len = points.Count; StringBuilder encoded_points = new StringBuilder(); for (int i = 0; i < len; ++i) { //Round to 5 decimal places and drop the decimal int late5 = (int)(points[i].Lat * 1e5); int lnge5 = (int)(points[i].Lon * 1e5); //encode the differences between the points encoded_points.Append(encodeSignedNumber(late5 - plat)); encoded_points.Append(encodeSignedNumber(lnge5 - plng)); //store the current point plat = late5; plng = lnge5; } return encoded_points.ToString();}///
/// Encode a signed number in the encode format./// ///
the signed number///
the encoded string
private static string encodeSignedNumber(int num){ int sgn_num = num << 1; //shift the binary value if (num < 0) //if negative invert { sgn_num = ~(sgn_num); } return (encodeNumber(sgn_num));}///
/// Encode an unsigned number in the encode format./// ///
the unsigned number///
the encoded string
private static string encodeNumber(int num){ StringBuilder encodeString = new StringBuilder(); while (num >= 0x20) { //while another chunk follows encodeString.Append((char)((0x20 | (num & 0x1f)) + minASCII)); //OR value with 0x20, convert to decimal and add 63 num >>= binaryChunkSize; //shift to next chunk } encodeString.Append((char)(num + minASCII)); return encodeString.ToString();}

  

Decoding

JavaScript

// Decode an encoded string into a list of VE lat/lng.function decodeLine(encoded) {    var len = encoded.length;    var index = 0;    var array = [];    var lat = 0;    var lng = 0;    try    {        while (index < len) {            var b;            var shift = 0;            var result = 0;            do {                  b = encoded.charCodeAt(index++) - 63;                  result |= (b & 0x1f) << shift;                  shift += 5;            } while (b >= 0x20);            var dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));            lat += dlat;            shift = 0;            result = 0;            do {                  b = encoded.charCodeAt(index++) - 63;                  result |= (b & 0x1f) << shift;                  shift += 5;            } while (b >= 0x20);            var dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));            lng += dlng;            array.push(new VELatLong((lat * 1e-5), (lng * 1e-5)));        }    } catch(ex)    {        //error in encoding.    }    return array;}

C#

/// /// decodes a string into a list of latlon objects/// /// encoded string/// 
list of latlon
public static List
DecodeLatLong(string encoded){ List
locs = new List
(); int index = 0; int lat = 0; int lng = 0; int len = encoded.Length; while (index < len) { lat += decodePoint(encoded, index, out index); lng += decodePoint(encoded, index, out index); locs.Add(new LatLong((lat * 1e-5), (lng * 1e-5))); } return locs;}///
/// decodes the cuurent chunk into a single integer value/// ///
the complete encodered string///
the current position in that string///
output - the position we end up in that string///
the decoded integer
private static int decodePoint(string encoded, int startindex, out int finishindex){ int b; int shift = 0; int result = 0; do { //get binary encoding b = Convert.ToInt32(encoded[startindex++]) - minASCII; //binary shift result |= (b & 0x1f) << shift; //move to next chunk shift += binaryChunkSize; } while (b >= 0x20); //see if another binary value //if negivite flip int dlat = (((result & 1) > 0) ? ~(result >> 1) : (result >> 1)); //set output index finishindex = startindex; return dlat;}

Utilising the above function you can encode your lat/lon values server or client side and see a 400% decrease in transmission size. If you need to store a few values these encoding are much easier to deal with then an array of lat/lon.

Additionally if you are able to use some form of compression, like that found in IIS6 you can reduce the data size again.

Final Thoughts

Using the encoding as a base it is possible to not only encode lat/lon values but also other simple information.

I had an application that was found to be transmitting 640KB of data to the VE map. I got it down to less than 25KB by removing everything that wasn’t necessary and encoding what was left. With IIS compression this would go down to less than 10KB. That’s the different between a slow Virtual Earth application and a high performance one.
Stay tuned for my next Article: “”.

 

转载于:https://www.cnblogs.com/Health/archive/2012/07/05/2577442.html

你可能感兴趣的文章
LOCK TABLES和UNLOCK TABLES
查看>>
cssText()
查看>>
微信小程序里碰到的坑和小知识
查看>>
ITOO高校云平台V3.1--项目总结(二)
查看>>
Spring Java-based容器配置
查看>>
android launcher2开发之 有抽屉改成无抽屉
查看>>
Android App补丁更新
查看>>
混用Int与IntPtr导致GetProcAddress始终返回null
查看>>
第四次网络原理笔记
查看>>
mac笔记本怎样显示隐藏的文件
查看>>
关于socket通讯,如何才能高效?
查看>>
NPOI导Excel样式设置
查看>>
webp图像批量转换软件推荐——XnConvert
查看>>
PHP session用redis存储
查看>>
hdu1232畅通工程 并查集
查看>>
JS和CSS实现响应式
查看>>
动态修改JS对象的值及React setState
查看>>
51nod1244 莫比乌斯函数之和
查看>>
$(document).height 与$(window).height的区别
查看>>
Android WebView默认GONE出现的问题记录
查看>>