代码改变世界

Google静态地图-如何显示两点之间路线3(url过长–路径简化-完结篇)

2012-01-17 10:23  快乐乔巴  阅读(1813)  评论(0编辑  收藏  举报

非智能手机浏览器的URL长度限制更糟糕

在上一篇Google静态地图-如何显示两点之间路线2(url过长问题)中,利用Google Geocoding API位置路线服务中的折线编码,大大缩短了路线path的字符长度。但是,折线编码也是一长串字符也是有长度的,万一折线编码的长度也太长,也会出现url过长的问题。

这个问题也是我在开发项目时遇到的问题,手机种类繁多独自开发的的浏览器也是让我头疼的地方。我们来看看日本的三大运营商au,softbank,docomo中一些非智能手机浏览器的情况:

浏览器 长度
i-mode(DoCoMo) 512bytes(直接入力時100bytes)
EZweb(au) 1024文字?
Yahoo!ケータイ(SoftBank) 端末 a要素 form要素
DN02※1 300bytes 300bytes
SH02, SH02_a、SH03, SH03_a 1024bytes 255bytes
3GC※2 1024bytes 1024bytes

这是au,softbank,docomo中非智能手机浏览器url长度限制的情况,可以看出url的长度远远小于PC浏览器限制的长度,尤其是i-Mode才520字节(不是绝对,相对于老的手机)…,折线编码的字符长度肯定会超过的,哎,又回到原点了。

如何优化路线

该怎么办呢?还记得第一篇google静态地图-如何显示两点之间路线中利用一个一个点坐标连成路线的方法吗,只要把这些点优化舍去一部分点,字符串不就短了~再转成折线编码就更短了,恩,看起来这个想法可行~~

我们先不考虑如何优化路线,那些从Google Directions API服务中取的一个一个拐点真的是完全路径吗??经过我测试连成路径之后发现,如果路线距离很长,好像拐点个数有限路线上就显示一部分有拐点,后面的就没了。。。结果就是前一部分是曲线后面就是一条直线。。。,汗!完了,看来原来的方法不行了。

那该怎么办呢,我们回顾下Google静态地图-如何显示两点之间路线2(url过长问题),是利用那个折线编码画出路线的,那我们反过来想想,假如将折线编码转化成一个一个的点坐标,这不就是是完全路径的点集合嘛~~前面那个问题不就解决了。慢!,怎么把折线编码还原成一个一个点坐标集合呢??这不,折线编码其实也是将点集合转换过来的,再转换回去就是了。。。

http://code.google.com/intl/zh-CN/apis/maps/documentation/utilities/polylinealgorithm.html

这是如何点集合转化成折线编码的文章,按照上面算法反过来就可以得到点坐标集合了~呵呵,说的轻巧了,本人算法差,惭愧~以下是网上搜索的代码然后加工下。。(其中的List<GLatLng>就是点集合,这是为了程序需要):

 1 /// <summary>
2 /// 折线编码转点集合
3 /// eg : szmrE}japXrX`zE
4 /// decode : 34.646343,133.86943  34.642247,133.834389
5 /// </summary>
6 /// <param name="str"></param>
7 /// <returns></returns>
8 public static List<GLatLng> DecodePath(string str)
9 {
10 int b = str.Length;
11 decimal dec = str.Length / 2;
12 //GLatLng[] c = new GLatLng[int.Parse(Math.Floor(dec).ToString())];
13 List<GLatLng> c = new List<GLatLng>();
14
15 int d = 0, e = 0, f = 0, g = 0;
16
17 for (; d < b; ++g)
18 {
19 int h = 1, n = 0, q;
20 do
21 {
22 q = str.ToCharArray()[d++] - 63 - 1;
23 h += q << n;
24 n += 5;
25 } while (q >= 31);
26 e += (h & 1) != 0 ? ~(h >> 1) : h >> 1;
27
28 h = 1;
29 n = 0;
30
31 do
32 {
33 q = str.ToCharArray()[d++] - 63 - 1;
34 h += q << n;
35 n += 5;
36 } while (q >= 31);
37 f += (h & 1) != 0 ? ~(h >> 1) : h >> 1;
38 //c[g] = new GLatLng(e * 1.0E-5, f * 1.0E-5);
39 c.Add(new GLatLng(e * 1.0E-5, f * 1.0E-5));
40 }
41
42 //c.Length = g;
43 return c;
44 }

OK,完整的点集合取出来了,如何优化这些点呢?请看这下面一篇文章,当然要感谢下这篇文章的作者,对我帮助很大~

作者:阿修的部落格

文章:如何在Google Static Map上顯示超長路徑?

里面讲述的很详细,我就简单摘抄几个重要的地方~

文章中使用的路线算法是道格拉斯-派克爾法(Ramer–Douglas–Peucker algorithm)

credit: 維基百科

道格拉斯-派克爾法的做法就是保留頭尾兩點。將頭尾用一條直線連接,接著找出中間每個點距離這個最大的值b,接著保留這個距離頭尾連接起來的直線最遠的點c。然後設定一個容許值,這個容許值必須小於b。再檢查中間每個點到直線的距離,如果距離大於容許值,就保留這個點。然後用c點,把這條路徑分為兩部分,再依照前面的方法一直做下去。

GDouglasPeuker.js

如果要在Google Maps API或Google Static Maps API上使用道格拉斯-派克爾法,我們可以直接用Bill Chadwick寫好的GDouglasPeuker.js

算法已经有人写好了,不过是js版的~我们知道有些非智能手机上不支持javascript的,所以要转成C#, 转成C#版也不难 就类型什么的转换下就好了~我就不贴代码了.

好了,优化后的点就可以取出来了~为了字符更短,那么就该把这些点集合再一次转化成折线编码,代码我再贴下吧:

 1 /// <summary>
2 /// 点集合转折线编码
3 /// eg : 34.646343,133.86943|34.642247,133.834389
4 /// encode: szmrE}japXrX`zE
5 /// </summary>
6 /// <param name="points"></param>
7 /// <returns></returns>
8 public static string EncodePoints(List<GLatLng> points)
9 {
10 string _result = "";
11 int plat = 0;
12 int plng = 0;
13
14 foreach (GLatLng item in points)
15 {
16 int late5 = (int)Math.Floor(item.Lat * 1e5);
17 int lnge5 = (int)Math.Floor(item.Lng * 1e5);
18
19 int dlat = late5 - plat;
20 int dlng = lnge5 - plng;
21
22 plat = late5;
23 plng = lnge5;
24
25 _result += encodeSignedNumber(dlat) + encodeSignedNumber(dlng);
26 }
27
28 return _result;
29 }
30
31 private static string encodeSignedNumber(int point)
32 {
33
34 int _point_int = point << 1;
35
36 if (point < 0)
37 {
38 _point_int = ~_point_int;
39 }
40 return (encodeNumber(_point_int));
41 }
42
43 private static string encodeNumber(int num)
44 {
45 string resultString = "";
46
47 while (num >= 0x20)
48 {
49 int _block = num & 0x1F;
50 _block = (_block | 0x20) + 63;
51 char _result = (char)_block;
52 resultString += _result;
53 num >>= 5;
54 }
55
56 resultString += (char)(num + 63);
57 return resultString;
58 }

这样,优化的折线编码就出来了~~只要设置那个什么派克爾法算法设置优化距离大小,就可以随意控制路线拐点的个数了,也就可以控制长度了~~这里还是要再次感谢下阿部的文章~

对了,介绍个个折线编码实用工具,这里面大家可以添加个个点后转换成折线编码,哦!对了,刚才的链接是中文的,不知道什么原因那个工具不好用了!!我测试了下英文版的是可以的,大家还是去英文版面的吧

http://code.google.com/intl/en/apis/maps/documentation/utilities/polylineutility.html