地图经纬度C#和Javascript的压缩以及解压
来源:互联网 发布:51单片机电子设计报告 编辑:程序博客网 时间:2024/05/22 13:50
此方法没有只适用于数字类型。不适应于字符串类型。(转摘:http://soulsolutions.com.au/Default.aspx?tabid=96,其中有些变量没有赋值,可以看转摘网址后面的评论中有说明。)
http://www.cnblogs.com/Health/archive/2012/07/05/2577442.html
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)
- Take the initial signed value:
-179.9832104 - Take the decimal value and multiply it by 1e5, flooring the result:
-17998321 - 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 - Shift the binary value:
11111110 11101101 01011110 00001111 0 - If the original decimal value is negative, invert this encoding:
00000001 00010010 10100001 11110000 1 - Break the binary value out into 5-bit chunks (starting from the right hand side):
00001 00010 01010 10000 11111 00001 - Place the 5-bit chunks into reverse order:
00001 11111 10000 01010 00010 00001 - OR each value with 0x20 if another bit chunk follows:
100001 111111 110000 101010 100010 000001 - Convert each value to decimal:
33 63 48 42 34 1 - Add 63 to each value:
96 126 111 105 97 64 - 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#
/// <summary>
/// encoded a list of latlon objects into a string
/// </summary>
/// <param name="points">the list of latlon objects to encode</param>
/// <returns>the encoded string</returns>
public
static
string
EncodeLatLong(List<LatLong> 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();
}
/// <summary>
/// Encode a signed number in the encode format.
/// </summary>
/// <param name="num">the signed number</param>
/// <returns>the encoded string</returns>
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));
}
/// <summary>
/// Encode an unsigned number in the encode format.
/// </summary>
/// <param name="num">the unsigned number</param>
/// <returns>the encoded string</returns>
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#
/// <summary>/// decodes a string into a list of latlon objects/// </summary>/// <param name="encoded">encoded string</param>/// <returns>list of latlon</returns>public static List<LatLong> DecodeLatLong(string encoded){ List<LatLong> locs = new List<LatLong>(); 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;}/// <summary>/// decodes the cuurent chunk into a single integer value/// </summary>/// <param name="encoded">the complete encodered string</param>/// <param name="startindex">the current position in that string</param>/// <param name="finishindex">output - the position we end up in that string</param>/// <returns>the decoded integer</returns>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: “Loading your pushpin popup content on demand”.
- 地图经纬度C#和Javascript的压缩以及解压
- C#压缩和解压
- C# 对字符串的压缩和解压
- C#对文件操作(基本的读写以及压缩和解压)
- c#实现压缩和解压
- C# 压缩和解压文件
- C#字符串压缩和解压
- c#中关于压缩数据流和解压数据流的实现
- javascript 在线压缩和解压工具
- 使用C#进行文件压缩和解压
- 使用C#进行文件压缩和解压
- c# 使用GZipStream压缩和解压流
- C# GZip对字符串压缩和解压
- C# GZip对字符串压缩和解压
- C# 实现ZIP 压缩和解压
- C#对byte数组压缩和解压
- C# GZip对字符串压缩和解压
- C#实现zip压缩和解压
- gcc里的switch,刚发现的一个好玩的地方!
- linux C程序中获取shell脚本输出
- MFC创建一个全屏窗口(附源码)
- 关于Oracle Data Guard的角色切换
- C++中的"Union" 转成C#
- 地图经纬度C#和Javascript的压缩以及解压
- hibernate源码下载地址及对应hibernate-annotation、slf4j版本
- cf219e
- C盘中各个文件夹的作用
- PDU短信的编码一般规则
- sybase数据库的两种备份方法
- CSS3 border-image 属性
- 提高MYSQL大数据量查询的速度
- C++ 值传递、指针传递、引用传递详解